reasonix 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -7
- package/README.zh-CN.md +2 -6
- package/dashboard/dist/app.js +348 -80
- package/dashboard/dist/app.js.map +1 -1
- package/dist/cli/chat-EIFLHBZ6.js +39 -0
- package/dist/cli/chunk-2AWTGJ2C.js +110 -0
- package/dist/cli/chunk-2AWTGJ2C.js.map +1 -0
- package/dist/cli/chunk-3Q3C4W66.js +30 -0
- package/dist/cli/chunk-3Q3C4W66.js.map +1 -0
- package/dist/cli/chunk-4DCHFFEY.js +149 -0
- package/dist/cli/chunk-4DCHFFEY.js.map +1 -0
- package/dist/cli/chunk-5X7LZJDE.js +36 -0
- package/dist/cli/chunk-5X7LZJDE.js.map +1 -0
- package/dist/cli/chunk-6TMHAK5D.js +576 -0
- package/dist/cli/chunk-6TMHAK5D.js.map +1 -0
- package/dist/cli/chunk-APPB3ZPQ.js +43 -0
- package/dist/cli/chunk-APPB3ZPQ.js.map +1 -0
- package/dist/cli/chunk-BQNUJJN7.js +42 -0
- package/dist/cli/chunk-BQNUJJN7.js.map +1 -0
- package/dist/cli/chunk-CPOV2O73.js +39 -0
- package/dist/cli/chunk-CPOV2O73.js.map +1 -0
- package/dist/cli/chunk-D5DKXIP5.js +368 -0
- package/dist/cli/chunk-D5DKXIP5.js.map +1 -0
- package/dist/cli/chunk-DFP4YSVM.js +247 -0
- package/dist/cli/chunk-DFP4YSVM.js.map +1 -0
- package/dist/cli/chunk-DULSP7JH.js +410 -0
- package/dist/cli/chunk-DULSP7JH.js.map +1 -0
- package/dist/cli/chunk-FM57FNPJ.js +46 -0
- package/dist/cli/chunk-FM57FNPJ.js.map +1 -0
- package/dist/cli/chunk-FWGEHRB7.js +54 -0
- package/dist/cli/chunk-FWGEHRB7.js.map +1 -0
- package/dist/cli/chunk-FXGQ5NHE.js +513 -0
- package/dist/cli/chunk-FXGQ5NHE.js.map +1 -0
- package/dist/cli/chunk-G3XNWSFN.js +53 -0
- package/dist/cli/chunk-G3XNWSFN.js.map +1 -0
- package/dist/cli/chunk-I6YIAK6C.js +757 -0
- package/dist/cli/chunk-I6YIAK6C.js.map +1 -0
- package/dist/cli/chunk-J5VLP23S.js +94 -0
- package/dist/cli/chunk-J5VLP23S.js.map +1 -0
- package/dist/cli/chunk-KMWKGPFZ.js +303 -0
- package/dist/cli/chunk-KMWKGPFZ.js.map +1 -0
- package/dist/cli/chunk-LVQX5KGF.js +14934 -0
- package/dist/cli/chunk-LVQX5KGF.js.map +1 -0
- package/dist/cli/chunk-MHDNZXJJ.js +48 -0
- package/dist/cli/chunk-MHDNZXJJ.js.map +1 -0
- package/dist/cli/chunk-ORM6PK57.js +140 -0
- package/dist/cli/chunk-ORM6PK57.js.map +1 -0
- package/dist/cli/chunk-Q5GRLZJF.js +99 -0
- package/dist/cli/chunk-Q5GRLZJF.js.map +1 -0
- package/dist/cli/chunk-Q6YFXW7H.js +4986 -0
- package/dist/cli/chunk-Q6YFXW7H.js.map +1 -0
- package/dist/cli/chunk-QGE6AF76.js +1467 -0
- package/dist/cli/chunk-QGE6AF76.js.map +1 -0
- package/dist/cli/chunk-RFX7TYVV.js +28 -0
- package/dist/cli/chunk-RFX7TYVV.js.map +1 -0
- package/dist/cli/chunk-RZILUXUC.js +940 -0
- package/dist/cli/chunk-RZILUXUC.js.map +1 -0
- package/dist/cli/chunk-SDE5U32Z.js +535 -0
- package/dist/cli/chunk-SDE5U32Z.js.map +1 -0
- package/dist/cli/chunk-SOZE7V7V.js +340 -0
- package/dist/cli/chunk-SOZE7V7V.js.map +1 -0
- package/dist/cli/chunk-U3V2ZQ5J.js +479 -0
- package/dist/cli/chunk-U3V2ZQ5J.js.map +1 -0
- package/dist/cli/chunk-W4LDFAZ6.js +1544 -0
- package/dist/cli/chunk-W4LDFAZ6.js.map +1 -0
- package/dist/cli/chunk-WBDE4IRI.js +208 -0
- package/dist/cli/chunk-WBDE4IRI.js.map +1 -0
- package/dist/cli/chunk-XHQIK7B6.js +189 -0
- package/dist/cli/chunk-XHQIK7B6.js.map +1 -0
- package/dist/cli/chunk-XJLZ4HKU.js +307 -0
- package/dist/cli/chunk-XJLZ4HKU.js.map +1 -0
- package/dist/cli/chunk-ZPTSJGX5.js +88 -0
- package/dist/cli/chunk-ZPTSJGX5.js.map +1 -0
- package/dist/cli/chunk-ZTLZO42A.js +231 -0
- package/dist/cli/chunk-ZTLZO42A.js.map +1 -0
- package/dist/cli/code-F4KJOE3K.js +151 -0
- package/dist/cli/code-F4KJOE3K.js.map +1 -0
- package/dist/cli/commands-JWT2MWVH.js +352 -0
- package/dist/cli/commands-JWT2MWVH.js.map +1 -0
- package/dist/cli/commit-RPZBOZS2.js +288 -0
- package/dist/cli/commit-RPZBOZS2.js.map +1 -0
- package/dist/cli/diff-NTEHCSDW.js +145 -0
- package/dist/cli/diff-NTEHCSDW.js.map +1 -0
- package/dist/cli/doctor-3TGB2NZN.js +19 -0
- package/dist/cli/doctor-3TGB2NZN.js.map +1 -0
- package/dist/cli/events-P27CX7LN.js +338 -0
- package/dist/cli/events-P27CX7LN.js.map +1 -0
- package/dist/cli/index.js +83 -34028
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-ARTNQ24O.js +266 -0
- package/dist/cli/mcp-ARTNQ24O.js.map +1 -0
- package/dist/cli/mcp-browse-HLO2ENDL.js +163 -0
- package/dist/cli/mcp-browse-HLO2ENDL.js.map +1 -0
- package/dist/cli/mcp-inspect-T2HBR22P.js +103 -0
- package/dist/cli/mcp-inspect-T2HBR22P.js.map +1 -0
- package/dist/cli/{prompt-XHICFAYN.js → prompt-V47QKSAR.js} +3 -2
- package/dist/cli/prompt-V47QKSAR.js.map +1 -0
- package/dist/cli/prune-sessions-ERL6B4G5.js +42 -0
- package/dist/cli/prune-sessions-ERL6B4G5.js.map +1 -0
- package/dist/cli/replay-TMJASRC4.js +273 -0
- package/dist/cli/replay-TMJASRC4.js.map +1 -0
- package/dist/cli/run-JMEOTQCG.js +215 -0
- package/dist/cli/run-JMEOTQCG.js.map +1 -0
- package/dist/cli/server-SYC3OVOP.js +2967 -0
- package/dist/cli/server-SYC3OVOP.js.map +1 -0
- package/dist/cli/sessions-MOJAALJI.js +102 -0
- package/dist/cli/sessions-MOJAALJI.js.map +1 -0
- package/dist/cli/setup-CCJZAWTY.js +404 -0
- package/dist/cli/setup-CCJZAWTY.js.map +1 -0
- package/dist/cli/stats-5RJCATCE.js +12 -0
- package/dist/cli/stats-5RJCATCE.js.map +1 -0
- package/dist/cli/update-4TJWRUIN.js +90 -0
- package/dist/cli/update-4TJWRUIN.js.map +1 -0
- package/dist/cli/version-3MYFE4G6.js +29 -0
- package/dist/cli/version-3MYFE4G6.js.map +1 -0
- package/dist/index.d.ts +49 -96
- package/dist/index.js +567 -759
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/chunk-VWFJNLIK.js +0 -1031
- package/dist/cli/chunk-VWFJNLIK.js.map +0 -1
- /package/dist/cli/{prompt-XHICFAYN.js.map → chat-EIFLHBZ6.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -294,165 +294,6 @@ var DeepSeekClient = class {
|
|
|
294
294
|
}
|
|
295
295
|
};
|
|
296
296
|
|
|
297
|
-
// src/harvest.ts
|
|
298
|
-
function emptyPlanState() {
|
|
299
|
-
return { subgoals: [], hypotheses: [], uncertainties: [], rejectedPaths: [] };
|
|
300
|
-
}
|
|
301
|
-
function isPlanStateEmpty(s) {
|
|
302
|
-
if (!s) return true;
|
|
303
|
-
return s.subgoals.length === 0 && s.hypotheses.length === 0 && s.uncertainties.length === 0 && s.rejectedPaths.length === 0;
|
|
304
|
-
}
|
|
305
|
-
var SYSTEM_PROMPT = `You extract a typed plan state from a reasoning trace produced by another LLM.
|
|
306
|
-
Output ONLY a JSON object. No markdown, no prose, no backticks.
|
|
307
|
-
|
|
308
|
-
Schema:
|
|
309
|
-
{
|
|
310
|
-
"subgoals": string[], // concrete intermediate objectives the trace identifies
|
|
311
|
-
"hypotheses": string[], // candidate approaches or assumptions being weighed
|
|
312
|
-
"uncertainties": string[], // facts the trace flags as unclear / to verify
|
|
313
|
-
"rejectedPaths": string[] // approaches the trace considered and then abandoned
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
Constraints:
|
|
317
|
-
- Every field must be present. Use [] if not applicable.
|
|
318
|
-
- Each array has at most {maxItems} items.
|
|
319
|
-
- Each item is plain text, at most {maxItemLen} characters, no markdown.
|
|
320
|
-
- Write in the same language as the trace (Chinese in \u2192 Chinese out, etc.).
|
|
321
|
-
- Do not quote back the trace; write short, specific phrases.`;
|
|
322
|
-
async function harvest(reasoningContent, client, options = {}, signal) {
|
|
323
|
-
if (!client || !reasoningContent) return emptyPlanState();
|
|
324
|
-
if (signal?.aborted) return emptyPlanState();
|
|
325
|
-
const minLen = options.minReasoningLen ?? 40;
|
|
326
|
-
const trimmed = reasoningContent.trim();
|
|
327
|
-
if (trimmed.length < minLen) return emptyPlanState();
|
|
328
|
-
const model = options.model ?? "deepseek-v4-flash";
|
|
329
|
-
const maxItems = options.maxItems ?? 5;
|
|
330
|
-
const maxItemLen = options.maxItemLen ?? 80;
|
|
331
|
-
const system = SYSTEM_PROMPT.replace("{maxItems}", String(maxItems)).replace(
|
|
332
|
-
"{maxItemLen}",
|
|
333
|
-
String(maxItemLen)
|
|
334
|
-
);
|
|
335
|
-
try {
|
|
336
|
-
const resp = await client.chat({
|
|
337
|
-
model,
|
|
338
|
-
messages: [
|
|
339
|
-
{ role: "system", content: system },
|
|
340
|
-
{ role: "user", content: trimmed }
|
|
341
|
-
],
|
|
342
|
-
responseFormat: { type: "json_object" },
|
|
343
|
-
temperature: 0,
|
|
344
|
-
maxTokens: 600,
|
|
345
|
-
// Pin mode + effort so a future default-model swap (e.g. someone
|
|
346
|
-
// sets `options.model = "deepseek-v4-pro"`) can't accidentally
|
|
347
|
-
// turn this micro-extraction into a multi-thousand-reasoning-
|
|
348
|
-
// token call. DeepSeek ignores these on non-thinking models, so
|
|
349
|
-
// the request stays valid regardless of the chosen model.
|
|
350
|
-
thinking: "disabled",
|
|
351
|
-
reasoningEffort: "high",
|
|
352
|
-
signal
|
|
353
|
-
});
|
|
354
|
-
return parsePlanState(resp.content, maxItems, maxItemLen);
|
|
355
|
-
} catch {
|
|
356
|
-
return emptyPlanState();
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
function parsePlanState(raw, maxItems, maxItemLen) {
|
|
360
|
-
const text = (raw ?? "").trim();
|
|
361
|
-
if (!text) return emptyPlanState();
|
|
362
|
-
let parsed;
|
|
363
|
-
try {
|
|
364
|
-
parsed = JSON.parse(text);
|
|
365
|
-
} catch {
|
|
366
|
-
const match = text.match(/\{[\s\S]*\}/);
|
|
367
|
-
if (!match) return emptyPlanState();
|
|
368
|
-
try {
|
|
369
|
-
parsed = JSON.parse(match[0]);
|
|
370
|
-
} catch {
|
|
371
|
-
return emptyPlanState();
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (!parsed || typeof parsed !== "object") return emptyPlanState();
|
|
375
|
-
const obj = parsed;
|
|
376
|
-
return {
|
|
377
|
-
subgoals: sanitizeArray(obj.subgoals, maxItems, maxItemLen),
|
|
378
|
-
hypotheses: sanitizeArray(obj.hypotheses, maxItems, maxItemLen),
|
|
379
|
-
uncertainties: sanitizeArray(obj.uncertainties, maxItems, maxItemLen),
|
|
380
|
-
rejectedPaths: sanitizeArray(obj.rejectedPaths ?? obj.rejected_paths, maxItems, maxItemLen)
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
function sanitizeArray(raw, maxItems, maxItemLen) {
|
|
384
|
-
if (!Array.isArray(raw)) return [];
|
|
385
|
-
const out = [];
|
|
386
|
-
for (const item of raw) {
|
|
387
|
-
if (out.length >= maxItems) break;
|
|
388
|
-
if (typeof item !== "string") continue;
|
|
389
|
-
const cleaned = item.trim().replace(/\s+/g, " ");
|
|
390
|
-
if (!cleaned) continue;
|
|
391
|
-
out.push(cleaned.length <= maxItemLen ? cleaned : `${cleaned.slice(0, maxItemLen - 1)}\u2026`);
|
|
392
|
-
}
|
|
393
|
-
return out;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// src/consistency.ts
|
|
397
|
-
var defaultSelector = (samples) => {
|
|
398
|
-
if (samples.length === 0) throw new Error("defaultSelector: samples is empty");
|
|
399
|
-
return samples.slice().sort((a, b) => {
|
|
400
|
-
const uDiff = a.planState.uncertainties.length - b.planState.uncertainties.length;
|
|
401
|
-
if (uDiff !== 0) return uDiff;
|
|
402
|
-
const aLen = a.response.content?.length ?? 0;
|
|
403
|
-
const bLen = b.response.content?.length ?? 0;
|
|
404
|
-
return aLen - bLen;
|
|
405
|
-
})[0];
|
|
406
|
-
};
|
|
407
|
-
async function runBranches(client, request, opts = {}) {
|
|
408
|
-
const budget = Math.max(1, opts.budget ?? 1);
|
|
409
|
-
const temperatures = resolveTemperatures(budget, opts.temperatures);
|
|
410
|
-
const selector = opts.selector ?? defaultSelector;
|
|
411
|
-
const samples = await Promise.all(
|
|
412
|
-
temperatures.map(async (temperature, index) => {
|
|
413
|
-
const response = await client.chat({ ...request, temperature });
|
|
414
|
-
const planState = await harvest(response.reasoningContent, client, opts.harvestOptions);
|
|
415
|
-
const sample = { index, temperature, response, planState };
|
|
416
|
-
try {
|
|
417
|
-
opts.onSampleDone?.(sample);
|
|
418
|
-
} catch {
|
|
419
|
-
}
|
|
420
|
-
return sample;
|
|
421
|
-
})
|
|
422
|
-
);
|
|
423
|
-
return { chosen: selector(samples), samples };
|
|
424
|
-
}
|
|
425
|
-
function aggregateBranchUsage(samples) {
|
|
426
|
-
let promptTokens = 0;
|
|
427
|
-
let completionTokens = 0;
|
|
428
|
-
let totalTokens = 0;
|
|
429
|
-
let promptCacheHitTokens = 0;
|
|
430
|
-
let promptCacheMissTokens = 0;
|
|
431
|
-
for (const s of samples) {
|
|
432
|
-
promptTokens += s.response.usage.promptTokens;
|
|
433
|
-
completionTokens += s.response.usage.completionTokens;
|
|
434
|
-
totalTokens += s.response.usage.totalTokens;
|
|
435
|
-
promptCacheHitTokens += s.response.usage.promptCacheHitTokens;
|
|
436
|
-
promptCacheMissTokens += s.response.usage.promptCacheMissTokens;
|
|
437
|
-
}
|
|
438
|
-
return {
|
|
439
|
-
promptTokens,
|
|
440
|
-
completionTokens,
|
|
441
|
-
totalTokens,
|
|
442
|
-
promptCacheHitTokens,
|
|
443
|
-
promptCacheMissTokens
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
function resolveTemperatures(budget, custom) {
|
|
447
|
-
if (custom && custom.length >= budget) return [...custom.slice(0, budget)];
|
|
448
|
-
if (budget === 1) return [0];
|
|
449
|
-
const out = [];
|
|
450
|
-
for (let i = 0; i < budget; i++) {
|
|
451
|
-
out.push(Number((i / (budget - 1)).toFixed(2)));
|
|
452
|
-
}
|
|
453
|
-
return out;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
297
|
// src/core/pause-gate.ts
|
|
457
298
|
var PauseGate = class {
|
|
458
299
|
_nextId = 0;
|
|
@@ -775,21 +616,16 @@ var EN = {
|
|
|
775
616
|
resumeHint: "force-resume the named session (even if idle)",
|
|
776
617
|
newHint: "force a fresh session (ignore --session / --continue)",
|
|
777
618
|
transcriptHint: "path to write the JSONL transcript",
|
|
778
|
-
harvestHint: "opt into Pillar-2 plan-state extraction (costs +1 flash call per turn)",
|
|
779
619
|
budgetHint: "session USD cap \u2014 warns at 80%, refuses next turn at 100%",
|
|
780
620
|
modelIdHint: "DeepSeek model id (e.g. deepseek-v4-flash)",
|
|
781
621
|
systemPromptHint: "override the default system prompt",
|
|
782
622
|
presetHint: "model bundle \u2014 auto|flash|pro",
|
|
783
|
-
harvestOptInHint: "opt into Pillar-2 plan-state extraction",
|
|
784
|
-
branchHint: "run N parallel samples per turn (N>=2, manual only)",
|
|
785
623
|
sessionNameHint: "session name (default: 'default')",
|
|
786
624
|
ephemeralHint: "disable session persistence for this run",
|
|
787
625
|
mcpSpecHint: "MCP server spec (repeatable)",
|
|
788
626
|
mcpPrefixHint: "prefix MCP tool names with this string",
|
|
789
627
|
noConfigHint: "ignore ~/.reasonix/config.json for this run",
|
|
790
628
|
presetHintShort: "model bundle \u2014 auto|flash|pro",
|
|
791
|
-
harvestHintShort: "Pillar-2 plan-state extraction",
|
|
792
|
-
branchHintShort: "parallel samples per turn (N>=2)",
|
|
793
629
|
budgetHintShort: "session USD cap",
|
|
794
630
|
transcriptHintShort: "JSONL transcript path",
|
|
795
631
|
mcpSpecHintShort: "MCP server spec (repeatable)",
|
|
@@ -847,12 +683,6 @@ var EN = {
|
|
|
847
683
|
success: "Language switched to English.",
|
|
848
684
|
unsupported: "Unsupported language code: {code}. Supported: {supported}."
|
|
849
685
|
},
|
|
850
|
-
harvest: { description: "toggle Pillar-2 plan-state extraction", argsHint: "[on|off]" },
|
|
851
|
-
branch: { description: "run N parallel samples per turn (N>=2)", argsHint: "<N|off>" },
|
|
852
|
-
effort: {
|
|
853
|
-
description: "reasoning_effort cap \u2014 max is default (agent-class), high is cheaper/faster",
|
|
854
|
-
argsHint: "<high|max>"
|
|
855
|
-
},
|
|
856
686
|
pro: {
|
|
857
687
|
description: "arm v4-pro for the NEXT turn only (one-shot \xB7 auto-disarms after turn)",
|
|
858
688
|
argsHint: "[off]"
|
|
@@ -870,7 +700,6 @@ var EN = {
|
|
|
870
700
|
description: "browse + fetch MCP prompts (no arg \u2192 list names; <name> \u2192 render prompt)",
|
|
871
701
|
argsHint: "[name]"
|
|
872
702
|
},
|
|
873
|
-
tool: { description: "dump full output of the Nth tool call (1=latest)", argsHint: "[N]" },
|
|
874
703
|
memory: {
|
|
875
704
|
description: "show / manage pinned memory (REASONIX.md + ~/.reasonix/memory)",
|
|
876
705
|
argsHint: "[list|show <name>|forget <name>|clear <scope> confirm]"
|
|
@@ -900,7 +729,6 @@ var EN = {
|
|
|
900
729
|
argsHint: "[text]"
|
|
901
730
|
},
|
|
902
731
|
doctor: { description: "health check (api / config / api-reach / index / hooks / project)" },
|
|
903
|
-
think: { description: "dump the last turn's full R1 reasoning (reasoner only)" },
|
|
904
732
|
context: { description: "show context-window breakdown (system / tools / log / input)" },
|
|
905
733
|
retry: { description: "truncate & resend your last message (fresh sample)" },
|
|
906
734
|
compact: {
|
|
@@ -914,12 +742,6 @@ var EN = {
|
|
|
914
742
|
argsHint: "[N]"
|
|
915
743
|
},
|
|
916
744
|
sessions: { description: "list saved sessions (current marked with \u25B8)" },
|
|
917
|
-
rename: { description: "rename the current session on disk", argsHint: "<new-name>" },
|
|
918
|
-
resume: {
|
|
919
|
-
description: "show the launch command to resume a saved session",
|
|
920
|
-
argsHint: "<name>"
|
|
921
|
-
},
|
|
922
|
-
forget: { description: "delete the current session from disk" },
|
|
923
745
|
setup: { description: "reminds you to exit and run `reasonix setup`" },
|
|
924
746
|
semantic: {
|
|
925
747
|
description: "show semantic_search status \u2014 built? Ollama installed? how to enable"
|
|
@@ -965,9 +787,6 @@ var EN = {
|
|
|
965
787
|
description: "toggle read-only plan mode (writes bounced until submit_plan + approval)",
|
|
966
788
|
argsHint: "[on|off]"
|
|
967
789
|
},
|
|
968
|
-
"apply-plan": {
|
|
969
|
-
description: "force-approve a pending / in-text plan (fallback if picker was missed)"
|
|
970
|
-
},
|
|
971
790
|
mode: {
|
|
972
791
|
description: "edit-gate: review (queue) \xB7 auto (apply+undo) \xB7 yolo (apply+auto-shell). Shift+Tab cycles.",
|
|
973
792
|
argsHint: "[review|auto|yolo]"
|
|
@@ -1111,49 +930,8 @@ var EN = {
|
|
|
1111
930
|
},
|
|
1112
931
|
handlers: {
|
|
1113
932
|
basic: {
|
|
1114
|
-
clearInfo: "\u25B8 terminal cleared (viewport + scrollback). Context (message log) is intact \u2014 next turn still sees everything. Use /new to start fresh, or /forget to delete the session entirely.",
|
|
1115
933
|
newInfo: "\u25B8 new conversation \u2014 dropped {count} message(s) from context. Same session, fresh slate.",
|
|
1116
934
|
helpTitle: "Commands:",
|
|
1117
|
-
helpHelp: " /help this message",
|
|
1118
|
-
helpKeys: " /keys keyboard shortcuts + prompt prefixes (!, @, /)",
|
|
1119
|
-
helpStatus: " /status show current settings",
|
|
1120
|
-
helpPreset: " /preset <auto|flash|pro> model bundle \u2014 see below",
|
|
1121
|
-
helpModel: " /model <id> deepseek-v4-flash or deepseek-v4-pro",
|
|
1122
|
-
helpPro: " /pro [off] arm v4-pro for NEXT turn only (one-shot, auto-disarms)",
|
|
1123
|
-
helpHarvest: " /harvest [on|off] Pillar 2: structured plan-state extraction (OPT-IN \u2014 costs extra)",
|
|
1124
|
-
helpBranch: " /branch <N|off> run N parallel samples (N>=2) \u2014 MANUAL ONLY, N\xD7 cost",
|
|
1125
|
-
helpEffort: " /effort <high|max> reasoning_effort cap (max=full thinking, high=cheaper/faster)",
|
|
1126
|
-
helpMcp: " /mcp list MCP servers + tools attached to this session",
|
|
1127
|
-
helpResource: " /resource [uri] browse + read MCP resources (no arg \u2192 list URIs; <uri> \u2192 fetch)",
|
|
1128
|
-
helpPrompt: " /prompt [name] browse + fetch MCP prompts (no arg \u2192 list names; <name> \u2192 render)",
|
|
1129
|
-
helpCompact: " /compact fold older turns into a summary (cache-safe; auto-fires at 50% ctx)",
|
|
1130
|
-
helpThink: " /think dump the most recent turn's full R1 reasoning (reasoner only)",
|
|
1131
|
-
helpTool: " /tool [N] list tool calls (or dump full output of #N, 1=most recent)",
|
|
1132
|
-
helpCost: " /cost [text] bare \u2192 last turn's spend; with text \u2192 estimate cost of sending it next",
|
|
1133
|
-
helpMemory: " /memory [sub] show pinned memory (REASONIX.md + ~/.reasonix/memory).",
|
|
1134
|
-
helpMemorySub: " subs: list | show <name> | forget <name> | clear <scope> confirm",
|
|
1135
|
-
helpSkill: " /skill [sub] list / run user skills (project/.reasonix/skills + ~/.reasonix/skills).",
|
|
1136
|
-
helpSkillSub: " subs: list | show <name> | <name> [args] (injects skill body as user turn)",
|
|
1137
|
-
helpRetry: " /retry truncate & resend your last message (fresh sample from the model)",
|
|
1138
|
-
helpApply: " /apply [N|1,3|1-4] (code mode) commit pending edit blocks (no arg \u2192 all; index \u2192 subset)",
|
|
1139
|
-
helpDiscard: " /discard [N|1,3|1-4] (code mode) drop pending edits (no arg \u2192 all; index \u2192 subset)",
|
|
1140
|
-
helpWalk: " /walk (code mode) step through pending edits one block at a time (y/n per block, a apply rest, A flip AUTO)",
|
|
1141
|
-
helpUndo: " /undo (code mode) roll back the latest non-undone edit batch",
|
|
1142
|
-
helpHistory: " /history (code mode) list every edit batch this session",
|
|
1143
|
-
helpShow: " /show [id] (code mode) dump a stored edit diff (newest when id omitted)",
|
|
1144
|
-
helpCommit: ' /commit "msg" (code mode) git add -A && git commit -m "msg"',
|
|
1145
|
-
helpPlan: " /plan [on|off] (code mode) toggle read-only plan mode; writes gated behind submit_plan + your approval",
|
|
1146
|
-
helpApplyPlan: " /apply-plan (code mode) force-approve pending/in-text plan (fallback)",
|
|
1147
|
-
helpMode: " /mode [review|auto|yolo] (code mode) review = queue \xB7 auto = apply+undo banner \xB7 yolo = apply+auto-shell. Shift+Tab cycles all three.",
|
|
1148
|
-
helpJobs: " /jobs (code mode) list background processes (run_background) \u2014 running and exited",
|
|
1149
|
-
helpKill: " /kill <id> (code mode) stop a background job by id (SIGTERM \u2192 SIGKILL)",
|
|
1150
|
-
helpLogs: " /logs <id> [lines] (code mode) tail a background job's output (default 80 lines)",
|
|
1151
|
-
helpSessions: " /sessions list saved sessions (current is marked with \u25B8)",
|
|
1152
|
-
helpForget: " /forget delete the current session from disk",
|
|
1153
|
-
helpNew: " /new start fresh: drop all context + clear scrollback",
|
|
1154
|
-
helpClear: " /clear clear displayed scrollback only (context kept \u2014 model still sees it)",
|
|
1155
|
-
helpLoop: " /loop <interval> <prompt> auto-resubmit <prompt> every <interval> (5s..6h). /loop stop \xB7 type anything to cancel.",
|
|
1156
|
-
helpExit: " /exit quit (aliases: /quit, /q)",
|
|
1157
935
|
helpShellTitle: "Shell shortcut:",
|
|
1158
936
|
helpShell: " !<cmd> run <cmd> in the sandbox root; output goes into",
|
|
1159
937
|
helpShellDetail: " the conversation so the model sees it next turn.",
|
|
@@ -1180,46 +958,6 @@ var EN = {
|
|
|
1180
958
|
helpSessionsTitle: "Sessions (auto-enabled by default, named 'default'):",
|
|
1181
959
|
helpSessionCustom: " reasonix chat --session <name> use a different named session",
|
|
1182
960
|
helpSessionNone: " reasonix chat --no-session disable persistence for this run",
|
|
1183
|
-
helpLimitationTitle: "Known limitation:",
|
|
1184
|
-
helpLimitation1: " Resizing the terminal mid-session may stack ghost header frames in",
|
|
1185
|
-
helpLimitation2: " scrollback (Ink library's live-region clear doesn't account for line",
|
|
1186
|
-
helpLimitation3: " re-wrapping at the new width). Scroll-up history is unaffected; the",
|
|
1187
|
-
helpLimitation4: " artifact is purely visual and clears the next time you /clear.",
|
|
1188
|
-
keysTitle: "Keyboard & prompt shortcuts:",
|
|
1189
|
-
keysEnter: " Enter submit the current prompt",
|
|
1190
|
-
keysNewline: " Shift+Enter / Ctrl+J insert a newline (multi-line prompt)",
|
|
1191
|
-
keysContinue: " \\<Enter> bash-style line continuation",
|
|
1192
|
-
keysArrow: " \u2190 \u2192 \u2191 \u2193 move cursor / recall history at buffer boundary",
|
|
1193
|
-
keysPage: " PageUp / PageDown jump to top / bottom of the WHOLE buffer (handy after a big paste)",
|
|
1194
|
-
keysHomeEnd: " Ctrl+A / Ctrl+E jump to start / end of the CURRENT line",
|
|
1195
|
-
keysClearLine: " Ctrl+U clear the entire input buffer",
|
|
1196
|
-
keysDeleteWord: " Ctrl+W delete the word before the cursor",
|
|
1197
|
-
keysBackspace: " Backspace delete left; Delete delete under cursor",
|
|
1198
|
-
keysEsc: " Esc abort the in-flight turn",
|
|
1199
|
-
keysEditYn: " y / n accept / reject pending edits (code mode)",
|
|
1200
|
-
keysEditTab: " Shift+Tab cycle edit gate: review \u2194 AUTO (code mode, persists to config)",
|
|
1201
|
-
keysEditUndo: " u undo the latest non-undone edit batch (session-wide, not just banner)",
|
|
1202
|
-
keysPromptTitle: "Prompt prefixes:",
|
|
1203
|
-
keysSlash: " /<name> slash command; Tab/Enter picks from the suggestion list",
|
|
1204
|
-
keysAtFile: " @<path> inline a file under [Referenced files] (code mode).",
|
|
1205
|
-
keysAtFilePicker: " Trailing `@\u2026` opens a file picker; \u2191/\u2193 navigate, Tab/Enter pick.",
|
|
1206
|
-
keysAtUrl: " @https://... fetch the URL, strip HTML, inline under [Referenced URLs].",
|
|
1207
|
-
keysAtUrlCache: " Cached per session \u2014 same URL twice fetches once.",
|
|
1208
|
-
keysBang: " !<cmd> run <cmd> as shell in the sandbox root; output goes into context",
|
|
1209
|
-
keysBangDetail: " so the model sees it next turn. No allowlist gate.",
|
|
1210
|
-
keysHash: " #<note> append <note> to <project>/REASONIX.md (committable, team-shared).",
|
|
1211
|
-
keysHashGlobal: " #g <note> append <note> to ~/.reasonix/REASONIX.md (global, never committed).",
|
|
1212
|
-
keysHashBoth: " Both pin into the immutable prefix every future session.",
|
|
1213
|
-
keysHashEscape: " Use `\\#literal` if you actually want a `#` heading sent to the model.",
|
|
1214
|
-
keysPickersTitle: "Pickers (slash + @-mention):",
|
|
1215
|
-
keysPickerNav: " \u2191 / \u2193 navigate the suggestion list",
|
|
1216
|
-
keysPickerTab: " Tab insert the highlighted item without submitting",
|
|
1217
|
-
keysPickerEnter: " Enter insert and (slash) run it, (@) keep editing",
|
|
1218
|
-
keysMcpTitle: "MCP exploration:",
|
|
1219
|
-
keysMcpServers: " /mcp servers + tool/resource/prompt counts",
|
|
1220
|
-
keysMcpResource: " /resource [uri] browse & read resources exposed by your MCP servers",
|
|
1221
|
-
keysMcpPrompt: " /prompt [name] browse & fetch prompts exposed by your MCP servers",
|
|
1222
|
-
keysUseful: "Useful slashes: /help \xB7 /context \xB7 /stats \xB7 /compact \xB7 /new \xB7 /exit",
|
|
1223
961
|
retryNone: "nothing to retry \u2014 no prior user message in this session's log.",
|
|
1224
962
|
retryInfo: '\u25B8 retrying: "{preview}"',
|
|
1225
963
|
loopTuiOnly: "/loop is only available in the interactive TUI (not in run/replay).",
|
|
@@ -1269,9 +1007,6 @@ var EN = {
|
|
|
1269
1007
|
planCodeOnly: "/plan is only available inside `reasonix code` \u2014 chat mode doesn't gate tool writes.",
|
|
1270
1008
|
planOn: "\u25B8 plan mode ON \u2014 write tools are gated; the model MUST call `submit_plan` before anything executes. (The model can also call submit_plan on its own for big tasks even when plan mode is off \u2014 this toggle is the stronger, explicit constraint.) Type /plan off to leave.",
|
|
1271
1009
|
planOff: "\u25B8 plan mode OFF \u2014 write tools are live again. Model can still propose plans autonomously for large tasks.",
|
|
1272
|
-
applyPlanCodeOnly: "/apply-plan is only available inside `reasonix code`.",
|
|
1273
|
-
applyPlanInfo: "\u25B8 plan approved \u2014 implementing",
|
|
1274
|
-
applyPlanResubmit: "The plan above has been approved. Implement it now. You are out of plan mode \u2014 use edit_file / write_file / run_command as needed. Stick to the plan unless you discover a concrete reason to deviate; if you do, tell me and wait for a response before making that deviation.",
|
|
1275
1010
|
modeCodeOnly: "/mode is only available inside `reasonix code`.",
|
|
1276
1011
|
modeUsage: "usage: /mode <review|auto|yolo> (Shift+Tab also cycles)",
|
|
1277
1012
|
modeYolo: "\u25B8 edit mode: YOLO \u2014 edits AND shell commands auto-run with no prompt. /undo still rolls back edits. Use carefully.",
|
|
@@ -1297,31 +1032,20 @@ var EN = {
|
|
|
1297
1032
|
restoreInfo: '\u25B8 restored "{name}" ({id}) from {when}',
|
|
1298
1033
|
restoreWrote: " \xB7 wrote back {count} file{s}",
|
|
1299
1034
|
restoreRemoved: " \xB7 removed {count} file{s} (didn't exist at checkpoint time)",
|
|
1300
|
-
restoreSkipped: " \u2717 {count} file{s} skipped:"
|
|
1035
|
+
restoreSkipped: " \u2717 {count} file{s} skipped:",
|
|
1036
|
+
cwdCodeOnly: "/cwd is only available inside `reasonix code`.",
|
|
1037
|
+
cwdUsage: "usage: /cwd <path> (current root: {current}). Re-points filesystem / shell / memory tools to <path>.",
|
|
1038
|
+
cwdUsageNoCurrent: "usage: /cwd <path> re-points the workspace root to <path>."
|
|
1301
1039
|
},
|
|
1302
1040
|
model: {
|
|
1303
1041
|
modelHint: "try deepseek-v4-flash or deepseek-v4-pro \u2014 run /models to fetch the live list",
|
|
1304
1042
|
modelUsage: "usage: /model <id> ({hint})",
|
|
1305
1043
|
modelNotInCatalog: "model \u2192 {id} (\u26A0 not in the fetched catalog: {list}. If this is wrong the next call will 400 \u2014 run /models to refresh.)",
|
|
1306
1044
|
modelSet: "model \u2192 {id}",
|
|
1307
|
-
modelsFetching: "fetching /models from DeepSeek\u2026 run /models again in a moment. If it stays empty, your API key may lack permission or the network is blocked.",
|
|
1308
|
-
modelsEmpty: "DeepSeek /models returned an empty list. Try /models again, or check your account status at api-docs.deepseek.com.",
|
|
1309
|
-
modelsHeader: "Available models (DeepSeek /models \xB7 {count} total):",
|
|
1310
|
-
modelsCurrent: "\u25B8 {id} (current)",
|
|
1311
|
-
modelsSwitch: "Switch with: /model <id>",
|
|
1312
|
-
harvestOn: "harvest \u2192 on (Pillar-2 plan-state extraction \xB7 +1 cheap flash call per turn \xB7 opt-in only; no preset turns it on)",
|
|
1313
|
-
harvestOff: "harvest \u2192 off",
|
|
1314
1045
|
presetAuto: "preset \u2192 auto (v4-flash \u2192 v4-pro on hard turns \xB7 default)",
|
|
1315
1046
|
presetFlash: "preset \u2192 flash (v4-flash always \xB7 cheapest \xB7 /pro still bumps one turn)",
|
|
1316
1047
|
presetPro: "preset \u2192 pro (v4-pro always \xB7 ~3\xD7 flash \xB7 for hard multi-turn work)",
|
|
1317
1048
|
presetUsage: "usage: /preset <auto|flash|pro>",
|
|
1318
|
-
branchOff: "branch \u2192 off",
|
|
1319
|
-
branchUsage: "usage: /branch <N> (N>=2, or 'off')",
|
|
1320
|
-
branchCapped: "branch budget capped at 8 to prevent runaway cost",
|
|
1321
|
-
branchSet: "branch \u2192 {n} (runs {n} parallel samples per turn \xB7 {n}\xD7 per-turn cost \xB7 streaming disabled \xB7 manual only, no preset enables branching)",
|
|
1322
|
-
effortStatus: "reasoning_effort \u2192 {effort} (use /effort high for cheaper/faster, /effort max for the agent-class default \xB7 persisted across relaunches)",
|
|
1323
|
-
effortUsage: "usage: /effort <high|max>",
|
|
1324
|
-
effortSet: "reasoning_effort \u2192 {effort} (persisted)",
|
|
1325
1049
|
proNothingArmed: "nothing armed \u2014 /pro with no args will arm pro for your next turn",
|
|
1326
1050
|
proDisarmed: "\u25B8 /pro disarmed \u2014 next turn falls back to the current preset",
|
|
1327
1051
|
proUsage: "usage: /pro arm pro for the next turn (one-shot, auto-disarms after)\n /pro off cancel armed state before the next turn",
|
|
@@ -1333,18 +1057,6 @@ var EN = {
|
|
|
1333
1057
|
budgetExhausted: "\u25B2 budget \u2192 ${cap} but already spent ${spent}. Next turn will be refused \u2014 bump the cap higher to keep going, or end the session.",
|
|
1334
1058
|
budgetSet: "budget \u2192 ${cap} (so far: ${spent} \xB7 warns at 80%, refuses next turn at 100% \xB7 /budget off to clear)"
|
|
1335
1059
|
},
|
|
1336
|
-
sessions: {
|
|
1337
|
-
forgetNoSession: "not in a session \u2014 nothing to forget",
|
|
1338
|
-
forgetInfo: '\u25B8 deleted session "{name}" \u2014 current screen still shows the conversation, but next launch starts fresh',
|
|
1339
|
-
forgetFailed: 'could not delete session "{name}" (already gone?)',
|
|
1340
|
-
renameUsage: "usage: /rename <new-name>",
|
|
1341
|
-
renameNoSession: "not in a session \u2014 nothing to rename",
|
|
1342
|
-
renameFailed: 'could not rename \u2014 "{name}" already exists or sanitises to the same id as the current session',
|
|
1343
|
-
renameInfo: '\u25B8 renamed session \u2192 "{name}". Restart the TUI to pick it up under its new name.',
|
|
1344
|
-
resumeUsage: "usage: /resume <session-name> \u2014 list with /sessions",
|
|
1345
|
-
resumeNotFound: 'no session named "{name}" \u2014 list with /sessions',
|
|
1346
|
-
resumeInfo: '\u25B8 to resume "{name}", quit and run: reasonix chat --session {name}\n (mid-session swap requires a restart so the message log can rewind cleanly)'
|
|
1347
|
-
},
|
|
1348
1060
|
permissions: {
|
|
1349
1061
|
mutateCodeOnly: "/permissions add / remove / clear are only available inside `reasonix code` \u2014 they edit the project-scoped allowlist (`~/.reasonix/config.json` projects[<root>].shellAllowed).",
|
|
1350
1062
|
addUsage: 'usage: /permissions add <prefix> (multi-token OK: /permissions add "git push origin")',
|
|
@@ -1386,13 +1098,6 @@ var EN = {
|
|
|
1386
1098
|
starting: "\u25B8 starting dashboard server\u2026"
|
|
1387
1099
|
},
|
|
1388
1100
|
observability: {
|
|
1389
|
-
thinkEmpty: "no reasoning cached. `/think` shows the full thinking-mode thought for the most recent turn \u2014 only thinking-mode models (deepseek-v4-flash / -v4-pro / -reasoner) produce it, and only once the turn completes.",
|
|
1390
|
-
thinkInfo: "\u21B3 full thinking ({count} chars):",
|
|
1391
|
-
toolEmpty: "no tool calls yet in this session. `/tool` lists them once the model has actually used a tool; `/tool N` dumps the full (untruncated) output of the Nth-most-recent.",
|
|
1392
|
-
toolUsage: "usage: /tool [N] (no arg \u2192 list; N=1 \u2192 most recent result in full, N=2 \u2192 previous, \u2026)",
|
|
1393
|
-
toolOob: "only {count} tool call(s) in history \u2014 asked for #{n}. Try /tool with no arg to see the list.",
|
|
1394
|
-
toolNotFound: "could not read tool call #{n}",
|
|
1395
|
-
toolInfo: "\u21B3 tool<{name}> #{n} ({chars} chars):",
|
|
1396
1101
|
contextInfo: "context: ~{total} of {max} ({pct}%) \xB7 system {sys} \xB7 tools {tools} \xB7 log {log}",
|
|
1397
1102
|
compactStarting: "\u25B8 folding older turns into a summary\u2026",
|
|
1398
1103
|
compactNoop: "\u25B8 nothing to fold \u2014 log already small or recent turns alone exceed the budget.",
|
|
@@ -1406,7 +1111,7 @@ var EN = {
|
|
|
1406
1111
|
costLikely: " likely ({pct}% session cache hit): {input} input + ~{output} output \u2248 {total}",
|
|
1407
1112
|
costLikelyCold: " likely: matches worst case until cache fills (no completed turns yet)",
|
|
1408
1113
|
statusModel: " model {model}",
|
|
1409
|
-
statusFlags: " flags
|
|
1114
|
+
statusFlags: " flags stream={stream} \xB7 effort={effort}",
|
|
1410
1115
|
statusCtx: " ctx {bar} {used}/{max} ({pct}%)",
|
|
1411
1116
|
statusCtxNone: " ctx no turns yet",
|
|
1412
1117
|
statusCost: " cost ${cost} \xB7 cache {bar} {pct}% \xB7 turns {turns}",
|
|
@@ -1508,10 +1213,6 @@ var EN = {
|
|
|
1508
1213
|
existsPinned: " pinned into the system prompt every launch as-is.",
|
|
1509
1214
|
info: "\u25B8 /init \u2014 model will scan the project and synthesize REASONIX.md.\n The result lands as a pending edit; review with /apply or /walk."
|
|
1510
1215
|
},
|
|
1511
|
-
semantic: {
|
|
1512
|
-
codeOnly: "/semantic is only available inside `reasonix code` (needs a project root).",
|
|
1513
|
-
checking: "\u25B8 checking semantic_search status\u2026"
|
|
1514
|
-
},
|
|
1515
1216
|
webSearchEngine: {
|
|
1516
1217
|
currentEngine: "Current web search engine: {engine}",
|
|
1517
1218
|
endpoint: "SearXNG endpoint: {url}",
|
|
@@ -1608,21 +1309,16 @@ var zhCN = {
|
|
|
1608
1309
|
resumeHint: "\u5F3A\u5236\u6062\u590D\u6307\u5B9A\u4F1A\u8BDD\uFF08\u5373\u4F7F\u7A7A\u95F2\uFF09",
|
|
1609
1310
|
newHint: "\u5F3A\u5236\u521B\u5EFA\u65B0\u4F1A\u8BDD\uFF08\u5FFD\u7565 --session / --continue\uFF09",
|
|
1610
1311
|
transcriptHint: "JSONL \u8F6C\u5F55\u7A3F\u7684\u5199\u5165\u8DEF\u5F84",
|
|
1611
|
-
harvestHint: "\u542F\u7528 Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6\uFF08\u6BCF\u8F6E\u989D\u5916\u6D88\u8017 1 \u6B21 flash \u8C03\u7528\uFF09",
|
|
1612
1312
|
budgetHint: "\u4F1A\u8BDD\u7F8E\u5143\u4E0A\u9650 \u2014 80% \u65F6\u8B66\u544A\uFF0C100% \u65F6\u62D2\u7EDD\u4E0B\u4E00\u8F6E",
|
|
1613
1313
|
modelIdHint: "DeepSeek \u6A21\u578B ID\uFF08\u4F8B\u5982 deepseek-v4-flash\uFF09",
|
|
1614
1314
|
systemPromptHint: "\u8986\u76D6\u9ED8\u8BA4\u7CFB\u7EDF\u63D0\u793A\u8BCD",
|
|
1615
1315
|
presetHint: "\u6A21\u578B\u7EC4\u5408 \u2014 auto|flash|pro",
|
|
1616
|
-
harvestOptInHint: "\u542F\u7528 Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6",
|
|
1617
|
-
branchHint: "\u6BCF\u8F6E\u8FD0\u884C N \u4E2A\u5E76\u884C\u91C7\u6837\uFF08N>=2\uFF0C\u4EC5\u624B\u52A8\uFF09",
|
|
1618
1316
|
sessionNameHint: "\u4F1A\u8BDD\u540D\u79F0\uFF08\u9ED8\u8BA4\uFF1A'default'\uFF09",
|
|
1619
1317
|
ephemeralHint: "\u7981\u7528\u672C\u6B21\u8FD0\u884C\u7684\u4F1A\u8BDD\u6301\u4E45\u5316",
|
|
1620
1318
|
mcpSpecHint: "MCP \u670D\u52A1\u5668\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF09",
|
|
1621
1319
|
mcpPrefixHint: "\u7528\u6B64\u5B57\u7B26\u4E32\u4E3A MCP \u5DE5\u5177\u540D\u6DFB\u52A0\u524D\u7F00",
|
|
1622
1320
|
noConfigHint: "\u672C\u6B21\u8FD0\u884C\u5FFD\u7565 ~/.reasonix/config.json",
|
|
1623
1321
|
presetHintShort: "\u6A21\u578B\u7EC4\u5408 \u2014 auto|flash|pro",
|
|
1624
|
-
harvestHintShort: "Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6",
|
|
1625
|
-
branchHintShort: "\u6BCF\u8F6E\u5E76\u884C\u91C7\u6837\u6570\uFF08N>=2\uFF09",
|
|
1626
1322
|
budgetHintShort: "\u4F1A\u8BDD\u7F8E\u5143\u4E0A\u9650",
|
|
1627
1323
|
transcriptHintShort: "JSONL \u8F6C\u5F55\u7A3F\u8DEF\u5F84",
|
|
1628
1324
|
mcpSpecHintShort: "MCP \u670D\u52A1\u5668\u89C4\u683C\uFF08\u53EF\u91CD\u590D\uFF09",
|
|
@@ -1680,12 +1376,6 @@ var zhCN = {
|
|
|
1680
1376
|
success: "\u8BED\u8A00\u5DF2\u5207\u6362\u4E3A\u7B80\u4F53\u4E2D\u6587\u3002",
|
|
1681
1377
|
unsupported: "\u4E0D\u652F\u6301\u7684\u8BED\u8A00\u4EE3\u7801\uFF1A{code}\u3002\u652F\u6301\u7684\u8BED\u8A00\uFF1A{supported}\u3002"
|
|
1682
1378
|
},
|
|
1683
|
-
harvest: { description: "\u5207\u6362 Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6", argsHint: "[on|off]" },
|
|
1684
|
-
branch: { description: "\u6BCF\u8F6E\u8FD0\u884C N \u4E2A\u5E76\u884C\u91C7\u6837\uFF08N>=2\uFF09", argsHint: "<N|off>" },
|
|
1685
|
-
effort: {
|
|
1686
|
-
description: "reasoning_effort \u4E0A\u9650 \u2014 max \u4E3A\u9ED8\u8BA4\uFF08\u667A\u80FD\u4F53\u7EA7\uFF09\uFF0Chigh \u66F4\u4FBF\u5B9C/\u66F4\u5FEB",
|
|
1687
|
-
argsHint: "<high|max>"
|
|
1688
|
-
},
|
|
1689
1379
|
pro: {
|
|
1690
1380
|
description: "\u4EC5\u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 v4-pro\uFF08\u4E00\u6B21\u6027 \xB7 \u81EA\u52A8\u89E3\u9664\uFF09",
|
|
1691
1381
|
argsHint: "[off]"
|
|
@@ -1703,7 +1393,6 @@ var zhCN = {
|
|
|
1703
1393
|
description: "\u6D4F\u89C8 + \u83B7\u53D6 MCP \u63D0\u793A\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA\u540D\u79F0\uFF1B<name> \u2192 \u6E32\u67D3\u63D0\u793A\uFF09",
|
|
1704
1394
|
argsHint: "[name]"
|
|
1705
1395
|
},
|
|
1706
|
-
tool: { description: "\u8F6C\u50A8\u7B2C N \u4E2A\u5DE5\u5177\u8C03\u7528\u7684\u5B8C\u6574\u8F93\u51FA\uFF081=\u6700\u8FD1\uFF09", argsHint: "[N]" },
|
|
1707
1396
|
memory: {
|
|
1708
1397
|
description: "\u663E\u793A / \u7BA1\u7406\u56FA\u5B9A\u8BB0\u5FC6\uFF08REASONIX.md + ~/.reasonix/memory\uFF09",
|
|
1709
1398
|
argsHint: "[list|show <name>|forget <name>|clear <scope> confirm]"
|
|
@@ -1735,7 +1424,6 @@ var zhCN = {
|
|
|
1735
1424
|
doctor: {
|
|
1736
1425
|
description: "\u5065\u5EB7\u68C0\u67E5\uFF08api / config / api-reach / index / hooks / project\uFF09"
|
|
1737
1426
|
},
|
|
1738
|
-
think: { description: "\u8F6C\u50A8\u6700\u8FD1\u4E00\u8F6E\u7684\u5B8C\u6574 R1 \u63A8\u7406\uFF08\u4EC5\u63A8\u7406\u6A21\u578B\uFF09" },
|
|
1739
1427
|
context: { description: "\u663E\u793A\u4E0A\u4E0B\u6587\u7A97\u53E3\u5206\u89E3\uFF08\u7CFB\u7EDF / \u5DE5\u5177 / \u65E5\u5FD7 / \u8F93\u5165\uFF09" },
|
|
1740
1428
|
retry: { description: "\u622A\u65AD\u5E76\u91CD\u53D1\u60A8\u7684\u6700\u540E\u4E00\u6761\u6D88\u606F\uFF08\u91CD\u65B0\u91C7\u6837\uFF09" },
|
|
1741
1429
|
compact: {
|
|
@@ -1749,12 +1437,6 @@ var zhCN = {
|
|
|
1749
1437
|
argsHint: "[N]"
|
|
1750
1438
|
},
|
|
1751
1439
|
sessions: { description: "\u5217\u51FA\u5DF2\u4FDD\u5B58\u7684\u4F1A\u8BDD\uFF08\u5F53\u524D\u6807\u8BB0\u4E3A \u25B8\uFF09" },
|
|
1752
|
-
rename: { description: "\u91CD\u547D\u540D\u78C1\u76D8\u4E0A\u7684\u5F53\u524D\u4F1A\u8BDD", argsHint: "<new-name>" },
|
|
1753
|
-
resume: {
|
|
1754
|
-
description: "\u663E\u793A\u6062\u590D\u5DF2\u4FDD\u5B58\u4F1A\u8BDD\u7684\u542F\u52A8\u547D\u4EE4",
|
|
1755
|
-
argsHint: "<name>"
|
|
1756
|
-
},
|
|
1757
|
-
forget: { description: "\u4ECE\u78C1\u76D8\u5220\u9664\u5F53\u524D\u4F1A\u8BDD" },
|
|
1758
1440
|
setup: { description: "\u63D0\u9192\u60A8\u9000\u51FA\u5E76\u8FD0\u884C `reasonix setup`" },
|
|
1759
1441
|
semantic: {
|
|
1760
1442
|
description: "\u663E\u793A semantic_search \u72B6\u6001 \u2014 \u5DF2\u6784\u5EFA\uFF1FOllama \u5DF2\u5B89\u88C5\uFF1F\u5982\u4F55\u542F\u7528"
|
|
@@ -1802,9 +1484,6 @@ var zhCN = {
|
|
|
1802
1484
|
description: "\u5207\u6362\u53EA\u8BFB\u8BA1\u5212\u6A21\u5F0F\uFF08\u5199\u5165\u88AB\u5F39\u56DE\u76F4\u5230 submit_plan + \u5BA1\u6279\uFF09",
|
|
1803
1485
|
argsHint: "[on|off]"
|
|
1804
1486
|
},
|
|
1805
|
-
"apply-plan": {
|
|
1806
|
-
description: "\u5F3A\u5236\u6279\u51C6\u5F85\u5904\u7406 / \u6587\u672C\u4E2D\u7684\u8BA1\u5212\uFF08\u5982\u679C\u9519\u8FC7\u4E86\u9009\u62E9\u5668\u65F6\u7684\u56DE\u9000\uFF09"
|
|
1807
|
-
},
|
|
1808
1487
|
mode: {
|
|
1809
1488
|
description: "\u7F16\u8F91\u95E8\u63A7\uFF1Areview\uFF08\u6392\u961F\uFF09\xB7 auto\uFF08\u5E94\u7528+\u64A4\u6D88\uFF09\xB7 yolo\uFF08\u5E94\u7528+\u81EA\u52A8 shell\uFF09\u3002Shift+Tab \u5FAA\u73AF\u3002",
|
|
1810
1489
|
argsHint: "[review|auto|yolo]"
|
|
@@ -1948,49 +1627,8 @@ var zhCN = {
|
|
|
1948
1627
|
},
|
|
1949
1628
|
handlers: {
|
|
1950
1629
|
basic: {
|
|
1951
|
-
clearInfo: "\u25B8 \u7EC8\u7AEF\u5DF2\u6E05\u9664\uFF08\u89C6\u53E3 + \u6EDA\u52A8\u56DE\u653E\uFF09\u3002\u4E0A\u4E0B\u6587\uFF08\u6D88\u606F\u65E5\u5FD7\uFF09\u5B8C\u597D\u65E0\u635F \u2014 \u4E0B\u4E00\u8F6E\u4ECD\u80FD\u770B\u5230\u6240\u6709\u5185\u5BB9\u3002\u4F7F\u7528 /new \u5168\u65B0\u5F00\u59CB\uFF0C\u6216 /forget \u5220\u9664\u6574\u4E2A\u4F1A\u8BDD\u3002",
|
|
1952
1630
|
newInfo: "\u25B8 \u65B0\u5BF9\u8BDD \u2014 \u5DF2\u4ECE\u4E0A\u4E0B\u6587\u4E2D\u4E22\u5F03 {count} \u6761\u6D88\u606F\u3002\u540C\u4E00\u4F1A\u8BDD\uFF0C\u5168\u65B0\u5F00\u59CB\u3002",
|
|
1953
1631
|
helpTitle: "\u547D\u4EE4\uFF1A",
|
|
1954
|
-
helpHelp: " /help \u663E\u793A\u6B64\u6D88\u606F",
|
|
1955
|
-
helpKeys: " /keys \u952E\u76D8\u5FEB\u6377\u952E + \u63D0\u793A\u524D\u7F00 (!, @, /)",
|
|
1956
|
-
helpStatus: " /status \u663E\u793A\u5F53\u524D\u8BBE\u7F6E",
|
|
1957
|
-
helpPreset: " /preset <auto|flash|pro> \u6A21\u578B\u7EC4\u5408 \u2014 \u89C1\u4E0B\u6587",
|
|
1958
|
-
helpModel: " /model <id> deepseek-v4-flash \u6216 deepseek-v4-pro",
|
|
1959
|
-
helpPro: " /pro [off] \u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 v4-pro\uFF08\u4E00\u6B21\u6027\uFF0C\u81EA\u52A8\u89E3\u9664\uFF09",
|
|
1960
|
-
helpHarvest: " /harvest [on|off] Pillar 2\uFF1A\u7ED3\u6784\u5316\u8BA1\u5212\u72B6\u6001\u63D0\u53D6\uFF08\u53EF\u9009 \u2014 \u989D\u5916\u6536\u8D39\uFF09",
|
|
1961
|
-
helpBranch: " /branch <N|off> \u8FD0\u884C N \u4E2A\u5E76\u884C\u91C7\u6837\uFF08N>=2\uFF09\u2014 \u4EC5\u624B\u52A8\uFF0CN \u500D\u6210\u672C",
|
|
1962
|
-
helpEffort: " /effort <high|max> reasoning_effort \u4E0A\u9650\uFF08max=\u5B8C\u6574\u601D\u8003\uFF0Chigh=\u66F4\u4FBF\u5B9C/\u66F4\u5FEB\uFF09",
|
|
1963
|
-
helpMcp: " /mcp \u5217\u51FA\u9644\u52A0\u5230\u6B64\u4F1A\u8BDD\u7684 MCP \u670D\u52A1\u5668 + \u5DE5\u5177",
|
|
1964
|
-
helpResource: " /resource [uri] \u6D4F\u89C8 + \u8BFB\u53D6 MCP \u8D44\u6E90\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA URI\uFF1B<uri> \u2192 \u83B7\u53D6\uFF09",
|
|
1965
|
-
helpPrompt: " /prompt [name] \u6D4F\u89C8 + \u83B7\u53D6 MCP \u63D0\u793A\uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u51FA\u540D\u79F0\uFF1B<name> \u2192 \u6E32\u67D3\uFF09",
|
|
1966
|
-
helpCompact: " /compact \u6298\u53E0\u65E7\u8F6E\u6B21\u4E3A\u6458\u8981\uFF08cache-safe\uFF0C50% \u81EA\u52A8\u89E6\u53D1\uFF09",
|
|
1967
|
-
helpThink: " /think \u8F6C\u50A8\u6700\u8FD1\u4E00\u8F6E\u7684\u5B8C\u6574 R1 \u63A8\u7406\uFF08\u4EC5\u63A8\u7406\u6A21\u578B\uFF09",
|
|
1968
|
-
helpTool: " /tool [N] \u5217\u51FA\u5DE5\u5177\u8C03\u7528\uFF08\u6216\u8F6C\u50A8\u7B2C N \u4E2A\u7684\u5B8C\u6574\u8F93\u51FA\uFF0C1=\u6700\u8FD1\uFF09",
|
|
1969
|
-
helpCost: " /cost [text] \u7A7A \u2192 \u4E0A\u4E00\u8F6E\u82B1\u8D39\uFF1B\u5E26\u6587\u672C \u2192 \u4F30\u7B97\u53D1\u9001\u6210\u672C",
|
|
1970
|
-
helpMemory: " /memory [sub] \u663E\u793A\u56FA\u5B9A\u8BB0\u5FC6\uFF08REASONIX.md + ~/.reasonix/memory\uFF09\u3002",
|
|
1971
|
-
helpMemorySub: " \u5B50\u547D\u4EE4\uFF1Alist | show <name> | forget <name> | clear <scope> confirm",
|
|
1972
|
-
helpSkill: " /skill [sub] \u5217\u51FA / \u8FD0\u884C\u7528\u6237\u6280\u80FD\uFF08project/.reasonix/skills + ~/.reasonix/skills\uFF09\u3002",
|
|
1973
|
-
helpSkillSub: " \u5B50\u547D\u4EE4\uFF1Alist | show <name> | <name> [args]\uFF08\u5C06\u6280\u80FD\u4F53\u6CE8\u5165\u4E3A\u7528\u6237\u8F6E\u6B21\uFF09",
|
|
1974
|
-
helpRetry: " /retry \u622A\u65AD\u5E76\u91CD\u53D1\u60A8\u7684\u6700\u540E\u4E00\u6761\u6D88\u606F\uFF08\u6A21\u578B\u91CD\u65B0\u91C7\u6837\uFF09",
|
|
1975
|
-
helpApply: " /apply [N|1,3|1-4] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u63D0\u4EA4\u5F85\u5904\u7406\u7684\u7F16\u8F91\u5757\uFF08\u65E0\u53C2\u6570 \u2192 \u5168\u90E8\uFF1B\u7D22\u5F15 \u2192 \u5B50\u96C6\uFF09",
|
|
1976
|
-
helpDiscard: " /discard [N|1,3|1-4] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u4E22\u5F03\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08\u65E0\u53C2\u6570 \u2192 \u5168\u90E8\uFF1B\u7D22\u5F15 \u2192 \u5B50\u96C6\uFF09",
|
|
1977
|
-
helpWalk: " /walk \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u9010\u5757\u9010\u6B65\u5904\u7406\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08\u6BCF\u5757 y/n\uFF0Ca \u5E94\u7528\u5269\u4F59\uFF0CA \u5207\u6362 AUTO\uFF09",
|
|
1978
|
-
helpUndo: " /undo \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u56DE\u6EDA\u6700\u8FD1\u672A\u64A4\u6D88\u7684\u7F16\u8F91\u6279\u5904\u7406",
|
|
1979
|
-
helpHistory: " /history \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5217\u51FA\u6B64\u4F1A\u8BDD\u7684\u6BCF\u4E2A\u7F16\u8F91\u6279\u5904\u7406",
|
|
1980
|
-
helpShow: " /show [id] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u8F6C\u50A8\u5B58\u50A8\u7684\u7F16\u8F91\u5DEE\u5F02\uFF08\u7701\u7565 id \u65F6\u4E3A\u6700\u65B0\uFF09",
|
|
1981
|
-
helpCommit: ' /commit "msg" \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09git add -A && git commit -m "msg"',
|
|
1982
|
-
helpPlan: " /plan [on|off] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5207\u6362\u53EA\u8BFB\u8BA1\u5212\u6A21\u5F0F\uFF1B\u5199\u5165\u9700\u7ECF submit_plan + \u5BA1\u6279",
|
|
1983
|
-
helpApplyPlan: " /apply-plan \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5F3A\u5236\u6279\u51C6\u5F85\u5904\u7406/\u6587\u672C\u4E2D\u7684\u8BA1\u5212\uFF08\u56DE\u9000\uFF09",
|
|
1984
|
-
helpMode: " /mode [review|auto|yolo] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09review = \u6392\u961F \xB7 auto = \u5E94\u7528+\u64A4\u6D88\u6A2A\u5E45 \xB7 yolo = \u5E94\u7528+\u81EA\u52A8 shell\u3002Shift+Tab \u5FAA\u73AF\u5207\u6362\u3002",
|
|
1985
|
-
helpJobs: " /jobs \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u5217\u51FA\u540E\u53F0\u8FDB\u7A0B\uFF08run_background\uFF09\u2014 \u8FD0\u884C\u4E2D\u548C\u5DF2\u9000\u51FA",
|
|
1986
|
-
helpKill: " /kill <id> \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u6309 ID \u505C\u6B62\u540E\u53F0\u4F5C\u4E1A\uFF08SIGTERM \u2192 SIGKILL\uFF09",
|
|
1987
|
-
helpLogs: " /logs <id> [lines] \uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u8DDF\u8E2A\u540E\u53F0\u4F5C\u4E1A\u8F93\u51FA\uFF08\u9ED8\u8BA4\u6700\u540E 80 \u884C\uFF09",
|
|
1988
|
-
helpSessions: " /sessions \u5217\u51FA\u5DF2\u4FDD\u5B58\u7684\u4F1A\u8BDD\uFF08\u5F53\u524D\u6807\u8BB0\u4E3A \u25B8\uFF09",
|
|
1989
|
-
helpForget: " /forget \u4ECE\u78C1\u76D8\u5220\u9664\u5F53\u524D\u4F1A\u8BDD",
|
|
1990
|
-
helpNew: " /new \u5168\u65B0\u5F00\u59CB\uFF1A\u4E22\u5F03\u6240\u6709\u4E0A\u4E0B\u6587 + \u6E05\u9664\u6EDA\u52A8\u56DE\u653E",
|
|
1991
|
-
helpClear: " /clear \u4EC5\u6E05\u9664\u663E\u793A\u7684\u6EDA\u52A8\u56DE\u653E\uFF08\u4E0A\u4E0B\u6587\u4FDD\u7559 \u2014 \u6A21\u578B\u4ECD\u80FD\u770B\u5230\uFF09",
|
|
1992
|
-
helpLoop: " /loop <interval> <prompt> \u6BCF <interval> \u81EA\u52A8\u91CD\u65B0\u63D0\u4EA4 <prompt>\uFF085\u79D2..6\u5C0F\u65F6\uFF09\u3002/loop stop \xB7 \u8F93\u5165\u4EFB\u4F55\u5185\u5BB9\u53D6\u6D88\u3002",
|
|
1993
|
-
helpExit: " /exit \u9000\u51FA\uFF08\u522B\u540D\uFF1A/quit, /q\uFF09",
|
|
1994
1632
|
helpShellTitle: "Shell \u5FEB\u6377\u65B9\u5F0F\uFF1A",
|
|
1995
1633
|
helpShell: " !<cmd> \u5728\u6C99\u7BB1\u6839\u76EE\u5F55\u8FD0\u884C <cmd>\uFF1B\u8F93\u51FA\u8FDB\u5165\u5BF9\u8BDD",
|
|
1996
1634
|
helpShellDetail: " \u4EE5\u4FBF\u6A21\u578B\u5728\u4E0B\u4E00\u8F6E\u770B\u5230\u3002\u65E0\u5141\u8BB8\u5217\u8868\u9650\u5236\u3002",
|
|
@@ -2017,46 +1655,6 @@ var zhCN = {
|
|
|
2017
1655
|
helpSessionsTitle: "\u4F1A\u8BDD\uFF08\u9ED8\u8BA4\u81EA\u52A8\u542F\u7528\uFF0C\u547D\u540D\u4E3A 'default'\uFF09\uFF1A",
|
|
2018
1656
|
helpSessionCustom: " reasonix chat --session <name> \u4F7F\u7528\u4E0D\u540C\u7684\u547D\u540D\u4F1A\u8BDD",
|
|
2019
1657
|
helpSessionNone: " reasonix chat --no-session \u7981\u7528\u672C\u6B21\u8FD0\u884C\u7684\u6301\u4E45\u5316",
|
|
2020
|
-
helpLimitationTitle: "\u5DF2\u77E5\u9650\u5236\uFF1A",
|
|
2021
|
-
helpLimitation1: " \u5728\u4F1A\u8BDD\u4E2D\u9014\u8C03\u6574\u7EC8\u7AEF\u5927\u5C0F\u53EF\u80FD\u4F1A\u5728\u6EDA\u52A8\u56DE\u653E\u4E2D\u5806\u53E0\u5E7D\u7075\u6807\u9898\u5E27",
|
|
2022
|
-
helpLimitation2: " \uFF08Ink \u5E93\u7684\u6D3B\u52A8\u533A\u57DF\u6E05\u9664\u672A\u8003\u8651\u65B0\u5BBD\u5EA6\u4E0B\u7684\u884C\u91CD\u6392\uFF09\u3002",
|
|
2023
|
-
helpLimitation3: " \u6EDA\u52A8\u5386\u53F2\u4E0D\u53D7\u5F71\u54CD\uFF1B\u8BE5\u7455\u75B5\u7EAF\u5C5E\u89C6\u89C9\u95EE\u9898\uFF0C",
|
|
2024
|
-
helpLimitation4: " \u4E0B\u6B21 /clear \u65F6\u6E05\u9664\u3002",
|
|
2025
|
-
keysTitle: "\u952E\u76D8\u548C\u63D0\u793A\u5FEB\u6377\u952E\uFF1A",
|
|
2026
|
-
keysEnter: " Enter \u63D0\u4EA4\u5F53\u524D\u63D0\u793A",
|
|
2027
|
-
keysNewline: " Shift+Enter / Ctrl+J \u63D2\u5165\u6362\u884C\uFF08\u591A\u884C\u63D0\u793A\uFF09",
|
|
2028
|
-
keysContinue: " \\<Enter> bash \u98CE\u683C\u7684\u884C\u7EE7\u7EED",
|
|
2029
|
-
keysArrow: " \u2190 \u2192 \u2191 \u2193 \u79FB\u52A8\u5149\u6807 / \u5728\u7F13\u51B2\u533A\u8FB9\u754C\u53EC\u56DE\u5386\u53F2",
|
|
2030
|
-
keysPage: " PageUp / PageDown \u8DF3\u8F6C\u5230\u6574\u4E2A\u7F13\u51B2\u533A\u7684\u9876\u90E8/\u5E95\u90E8\uFF08\u5927\u6BB5\u7C98\u8D34\u540E\u5F88\u6709\u7528\uFF09",
|
|
2031
|
-
keysHomeEnd: " Ctrl+A / Ctrl+E \u8DF3\u8F6C\u5230\u5F53\u524D\u884C\u7684\u5F00\u5934/\u7ED3\u5C3E",
|
|
2032
|
-
keysClearLine: " Ctrl+U \u6E05\u9664\u6574\u4E2A\u8F93\u5165\u7F13\u51B2\u533A",
|
|
2033
|
-
keysDeleteWord: " Ctrl+W \u5220\u9664\u5149\u6807\u524D\u7684\u5355\u8BCD",
|
|
2034
|
-
keysBackspace: " Backspace \u5411\u5DE6\u5220\u9664\uFF1BDelete \u5220\u9664\u5149\u6807\u4E0B\u7684\u5B57\u7B26",
|
|
2035
|
-
keysEsc: " Esc \u4E2D\u6B62\u6B63\u5728\u8FDB\u884C\u7684\u8F6E\u6B21",
|
|
2036
|
-
keysEditYn: " y / n \u63A5\u53D7/\u62D2\u7EDD\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09",
|
|
2037
|
-
keysEditTab: " Shift+Tab \u5FAA\u73AF\u7F16\u8F91\u95E8\u63A7\uFF1Areview \u2194 AUTO\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF0C\u6301\u4E45\u5316\u5230\u914D\u7F6E\uFF09",
|
|
2038
|
-
keysEditUndo: " u \u64A4\u6D88\u6700\u8FD1\u672A\u64A4\u6D88\u7684\u7F16\u8F91\u6279\u5904\u7406\uFF08\u4F1A\u8BDD\u8303\u56F4\uFF0C\u975E\u4EC5\u6A2A\u5E45\uFF09",
|
|
2039
|
-
keysPromptTitle: "\u63D0\u793A\u524D\u7F00\uFF1A",
|
|
2040
|
-
keysSlash: " /<name> \u659C\u6760\u547D\u4EE4\uFF1BTab/Enter \u4ECE\u5EFA\u8BAE\u5217\u8868\u4E2D\u9009\u62E9",
|
|
2041
|
-
keysAtFile: " @<path> \u5C06\u6587\u4EF6\u5185\u8054\u5230 [Referenced files] \u4E0B\uFF08\u4EE3\u7801\u6A21\u5F0F\uFF09\u3002",
|
|
2042
|
-
keysAtFilePicker: " \u5C3E\u90E8 `@\u2026` \u6253\u5F00\u6587\u4EF6\u9009\u62E9\u5668\uFF1B\u2191/\u2193 \u5BFC\u822A\uFF0CTab/Enter \u9009\u62E9\u3002",
|
|
2043
|
-
keysAtUrl: " @https://... \u83B7\u53D6 URL\uFF0C\u5265\u79BB HTML\uFF0C\u5185\u8054\u5230 [Referenced URLs] \u4E0B\u3002",
|
|
2044
|
-
keysAtUrlCache: " \u6BCF\u4F1A\u8BDD\u7F13\u5B58 \u2014 \u76F8\u540C URL \u83B7\u53D6\u4E24\u6B21\u53EA\u53D6\u4E00\u6B21\u3002",
|
|
2045
|
-
keysBang: " !<cmd> \u5728\u6C99\u7BB1\u6839\u76EE\u5F55\u8FD0\u884C <cmd>\uFF1B\u8F93\u51FA\u8FDB\u5165\u4E0A\u4E0B\u6587",
|
|
2046
|
-
keysBangDetail: " \u4EE5\u4FBF\u6A21\u578B\u5728\u4E0B\u4E00\u8F6E\u770B\u5230\u3002\u65E0\u5141\u8BB8\u5217\u8868\u9650\u5236\u3002",
|
|
2047
|
-
keysHash: " #<note> \u5C06 <note> \u8FFD\u52A0\u5230 <project>/REASONIX.md\uFF08\u53EF\u63D0\u4EA4\uFF0C\u56E2\u961F\u5171\u4EAB\uFF09\u3002",
|
|
2048
|
-
keysHashGlobal: " #g <note> \u5C06 <note> \u8FFD\u52A0\u5230 ~/.reasonix/REASONIX.md\uFF08\u5168\u5C40\uFF0C\u4E0D\u63D0\u4EA4\uFF09\u3002",
|
|
2049
|
-
keysHashBoth: " \u4E24\u8005\u90FD\u56FA\u5B9A\u5230\u6BCF\u4E2A\u672A\u6765\u4F1A\u8BDD\u7684\u4E0D\u53EF\u53D8\u524D\u7F00\u4E2D\u3002",
|
|
2050
|
-
keysHashEscape: " \u4F7F\u7528 `\\#literal` \u5982\u679C\u60A8\u786E\u5B9E\u60F3\u53D1\u9001 `#` \u6807\u9898\u7ED9\u6A21\u578B\u3002",
|
|
2051
|
-
keysPickersTitle: "\u9009\u62E9\u5668\uFF08\u659C\u6760 + @\u63D0\u53CA\uFF09\uFF1A",
|
|
2052
|
-
keysPickerNav: " \u2191 / \u2193 \u5BFC\u822A\u5EFA\u8BAE\u5217\u8868",
|
|
2053
|
-
keysPickerTab: " Tab \u63D2\u5165\u9AD8\u4EAE\u9879\u76EE\u4F46\u4E0D\u63D0\u4EA4",
|
|
2054
|
-
keysPickerEnter: " Enter \u63D2\u5165\u5E76\uFF08\u659C\u6760\uFF09\u8FD0\u884C\uFF0C\uFF08@\uFF09\u7EE7\u7EED\u7F16\u8F91",
|
|
2055
|
-
keysMcpTitle: "MCP \u63A2\u7D22\uFF1A",
|
|
2056
|
-
keysMcpServers: " /mcp \u670D\u52A1\u5668 + \u5DE5\u5177/\u8D44\u6E90/\u63D0\u793A\u8BA1\u6570",
|
|
2057
|
-
keysMcpResource: " /resource [uri] \u6D4F\u89C8\u5E76\u8BFB\u53D6 MCP \u670D\u52A1\u5668\u66B4\u9732\u7684\u8D44\u6E90",
|
|
2058
|
-
keysMcpPrompt: " /prompt [name] \u6D4F\u89C8\u5E76\u83B7\u53D6 MCP \u670D\u52A1\u5668\u66B4\u9732\u7684\u63D0\u793A",
|
|
2059
|
-
keysUseful: "\u5E38\u7528\u659C\u6760\u547D\u4EE4\uFF1A/help \xB7 /context \xB7 /stats \xB7 /compact \xB7 /new \xB7 /exit",
|
|
2060
1658
|
retryNone: "\u6CA1\u6709\u53EF\u91CD\u8BD5\u7684\u5185\u5BB9 \u2014 \u6B64\u4F1A\u8BDD\u65E5\u5FD7\u4E2D\u6CA1\u6709\u5148\u524D\u7684\u7528\u6237\u6D88\u606F\u3002",
|
|
2061
1659
|
retryInfo: '\u25B8 \u91CD\u8BD5\u4E2D\uFF1A"{preview}"',
|
|
2062
1660
|
loopTuiOnly: "/loop \u4EC5\u5728\u4EA4\u4E92\u5F0F TUI \u4E2D\u53EF\u7528\uFF08\u4E0D\u5728 run/replay \u4E2D\uFF09\u3002",
|
|
@@ -2106,9 +1704,6 @@ var zhCN = {
|
|
|
2106
1704
|
planCodeOnly: "/plan \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528 \u2014 \u804A\u5929\u6A21\u5F0F\u4E0D\u9650\u5236\u5DE5\u5177\u5199\u5165\u3002",
|
|
2107
1705
|
planOn: "\u25B8 \u8BA1\u5212\u6A21\u5F0F\u5F00\u542F \u2014 \u5199\u5165\u5DE5\u5177\u88AB\u9650\u5236\uFF1B\u6A21\u578B\u5FC5\u987B\u5148\u8C03\u7528 `submit_plan` \u624D\u80FD\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C\u3002\uFF08\u6A21\u578B\u4E5F\u53EF\u4EE5\u5728\u8BA1\u5212\u6A21\u5F0F\u5173\u95ED\u65F6\u81EA\u4E3B\u8C03\u7528 submit_plan \u5904\u7406\u5927\u578B\u4EFB\u52A1 \u2014 \u6B64\u5F00\u5173\u662F\u66F4\u5F3A\u7684\u663E\u5F0F\u7EA6\u675F\u3002\uFF09\u8F93\u5165 /plan off \u9000\u51FA\u3002",
|
|
2108
1706
|
planOff: "\u25B8 \u8BA1\u5212\u6A21\u5F0F\u5173\u95ED \u2014 \u5199\u5165\u5DE5\u5177\u518D\u6B21\u53EF\u7528\u3002\u6A21\u578B\u4ECD\u53EF\u4E3A\u5927\u578B\u4EFB\u52A1\u81EA\u4E3B\u63D0\u51FA\u8BA1\u5212\u3002",
|
|
2109
|
-
applyPlanCodeOnly: "/apply-plan \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2110
|
-
applyPlanInfo: "\u25B8 \u8BA1\u5212\u5DF2\u6279\u51C6 \u2014 \u6B63\u5728\u6267\u884C",
|
|
2111
|
-
applyPlanResubmit: "\u4E0A\u65B9\u7684\u8BA1\u5212\u5DF2\u88AB\u6279\u51C6\u3002\u7ACB\u5373\u6267\u884C\u3002\u60A8\u5DF2\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F \u2014 \u6839\u636E\u9700\u8981\u4F7F\u7528 edit_file / write_file / run_command\u3002\u9664\u975E\u53D1\u73B0\u5177\u4F53\u539F\u56E0\uFF0C\u5426\u5219\u8BF7\u9075\u5FAA\u8BA1\u5212\uFF1B\u5982\u679C\u786E\u5B9E\u9700\u8981\u504F\u79BB\uFF0C\u8BF7\u544A\u77E5\u5E76\u7B49\u5F85\u56DE\u590D\u540E\u518D\u8FDB\u884C\u3002",
|
|
2112
1707
|
modeCodeOnly: "/mode \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
2113
1708
|
modeUsage: "\u7528\u6CD5\uFF1A/mode <review|auto|yolo> \uFF08Shift+Tab \u4E5F\u53EF\u5FAA\u73AF\uFF09",
|
|
2114
1709
|
modeYolo: "\u25B8 \u7F16\u8F91\u6A21\u5F0F\uFF1AYOLO \u2014 \u7F16\u8F91\u548C Shell \u547D\u4EE4\u81EA\u52A8\u8FD0\u884C\uFF0C\u65E0\u63D0\u793A\u3002/undo \u4ECD\u53EF\u56DE\u6EDA\u7F16\u8F91\u3002\u8BF7\u8C28\u614E\u4F7F\u7528\u3002",
|
|
@@ -2134,31 +1729,20 @@ var zhCN = {
|
|
|
2134
1729
|
restoreInfo: '\u25B8 \u5DF2\u6062\u590D "{name}"\uFF08{id}\uFF09\uFF0C\u6765\u81EA {when}',
|
|
2135
1730
|
restoreWrote: " \xB7 \u5199\u56DE\u4E86 {count} \u4E2A\u6587\u4EF6",
|
|
2136
1731
|
restoreRemoved: " \xB7 \u79FB\u9664\u4E86 {count} \u4E2A\u6587\u4EF6\uFF08\u68C0\u67E5\u70B9\u65F6\u4E0D\u5B58\u5728\uFF09",
|
|
2137
|
-
restoreSkipped: " \u2717 \u8DF3\u8FC7\u4E86 {count} \u4E2A\u6587\u4EF6\uFF1A"
|
|
1732
|
+
restoreSkipped: " \u2717 \u8DF3\u8FC7\u4E86 {count} \u4E2A\u6587\u4EF6\uFF1A",
|
|
1733
|
+
cwdCodeOnly: "/cwd \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\u3002",
|
|
1734
|
+
cwdUsage: "\u7528\u6CD5\uFF1A/cwd <path> \uFF08\u5F53\u524D\u6839\u76EE\u5F55\uFF1A{current}\uFF09\u3002\u91CD\u65B0\u6307\u5411 filesystem / shell / memory \u5DE5\u5177\u5230 <path>\u3002",
|
|
1735
|
+
cwdUsageNoCurrent: "\u7528\u6CD5\uFF1A/cwd <path> \u5C06\u5DE5\u4F5C\u533A\u6839\u76EE\u5F55\u5207\u6362\u5230 <path>\u3002"
|
|
2138
1736
|
},
|
|
2139
1737
|
model: {
|
|
2140
1738
|
modelHint: "\u5C1D\u8BD5 deepseek-v4-flash \u6216 deepseek-v4-pro \u2014 \u8FD0\u884C /models \u83B7\u53D6\u5B9E\u65F6\u5217\u8868",
|
|
2141
1739
|
modelUsage: "\u7528\u6CD5\uFF1A/model <id> \uFF08{hint}\uFF09",
|
|
2142
1740
|
modelNotInCatalog: "model \u2192 {id} \uFF08\u26A0 \u4E0D\u5728\u83B7\u53D6\u7684\u76EE\u5F55\u4E2D\uFF1A{list}\u3002\u5982\u679C\u8FD9\u662F\u9519\u8BEF\u7684\uFF0C\u4E0B\u6B21\u8C03\u7528\u5C06\u8FD4\u56DE 400 \u2014 \u8FD0\u884C /models \u5237\u65B0\u3002\uFF09",
|
|
2143
1741
|
modelSet: "model \u2192 {id}",
|
|
2144
|
-
modelsFetching: "\u6B63\u5728\u4ECE DeepSeek \u83B7\u53D6 /models\u2026 \u7A0D\u540E\u518D\u8FD0\u884C /models\u3002\u5982\u679C\u6301\u7EED\u4E3A\u7A7A\uFF0C\u60A8\u7684 API \u5BC6\u94A5\u53EF\u80FD\u7F3A\u5C11\u6743\u9650\u6216\u7F51\u7EDC\u88AB\u963B\u6B62\u3002",
|
|
2145
|
-
modelsEmpty: "DeepSeek /models \u8FD4\u56DE\u4E86\u7A7A\u5217\u8868\u3002\u518D\u8BD5 /models\uFF0C\u6216\u5728 api-docs.deepseek.com \u68C0\u67E5\u60A8\u7684\u8D26\u6237\u72B6\u6001\u3002",
|
|
2146
|
-
modelsHeader: "\u53EF\u7528\u6A21\u578B\uFF08DeepSeek /models \xB7 \u5171 {count} \u4E2A\uFF09\uFF1A",
|
|
2147
|
-
modelsCurrent: "\u25B8 {id} \uFF08\u5F53\u524D\uFF09",
|
|
2148
|
-
modelsSwitch: "\u5207\u6362\u65B9\u5F0F\uFF1A/model <id>",
|
|
2149
|
-
harvestOn: "harvest \u2192 \u5F00\u542F \uFF08Pillar-2 \u8BA1\u5212\u72B6\u6001\u63D0\u53D6 \xB7 \u6BCF\u8F6E\u989D\u5916 1 \u6B21\u5EC9\u4EF7 flash \u8C03\u7528 \xB7 \u4EC5\u624B\u52A8\u9009\u62E9\uFF1B\u65E0\u9884\u8BBE\u4F1A\u5F00\u542F\u5B83\uFF09",
|
|
2150
|
-
harvestOff: "harvest \u2192 \u5173\u95ED",
|
|
2151
1742
|
presetAuto: "preset \u2192 auto \uFF08v4-flash \u2192 v4-pro \u5728\u56F0\u96BE\u8F6E\u6B21\u5207\u6362 \xB7 \u9ED8\u8BA4\uFF09",
|
|
2152
1743
|
presetFlash: "preset \u2192 flash \uFF08\u59CB\u7EC8\u4F7F\u7528 v4-flash \xB7 \u6700\u4FBF\u5B9C \xB7 /pro \u4ECD\u53EF\u4E34\u65F6\u63D0\u5347\u4E00\u8F6E\uFF09",
|
|
2153
1744
|
presetPro: "preset \u2192 pro \uFF08\u59CB\u7EC8\u4F7F\u7528 v4-pro \xB7 \u7EA6 3 \u500D flash \xB7 \u7528\u4E8E\u56F0\u96BE\u7684\u591A\u8F6E\u5DE5\u4F5C\uFF09",
|
|
2154
1745
|
presetUsage: "\u7528\u6CD5\uFF1A/preset <auto|flash|pro>",
|
|
2155
|
-
branchOff: "branch \u2192 \u5173\u95ED",
|
|
2156
|
-
branchUsage: "\u7528\u6CD5\uFF1A/branch <N> \uFF08N>=2\uFF0C\u6216 'off'\uFF09",
|
|
2157
|
-
branchCapped: "branch \u9884\u7B97\u4E0A\u9650\u4E3A 8\uFF0C\u9632\u6B62\u6210\u672C\u5931\u63A7",
|
|
2158
|
-
branchSet: "branch \u2192 {n} \uFF08\u6BCF\u8F6E\u8FD0\u884C {n} \u4E2A\u5E76\u884C\u91C7\u6837 \xB7 {n} \u500D\u6BCF\u8F6E\u6210\u672C \xB7 \u7981\u7528\u6D41\u5F0F \xB7 \u4EC5\u624B\u52A8\uFF0C\u65E0\u9884\u8BBE\u542F\u7528\u5206\u652F\uFF09",
|
|
2159
|
-
effortStatus: "reasoning_effort \u2192 {effort} \uFF08\u4F7F\u7528 /effort high \u66F4\u4FBF\u5B9C/\u66F4\u5FEB\uFF0C/effort max \u4E3A\u667A\u80FD\u4F53\u7EA7\u9ED8\u8BA4 \xB7 \u8DE8\u91CD\u542F\u6301\u4E45\u5316\uFF09",
|
|
2160
|
-
effortUsage: "\u7528\u6CD5\uFF1A/effort <high|max>",
|
|
2161
|
-
effortSet: "reasoning_effort \u2192 {effort}\uFF08\u5DF2\u6301\u4E45\u5316\uFF09",
|
|
2162
1746
|
proNothingArmed: "\u672A\u542F\u7528 \u2014 /pro \u4E0D\u5E26\u53C2\u6570\u5C06\u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 pro",
|
|
2163
1747
|
proDisarmed: "\u25B8 /pro \u5DF2\u89E3\u9664 \u2014 \u4E0B\u4E00\u8F6E\u56DE\u9000\u5230\u5F53\u524D\u9884\u8BBE",
|
|
2164
1748
|
proUsage: "\u7528\u6CD5\uFF1A/pro \u4E3A\u4E0B\u4E00\u8F6E\u542F\u7528 pro\uFF08\u4E00\u6B21\u6027\uFF0C\u81EA\u52A8\u89E3\u9664\uFF09\n /pro off \u5728\u4E0B\u4E00\u8F6E\u524D\u53D6\u6D88\u542F\u7528\u72B6\u6001",
|
|
@@ -2170,18 +1754,6 @@ var zhCN = {
|
|
|
2170
1754
|
budgetExhausted: "\u25B2 budget \u2192 ${cap} \u4F46\u5DF2\u82B1\u8D39 ${spent}\u3002\u4E0B\u4E00\u8F6E\u5C06\u88AB\u62D2\u7EDD \u2014 \u63D0\u9AD8\u4E0A\u9650\u4EE5\u7EE7\u7EED\uFF0C\u6216\u7ED3\u675F\u4F1A\u8BDD\u3002",
|
|
2171
1755
|
budgetSet: "budget \u2192 ${cap} \uFF08\u8FC4\u4ECA\uFF1A${spent} \xB7 80% \u65F6\u8B66\u544A\uFF0C100% \u65F6\u62D2\u7EDD\u4E0B\u4E00\u8F6E \xB7 /budget off \u6E05\u9664\uFF09"
|
|
2172
1756
|
},
|
|
2173
|
-
sessions: {
|
|
2174
|
-
forgetNoSession: "\u4E0D\u5728\u4F1A\u8BDD\u4E2D \u2014 \u65E0\u5185\u5BB9\u53EF\u9057\u5FD8",
|
|
2175
|
-
forgetInfo: '\u25B8 \u5DF2\u5220\u9664\u4F1A\u8BDD "{name}" \u2014 \u5F53\u524D\u5C4F\u5E55\u4ECD\u663E\u793A\u5BF9\u8BDD\uFF0C\u4F46\u4E0B\u6B21\u542F\u52A8\u5C06\u5168\u65B0\u5F00\u59CB',
|
|
2176
|
-
forgetFailed: '\u65E0\u6CD5\u5220\u9664\u4F1A\u8BDD "{name}"\uFF08\u5DF2\u6D88\u5931\uFF1F\uFF09',
|
|
2177
|
-
renameUsage: "\u7528\u6CD5\uFF1A/rename <new-name>",
|
|
2178
|
-
renameNoSession: "\u4E0D\u5728\u4F1A\u8BDD\u4E2D \u2014 \u65E0\u5185\u5BB9\u53EF\u91CD\u547D\u540D",
|
|
2179
|
-
renameFailed: '\u65E0\u6CD5\u91CD\u547D\u540D \u2014 "{name}" \u5DF2\u5B58\u5728\u6216\u6E05\u7406\u540E\u4E0E\u5F53\u524D\u4F1A\u8BDD ID \u76F8\u540C',
|
|
2180
|
-
renameInfo: '\u25B8 \u4F1A\u8BDD\u5DF2\u91CD\u547D\u540D\u4E3A \u2192 "{name}"\u3002\u91CD\u542F TUI \u4EE5\u4F7F\u7528\u65B0\u540D\u79F0\u3002',
|
|
2181
|
-
resumeUsage: "\u7528\u6CD5\uFF1A/resume <session-name> \u2014 \u4F7F\u7528 /sessions \u5217\u51FA",
|
|
2182
|
-
resumeNotFound: '\u6CA1\u6709\u540D\u4E3A "{name}" \u7684\u4F1A\u8BDD \u2014 \u4F7F\u7528 /sessions \u5217\u51FA',
|
|
2183
|
-
resumeInfo: '\u25B8 \u8981\u6062\u590D "{name}"\uFF0C\u8BF7\u9000\u51FA\u5E76\u8FD0\u884C\uFF1Areasonix chat --session {name}\n \uFF08\u4F1A\u8BDD\u4E2D\u5207\u6362\u9700\u8981\u91CD\u542F\uFF0C\u4EE5\u4FBF\u6D88\u606F\u65E5\u5FD7\u53EF\u4EE5\u5E72\u51C0\u5730\u56DE\u9000\uFF09'
|
|
2184
|
-
},
|
|
2185
1757
|
permissions: {
|
|
2186
1758
|
mutateCodeOnly: "/permissions add / remove / clear \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528 \u2014 \u5B83\u4EEC\u7F16\u8F91\u9879\u76EE\u8303\u56F4\u7684\u5141\u8BB8\u5217\u8868\uFF08`~/.reasonix/config.json` projects[<root>].shellAllowed\uFF09\u3002",
|
|
2187
1759
|
addUsage: '\u7528\u6CD5\uFF1A/permissions add <prefix> \uFF08\u591A token \u53EF\u7528\uFF1A/permissions add "git push origin"\uFF09',
|
|
@@ -2223,13 +1795,6 @@ var zhCN = {
|
|
|
2223
1795
|
starting: "\u25B8 \u6B63\u5728\u542F\u52A8\u4EEA\u8868\u677F\u670D\u52A1\u5668\u2026"
|
|
2224
1796
|
},
|
|
2225
1797
|
observability: {
|
|
2226
|
-
thinkEmpty: "\u672A\u7F13\u5B58\u63A8\u7406\u5185\u5BB9\u3002`/think` \u663E\u793A\u6700\u8FD1\u4E00\u8F6E\u7684\u5B8C\u6574\u601D\u8003\u6A21\u5F0F\u601D\u7EF4 \u2014 \u4EC5\u601D\u8003\u6A21\u5F0F\u6A21\u578B\uFF08deepseek-v4-flash / -v4-pro / -reasoner\uFF09\u4EA7\u751F\u5B83\uFF0C\u4E14\u4EC5\u5728\u8F6E\u6B21\u5B8C\u6210\u540E\u3002",
|
|
2227
|
-
thinkInfo: "\u21B3 \u5B8C\u6574\u601D\u8003\uFF08{count} \u5B57\u7B26\uFF09\uFF1A",
|
|
2228
|
-
toolEmpty: "\u6B64\u4F1A\u8BDD\u4E2D\u5C1A\u65E0\u5DE5\u5177\u8C03\u7528\u3002`/tool` \u5728\u6A21\u578B\u5B9E\u9645\u4F7F\u7528\u5DE5\u5177\u540E\u5217\u51FA\u5B83\u4EEC\uFF1B`/tool N` \u8F6C\u50A8\u7B2C N \u4E2A\u6700\u8FD1\u7684\u5B8C\u6574\uFF08\u672A\u622A\u65AD\uFF09\u8F93\u51FA\u3002",
|
|
2229
|
-
toolUsage: "\u7528\u6CD5\uFF1A/tool [N] \uFF08\u65E0\u53C2\u6570 \u2192 \u5217\u8868\uFF1BN=1 \u2192 \u6700\u8FD1\u7684\u5B8C\u6574\u7ED3\u679C\uFF0CN=2 \u2192 \u4E0A\u4E00\u4E2A\uFF0C\u2026\uFF09",
|
|
2230
|
-
toolOob: "\u5386\u53F2\u4E2D\u4EC5\u6709 {count} \u6B21\u5DE5\u5177\u8C03\u7528 \u2014 \u8BF7\u6C42\u4E86 #{n}\u3002\u5C1D\u8BD5\u4E0D\u5E26\u53C2\u6570\u7684 /tool \u67E5\u770B\u5217\u8868\u3002",
|
|
2231
|
-
toolNotFound: "\u65E0\u6CD5\u8BFB\u53D6\u5DE5\u5177\u8C03\u7528 #{n}",
|
|
2232
|
-
toolInfo: "\u21B3 tool<{name}> #{n}\uFF08{chars} \u5B57\u7B26\uFF09\uFF1A",
|
|
2233
1798
|
contextInfo: "\u4E0A\u4E0B\u6587\uFF1A~{total} / {max}\uFF08{pct}%\uFF09\xB7 \u7CFB\u7EDF {sys} \xB7 \u5DE5\u5177 {tools} \xB7 \u65E5\u5FD7 {log}",
|
|
2234
1799
|
compactStarting: "\u25B8 \u6B63\u5728\u6298\u53E0\u65E7\u8F6E\u6B21\u4E3A\u6458\u8981\u2026",
|
|
2235
1800
|
compactNoop: "\u25B8 \u65E0\u9700\u6298\u53E0 \u2014 \u65E5\u5FD7\u5DF2\u8DB3\u591F\u5C0F\uFF0C\u6216\u6700\u8FD1\u8F6E\u6B21\u672C\u8EAB\u5DF2\u8D85\u8FC7\u9884\u7B97\u3002",
|
|
@@ -2243,7 +1808,7 @@ var zhCN = {
|
|
|
2243
1808
|
costLikely: " \u53EF\u80FD\uFF08{pct}% \u4F1A\u8BDD\u7F13\u5B58\u547D\u4E2D\uFF09\uFF1A{input} \u8F93\u5165 + ~{output} \u8F93\u51FA \u2248 {total}",
|
|
2244
1809
|
costLikelyCold: " \u53EF\u80FD\uFF1A\u5728\u7F13\u5B58\u586B\u5145\u524D\u4E0E\u6700\u574F\u60C5\u51B5\u76F8\u540C\uFF08\u65E0\u5DF2\u5B8C\u6210\u7684\u8F6E\u6B21\uFF09",
|
|
2245
1810
|
statusModel: " \u6A21\u578B {model}",
|
|
2246
|
-
statusFlags: " \u6807\u5FD7
|
|
1811
|
+
statusFlags: " \u6807\u5FD7 stream={stream} \xB7 effort={effort}",
|
|
2247
1812
|
statusCtx: " \u4E0A\u4E0B\u6587 {bar} {used}/{max}\uFF08{pct}%\uFF09",
|
|
2248
1813
|
statusCtxNone: " \u4E0A\u4E0B\u6587 \u5C1A\u65E0\u8F6E\u6B21",
|
|
2249
1814
|
statusCost: " \u6210\u672C ${cost} \xB7 \u7F13\u5B58 {bar} {pct}% \xB7 \u8F6E\u6B21 {turns}",
|
|
@@ -2345,10 +1910,6 @@ var zhCN = {
|
|
|
2345
1910
|
existsPinned: " \u56FA\u5B9A\u5230\u6BCF\u6B21\u542F\u52A8\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E2D\u3002",
|
|
2346
1911
|
info: "\u25B8 /init \u2014 \u6A21\u578B\u5C06\u626B\u63CF\u9879\u76EE\u5E76\u5408\u6210 REASONIX.md\u3002\n \u7ED3\u679C\u5C06\u4F5C\u4E3A\u5F85\u5904\u7406\u7684\u7F16\u8F91\uFF1B\u4F7F\u7528 /apply \u6216 /walk \u5BA1\u67E5\u3002"
|
|
2347
1912
|
},
|
|
2348
|
-
semantic: {
|
|
2349
|
-
codeOnly: "/semantic \u4EC5\u5728 `reasonix code` \u4E2D\u53EF\u7528\uFF08\u9700\u8981\u9879\u76EE\u6839\u76EE\u5F55\uFF09\u3002",
|
|
2350
|
-
checking: "\u25B8 \u6B63\u5728\u68C0\u67E5 semantic_search \u72B6\u6001\u2026"
|
|
2351
|
-
},
|
|
2352
1913
|
webSearchEngine: {
|
|
2353
1914
|
currentEngine: "\u5F53\u524D\u7F51\u9875\u641C\u7D22\u5F15\u64CE\uFF1A{engine}",
|
|
2354
1915
|
endpoint: "SearXNG \u7AEF\u70B9\uFF1A{url}",
|
|
@@ -3579,16 +3140,6 @@ var ContextManager = class {
|
|
|
3579
3140
|
}
|
|
3580
3141
|
};
|
|
3581
3142
|
|
|
3582
|
-
// src/loop/branch.ts
|
|
3583
|
-
function summarizeBranch(chosen, samples) {
|
|
3584
|
-
return {
|
|
3585
|
-
budget: samples.length,
|
|
3586
|
-
chosenIndex: chosen.index,
|
|
3587
|
-
uncertainties: samples.map((s) => s.planState.uncertainties.length),
|
|
3588
|
-
temperatures: samples.map((s) => s.temperature)
|
|
3589
|
-
};
|
|
3590
|
-
}
|
|
3591
|
-
|
|
3592
3143
|
// src/loop/errors.ts
|
|
3593
3144
|
function formatLoopError(err, probe) {
|
|
3594
3145
|
const msg = err.message ?? "";
|
|
@@ -4351,13 +3902,9 @@ var CacheFirstLoop = class {
|
|
|
4351
3902
|
stats = new SessionStats();
|
|
4352
3903
|
repair;
|
|
4353
3904
|
// Mutable via configure() — slash commands in the TUI / library callers tweak
|
|
4354
|
-
// these mid-session so users don't have to restart
|
|
3905
|
+
// these mid-session so users don't have to restart.
|
|
4355
3906
|
model;
|
|
4356
3907
|
stream;
|
|
4357
|
-
harvestEnabled;
|
|
4358
|
-
harvestOptions;
|
|
4359
|
-
branchEnabled;
|
|
4360
|
-
branchOptions;
|
|
4361
3908
|
reasoningEffort;
|
|
4362
3909
|
autoEscalate = true;
|
|
4363
3910
|
budgetUsd;
|
|
@@ -4395,19 +3942,8 @@ var CacheFirstLoop = class {
|
|
|
4395
3942
|
this.hooks = opts.hooks ?? [];
|
|
4396
3943
|
this.hookCwd = opts.hookCwd ?? process.cwd();
|
|
4397
3944
|
this.confirmationGate = opts.confirmationGate ?? pauseGate;
|
|
4398
|
-
if (typeof opts.branch === "number") {
|
|
4399
|
-
this.branchOptions = { budget: opts.branch };
|
|
4400
|
-
} else if (opts.branch && typeof opts.branch === "object") {
|
|
4401
|
-
this.branchOptions = opts.branch;
|
|
4402
|
-
} else {
|
|
4403
|
-
this.branchOptions = {};
|
|
4404
|
-
}
|
|
4405
|
-
this.branchEnabled = (this.branchOptions.budget ?? 1) > 1;
|
|
4406
|
-
const harvestForced = this.branchEnabled;
|
|
4407
|
-
this.harvestEnabled = harvestForced || opts.harvest === true || typeof opts.harvest === "object" && opts.harvest !== null;
|
|
4408
|
-
this.harvestOptions = typeof opts.harvest === "object" && opts.harvest !== null ? opts.harvest : this.branchOptions.harvestOptions ?? {};
|
|
4409
3945
|
this._streamPreference = opts.stream ?? true;
|
|
4410
|
-
this.stream = this.
|
|
3946
|
+
this.stream = this._streamPreference;
|
|
4411
3947
|
const allowedNames = /* @__PURE__ */ new Set([...this.prefix.toolSpecs.map((s) => s.function.name)]);
|
|
4412
3948
|
const registry = this.tools;
|
|
4413
3949
|
const isMutating = (call) => {
|
|
@@ -4525,29 +4061,12 @@ var CacheFirstLoop = class {
|
|
|
4525
4061
|
}
|
|
4526
4062
|
configure(opts) {
|
|
4527
4063
|
if (opts.model !== void 0) this.model = opts.model;
|
|
4528
|
-
if (opts.stream !== void 0)
|
|
4064
|
+
if (opts.stream !== void 0) {
|
|
4065
|
+
this._streamPreference = opts.stream;
|
|
4066
|
+
this.stream = opts.stream;
|
|
4067
|
+
}
|
|
4529
4068
|
if (opts.reasoningEffort !== void 0) this.reasoningEffort = opts.reasoningEffort;
|
|
4530
4069
|
if (opts.autoEscalate !== void 0) this.autoEscalate = opts.autoEscalate;
|
|
4531
|
-
if (opts.branch !== void 0) {
|
|
4532
|
-
if (typeof opts.branch === "number") {
|
|
4533
|
-
this.branchOptions = { budget: opts.branch };
|
|
4534
|
-
} else if (opts.branch && typeof opts.branch === "object") {
|
|
4535
|
-
this.branchOptions = opts.branch;
|
|
4536
|
-
} else {
|
|
4537
|
-
this.branchOptions = {};
|
|
4538
|
-
}
|
|
4539
|
-
this.branchEnabled = (this.branchOptions.budget ?? 1) > 1;
|
|
4540
|
-
}
|
|
4541
|
-
if (opts.harvest !== void 0) {
|
|
4542
|
-
const want = opts.harvest === true || typeof opts.harvest === "object" && opts.harvest !== null;
|
|
4543
|
-
this.harvestEnabled = want || this.branchEnabled;
|
|
4544
|
-
if (typeof opts.harvest === "object" && opts.harvest !== null) {
|
|
4545
|
-
this.harvestOptions = opts.harvest;
|
|
4546
|
-
}
|
|
4547
|
-
} else if (this.branchEnabled) {
|
|
4548
|
-
this.harvestEnabled = true;
|
|
4549
|
-
}
|
|
4550
|
-
this.stream = this.branchEnabled ? false : this._streamPreference;
|
|
4551
4070
|
}
|
|
4552
4071
|
/** `null` disables the cap; any change re-arms the 80% warning. */
|
|
4553
4072
|
setBudget(usd) {
|
|
@@ -4789,89 +4308,8 @@ ${reason}`
|
|
|
4789
4308
|
let reasoningContent = "";
|
|
4790
4309
|
let toolCalls = [];
|
|
4791
4310
|
let usage = null;
|
|
4792
|
-
let branchSummary;
|
|
4793
|
-
let preHarvestedPlanState;
|
|
4794
4311
|
try {
|
|
4795
|
-
if (this.
|
|
4796
|
-
const budget = this.branchOptions.budget ?? 1;
|
|
4797
|
-
yield {
|
|
4798
|
-
turn: this._turn,
|
|
4799
|
-
role: "branch_start",
|
|
4800
|
-
content: "",
|
|
4801
|
-
branchProgress: {
|
|
4802
|
-
completed: 0,
|
|
4803
|
-
total: budget,
|
|
4804
|
-
latestIndex: -1,
|
|
4805
|
-
latestTemperature: -1,
|
|
4806
|
-
latestUncertainties: -1
|
|
4807
|
-
}
|
|
4808
|
-
};
|
|
4809
|
-
const queue = [];
|
|
4810
|
-
let waiter = null;
|
|
4811
|
-
const onSampleDone = (sample) => {
|
|
4812
|
-
if (waiter) {
|
|
4813
|
-
const w = waiter;
|
|
4814
|
-
waiter = null;
|
|
4815
|
-
w(sample);
|
|
4816
|
-
} else {
|
|
4817
|
-
queue.push(sample);
|
|
4818
|
-
}
|
|
4819
|
-
};
|
|
4820
|
-
const callModel = this.modelForCurrentCall();
|
|
4821
|
-
const branchPromise = runBranches(
|
|
4822
|
-
this.client,
|
|
4823
|
-
{
|
|
4824
|
-
model: callModel,
|
|
4825
|
-
messages,
|
|
4826
|
-
tools: toolSpecs.length ? toolSpecs : void 0,
|
|
4827
|
-
signal,
|
|
4828
|
-
thinking: thinkingModeForModel(callModel),
|
|
4829
|
-
reasoningEffort: this.reasoningEffort
|
|
4830
|
-
},
|
|
4831
|
-
{
|
|
4832
|
-
...this.branchOptions,
|
|
4833
|
-
harvestOptions: this.harvestOptions,
|
|
4834
|
-
onSampleDone
|
|
4835
|
-
}
|
|
4836
|
-
);
|
|
4837
|
-
for (let k = 0; k < budget; k++) {
|
|
4838
|
-
const sample = queue.shift() ?? await new Promise((resolve10) => {
|
|
4839
|
-
waiter = resolve10;
|
|
4840
|
-
});
|
|
4841
|
-
yield {
|
|
4842
|
-
turn: this._turn,
|
|
4843
|
-
role: "branch_progress",
|
|
4844
|
-
content: "",
|
|
4845
|
-
branchProgress: {
|
|
4846
|
-
completed: k + 1,
|
|
4847
|
-
total: budget,
|
|
4848
|
-
latestIndex: sample.index,
|
|
4849
|
-
latestTemperature: sample.temperature,
|
|
4850
|
-
latestUncertainties: sample.planState.uncertainties.length
|
|
4851
|
-
}
|
|
4852
|
-
};
|
|
4853
|
-
}
|
|
4854
|
-
const result = await branchPromise;
|
|
4855
|
-
assistantContent = result.chosen.response.content;
|
|
4856
|
-
reasoningContent = result.chosen.response.reasoningContent ?? "";
|
|
4857
|
-
toolCalls = result.chosen.response.toolCalls;
|
|
4858
|
-
const agg = aggregateBranchUsage(result.samples);
|
|
4859
|
-
usage = new Usage(
|
|
4860
|
-
agg.promptTokens,
|
|
4861
|
-
agg.completionTokens,
|
|
4862
|
-
agg.totalTokens,
|
|
4863
|
-
agg.promptCacheHitTokens,
|
|
4864
|
-
agg.promptCacheMissTokens
|
|
4865
|
-
);
|
|
4866
|
-
preHarvestedPlanState = result.chosen.planState;
|
|
4867
|
-
branchSummary = summarizeBranch(result.chosen, result.samples);
|
|
4868
|
-
yield {
|
|
4869
|
-
turn: this._turn,
|
|
4870
|
-
role: "branch_done",
|
|
4871
|
-
content: "",
|
|
4872
|
-
branch: branchSummary
|
|
4873
|
-
};
|
|
4874
|
-
} else if (this.stream) {
|
|
4312
|
+
if (this.stream) {
|
|
4875
4313
|
const callBuf = /* @__PURE__ */ new Map();
|
|
4876
4314
|
const readyIndices = /* @__PURE__ */ new Set();
|
|
4877
4315
|
const callModel = this.modelForCurrentCall();
|
|
@@ -5001,8 +4439,6 @@ ${reason}`
|
|
|
5001
4439
|
reasoningContent = "";
|
|
5002
4440
|
toolCalls = [];
|
|
5003
4441
|
usage = null;
|
|
5004
|
-
branchSummary = void 0;
|
|
5005
|
-
preHarvestedPlanState = void 0;
|
|
5006
4442
|
iter--;
|
|
5007
4443
|
continue;
|
|
5008
4444
|
}
|
|
@@ -5016,14 +4452,6 @@ ${reason}`
|
|
|
5016
4452
|
pendingUser = null;
|
|
5017
4453
|
}
|
|
5018
4454
|
this.scratch.reasoning = reasoningContent || null;
|
|
5019
|
-
if (!preHarvestedPlanState && this.harvestEnabled && (reasoningContent?.trim().length ?? 0) >= 40) {
|
|
5020
|
-
yield {
|
|
5021
|
-
turn: this._turn,
|
|
5022
|
-
role: "status",
|
|
5023
|
-
content: t("loop.harvestStatus")
|
|
5024
|
-
};
|
|
5025
|
-
}
|
|
5026
|
-
const planState = preHarvestedPlanState ? preHarvestedPlanState : this.harvestEnabled ? await harvest(reasoningContent || null, this.client, this.harvestOptions, signal) : emptyPlanState();
|
|
5027
4455
|
const { calls: repairedCalls, report } = this.repair.process(
|
|
5028
4456
|
toolCalls,
|
|
5029
4457
|
reasoningContent || null,
|
|
@@ -5042,9 +4470,7 @@ ${reason}`
|
|
|
5042
4470
|
role: "assistant_final",
|
|
5043
4471
|
content: assistantContent,
|
|
5044
4472
|
stats: turnStats,
|
|
5045
|
-
|
|
5046
|
-
repair: report,
|
|
5047
|
-
branch: branchSummary
|
|
4473
|
+
repair: report
|
|
5048
4474
|
};
|
|
5049
4475
|
if (this.noteToolFailureSignal("", report)) {
|
|
5050
4476
|
yield {
|
|
@@ -5278,6 +4704,7 @@ function ignoredByLayers(layers, abs, isDir) {
|
|
|
5278
4704
|
|
|
5279
4705
|
// src/at-mentions.ts
|
|
5280
4706
|
var DEFAULT_AT_MENTION_MAX_BYTES = 64 * 1024;
|
|
4707
|
+
var DEFAULT_AT_DIR_MAX_ENTRIES = 200;
|
|
5281
4708
|
var DEFAULT_PICKER_IGNORE_DIRS = [
|
|
5282
4709
|
"node_modules",
|
|
5283
4710
|
".git",
|
|
@@ -5333,6 +4760,16 @@ function listFilesWithStatsSync(root, opts = {}) {
|
|
|
5333
4760
|
} catch {
|
|
5334
4761
|
}
|
|
5335
4762
|
out.push({ path: relPath, mtimeMs });
|
|
4763
|
+
} else if (ent.isSymbolicLink()) {
|
|
4764
|
+
let target = null;
|
|
4765
|
+
try {
|
|
4766
|
+
target = statSync2(absPath);
|
|
4767
|
+
} catch {
|
|
4768
|
+
continue;
|
|
4769
|
+
}
|
|
4770
|
+
if (!target.isFile()) continue;
|
|
4771
|
+
if (ignoredByLayers(effectiveLayers, absPath, false)) continue;
|
|
4772
|
+
out.push({ path: relPath, mtimeMs: target.mtimeMs });
|
|
5336
4773
|
}
|
|
5337
4774
|
}
|
|
5338
4775
|
};
|
|
@@ -5373,7 +4810,7 @@ async function listFilesWithStatsAsync(root, opts = {}) {
|
|
|
5373
4810
|
if (out.length >= maxResults) return;
|
|
5374
4811
|
}
|
|
5375
4812
|
await walk2(absPath, relPath, effectiveLayers);
|
|
5376
|
-
} else if (ent.isFile()) {
|
|
4813
|
+
} else if (ent.isFile() || ent.isSymbolicLink()) {
|
|
5377
4814
|
fileEnts.push(ent);
|
|
5378
4815
|
}
|
|
5379
4816
|
}
|
|
@@ -5393,14 +4830,18 @@ async function statBatch(ents, dirAbs, dirRel, out, maxResults, layers) {
|
|
|
5393
4830
|
}
|
|
5394
4831
|
const stats = await Promise.all(
|
|
5395
4832
|
accepted.map(
|
|
5396
|
-
(e) => stat(join5(dirAbs, e.name)).then((s) => s.mtimeMs).catch(() =>
|
|
4833
|
+
(e) => stat(join5(dirAbs, e.name)).then((s) => ({ mtimeMs: s.mtimeMs, isFile: s.isFile() })).catch(() => null)
|
|
5397
4834
|
)
|
|
5398
4835
|
);
|
|
5399
4836
|
for (let i = 0; i < accepted.length; i++) {
|
|
5400
4837
|
const ent = accepted[i];
|
|
4838
|
+
const s = stats[i];
|
|
4839
|
+
if (ent.isSymbolicLink()) {
|
|
4840
|
+
if (!s || !s.isFile) continue;
|
|
4841
|
+
}
|
|
5401
4842
|
out.push({
|
|
5402
4843
|
path: dirRel ? `${dirRel}/${ent.name}` : ent.name,
|
|
5403
|
-
mtimeMs:
|
|
4844
|
+
mtimeMs: s?.mtimeMs ?? 0
|
|
5404
4845
|
});
|
|
5405
4846
|
}
|
|
5406
4847
|
}
|
|
@@ -5438,15 +4879,25 @@ function rankPickerCandidates(files, query, limitOrOpts) {
|
|
|
5438
4879
|
for (const e of entries) {
|
|
5439
4880
|
const lower = e.path.toLowerCase();
|
|
5440
4881
|
const hit = lower.indexOf(needle);
|
|
5441
|
-
if (hit
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
4882
|
+
if (hit >= 0) {
|
|
4883
|
+
const slash = lower.lastIndexOf("/");
|
|
4884
|
+
const base = slash >= 0 ? lower.slice(slash + 1) : lower;
|
|
4885
|
+
let cls = 2;
|
|
4886
|
+
if (base.startsWith(needle)) cls = 0;
|
|
4887
|
+
else if (lower.startsWith(needle)) cls = 1;
|
|
4888
|
+
scored.push({
|
|
4889
|
+
path: e.path,
|
|
4890
|
+
score: cls * 1e4 + Math.min(hit, 9999),
|
|
4891
|
+
mtimeMs: e.mtimeMs,
|
|
4892
|
+
recent: recent.has(e.path)
|
|
4893
|
+
});
|
|
4894
|
+
continue;
|
|
4895
|
+
}
|
|
4896
|
+
const fuzzy = fuzzySubseqScore(needle, lower);
|
|
4897
|
+
if (fuzzy === null) continue;
|
|
5447
4898
|
scored.push({
|
|
5448
4899
|
path: e.path,
|
|
5449
|
-
score:
|
|
4900
|
+
score: 3e4 + fuzzy,
|
|
5450
4901
|
mtimeMs: e.mtimeMs,
|
|
5451
4902
|
recent: recent.has(e.path)
|
|
5452
4903
|
});
|
|
@@ -5458,29 +4909,63 @@ function rankPickerCandidates(files, query, limitOrOpts) {
|
|
|
5458
4909
|
});
|
|
5459
4910
|
return scored.slice(0, limit).map((s) => s.path);
|
|
5460
4911
|
}
|
|
4912
|
+
function fuzzySubseqScore(needle, target) {
|
|
4913
|
+
if (needle.length === 0) return 0;
|
|
4914
|
+
const slashIdx = target.lastIndexOf("/");
|
|
4915
|
+
const basenameStart = slashIdx >= 0 ? slashIdx + 1 : 0;
|
|
4916
|
+
let qi = 0;
|
|
4917
|
+
let lastMatchIdx = -2;
|
|
4918
|
+
let consecutive = 0;
|
|
4919
|
+
let basenameMatches = 0;
|
|
4920
|
+
let totalGap = 0;
|
|
4921
|
+
for (let ti = 0; ti < target.length && qi < needle.length; ti++) {
|
|
4922
|
+
if (target[ti] !== needle[qi]) continue;
|
|
4923
|
+
if (ti === lastMatchIdx + 1) consecutive++;
|
|
4924
|
+
else if (lastMatchIdx >= 0) totalGap += ti - lastMatchIdx - 1;
|
|
4925
|
+
if (ti >= basenameStart) basenameMatches++;
|
|
4926
|
+
lastMatchIdx = ti;
|
|
4927
|
+
qi++;
|
|
4928
|
+
}
|
|
4929
|
+
if (qi < needle.length) return null;
|
|
4930
|
+
const quality = Math.max(0, totalGap - consecutive * 10 - basenameMatches * 5);
|
|
4931
|
+
const lengthPenalty = Math.floor(target.length / 4);
|
|
4932
|
+
return quality + lengthPenalty;
|
|
4933
|
+
}
|
|
5461
4934
|
var AT_MENTION_PATTERN = /(?<=^|\s)@([a-zA-Z0-9_./\\-]+)/g;
|
|
5462
4935
|
function expandAtMentions(text, rootDir, opts = {}) {
|
|
5463
4936
|
const maxBytes = opts.maxBytes ?? DEFAULT_AT_MENTION_MAX_BYTES;
|
|
5464
|
-
const
|
|
4937
|
+
const maxDirEntries = Math.max(1, opts.maxDirEntries ?? DEFAULT_AT_DIR_MAX_ENTRIES);
|
|
4938
|
+
const fs5 = opts.fs ?? defaultFs;
|
|
5465
4939
|
const root = resolve(rootDir);
|
|
5466
4940
|
const seen = /* @__PURE__ */ new Map();
|
|
5467
4941
|
const expansions = [];
|
|
4942
|
+
const dirListings = /* @__PURE__ */ new Map();
|
|
5468
4943
|
for (const match of text.matchAll(AT_MENTION_PATTERN)) {
|
|
5469
4944
|
const rawPath = match[1] ?? "";
|
|
5470
4945
|
let cleaned = rawPath;
|
|
5471
4946
|
while (cleaned.endsWith(".")) cleaned = cleaned.slice(0, -1);
|
|
4947
|
+
if (cleaned.endsWith("/") || cleaned.endsWith("\\")) cleaned = cleaned.slice(0, -1);
|
|
5472
4948
|
if (!cleaned) continue;
|
|
5473
4949
|
const token = `@${cleaned}`;
|
|
5474
4950
|
if (seen.has(token)) continue;
|
|
5475
|
-
const expansion = resolveMention(cleaned, root, maxBytes,
|
|
4951
|
+
const expansion = resolveMention(cleaned, root, maxBytes, maxDirEntries, fs5, dirListings);
|
|
5476
4952
|
seen.set(token, expansion);
|
|
5477
4953
|
expansions.push(expansion);
|
|
5478
4954
|
}
|
|
5479
4955
|
if (expansions.length === 0) return { text, expansions };
|
|
5480
4956
|
const blocks = [];
|
|
5481
4957
|
for (const ex of expansions) {
|
|
5482
|
-
if (ex.ok) {
|
|
5483
|
-
const
|
|
4958
|
+
if (ex.ok && ex.isDirectory) {
|
|
4959
|
+
const files = dirListings.get(ex.path) ?? [];
|
|
4960
|
+
const truncAttr = ex.truncated ? ' truncated="true"' : "";
|
|
4961
|
+
const body = files.length > 0 ? `
|
|
4962
|
+
${files.join("\n")}
|
|
4963
|
+
` : "\n";
|
|
4964
|
+
blocks.push(
|
|
4965
|
+
`<directory path="${ex.path}" entries="${ex.entries ?? files.length}"${truncAttr}>${body}</directory>`
|
|
4966
|
+
);
|
|
4967
|
+
} else if (ex.ok) {
|
|
4968
|
+
const content = readSafe(root, ex.path, fs5);
|
|
5484
4969
|
blocks.push(`<file path="${ex.path}">
|
|
5485
4970
|
${content}
|
|
5486
4971
|
</file>`);
|
|
@@ -5494,7 +4979,7 @@ ${content}
|
|
|
5494
4979
|
${blocks.join("\n\n")}`;
|
|
5495
4980
|
return { text: augmented, expansions };
|
|
5496
4981
|
}
|
|
5497
|
-
function resolveMention(rawPath, root, maxBytes,
|
|
4982
|
+
function resolveMention(rawPath, root, maxBytes, maxDirEntries, fs5, dirListings) {
|
|
5498
4983
|
if (isAbsolute(rawPath)) {
|
|
5499
4984
|
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
5500
4985
|
}
|
|
@@ -5503,22 +4988,34 @@ function resolveMention(rawPath, root, maxBytes, fs4) {
|
|
|
5503
4988
|
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
5504
4989
|
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "escape" };
|
|
5505
4990
|
}
|
|
5506
|
-
if (!
|
|
4991
|
+
if (!fs5.exists(resolved)) {
|
|
5507
4992
|
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "missing" };
|
|
5508
4993
|
}
|
|
5509
|
-
if (
|
|
5510
|
-
|
|
4994
|
+
if (fs5.isFile(resolved)) {
|
|
4995
|
+
const size = fs5.size(resolved);
|
|
4996
|
+
if (size > maxBytes) {
|
|
4997
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "too-large", bytes: size };
|
|
4998
|
+
}
|
|
4999
|
+
return { token: `@${rawPath}`, path: rawPath, ok: true, bytes: size };
|
|
5511
5000
|
}
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5001
|
+
if (fs5.isDir?.(resolved) && fs5.listDir) {
|
|
5002
|
+
const { files, truncated } = fs5.listDir(resolved, root, maxDirEntries);
|
|
5003
|
+
dirListings.set(rawPath, files);
|
|
5004
|
+
return {
|
|
5005
|
+
token: `@${rawPath}`,
|
|
5006
|
+
path: rawPath,
|
|
5007
|
+
ok: true,
|
|
5008
|
+
isDirectory: true,
|
|
5009
|
+
entries: files.length,
|
|
5010
|
+
truncated
|
|
5011
|
+
};
|
|
5515
5012
|
}
|
|
5516
|
-
return { token: `@${rawPath}`, path: rawPath, ok:
|
|
5013
|
+
return { token: `@${rawPath}`, path: rawPath, ok: false, skip: "not-file" };
|
|
5517
5014
|
}
|
|
5518
|
-
function readSafe(root, rawPath,
|
|
5015
|
+
function readSafe(root, rawPath, fs5) {
|
|
5519
5016
|
const resolved = resolve(root, rawPath);
|
|
5520
5017
|
try {
|
|
5521
|
-
return
|
|
5018
|
+
return fs5.read(resolved);
|
|
5522
5019
|
} catch {
|
|
5523
5020
|
return "(read failed)";
|
|
5524
5021
|
}
|
|
@@ -5532,6 +5029,24 @@ var defaultFs = {
|
|
|
5532
5029
|
return false;
|
|
5533
5030
|
}
|
|
5534
5031
|
},
|
|
5032
|
+
isDir: (p) => {
|
|
5033
|
+
try {
|
|
5034
|
+
return statSync2(p).isDirectory();
|
|
5035
|
+
} catch {
|
|
5036
|
+
return false;
|
|
5037
|
+
}
|
|
5038
|
+
},
|
|
5039
|
+
listDir: (dirAbs, root, max) => {
|
|
5040
|
+
const dirRel = relative(root, dirAbs).split(/[\\/]/).join("/");
|
|
5041
|
+
const walkCap = Math.max(max * 4, 5e3);
|
|
5042
|
+
const all = listFilesSync(root, { maxResults: walkCap });
|
|
5043
|
+
const prefix = dirRel ? `${dirRel}/` : "";
|
|
5044
|
+
const filtered = dirRel ? all.filter((f) => f === dirRel || f.startsWith(prefix)) : all;
|
|
5045
|
+
return {
|
|
5046
|
+
files: filtered.slice(0, max),
|
|
5047
|
+
truncated: filtered.length > max
|
|
5048
|
+
};
|
|
5049
|
+
},
|
|
5535
5050
|
size: (p) => {
|
|
5536
5051
|
try {
|
|
5537
5052
|
return statSync2(p).size;
|
|
@@ -6313,9 +5828,9 @@ function applyMemoryStack(basePrompt, rootDir) {
|
|
|
6313
5828
|
}
|
|
6314
5829
|
|
|
6315
5830
|
// src/tools/filesystem.ts
|
|
6316
|
-
import { promises as
|
|
6317
|
-
import * as
|
|
6318
|
-
import
|
|
5831
|
+
import { promises as fs4 } from "fs";
|
|
5832
|
+
import * as pathMod4 from "path";
|
|
5833
|
+
import picomatch3 from "picomatch";
|
|
6319
5834
|
|
|
6320
5835
|
// src/tools/fs/edit.ts
|
|
6321
5836
|
import { promises as fs } from "fs";
|
|
@@ -6350,6 +5865,83 @@ async function applyEdit(rootDir, abs, args) {
|
|
|
6350
5865
|
return `${header}
|
|
6351
5866
|
${diff}`;
|
|
6352
5867
|
}
|
|
5868
|
+
async function applyMultiEdit(rootDir, edits) {
|
|
5869
|
+
if (edits.length === 0) {
|
|
5870
|
+
throw new Error("multi_edit: edits must contain at least one entry");
|
|
5871
|
+
}
|
|
5872
|
+
const filesByPath = /* @__PURE__ */ new Map();
|
|
5873
|
+
for (let i = 0; i < edits.length; i++) {
|
|
5874
|
+
const e = edits[i];
|
|
5875
|
+
if (typeof e.abs !== "string" || e.abs.length === 0) {
|
|
5876
|
+
throw new Error(`multi_edit: edit #${i + 1} requires a string \`path\` (no edits applied)`);
|
|
5877
|
+
}
|
|
5878
|
+
if (typeof e.search !== "string") {
|
|
5879
|
+
throw new Error(`multi_edit: edit #${i + 1} requires a string \`search\` (no edits applied)`);
|
|
5880
|
+
}
|
|
5881
|
+
if (typeof e.replace !== "string") {
|
|
5882
|
+
throw new Error(
|
|
5883
|
+
`multi_edit: edit #${i + 1} requires a string \`replace\` (no edits applied)`
|
|
5884
|
+
);
|
|
5885
|
+
}
|
|
5886
|
+
const rel = displayRel(rootDir, e.abs);
|
|
5887
|
+
if (e.search.length === 0) {
|
|
5888
|
+
throw new Error(
|
|
5889
|
+
`multi_edit: edit #${i + 1} (${rel}) search cannot be empty (no edits applied)`
|
|
5890
|
+
);
|
|
5891
|
+
}
|
|
5892
|
+
let state = filesByPath.get(e.abs);
|
|
5893
|
+
if (!state) {
|
|
5894
|
+
let before;
|
|
5895
|
+
try {
|
|
5896
|
+
before = await fs.readFile(e.abs, "utf8");
|
|
5897
|
+
} catch (err) {
|
|
5898
|
+
throw new Error(
|
|
5899
|
+
`multi_edit: edit #${i + 1} cannot read ${rel}: ${err.message} (no edits applied)`
|
|
5900
|
+
);
|
|
5901
|
+
}
|
|
5902
|
+
const le = before.includes("\r\n") ? "\r\n" : "\n";
|
|
5903
|
+
state = { buf: before, le, hunks: [], deltaChars: 0, touched: 0 };
|
|
5904
|
+
filesByPath.set(e.abs, state);
|
|
5905
|
+
}
|
|
5906
|
+
const adaptedSearch = e.search.replace(/\r?\n/g, state.le);
|
|
5907
|
+
const adaptedReplace = e.replace.replace(/\r?\n/g, state.le);
|
|
5908
|
+
const firstIdx = state.buf.indexOf(adaptedSearch);
|
|
5909
|
+
if (firstIdx < 0) {
|
|
5910
|
+
throw new Error(
|
|
5911
|
+
`multi_edit: edit #${i + 1} search text not found in ${rel} \u2014 no edits applied (multi_edit is atomic)`
|
|
5912
|
+
);
|
|
5913
|
+
}
|
|
5914
|
+
const nextIdx = state.buf.indexOf(adaptedSearch, firstIdx + 1);
|
|
5915
|
+
if (nextIdx >= 0) {
|
|
5916
|
+
throw new Error(
|
|
5917
|
+
`multi_edit: edit #${i + 1} search text appears multiple times in ${rel} \u2014 include more context to disambiguate (no edits applied)`
|
|
5918
|
+
);
|
|
5919
|
+
}
|
|
5920
|
+
const startLine = state.buf.slice(0, firstIdx).split(/\r?\n/).length;
|
|
5921
|
+
state.buf = state.buf.slice(0, firstIdx) + adaptedReplace + state.buf.slice(firstIdx + adaptedSearch.length);
|
|
5922
|
+
state.hunks.push(`# ${rel}
|
|
5923
|
+
${renderEditDiff(adaptedSearch, adaptedReplace, startLine)}`);
|
|
5924
|
+
state.deltaChars += adaptedReplace.length - adaptedSearch.length;
|
|
5925
|
+
state.touched++;
|
|
5926
|
+
}
|
|
5927
|
+
for (const [abs, state] of filesByPath) {
|
|
5928
|
+
await fs.writeFile(abs, state.buf, "utf8");
|
|
5929
|
+
}
|
|
5930
|
+
const fileCount = filesByPath.size;
|
|
5931
|
+
const editCount = edits.length;
|
|
5932
|
+
let totalDelta = 0;
|
|
5933
|
+
const allHunks = [];
|
|
5934
|
+
for (const state of filesByPath.values()) {
|
|
5935
|
+
totalDelta += state.deltaChars;
|
|
5936
|
+
allHunks.push(...state.hunks);
|
|
5937
|
+
}
|
|
5938
|
+
const sign = totalDelta >= 0 ? "+" : "";
|
|
5939
|
+
const editNoun = editCount === 1 ? "edit" : "edits";
|
|
5940
|
+
const fileNoun = fileCount === 1 ? "file" : "files";
|
|
5941
|
+
const header = `multi_edit: applied ${editCount} ${editNoun} across ${fileCount} ${fileNoun} (${sign}${totalDelta} chars)`;
|
|
5942
|
+
return `${header}
|
|
5943
|
+
${allHunks.join("\n")}`;
|
|
5944
|
+
}
|
|
6353
5945
|
function renderEditDiff(search, replace, startLine) {
|
|
6354
5946
|
const a = search.split(/\r?\n/);
|
|
6355
5947
|
const b = replace.split(/\r?\n/);
|
|
@@ -6396,15 +5988,78 @@ function lineDiff(a, b) {
|
|
|
6396
5988
|
return out;
|
|
6397
5989
|
}
|
|
6398
5990
|
|
|
6399
|
-
// src/tools/fs/
|
|
5991
|
+
// src/tools/fs/glob.ts
|
|
6400
5992
|
import { promises as fs2 } from "fs";
|
|
6401
5993
|
import * as pathMod2 from "path";
|
|
5994
|
+
import picomatch2 from "picomatch";
|
|
5995
|
+
function displayRel2(rootDir, full) {
|
|
5996
|
+
return pathMod2.relative(rootDir, full).replaceAll("\\", "/");
|
|
5997
|
+
}
|
|
5998
|
+
async function globFiles(ctx, startAbs, args) {
|
|
5999
|
+
if (args.signal?.aborted) {
|
|
6000
|
+
throw new DOMException("glob aborted by user", "AbortError");
|
|
6001
|
+
}
|
|
6002
|
+
const includeDeps = args.include_deps === true;
|
|
6003
|
+
const sortBy = args.sort_by ?? "mtime";
|
|
6004
|
+
const limit = Math.max(1, Math.min(1e3, Math.floor(args.limit ?? 200)));
|
|
6005
|
+
const isMatch = picomatch2(args.pattern, { dot: true, nocase: true });
|
|
6006
|
+
const hits = [];
|
|
6007
|
+
const walk2 = async (dir) => {
|
|
6008
|
+
if (args.signal?.aborted) {
|
|
6009
|
+
throw new DOMException("glob aborted by user", "AbortError");
|
|
6010
|
+
}
|
|
6011
|
+
let entries;
|
|
6012
|
+
try {
|
|
6013
|
+
entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
6014
|
+
} catch {
|
|
6015
|
+
return;
|
|
6016
|
+
}
|
|
6017
|
+
for (const e of entries) {
|
|
6018
|
+
const full = pathMod2.join(dir, e.name);
|
|
6019
|
+
if (e.isDirectory()) {
|
|
6020
|
+
if (!includeDeps && ctx.skipDirNames.has(e.name)) continue;
|
|
6021
|
+
await walk2(full);
|
|
6022
|
+
continue;
|
|
6023
|
+
}
|
|
6024
|
+
if (!e.isFile() && !e.isSymbolicLink()) continue;
|
|
6025
|
+
const rel = displayRel2(ctx.rootDir, full);
|
|
6026
|
+
if (!isMatch(rel)) continue;
|
|
6027
|
+
let mtimeMs = 0;
|
|
6028
|
+
if (sortBy === "mtime") {
|
|
6029
|
+
try {
|
|
6030
|
+
const st = await fs2.stat(full);
|
|
6031
|
+
mtimeMs = st.mtimeMs;
|
|
6032
|
+
} catch {
|
|
6033
|
+
continue;
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
hits.push({ rel, mtimeMs });
|
|
6037
|
+
}
|
|
6038
|
+
};
|
|
6039
|
+
await walk2(startAbs);
|
|
6040
|
+
if (hits.length === 0) return "(no matches)";
|
|
6041
|
+
if (sortBy === "mtime") hits.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
6042
|
+
else hits.sort((a, b) => a.rel.localeCompare(b.rel));
|
|
6043
|
+
const truncated = hits.length > limit;
|
|
6044
|
+
const shown = hits.slice(0, limit);
|
|
6045
|
+
const lines = shown.map((h) => h.rel);
|
|
6046
|
+
if (truncated) {
|
|
6047
|
+
lines.push(
|
|
6048
|
+
`[\u2026 ${hits.length - limit} more matches \u2014 refine pattern or raise limit (max 1000) \u2026]`
|
|
6049
|
+
);
|
|
6050
|
+
}
|
|
6051
|
+
return lines.join("\n");
|
|
6052
|
+
}
|
|
6053
|
+
|
|
6054
|
+
// src/tools/fs/search.ts
|
|
6055
|
+
import { promises as fs3 } from "fs";
|
|
6056
|
+
import * as pathMod3 from "path";
|
|
6402
6057
|
function throwIfAborted(signal) {
|
|
6403
6058
|
if (!signal?.aborted) return;
|
|
6404
6059
|
throw new DOMException("search aborted by user", "AbortError");
|
|
6405
6060
|
}
|
|
6406
|
-
function
|
|
6407
|
-
return
|
|
6061
|
+
function displayRel3(rootDir, full) {
|
|
6062
|
+
return pathMod3.relative(rootDir, full).replaceAll("\\", "/");
|
|
6408
6063
|
}
|
|
6409
6064
|
async function searchFiles(ctx, startAbs, args) {
|
|
6410
6065
|
throwIfAborted(args.signal);
|
|
@@ -6422,17 +6077,17 @@ async function searchFiles(ctx, startAbs, args) {
|
|
|
6422
6077
|
throwIfAborted(args.signal);
|
|
6423
6078
|
let entries;
|
|
6424
6079
|
try {
|
|
6425
|
-
entries = await
|
|
6080
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
6426
6081
|
} catch {
|
|
6427
6082
|
return;
|
|
6428
6083
|
}
|
|
6429
6084
|
for (const e of entries) {
|
|
6430
6085
|
throwIfAborted(args.signal);
|
|
6431
|
-
const full =
|
|
6086
|
+
const full = pathMod3.join(dir, e.name);
|
|
6432
6087
|
const lower = e.name.toLowerCase();
|
|
6433
6088
|
const hit = re ? re.test(e.name) : lower.includes(needle);
|
|
6434
6089
|
if (hit) {
|
|
6435
|
-
const rel =
|
|
6090
|
+
const rel = displayRel3(ctx.rootDir, full);
|
|
6436
6091
|
if (totalBytes + rel.length + 1 > ctx.maxListBytes) {
|
|
6437
6092
|
matches.push("[\u2026 search truncated \u2014 refine pattern \u2026]");
|
|
6438
6093
|
return;
|
|
@@ -6453,6 +6108,7 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
6453
6108
|
throwIfAborted(args.signal);
|
|
6454
6109
|
const caseSensitive = args.case_sensitive === true;
|
|
6455
6110
|
const includeDeps = args.include_deps === true;
|
|
6111
|
+
const ctxLines = Math.max(0, Math.min(20, Math.floor(args.context ?? 0)));
|
|
6456
6112
|
let re = null;
|
|
6457
6113
|
try {
|
|
6458
6114
|
re = new RegExp(args.pattern, caseSensitive ? "" : "i");
|
|
@@ -6464,12 +6120,22 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
6464
6120
|
let totalBytes = 0;
|
|
6465
6121
|
let scanned = 0;
|
|
6466
6122
|
let truncated = false;
|
|
6123
|
+
const pushLine = (out) => {
|
|
6124
|
+
if (totalBytes + out.length + 1 > ctx.maxListBytes) {
|
|
6125
|
+
matches.push(`[\u2026 truncated at ${ctx.maxListBytes} bytes \u2014 refine pattern or path \u2026]`);
|
|
6126
|
+
truncated = true;
|
|
6127
|
+
return false;
|
|
6128
|
+
}
|
|
6129
|
+
matches.push(out);
|
|
6130
|
+
totalBytes += out.length + 1;
|
|
6131
|
+
return true;
|
|
6132
|
+
};
|
|
6467
6133
|
const walk2 = async (dir) => {
|
|
6468
6134
|
if (truncated) return;
|
|
6469
6135
|
throwIfAborted(args.signal);
|
|
6470
6136
|
let entries;
|
|
6471
6137
|
try {
|
|
6472
|
-
entries = await
|
|
6138
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
6473
6139
|
} catch {
|
|
6474
6140
|
return;
|
|
6475
6141
|
}
|
|
@@ -6478,16 +6144,16 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
6478
6144
|
throwIfAborted(args.signal);
|
|
6479
6145
|
if (e.isDirectory()) {
|
|
6480
6146
|
if (!includeDeps && ctx.skipDirNames.has(e.name)) continue;
|
|
6481
|
-
await walk2(
|
|
6147
|
+
await walk2(pathMod3.join(dir, e.name));
|
|
6482
6148
|
continue;
|
|
6483
6149
|
}
|
|
6484
6150
|
if (!e.isFile()) continue;
|
|
6485
|
-
const full =
|
|
6486
|
-
if (ctx.nameMatch && !ctx.nameMatch(e.name,
|
|
6151
|
+
const full = pathMod3.join(dir, e.name);
|
|
6152
|
+
if (ctx.nameMatch && !ctx.nameMatch(e.name, displayRel3(ctx.rootDir, full))) continue;
|
|
6487
6153
|
if (ctx.isBinaryByName(e.name)) continue;
|
|
6488
6154
|
let fh;
|
|
6489
6155
|
try {
|
|
6490
|
-
fh = await
|
|
6156
|
+
fh = await fs3.open(full, "r");
|
|
6491
6157
|
} catch {
|
|
6492
6158
|
continue;
|
|
6493
6159
|
}
|
|
@@ -6510,25 +6176,45 @@ async function searchContent(ctx, startAbs, args) {
|
|
|
6510
6176
|
const firstNul = raw.indexOf(0);
|
|
6511
6177
|
if (firstNul !== -1 && firstNul < 8 * 1024) continue;
|
|
6512
6178
|
const text = raw.toString("utf8");
|
|
6513
|
-
const rel =
|
|
6179
|
+
const rel = displayRel3(ctx.rootDir, full);
|
|
6514
6180
|
const lines = text.split(/\r?\n/);
|
|
6181
|
+
const hits = [];
|
|
6515
6182
|
for (let li = 0; li < lines.length; li++) {
|
|
6516
6183
|
throwIfAborted(args.signal);
|
|
6517
6184
|
const line = lines[li];
|
|
6518
6185
|
const lineForCheck = caseSensitive ? line : line.toLowerCase();
|
|
6519
6186
|
const hit = re ? re.test(line) : lineForCheck.includes(needle);
|
|
6520
|
-
if (
|
|
6521
|
-
const display = line.length > 200 ? `${line.slice(0, 200)}\u2026` : line;
|
|
6522
|
-
const out = `${rel}:${li + 1}: ${display}`;
|
|
6523
|
-
if (totalBytes + out.length + 1 > ctx.maxListBytes) {
|
|
6524
|
-
matches.push(`[\u2026 truncated at ${ctx.maxListBytes} bytes \u2014 refine pattern or path \u2026]`);
|
|
6525
|
-
truncated = true;
|
|
6526
|
-
return;
|
|
6527
|
-
}
|
|
6528
|
-
matches.push(out);
|
|
6529
|
-
totalBytes += out.length + 1;
|
|
6187
|
+
if (hit) hits.push(li);
|
|
6530
6188
|
}
|
|
6531
6189
|
scanned++;
|
|
6190
|
+
if (hits.length === 0) continue;
|
|
6191
|
+
if (ctxLines === 0) {
|
|
6192
|
+
for (const li of hits) {
|
|
6193
|
+
if (truncated) return;
|
|
6194
|
+
const line = lines[li];
|
|
6195
|
+
const display = line.length > 200 ? `${line.slice(0, 200)}\u2026` : line;
|
|
6196
|
+
if (!pushLine(`${rel}:${li + 1}: ${display}`)) return;
|
|
6197
|
+
}
|
|
6198
|
+
continue;
|
|
6199
|
+
}
|
|
6200
|
+
const hitSet = new Set(hits);
|
|
6201
|
+
let prevWindowEnd = -2;
|
|
6202
|
+
for (const li of hits) {
|
|
6203
|
+
if (truncated) return;
|
|
6204
|
+
const winStart = Math.max(0, li - ctxLines);
|
|
6205
|
+
const winEnd = Math.min(lines.length - 1, li + ctxLines);
|
|
6206
|
+
if (winStart > prevWindowEnd + 1 && prevWindowEnd >= 0) {
|
|
6207
|
+
if (!pushLine("--")) return;
|
|
6208
|
+
}
|
|
6209
|
+
const realStart = winStart > prevWindowEnd + 1 ? winStart : prevWindowEnd + 1;
|
|
6210
|
+
for (let i = realStart; i <= winEnd; i++) {
|
|
6211
|
+
const line = lines[i];
|
|
6212
|
+
const display = line.length > 200 ? `${line.slice(0, 200)}\u2026` : line;
|
|
6213
|
+
const sep2 = hitSet.has(i) ? ":" : "-";
|
|
6214
|
+
if (!pushLine(`${rel}:${i + 1}${sep2} ${display}`)) return;
|
|
6215
|
+
}
|
|
6216
|
+
prevWindowEnd = winEnd;
|
|
6217
|
+
}
|
|
6532
6218
|
}
|
|
6533
6219
|
};
|
|
6534
6220
|
await walk2(startAbs);
|
|
@@ -6546,8 +6232,8 @@ var AUTO_PREVIEW_HEAD_LINES = 80;
|
|
|
6546
6232
|
var AUTO_PREVIEW_TAIL_LINES = 40;
|
|
6547
6233
|
var SKIP_DIR_NAMES = new Set(DEFAULT_INDEX_EXCLUDES.dirs);
|
|
6548
6234
|
var BINARY_EXTENSIONS = new Set(DEFAULT_INDEX_EXCLUDES.exts);
|
|
6549
|
-
function
|
|
6550
|
-
return
|
|
6235
|
+
function displayRel4(rootDir, full) {
|
|
6236
|
+
return pathMod4.relative(rootDir, full).replaceAll("\\", "/");
|
|
6551
6237
|
}
|
|
6552
6238
|
var GLOB_METACHARS = /[*?{[]/;
|
|
6553
6239
|
function compileNameFilter(filter) {
|
|
@@ -6557,7 +6243,7 @@ function compileNameFilter(filter) {
|
|
|
6557
6243
|
return (name) => name.toLowerCase().includes(needle);
|
|
6558
6244
|
}
|
|
6559
6245
|
const matchPath = filter.includes("/");
|
|
6560
|
-
const isMatch =
|
|
6246
|
+
const isMatch = picomatch3(filter, { dot: true, nocase: true });
|
|
6561
6247
|
return matchPath ? (_n, rel) => isMatch(rel) : (name) => isMatch(name);
|
|
6562
6248
|
}
|
|
6563
6249
|
function isLikelyBinaryByName(name) {
|
|
@@ -6566,7 +6252,7 @@ function isLikelyBinaryByName(name) {
|
|
|
6566
6252
|
return BINARY_EXTENSIONS.has(name.slice(dot).toLowerCase());
|
|
6567
6253
|
}
|
|
6568
6254
|
function registerFilesystemTools(registry, opts) {
|
|
6569
|
-
const rootDir =
|
|
6255
|
+
const rootDir = pathMod4.resolve(opts.rootDir);
|
|
6570
6256
|
const allowWriting = opts.allowWriting !== false;
|
|
6571
6257
|
const maxReadBytes = opts.maxReadBytes ?? DEFAULT_MAX_READ_BYTES;
|
|
6572
6258
|
const maxListBytes = opts.maxListBytes ?? DEFAULT_MAX_LIST_BYTES;
|
|
@@ -6579,10 +6265,10 @@ function registerFilesystemTools(registry, opts) {
|
|
|
6579
6265
|
normalized = normalized.slice(1);
|
|
6580
6266
|
}
|
|
6581
6267
|
if (normalized.length === 0) normalized = ".";
|
|
6582
|
-
const resolved =
|
|
6583
|
-
const normRoot =
|
|
6584
|
-
const rel =
|
|
6585
|
-
if (rel.startsWith("..") ||
|
|
6268
|
+
const resolved = pathMod4.resolve(rootDir, normalized);
|
|
6269
|
+
const normRoot = pathMod4.resolve(rootDir);
|
|
6270
|
+
const rel = pathMod4.relative(normRoot, resolved);
|
|
6271
|
+
if (rel.startsWith("..") || pathMod4.isAbsolute(rel)) {
|
|
6586
6272
|
throw new Error(
|
|
6587
6273
|
`path escapes sandbox root (${normRoot}): ${raw} \u2014 workspace is pinned at launch; quit and relaunch with \`reasonix code --dir <path>\` to work in a different folder`
|
|
6588
6274
|
);
|
|
@@ -6614,7 +6300,7 @@ When none of these is given AND the file is longer than ${DEFAULT_AUTO_PREVIEW_L
|
|
|
6614
6300
|
},
|
|
6615
6301
|
fn: async (args) => {
|
|
6616
6302
|
const abs = safePath(args.path);
|
|
6617
|
-
const fh = await
|
|
6303
|
+
const fh = await fs4.open(abs, "r");
|
|
6618
6304
|
let raw;
|
|
6619
6305
|
try {
|
|
6620
6306
|
const stat2 = await fh.stat();
|
|
@@ -6688,7 +6374,7 @@ ${slice.join("\n")}`;
|
|
|
6688
6374
|
},
|
|
6689
6375
|
fn: async (args) => {
|
|
6690
6376
|
const abs = safePath(args.path ?? ".");
|
|
6691
|
-
const entries = await
|
|
6377
|
+
const entries = await fs4.readdir(abs, { withFileTypes: true });
|
|
6692
6378
|
const lines = [];
|
|
6693
6379
|
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
6694
6380
|
lines.push(e.isDirectory() ? `${e.name}/` : e.name);
|
|
@@ -6732,7 +6418,7 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6732
6418
|
if (depth > maxDepth) return;
|
|
6733
6419
|
let entries;
|
|
6734
6420
|
try {
|
|
6735
|
-
entries = await
|
|
6421
|
+
entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
6736
6422
|
} catch {
|
|
6737
6423
|
return;
|
|
6738
6424
|
}
|
|
@@ -6767,7 +6453,7 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6767
6453
|
lines.push(line);
|
|
6768
6454
|
emitted++;
|
|
6769
6455
|
if (e.isDirectory() && !skip) {
|
|
6770
|
-
await walk2(
|
|
6456
|
+
await walk2(pathMod4.join(dir, e.name), depth + 1);
|
|
6771
6457
|
}
|
|
6772
6458
|
}
|
|
6773
6459
|
};
|
|
@@ -6828,6 +6514,10 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6828
6514
|
include_deps: {
|
|
6829
6515
|
type: "boolean",
|
|
6830
6516
|
description: "When true, also search inside node_modules / .git / dist / build / etc. Off by default \u2014 most exploration questions are about the user's own code."
|
|
6517
|
+
},
|
|
6518
|
+
context: {
|
|
6519
|
+
type: "integer",
|
|
6520
|
+
description: "Lines of context to show around each match (both before and after). Default 0 (just the matching line). Capped at 20. Output uses ripgrep style: `:` after the line number on the matching line, `-` on context lines, `--` separating non-adjacent windows."
|
|
6831
6521
|
}
|
|
6832
6522
|
},
|
|
6833
6523
|
required: ["pattern"]
|
|
@@ -6844,6 +6534,43 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6844
6534
|
{ ...args, signal: toolCtx?.signal }
|
|
6845
6535
|
)
|
|
6846
6536
|
});
|
|
6537
|
+
registry.register({
|
|
6538
|
+
name: "glob",
|
|
6539
|
+
parallelSafe: true,
|
|
6540
|
+
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).",
|
|
6541
|
+
readOnly: true,
|
|
6542
|
+
parameters: {
|
|
6543
|
+
type: "object",
|
|
6544
|
+
properties: {
|
|
6545
|
+
pattern: {
|
|
6546
|
+
type: "string",
|
|
6547
|
+
description: "Glob pattern, e.g. 'src/**/*.ts', '**/*.{md,mdx}', 'tests/*.test.ts'."
|
|
6548
|
+
},
|
|
6549
|
+
path: {
|
|
6550
|
+
type: "string",
|
|
6551
|
+
description: "Base directory to walk (default: sandbox root). The pattern matches relative to this path."
|
|
6552
|
+
},
|
|
6553
|
+
sort_by: {
|
|
6554
|
+
type: "string",
|
|
6555
|
+
enum: ["mtime", "name"],
|
|
6556
|
+
description: "Sort order. 'mtime' (default) shows most-recently-modified first \u2014 useful for 'what did I change today'. 'name' is alphabetical."
|
|
6557
|
+
},
|
|
6558
|
+
include_deps: {
|
|
6559
|
+
type: "boolean",
|
|
6560
|
+
description: "When true, also walk node_modules / .git / dist / build / etc. Off by default."
|
|
6561
|
+
},
|
|
6562
|
+
limit: {
|
|
6563
|
+
type: "integer",
|
|
6564
|
+
description: "Cap on returned matches. Default 200; clamped to [1, 1000]."
|
|
6565
|
+
}
|
|
6566
|
+
},
|
|
6567
|
+
required: ["pattern"]
|
|
6568
|
+
},
|
|
6569
|
+
fn: async (args, toolCtx) => globFiles({ rootDir, skipDirNames: SKIP_DIR_NAMES }, safePath(args.path ?? "."), {
|
|
6570
|
+
...args,
|
|
6571
|
+
signal: toolCtx?.signal
|
|
6572
|
+
})
|
|
6573
|
+
});
|
|
6847
6574
|
registry.register({
|
|
6848
6575
|
name: "get_file_info",
|
|
6849
6576
|
parallelSafe: true,
|
|
@@ -6858,7 +6585,7 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6858
6585
|
},
|
|
6859
6586
|
fn: async (args) => {
|
|
6860
6587
|
const abs = safePath(args.path);
|
|
6861
|
-
const st = await
|
|
6588
|
+
const st = await fs4.lstat(abs);
|
|
6862
6589
|
const type = st.isDirectory() ? "directory" : st.isSymbolicLink() ? "symlink" : "file";
|
|
6863
6590
|
return JSON.stringify({
|
|
6864
6591
|
type,
|
|
@@ -6881,9 +6608,9 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6881
6608
|
},
|
|
6882
6609
|
fn: async (args) => {
|
|
6883
6610
|
const abs = safePath(args.path);
|
|
6884
|
-
await
|
|
6885
|
-
await
|
|
6886
|
-
return `wrote ${args.content.length} chars to ${
|
|
6611
|
+
await fs4.mkdir(pathMod4.dirname(abs), { recursive: true });
|
|
6612
|
+
await fs4.writeFile(abs, args.content, "utf8");
|
|
6613
|
+
return `wrote ${args.content.length} chars to ${displayRel4(rootDir, abs)}`;
|
|
6887
6614
|
}
|
|
6888
6615
|
});
|
|
6889
6616
|
registry.register({
|
|
@@ -6900,6 +6627,43 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6900
6627
|
},
|
|
6901
6628
|
fn: async (args) => applyEdit(rootDir, safePath(args.path), args)
|
|
6902
6629
|
});
|
|
6630
|
+
registry.register({
|
|
6631
|
+
name: "multi_edit",
|
|
6632
|
+
description: "Apply N SEARCH/REPLACE edits across ONE OR MORE files in a single atomic call. Edits run sequentially in array order; for edits that touch the same file, a later edit can match text inserted by an earlier one. If ANY edit fails (search not found, ambiguous match, empty search, file unreadable), NO files are written \u2014 atomic at the validation layer. Same per-edit rules as edit_file: `search` is exact text (whitespace sensitive, no regex) and must be unique in its target file at the moment that edit applies. Use this for renames spanning multiple files, cross-file refactors, or any batch where you'd otherwise loop edit_file.",
|
|
6633
|
+
parameters: {
|
|
6634
|
+
type: "object",
|
|
6635
|
+
properties: {
|
|
6636
|
+
edits: {
|
|
6637
|
+
type: "array",
|
|
6638
|
+
description: "Edits to apply in order. Length \u2265 1. Each edit names its own target file.",
|
|
6639
|
+
items: {
|
|
6640
|
+
type: "object",
|
|
6641
|
+
properties: {
|
|
6642
|
+
path: {
|
|
6643
|
+
type: "string",
|
|
6644
|
+
description: "File the edit targets (sandbox-relative or absolute)."
|
|
6645
|
+
},
|
|
6646
|
+
search: {
|
|
6647
|
+
type: "string",
|
|
6648
|
+
description: "Exact text to find (must be unique in the file)."
|
|
6649
|
+
},
|
|
6650
|
+
replace: { type: "string", description: "Text to substitute in place of `search`." }
|
|
6651
|
+
},
|
|
6652
|
+
required: ["path", "search", "replace"]
|
|
6653
|
+
}
|
|
6654
|
+
}
|
|
6655
|
+
},
|
|
6656
|
+
required: ["edits"]
|
|
6657
|
+
},
|
|
6658
|
+
fn: async (args) => {
|
|
6659
|
+
const resolved = (args.edits ?? []).map((e) => ({
|
|
6660
|
+
abs: safePath(e?.path),
|
|
6661
|
+
search: e?.search,
|
|
6662
|
+
replace: e?.replace
|
|
6663
|
+
}));
|
|
6664
|
+
return applyMultiEdit(rootDir, resolved);
|
|
6665
|
+
}
|
|
6666
|
+
});
|
|
6903
6667
|
registry.register({
|
|
6904
6668
|
name: "create_directory",
|
|
6905
6669
|
description: "Create a directory (and any missing parents) under the sandbox root.",
|
|
@@ -6910,8 +6674,8 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6910
6674
|
},
|
|
6911
6675
|
fn: async (args) => {
|
|
6912
6676
|
const abs = safePath(args.path);
|
|
6913
|
-
await
|
|
6914
|
-
return `created ${
|
|
6677
|
+
await fs4.mkdir(abs, { recursive: true });
|
|
6678
|
+
return `created ${displayRel4(rootDir, abs)}/`;
|
|
6915
6679
|
}
|
|
6916
6680
|
});
|
|
6917
6681
|
registry.register({
|
|
@@ -6928,9 +6692,9 @@ Prefer \`list_directory\` for a single-level view, \`search_files\` to find spec
|
|
|
6928
6692
|
fn: async (args) => {
|
|
6929
6693
|
const src = safePath(args.source);
|
|
6930
6694
|
const dst = safePath(args.destination);
|
|
6931
|
-
await
|
|
6932
|
-
await
|
|
6933
|
-
return `moved ${
|
|
6695
|
+
await fs4.mkdir(pathMod4.dirname(dst), { recursive: true });
|
|
6696
|
+
await fs4.rename(src, dst);
|
|
6697
|
+
return `moved ${displayRel4(rootDir, src)} \u2192 ${displayRel4(rootDir, dst)}`;
|
|
6934
6698
|
}
|
|
6935
6699
|
});
|
|
6936
6700
|
return registry;
|
|
@@ -7409,6 +7173,108 @@ function registerPlanTool(registry, opts = {}) {
|
|
|
7409
7173
|
return registry;
|
|
7410
7174
|
}
|
|
7411
7175
|
|
|
7176
|
+
// src/tools/todo.ts
|
|
7177
|
+
var DESCRIPTION = 'In-session task tracker for multi-step work. NOT a plan \u2014 no approval gate, no checkpoint pauses, doesn\'t touch any files. The tool replaces the entire todo list every call (set semantics, NOT append). Pass the FULL list every time.\n\nWhen to use:\n\u2022 The task has 3+ distinct steps and you want to keep them straight as you work.\n\u2022 The user gave you a multi-part request ("do A, then B, then C").\n\u2022 You\'re partway through a long task and want to record where you are so a future you doesn\'t lose the thread.\n\nWhen NOT to use:\n\u2022 One-shot edits, single-question answers, single-tool tasks.\n\u2022 User-facing approval gates \u2192 that\'s `submit_plan`.\n\u2022 Branching choices \u2192 that\'s `ask_choice`.\n\nRules:\n\u2022 Exactly ONE todo may have status:"in_progress" at a time (or zero \u2014 between steps).\n\u2022 Mark a todo "completed" the moment it\'s actually done \u2014 don\'t batch.\n\u2022 Each todo: `content` (imperative, e.g. "Add tests"), `activeForm` (gerund shown while running, e.g. "Adding tests"), `status`.\n\u2022 Empty `todos:[]` is allowed \u2014 it clears the list when work is fully done.';
|
|
7178
|
+
function validateTodos(raw) {
|
|
7179
|
+
if (!Array.isArray(raw)) {
|
|
7180
|
+
throw new Error("todo_write: `todos` must be an array");
|
|
7181
|
+
}
|
|
7182
|
+
const out = [];
|
|
7183
|
+
let inProgressCount = 0;
|
|
7184
|
+
for (let i = 0; i < raw.length; i++) {
|
|
7185
|
+
const entry = raw[i];
|
|
7186
|
+
if (!entry || typeof entry !== "object") {
|
|
7187
|
+
throw new Error(`todo_write: todo #${i + 1} must be an object`);
|
|
7188
|
+
}
|
|
7189
|
+
const e = entry;
|
|
7190
|
+
const content = typeof e.content === "string" ? e.content.trim() : "";
|
|
7191
|
+
const activeForm = typeof e.activeForm === "string" ? e.activeForm.trim() : "";
|
|
7192
|
+
const status = e.status;
|
|
7193
|
+
if (!content) {
|
|
7194
|
+
throw new Error(`todo_write: todo #${i + 1} \`content\` must be a non-empty string`);
|
|
7195
|
+
}
|
|
7196
|
+
if (!activeForm) {
|
|
7197
|
+
throw new Error(`todo_write: todo #${i + 1} \`activeForm\` must be a non-empty string`);
|
|
7198
|
+
}
|
|
7199
|
+
if (status !== "pending" && status !== "in_progress" && status !== "completed") {
|
|
7200
|
+
throw new Error(
|
|
7201
|
+
`todo_write: todo #${i + 1} \`status\` must be one of pending|in_progress|completed (got ${JSON.stringify(status)})`
|
|
7202
|
+
);
|
|
7203
|
+
}
|
|
7204
|
+
if (status === "in_progress") {
|
|
7205
|
+
inProgressCount++;
|
|
7206
|
+
if (inProgressCount > 1) {
|
|
7207
|
+
throw new Error(
|
|
7208
|
+
"todo_write: at most one todo may be in_progress at a time \u2014 mark the previous one completed first"
|
|
7209
|
+
);
|
|
7210
|
+
}
|
|
7211
|
+
}
|
|
7212
|
+
out.push({ content, status, activeForm });
|
|
7213
|
+
}
|
|
7214
|
+
return out;
|
|
7215
|
+
}
|
|
7216
|
+
function renderTodos(todos) {
|
|
7217
|
+
if (todos.length === 0) return "todos cleared (0 items)";
|
|
7218
|
+
let done = 0;
|
|
7219
|
+
let inProgress = 0;
|
|
7220
|
+
let pending = 0;
|
|
7221
|
+
for (const t2 of todos) {
|
|
7222
|
+
if (t2.status === "completed") done++;
|
|
7223
|
+
else if (t2.status === "in_progress") inProgress++;
|
|
7224
|
+
else pending++;
|
|
7225
|
+
}
|
|
7226
|
+
const header = `todos updated \xB7 ${done} done \xB7 ${inProgress} in progress \xB7 ${pending} pending`;
|
|
7227
|
+
const lines = todos.map((t2) => {
|
|
7228
|
+
if (t2.status === "completed") return `[x] ${t2.content}`;
|
|
7229
|
+
if (t2.status === "in_progress") return `[>] ${t2.activeForm}`;
|
|
7230
|
+
return `[ ] ${t2.content}`;
|
|
7231
|
+
});
|
|
7232
|
+
return `${header}
|
|
7233
|
+
${lines.join("\n")}`;
|
|
7234
|
+
}
|
|
7235
|
+
function registerTodoTool(registry, opts = {}) {
|
|
7236
|
+
registry.register({
|
|
7237
|
+
name: "todo_write",
|
|
7238
|
+
description: DESCRIPTION,
|
|
7239
|
+
readOnly: true,
|
|
7240
|
+
parameters: {
|
|
7241
|
+
type: "object",
|
|
7242
|
+
properties: {
|
|
7243
|
+
todos: {
|
|
7244
|
+
type: "array",
|
|
7245
|
+
description: "The COMPLETE new todo list. Replaces whatever was there before. Pass [] to clear.",
|
|
7246
|
+
items: {
|
|
7247
|
+
type: "object",
|
|
7248
|
+
properties: {
|
|
7249
|
+
content: {
|
|
7250
|
+
type: "string",
|
|
7251
|
+
description: 'Imperative step description, e.g. "Add tests for parser".'
|
|
7252
|
+
},
|
|
7253
|
+
status: {
|
|
7254
|
+
type: "string",
|
|
7255
|
+
enum: ["pending", "in_progress", "completed"],
|
|
7256
|
+
description: "Current state. Exactly one item may be in_progress."
|
|
7257
|
+
},
|
|
7258
|
+
activeForm: {
|
|
7259
|
+
type: "string",
|
|
7260
|
+
description: 'Gerund form shown while in_progress, e.g. "Adding tests for parser".'
|
|
7261
|
+
}
|
|
7262
|
+
},
|
|
7263
|
+
required: ["content", "status", "activeForm"]
|
|
7264
|
+
}
|
|
7265
|
+
}
|
|
7266
|
+
},
|
|
7267
|
+
required: ["todos"]
|
|
7268
|
+
},
|
|
7269
|
+
fn: async (args) => {
|
|
7270
|
+
const todos = validateTodos(args?.todos);
|
|
7271
|
+
opts.onTodosUpdated?.(todos);
|
|
7272
|
+
return renderTodos(todos);
|
|
7273
|
+
}
|
|
7274
|
+
});
|
|
7275
|
+
return registry;
|
|
7276
|
+
}
|
|
7277
|
+
|
|
7412
7278
|
// src/tools/subagent-types.ts
|
|
7413
7279
|
var EXPLORE_SYSTEM = `You are an exploration subagent. Wide-net read-only investigation; return one distilled answer.
|
|
7414
7280
|
|
|
@@ -7778,11 +7644,11 @@ function forkRegistryWithAllowList(parent, allow, alsoExclude) {
|
|
|
7778
7644
|
}
|
|
7779
7645
|
|
|
7780
7646
|
// src/tools/shell.ts
|
|
7781
|
-
import * as
|
|
7647
|
+
import * as pathMod8 from "path";
|
|
7782
7648
|
|
|
7783
7649
|
// src/tools/jobs.ts
|
|
7784
7650
|
import { spawn as spawn2 } from "child_process";
|
|
7785
|
-
import * as
|
|
7651
|
+
import * as pathMod5 from "path";
|
|
7786
7652
|
function killProcessTree(pid, signal) {
|
|
7787
7653
|
if (process.platform === "win32") {
|
|
7788
7654
|
const args = ["/pid", String(pid), "/T"];
|
|
@@ -7842,7 +7708,7 @@ var JobRegistry = class {
|
|
|
7842
7708
|
const maxBytes = opts.maxBufferBytes ?? DEFAULT_OUTPUT_CAP_BYTES;
|
|
7843
7709
|
const { bin, args, spawnOverrides } = prepareSpawn(argv);
|
|
7844
7710
|
const spawnOpts = {
|
|
7845
|
-
cwd:
|
|
7711
|
+
cwd: pathMod5.resolve(opts.cwd),
|
|
7846
7712
|
shell: false,
|
|
7847
7713
|
windowsHide: true,
|
|
7848
7714
|
env: process.env,
|
|
@@ -8128,12 +7994,12 @@ function latestOutputSince(before, after) {
|
|
|
8128
7994
|
// src/tools/shell/exec.ts
|
|
8129
7995
|
import { spawn as spawn4, spawnSync } from "child_process";
|
|
8130
7996
|
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
8131
|
-
import * as
|
|
7997
|
+
import * as pathMod7 from "path";
|
|
8132
7998
|
|
|
8133
7999
|
// src/tools/shell-chain.ts
|
|
8134
8000
|
import { spawn as spawn3 } from "child_process";
|
|
8135
8001
|
import { closeSync, openSync } from "fs";
|
|
8136
|
-
import * as
|
|
8002
|
+
import * as pathMod6 from "path";
|
|
8137
8003
|
var UnsupportedSyntaxError = class extends Error {
|
|
8138
8004
|
constructor(detail) {
|
|
8139
8005
|
super(`run_command: ${detail}`);
|
|
@@ -8400,7 +8266,7 @@ function openRedirects(redirects, cwd) {
|
|
|
8400
8266
|
let bothFd = null;
|
|
8401
8267
|
const toClose = [];
|
|
8402
8268
|
const open = (target, flags) => {
|
|
8403
|
-
const resolved =
|
|
8269
|
+
const resolved = pathMod6.resolve(cwd, target);
|
|
8404
8270
|
const fd = openSync(resolved, flags);
|
|
8405
8271
|
toClose.push(fd);
|
|
8406
8272
|
return fd;
|
|
@@ -8896,16 +8762,16 @@ function resolveExecutable(cmd, opts = {}) {
|
|
|
8896
8762
|
const platform = opts.platform ?? process.platform;
|
|
8897
8763
|
if (platform !== "win32") return cmd;
|
|
8898
8764
|
if (!cmd) return cmd;
|
|
8899
|
-
if (cmd.includes("/") || cmd.includes("\\") ||
|
|
8900
|
-
if (
|
|
8765
|
+
if (cmd.includes("/") || cmd.includes("\\") || pathMod7.isAbsolute(cmd)) return cmd;
|
|
8766
|
+
if (pathMod7.extname(cmd)) return cmd;
|
|
8901
8767
|
const env = opts.env ?? process.env;
|
|
8902
8768
|
const pathExt = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
|
|
8903
|
-
const delimiter2 = opts.pathDelimiter ?? (platform === "win32" ? ";" :
|
|
8769
|
+
const delimiter2 = opts.pathDelimiter ?? (platform === "win32" ? ";" : pathMod7.delimiter);
|
|
8904
8770
|
const pathDirs = (env.PATH ?? "").split(delimiter2).filter(Boolean);
|
|
8905
8771
|
const isFile = opts.isFile ?? defaultIsFile;
|
|
8906
8772
|
for (const dir of pathDirs) {
|
|
8907
8773
|
for (const ext of pathExt) {
|
|
8908
|
-
const full =
|
|
8774
|
+
const full = pathMod7.win32.join(dir, cmd + ext);
|
|
8909
8775
|
if (isFile(full)) return full;
|
|
8910
8776
|
}
|
|
8911
8777
|
}
|
|
@@ -8975,8 +8841,8 @@ function withUtf8Codepage(cmdline) {
|
|
|
8975
8841
|
function isBareWindowsName(s) {
|
|
8976
8842
|
if (!s) return false;
|
|
8977
8843
|
if (s.includes("/") || s.includes("\\")) return false;
|
|
8978
|
-
if (
|
|
8979
|
-
if (
|
|
8844
|
+
if (pathMod7.isAbsolute(s)) return false;
|
|
8845
|
+
if (pathMod7.extname(s)) return false;
|
|
8980
8846
|
return true;
|
|
8981
8847
|
}
|
|
8982
8848
|
function quoteForCmdExe(arg) {
|
|
@@ -8997,7 +8863,7 @@ var NeedsConfirmationError = class extends Error {
|
|
|
8997
8863
|
}
|
|
8998
8864
|
};
|
|
8999
8865
|
function registerShellTools(registry, opts) {
|
|
9000
|
-
const rootDir =
|
|
8866
|
+
const rootDir = pathMod8.resolve(opts.rootDir);
|
|
9001
8867
|
const timeoutSec = opts.timeoutSec ?? DEFAULT_TIMEOUT_SEC;
|
|
9002
8868
|
const maxOutputChars = opts.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
9003
8869
|
const jobs = opts.jobs ?? new JobRegistry();
|
|
@@ -9621,14 +9487,6 @@ function recordFromLoopEvent(ev, extra) {
|
|
|
9621
9487
|
if (ev.toolName !== void 0) rec.tool = ev.toolName;
|
|
9622
9488
|
if (ev.toolArgs !== void 0) rec.args = ev.toolArgs;
|
|
9623
9489
|
if (ev.error !== void 0) rec.error = ev.error;
|
|
9624
|
-
if (ev.planState && !isPlanStateEmptyShape(ev.planState)) {
|
|
9625
|
-
rec.planState = {
|
|
9626
|
-
subgoals: [...ev.planState.subgoals],
|
|
9627
|
-
hypotheses: [...ev.planState.hypotheses],
|
|
9628
|
-
uncertainties: [...ev.planState.uncertainties],
|
|
9629
|
-
rejectedPaths: [...ev.planState.rejectedPaths]
|
|
9630
|
-
};
|
|
9631
|
-
}
|
|
9632
9490
|
if (ev.stats) {
|
|
9633
9491
|
rec.usage = {
|
|
9634
9492
|
prompt_tokens: ev.stats.usage.promptTokens,
|
|
@@ -9664,9 +9522,6 @@ function readTranscript(path2) {
|
|
|
9664
9522
|
const raw = readFileSync11(path2, "utf8");
|
|
9665
9523
|
return parseTranscript(raw);
|
|
9666
9524
|
}
|
|
9667
|
-
function isPlanStateEmptyShape(s) {
|
|
9668
|
-
return s.subgoals.length === 0 && s.hypotheses.length === 0 && s.uncertainties.length === 0 && s.rejectedPaths.length === 0;
|
|
9669
|
-
}
|
|
9670
9525
|
function parseTranscript(raw) {
|
|
9671
9526
|
const out = { meta: null, records: [] };
|
|
9672
9527
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -9702,20 +9557,12 @@ function computeReplayStats(records) {
|
|
|
9702
9557
|
const prefixHashes = /* @__PURE__ */ new Set();
|
|
9703
9558
|
let userTurns = 0;
|
|
9704
9559
|
let toolCalls = 0;
|
|
9705
|
-
let harvestedTurns = 0;
|
|
9706
|
-
let totalUncertainties = 0;
|
|
9707
|
-
let totalSubgoals = 0;
|
|
9708
9560
|
for (const rec of records) {
|
|
9709
9561
|
if (rec.role === "user") userTurns++;
|
|
9710
9562
|
else if (rec.role === "tool") toolCalls++;
|
|
9711
9563
|
else if (rec.role === "assistant_final") {
|
|
9712
9564
|
if (rec.model) models.add(rec.model);
|
|
9713
9565
|
if (rec.prefixHash) prefixHashes.add(rec.prefixHash);
|
|
9714
|
-
if (rec.planState) {
|
|
9715
|
-
harvestedTurns++;
|
|
9716
|
-
totalUncertainties += rec.planState.uncertainties.length;
|
|
9717
|
-
totalSubgoals += rec.planState.subgoals.length;
|
|
9718
|
-
}
|
|
9719
9566
|
if (rec.usage && rec.model) {
|
|
9720
9567
|
const u = new Usage(
|
|
9721
9568
|
rec.usage.prompt_tokens ?? 0,
|
|
@@ -9743,9 +9590,6 @@ function computeReplayStats(records) {
|
|
|
9743
9590
|
prefixHashes: [...prefixHashes],
|
|
9744
9591
|
userTurns,
|
|
9745
9592
|
toolCalls,
|
|
9746
|
-
harvestedTurns,
|
|
9747
|
-
totalUncertainties,
|
|
9748
|
-
totalSubgoals,
|
|
9749
9593
|
...summarizeTurns(turns)
|
|
9750
9594
|
};
|
|
9751
9595
|
}
|
|
@@ -9923,41 +9767,6 @@ function renderSummaryTable(report, _opts = {}) {
|
|
|
9923
9767
|
)
|
|
9924
9768
|
);
|
|
9925
9769
|
lines.push(statRow("prefix hashes", a.stats.prefixHashes.length, b.stats.prefixHashes.length));
|
|
9926
|
-
if (a.stats.harvestedTurns > 0 || b.stats.harvestedTurns > 0) {
|
|
9927
|
-
lines.push(
|
|
9928
|
-
row(
|
|
9929
|
-
[
|
|
9930
|
-
"harvest turns",
|
|
9931
|
-
`${a.stats.harvestedTurns}`,
|
|
9932
|
-
`${b.stats.harvestedTurns}`,
|
|
9933
|
-
signed(b.stats.harvestedTurns - a.stats.harvestedTurns)
|
|
9934
|
-
],
|
|
9935
|
-
[20, 14, 14, 14]
|
|
9936
|
-
)
|
|
9937
|
-
);
|
|
9938
|
-
lines.push(
|
|
9939
|
-
row(
|
|
9940
|
-
[
|
|
9941
|
-
" subgoals",
|
|
9942
|
-
`${a.stats.totalSubgoals}`,
|
|
9943
|
-
`${b.stats.totalSubgoals}`,
|
|
9944
|
-
signed(b.stats.totalSubgoals - a.stats.totalSubgoals)
|
|
9945
|
-
],
|
|
9946
|
-
[20, 14, 14, 14]
|
|
9947
|
-
)
|
|
9948
|
-
);
|
|
9949
|
-
lines.push(
|
|
9950
|
-
row(
|
|
9951
|
-
[
|
|
9952
|
-
" uncertainties",
|
|
9953
|
-
`${a.stats.totalUncertainties}`,
|
|
9954
|
-
`${b.stats.totalUncertainties}`,
|
|
9955
|
-
signed(b.stats.totalUncertainties - a.stats.totalUncertainties)
|
|
9956
|
-
],
|
|
9957
|
-
[20, 14, 14, 14]
|
|
9958
|
-
)
|
|
9959
|
-
);
|
|
9960
|
-
}
|
|
9961
9770
|
lines.push("");
|
|
9962
9771
|
const aPrefixStable = a.stats.prefixHashes.length <= 1;
|
|
9963
9772
|
const bPrefixStable = b.stats.prefixHashes.length <= 1;
|
|
@@ -10029,17 +9838,6 @@ function renderMarkdown(report) {
|
|
|
10029
9838
|
out.push(
|
|
10030
9839
|
`| prefix hashes | ${a.stats.prefixHashes.length} | ${b.stats.prefixHashes.length} | \u2014 |`
|
|
10031
9840
|
);
|
|
10032
|
-
if (a.stats.harvestedTurns > 0 || b.stats.harvestedTurns > 0) {
|
|
10033
|
-
out.push(
|
|
10034
|
-
`| harvest turns | ${a.stats.harvestedTurns} | ${b.stats.harvestedTurns} | ${signed(b.stats.harvestedTurns - a.stats.harvestedTurns)} |`
|
|
10035
|
-
);
|
|
10036
|
-
out.push(
|
|
10037
|
-
`| harvest subgoals | ${a.stats.totalSubgoals} | ${b.stats.totalSubgoals} | ${signed(b.stats.totalSubgoals - a.stats.totalSubgoals)} |`
|
|
10038
|
-
);
|
|
10039
|
-
out.push(
|
|
10040
|
-
`| harvest uncertainties | ${a.stats.totalUncertainties} | ${b.stats.totalUncertainties} | ${signed(b.stats.totalUncertainties - a.stats.totalUncertainties)} |`
|
|
10041
|
-
);
|
|
10042
|
-
}
|
|
10043
9841
|
out.push("");
|
|
10044
9842
|
out.push("## Turn-by-turn");
|
|
10045
9843
|
out.push("");
|
|
@@ -10110,7 +9908,7 @@ function truncate(s, n) {
|
|
|
10110
9908
|
// src/version.ts
|
|
10111
9909
|
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
|
|
10112
9910
|
import { homedir as homedir6 } from "os";
|
|
10113
|
-
import { dirname as dirname6, join as
|
|
9911
|
+
import { dirname as dirname6, join as join12 } from "path";
|
|
10114
9912
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10115
9913
|
var REGISTRY_URL = "https://registry.npmjs.org/reasonix/latest";
|
|
10116
9914
|
var LATEST_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -10119,7 +9917,7 @@ function readPackageVersion() {
|
|
|
10119
9917
|
try {
|
|
10120
9918
|
let dir = dirname6(fileURLToPath2(import.meta.url));
|
|
10121
9919
|
for (let i = 0; i < 6; i++) {
|
|
10122
|
-
const p =
|
|
9920
|
+
const p = join12(dir, "package.json");
|
|
10123
9921
|
if (existsSync9(p)) {
|
|
10124
9922
|
const pkg = JSON.parse(readFileSync12(p, "utf8"));
|
|
10125
9923
|
if (pkg?.name === "reasonix" && typeof pkg.version === "string") {
|
|
@@ -10136,7 +9934,7 @@ function readPackageVersion() {
|
|
|
10136
9934
|
}
|
|
10137
9935
|
var VERSION = readPackageVersion();
|
|
10138
9936
|
function cachePath(homeDirOverride) {
|
|
10139
|
-
return
|
|
9937
|
+
return join12(homeDirOverride ?? homedir6(), ".reasonix", "version-cache.json");
|
|
10140
9938
|
}
|
|
10141
9939
|
function readCache(homeDirOverride) {
|
|
10142
9940
|
try {
|
|
@@ -11130,8 +10928,8 @@ function lineEndingOf(text) {
|
|
|
11130
10928
|
|
|
11131
10929
|
// src/code/prompt.ts
|
|
11132
10930
|
import { existsSync as existsSync11, readFileSync as readFileSync14 } from "fs";
|
|
11133
|
-
import { join as
|
|
11134
|
-
var CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, list_directory, directory_tree, search_files, search_content, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell.
|
|
10931
|
+
import { join as join13 } from "path";
|
|
10932
|
+
var CODE_SYSTEM_PROMPT = `You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, edit_file, multi_edit, list_directory, directory_tree, search_files, search_content, glob, get_file_info) rooted at the user's working directory, plus run_command / run_background for shell, plus \`todo_write\` for in-session multi-step tracking.
|
|
11135
10933
|
|
|
11136
10934
|
# Cite or shut up \u2014 non-negotiable
|
|
11137
10935
|
|
|
@@ -11179,10 +10977,23 @@ Skip it when one option is clearly correct (just do it, or submit_plan) or a fre
|
|
|
11179
10977
|
|
|
11180
10978
|
Each option: short stable id (A/B/C), one-line title, optional summary. \`allowCustom: true\` when their real answer might not fit. Max 6. A ~1-sentence lead-in before the call is fine ("I see three directions \u2014 letting you pick"); don't repeat the options in it. After the call, STOP.
|
|
11181
10979
|
|
|
10980
|
+
# When to track multi-step intent (todo_write)
|
|
10981
|
+
|
|
10982
|
+
\`todo_write\` is a lightweight in-session task tracker \u2014 NOT a plan. No approval gate, no checkpoint pauses, doesn't touch files. Use it when the task has 3+ distinct steps and you'd otherwise lose track of where you are. Each call REPLACES the entire list (set semantics). Exactly one item may be \`in_progress\` at a time \u2014 flip it to \`completed\` the moment that step's done, before starting the next.
|
|
10983
|
+
|
|
10984
|
+
Use it for:
|
|
10985
|
+
- Multi-part user requests ("do A, then B, then C") \u2014 record the parts so you don't drop one.
|
|
10986
|
+
- Long refactors where you've finished step 2 of 5 and want a visible record.
|
|
10987
|
+
- Any moment where you'd otherwise enumerate "1. ... 2. ... 3. ..." in prose \u2014 the tool is strictly better, the UI shows progress live.
|
|
10988
|
+
|
|
10989
|
+
Skip it for: one-shot edits, single-question answers, anything that fits in one tool call. Don't \`todo_write\` and \`submit_plan\` for the same work \u2014 \`submit_plan\` is for tasks that need a review gate; \`todo_write\` is for personal bookkeeping after the user has already given you the green light.
|
|
10990
|
+
|
|
10991
|
+
Call shape: \`{ todos: [{ content, activeForm, status }, ...] }\` \u2014 \`content\` is imperative ("Add tests"), \`activeForm\` is gerund ("Adding tests") shown while \`in_progress\`. Pass the FULL list every call, not a delta. Pass \`todos: []\` to clear when work's done.
|
|
10992
|
+
|
|
11182
10993
|
# Plan mode (/plan)
|
|
11183
10994
|
|
|
11184
10995
|
The user can ALSO enter "plan mode" via /plan, which is a stronger, explicit constraint:
|
|
11185
|
-
- Write tools (edit_file, write_file, create_directory, move_file) and non-allowlisted run_command calls are BOUNCED at dispatch \u2014 you'll get a tool result like "unavailable in plan mode". Don't retry them.
|
|
10996
|
+
- Write tools (edit_file, multi_edit, write_file, create_directory, move_file) and non-allowlisted run_command calls are BOUNCED at dispatch \u2014 you'll get a tool result like "unavailable in plan mode". Don't retry them.
|
|
11186
10997
|
- Read tools (read_file, list_directory, search_files, directory_tree, get_file_info) and allowlisted read-only / test shell commands still work \u2014 use them to investigate.
|
|
11187
10998
|
- You MUST call submit_plan before anything will execute. Approve exits plan mode; Refine stays in; Cancel exits without implementing.
|
|
11188
10999
|
|
|
@@ -11251,6 +11062,7 @@ Rules:
|
|
|
11251
11062
|
>>>>>>> REPLACE
|
|
11252
11063
|
- Do NOT use write_file to change existing files \u2014 the user reviews your edits as SEARCH/REPLACE. write_file is only for files you explicitly want to overwrite wholesale (rare).
|
|
11253
11064
|
- Paths are relative to the working directory. Don't use absolute paths.
|
|
11065
|
+
- For multi-site changes \u2014 same file or across files \u2014 prefer \`multi_edit\` over N \`edit_file\` calls. Shape: \`{ edits: [{ path, search, replace }, ...] }\`. All edits validate before any file is written; any failure \u2192 ALL files untouched. Per-file edits run in array order, so a later edit can match text inserted by an earlier one.
|
|
11254
11066
|
|
|
11255
11067
|
# Trust what you already know
|
|
11256
11068
|
|
|
@@ -11260,7 +11072,7 @@ Before exploring the filesystem to answer a factual question, check whether the
|
|
|
11260
11072
|
|
|
11261
11073
|
- Skip dependency, build, and VCS directories unless the user explicitly asks. The pinned .gitignore block (if any, below) is your authoritative denylist.
|
|
11262
11074
|
- Prefer \`search_files\` over \`list_directory\` when you know roughly what you're looking for \u2014 it saves context and avoids enumerating huge trees. Note: \`search_files\` matches file NAMES; for searching file CONTENTS use \`search_content\`.
|
|
11263
|
-
- Available exploration tools: \`read_file\`, \`list_directory\`, \`directory_tree\`, \`search_files\` (filename match), \`search_content\` (content grep \u2014 use for "where is X called", "find all references to Y"), \`get_file_info\`. Don't call \`grep\` or other tools that aren't in this list \u2014 they don't exist as functions.
|
|
11075
|
+
- Available exploration tools: \`read_file\`, \`list_directory\`, \`directory_tree\`, \`search_files\` (filename match), \`glob\` (mtime-sorted glob \u2014 use for "what changed lately", "all *.ts under src/"), \`search_content\` (content grep \u2014 use for "where is X called", "find all references to Y"; pass \`context:N\` for grep -C N around hits), \`get_file_info\`. Don't call \`grep\` or other tools that aren't in this list \u2014 they don't exist as functions.
|
|
11264
11076
|
|
|
11265
11077
|
# Path conventions
|
|
11266
11078
|
|
|
@@ -11333,7 +11145,7 @@ If \`semantic_search\` returns nothing useful (low scores, off-topic), THEN fall
|
|
|
11333
11145
|
function codeSystemPrompt(rootDir, opts = {}) {
|
|
11334
11146
|
const base = opts.hasSemanticSearch ? `${CODE_SYSTEM_PROMPT}${SEMANTIC_SEARCH_ROUTING}` : CODE_SYSTEM_PROMPT;
|
|
11335
11147
|
const withMemory = applyMemoryStack(base, rootDir);
|
|
11336
|
-
const gitignorePath =
|
|
11148
|
+
const gitignorePath = join13(rootDir, ".gitignore");
|
|
11337
11149
|
let result = withMemory;
|
|
11338
11150
|
if (existsSync11(gitignorePath)) {
|
|
11339
11151
|
let content;
|
|
@@ -11384,9 +11196,9 @@ import {
|
|
|
11384
11196
|
writeFileSync as writeFileSync7
|
|
11385
11197
|
} from "fs";
|
|
11386
11198
|
import { homedir as homedir7 } from "os";
|
|
11387
|
-
import { dirname as dirname8, join as
|
|
11199
|
+
import { dirname as dirname8, join as join14 } from "path";
|
|
11388
11200
|
function defaultUsageLogPath(homeDirOverride) {
|
|
11389
|
-
return
|
|
11201
|
+
return join14(homeDirOverride ?? homedir7(), ".reasonix", "usage.jsonl");
|
|
11390
11202
|
}
|
|
11391
11203
|
var USAGE_COMPACTION_THRESHOLD_BYTES = 5 * 1024 * 1024;
|
|
11392
11204
|
var USAGE_RETENTION_DAYS = 365;
|
|
@@ -11588,6 +11400,7 @@ export {
|
|
|
11588
11400
|
CODE_SYSTEM_PROMPT,
|
|
11589
11401
|
CacheFirstLoop,
|
|
11590
11402
|
ChoiceRequestedError,
|
|
11403
|
+
DEFAULT_AT_DIR_MAX_ENTRIES,
|
|
11591
11404
|
DEFAULT_AT_MENTION_MAX_BYTES,
|
|
11592
11405
|
DEFAULT_MAX_RESULT_CHARS,
|
|
11593
11406
|
DEFAULT_MAX_RESULT_TOKENS,
|
|
@@ -11620,7 +11433,6 @@ export {
|
|
|
11620
11433
|
Usage,
|
|
11621
11434
|
VERSION,
|
|
11622
11435
|
VolatileScratch,
|
|
11623
|
-
aggregateBranchUsage,
|
|
11624
11436
|
aggregateUsage,
|
|
11625
11437
|
analyzeSchema,
|
|
11626
11438
|
appendSessionMessage,
|
|
@@ -11640,13 +11452,11 @@ export {
|
|
|
11640
11452
|
costUsd,
|
|
11641
11453
|
decideOutcome,
|
|
11642
11454
|
defaultConfigPath,
|
|
11643
|
-
defaultSelector,
|
|
11644
11455
|
defaultUsageLogPath,
|
|
11645
11456
|
deleteSession,
|
|
11646
11457
|
detectAtPicker,
|
|
11647
11458
|
detectShellOperator,
|
|
11648
11459
|
diffTranscripts,
|
|
11649
|
-
emptyPlanState,
|
|
11650
11460
|
expandAtMentions,
|
|
11651
11461
|
fetchWithRetry,
|
|
11652
11462
|
fixToolCallPairing,
|
|
@@ -11660,7 +11470,6 @@ export {
|
|
|
11660
11470
|
formatSearchResults,
|
|
11661
11471
|
getLatestVersion,
|
|
11662
11472
|
globalSettingsPath,
|
|
11663
|
-
harvest,
|
|
11664
11473
|
healLoadedMessages,
|
|
11665
11474
|
healLoadedMessagesByTokens,
|
|
11666
11475
|
htmlToText,
|
|
@@ -11670,7 +11479,6 @@ export {
|
|
|
11670
11479
|
isAllowed,
|
|
11671
11480
|
isJsonRpcError,
|
|
11672
11481
|
isNpxInstall,
|
|
11673
|
-
isPlanStateEmpty,
|
|
11674
11482
|
isPlausibleKey,
|
|
11675
11483
|
listFilesSync,
|
|
11676
11484
|
listFilesWithStatsAsync,
|
|
@@ -11707,6 +11515,7 @@ export {
|
|
|
11707
11515
|
registerPlanTool,
|
|
11708
11516
|
registerShellTools,
|
|
11709
11517
|
registerSubagentTool,
|
|
11518
|
+
registerTodoTool,
|
|
11710
11519
|
registerWebTools,
|
|
11711
11520
|
renderMarkdown as renderDiffMarkdown,
|
|
11712
11521
|
renderSummaryTable as renderDiffSummary,
|
|
@@ -11714,7 +11523,6 @@ export {
|
|
|
11714
11523
|
replayFromFile,
|
|
11715
11524
|
resolveExecutable,
|
|
11716
11525
|
restoreSnapshots,
|
|
11717
|
-
runBranches,
|
|
11718
11526
|
runCommand,
|
|
11719
11527
|
runHooks,
|
|
11720
11528
|
sanitizeMemoryName,
|