reasonix 0.4.1 → 0.4.3
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/dist/cli/index.js +209 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +25 -2
- package/dist/index.js +60 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1283,6 +1283,39 @@ var CacheFirstLoop = class {
|
|
|
1283
1283
|
abort() {
|
|
1284
1284
|
this._aborted = true;
|
|
1285
1285
|
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Drop everything in the log after (and including) the most recent
|
|
1288
|
+
* user message. Used by `/retry` so the caller can re-send that
|
|
1289
|
+
* message with a fresh turn instead of layering another response on
|
|
1290
|
+
* top of the prior exchange. Returns the content of the dropped user
|
|
1291
|
+
* message, or `null` if there isn't one yet.
|
|
1292
|
+
*
|
|
1293
|
+
* Persists by rewriting the session file — otherwise the next
|
|
1294
|
+
* launch would rehydrate the old exchange and `/retry` would seem
|
|
1295
|
+
* to have done nothing.
|
|
1296
|
+
*/
|
|
1297
|
+
retryLastUser() {
|
|
1298
|
+
const entries = this.log.entries;
|
|
1299
|
+
let lastUserIdx = -1;
|
|
1300
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
1301
|
+
if (entries[i].role === "user") {
|
|
1302
|
+
lastUserIdx = i;
|
|
1303
|
+
break;
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
if (lastUserIdx < 0) return null;
|
|
1307
|
+
const raw = entries[lastUserIdx].content;
|
|
1308
|
+
const userText = typeof raw === "string" ? raw : "";
|
|
1309
|
+
const preserved = entries.slice(0, lastUserIdx).map((m) => ({ ...m }));
|
|
1310
|
+
this.log.compactInPlace(preserved);
|
|
1311
|
+
if (this.sessionName) {
|
|
1312
|
+
try {
|
|
1313
|
+
rewriteSession(this.sessionName, preserved);
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return userText;
|
|
1318
|
+
}
|
|
1286
1319
|
async *step(userInput) {
|
|
1287
1320
|
this._turn++;
|
|
1288
1321
|
this.scratch.reset();
|
|
@@ -1296,9 +1329,17 @@ var CacheFirstLoop = class {
|
|
|
1296
1329
|
yield {
|
|
1297
1330
|
turn: this._turn,
|
|
1298
1331
|
role: "warning",
|
|
1299
|
-
content: `aborted at iter ${iter}/${this.maxToolIters} \u2014
|
|
1332
|
+
content: `aborted at iter ${iter}/${this.maxToolIters} \u2014 stopped without producing a summary (press \u2191 + Enter or /retry to resume)`
|
|
1300
1333
|
};
|
|
1301
|
-
|
|
1334
|
+
const stoppedMsg = "[aborted by user (Esc) \u2014 no summary produced. Ask again or /retry when ready; prior tool output is still in the log.]";
|
|
1335
|
+
this.appendAndPersist({ role: "assistant", content: stoppedMsg });
|
|
1336
|
+
yield {
|
|
1337
|
+
turn: this._turn,
|
|
1338
|
+
role: "assistant_final",
|
|
1339
|
+
content: stoppedMsg,
|
|
1340
|
+
forcedSummary: true
|
|
1341
|
+
};
|
|
1342
|
+
yield { turn: this._turn, role: "done", content: stoppedMsg };
|
|
1302
1343
|
return;
|
|
1303
1344
|
}
|
|
1304
1345
|
if (!warnedForIterBudget && iter >= warnAt) {
|
|
@@ -1520,12 +1561,18 @@ var CacheFirstLoop = class {
|
|
|
1520
1561
|
async *forceSummaryAfterIterLimit(opts = { reason: "budget" }) {
|
|
1521
1562
|
try {
|
|
1522
1563
|
const messages = this.buildMessages(null);
|
|
1564
|
+
messages.push({
|
|
1565
|
+
role: "user",
|
|
1566
|
+
content: "I'm out of tool-call budget for this turn. Summarize in plain prose what you learned from the tool results above. Do NOT emit any tool calls, function-call markup, DSML invocations, or SEARCH/REPLACE edit blocks \u2014 they will be silently discarded. Just plain text."
|
|
1567
|
+
});
|
|
1523
1568
|
const resp = await this.client.chat({
|
|
1524
1569
|
model: this.model,
|
|
1525
1570
|
messages
|
|
1526
1571
|
// no tools → model is forced to answer in text
|
|
1527
1572
|
});
|
|
1528
|
-
const
|
|
1573
|
+
const rawContent = resp.content?.trim() ?? "";
|
|
1574
|
+
const cleaned = stripHallucinatedToolMarkup(rawContent);
|
|
1575
|
+
const summary = cleaned || "(model emitted fake tool-call markup instead of a prose summary \u2014 try /retry with a narrower question, or /think to inspect R1's reasoning)";
|
|
1529
1576
|
const reasonPrefix = reasonPrefixFor(opts.reason, this.maxToolIters);
|
|
1530
1577
|
const annotated = `${reasonPrefix}
|
|
1531
1578
|
|
|
@@ -1566,6 +1613,14 @@ ${summary}`;
|
|
|
1566
1613
|
return msg;
|
|
1567
1614
|
}
|
|
1568
1615
|
};
|
|
1616
|
+
function stripHallucinatedToolMarkup(s) {
|
|
1617
|
+
let out = s;
|
|
1618
|
+
out = out.replace(/<|DSML|function_calls>[\s\S]*?<\/?|DSML|function_calls>/g, "");
|
|
1619
|
+
out = out.replace(/<\|DSML\|function_calls>[\s\S]*?<\/?\|DSML\|function_calls>/g, "");
|
|
1620
|
+
out = out.replace(/<function_calls>[\s\S]*?<\/function_calls>/g, "");
|
|
1621
|
+
out = out.replace(/<|DSML|[\s\S]*$/g, "");
|
|
1622
|
+
return out.trim();
|
|
1623
|
+
}
|
|
1569
1624
|
function reasonPrefixFor(reason, iterCap) {
|
|
1570
1625
|
if (reason === "aborted") return "[aborted by user (Esc) \u2014 summarizing what I found so far]";
|
|
1571
1626
|
if (reason === "context-guard") {
|
|
@@ -2729,7 +2784,7 @@ function sep() {
|
|
|
2729
2784
|
}
|
|
2730
2785
|
|
|
2731
2786
|
// src/index.ts
|
|
2732
|
-
var VERSION = "0.4.
|
|
2787
|
+
var VERSION = "0.4.3";
|
|
2733
2788
|
|
|
2734
2789
|
// src/cli/commands/chat.tsx
|
|
2735
2790
|
import { render } from "ink";
|
|
@@ -2998,7 +3053,10 @@ var EventRow = React3.memo(function EventRow2({ event }) {
|
|
|
2998
3053
|
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: "green" }, "assistant")), event.branch ? /* @__PURE__ */ React3.createElement(BranchBlock, { branch: event.branch }) : null, event.reasoning ? /* @__PURE__ */ React3.createElement(ReasoningBlock, { reasoning: event.reasoning }) : null, !isPlanStateEmpty(event.planState) ? /* @__PURE__ */ React3.createElement(PlanStateBlock, { planState: event.planState }) : null, event.text ? /* @__PURE__ */ React3.createElement(Markdown, { text: event.text }) : /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "(no content)"), event.stats ? /* @__PURE__ */ React3.createElement(StatsLine, { stats: event.stats }) : null, event.repair ? /* @__PURE__ */ React3.createElement(Text3, { color: "magenta" }, event.repair) : null);
|
|
2999
3054
|
}
|
|
3000
3055
|
if (event.role === "tool") {
|
|
3001
|
-
|
|
3056
|
+
const isError = event.text.startsWith("ERROR:");
|
|
3057
|
+
const color = isError ? "red" : "yellow";
|
|
3058
|
+
const marker = isError ? "\u2717" : "\u2192";
|
|
3059
|
+
return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color }, `tool<${event.toolName ?? "?"}> ${marker}`), /* @__PURE__ */ React3.createElement(Text3, { color: isError ? "red" : void 0, dimColor: !isError }, " ", truncate2(event.text, 400)));
|
|
3002
3060
|
}
|
|
3003
3061
|
if (event.role === "error") {
|
|
3004
3062
|
return /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "red", bold: true }, "error", " "), /* @__PURE__ */ React3.createElement(Text3, { color: "red" }, event.text));
|
|
@@ -3020,9 +3078,9 @@ function BranchBlock({ branch }) {
|
|
|
3020
3078
|
return /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Text3, { color: "blue" }, "\u{1F500} branched ", /* @__PURE__ */ React3.createElement(Text3, { bold: true }, branch.budget), ` samples \u2192 picked #${branch.chosenIndex} `, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, per)));
|
|
3021
3079
|
}
|
|
3022
3080
|
function ReasoningBlock({ reasoning }) {
|
|
3023
|
-
const max =
|
|
3081
|
+
const max = 260;
|
|
3024
3082
|
const flat = reasoning.replace(/\s+/g, " ").trim();
|
|
3025
|
-
const preview = flat.length <= max ? flat :
|
|
3083
|
+
const preview = flat.length <= max ? flat : `\u2026 (+${flat.length - max} earlier chars) ${flat.slice(-max)}`;
|
|
3026
3084
|
return /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true, italic: true }, "\u21B3 thinking: ", preview));
|
|
3027
3085
|
}
|
|
3028
3086
|
function Elapsed() {
|
|
@@ -3150,6 +3208,8 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
3150
3208
|
" /mcp list MCP servers + tools attached to this session",
|
|
3151
3209
|
" /setup (exit + reconfigure) \u2192 run `reasonix setup`",
|
|
3152
3210
|
" /compact [cap] shrink large tool results in history (default 4k/result)",
|
|
3211
|
+
" /think dump the most recent turn's full R1 reasoning (reasoner only)",
|
|
3212
|
+
" /retry truncate & resend your last message (fresh sample from the model)",
|
|
3153
3213
|
" /apply (code mode) commit the pending edit blocks to disk",
|
|
3154
3214
|
" /discard (code mode) drop pending edits without writing",
|
|
3155
3215
|
" /undo (code mode) roll back the last applied edit batch",
|
|
@@ -3195,6 +3255,31 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
3195
3255
|
return {
|
|
3196
3256
|
info: "To reconfigure (preset, MCP servers, API key), exit this chat and run `reasonix setup`. Changes take effect on next launch."
|
|
3197
3257
|
};
|
|
3258
|
+
case "retry": {
|
|
3259
|
+
const prev = loop.retryLastUser();
|
|
3260
|
+
if (!prev) {
|
|
3261
|
+
return {
|
|
3262
|
+
info: "nothing to retry \u2014 no prior user message in this session's log."
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
3265
|
+
const preview = prev.length > 80 ? `${prev.slice(0, 80)}\u2026` : prev;
|
|
3266
|
+
return {
|
|
3267
|
+
info: `\u25B8 retrying: "${preview}"`,
|
|
3268
|
+
resubmit: prev
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
case "think":
|
|
3272
|
+
case "reasoning": {
|
|
3273
|
+
const raw = loop.scratch.reasoning;
|
|
3274
|
+
if (!raw || !raw.trim()) {
|
|
3275
|
+
return {
|
|
3276
|
+
info: "no reasoning cached. `/think` shows the full R1 thought for the most recent turn \u2014 only `deepseek-reasoner` produces it, and only once the turn completes."
|
|
3277
|
+
};
|
|
3278
|
+
}
|
|
3279
|
+
return { info: `\u21B3 full thinking (${raw.length} chars):
|
|
3280
|
+
|
|
3281
|
+
${raw.trim()}` };
|
|
3282
|
+
}
|
|
3198
3283
|
case "undo": {
|
|
3199
3284
|
if (!ctx.codeUndo) {
|
|
3200
3285
|
return {
|
|
@@ -3279,9 +3364,25 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
3279
3364
|
}
|
|
3280
3365
|
case "status": {
|
|
3281
3366
|
const branchBudget = loop.branchOptions.budget ?? 1;
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3367
|
+
const ctxMax = DEEPSEEK_CONTEXT_TOKENS[loop.model] ?? DEFAULT_CONTEXT_TOKENS;
|
|
3368
|
+
const lastPromptTokens = loop.stats.summary().lastPromptTokens;
|
|
3369
|
+
const ctxPct = ctxMax > 0 ? Math.round(lastPromptTokens / ctxMax * 100) : 0;
|
|
3370
|
+
const ctxLine = lastPromptTokens > 0 ? ` ctx ${compactNum(lastPromptTokens)}/${compactNum(ctxMax)} (${ctxPct}%)` : " ctx no turns yet";
|
|
3371
|
+
const pending = ctx.pendingEditCount ?? 0;
|
|
3372
|
+
const sessionLine = loop.sessionName ? ` session "${loop.sessionName}" \xB7 ${loop.log.length} messages in log (resumed ${loop.resumedMessageCount})` : " session (ephemeral \u2014 no persistence)";
|
|
3373
|
+
const mcpCount = ctx.mcpSpecs?.length ?? 0;
|
|
3374
|
+
const toolCount = loop.prefix.toolSpecs.length;
|
|
3375
|
+
const mcpLine = ` mcp ${mcpCount} server(s), ${toolCount} tool(s) in registry`;
|
|
3376
|
+
const pendingLine = pending > 0 ? ` edits ${pending} pending (/apply to commit, /discard to drop)` : "";
|
|
3377
|
+
const lines = [
|
|
3378
|
+
` model ${loop.model}`,
|
|
3379
|
+
` flags harvest=${loop.harvestEnabled ? "on" : "off"} \xB7 branch=${branchBudget > 1 ? branchBudget : "off"} \xB7 stream=${loop.stream ? "on" : "off"}`,
|
|
3380
|
+
ctxLine,
|
|
3381
|
+
mcpLine,
|
|
3382
|
+
sessionLine
|
|
3383
|
+
];
|
|
3384
|
+
if (pendingLine) lines.push(pendingLine);
|
|
3385
|
+
return { info: lines.join("\n") };
|
|
3285
3386
|
}
|
|
3286
3387
|
case "model": {
|
|
3287
3388
|
const id = args[0];
|
|
@@ -3333,6 +3434,11 @@ function handleSlash(cmd, args, loop, ctx = {}) {
|
|
|
3333
3434
|
return { unknown: true, info: `unknown command: /${cmd} (try /help)` };
|
|
3334
3435
|
}
|
|
3335
3436
|
}
|
|
3437
|
+
function compactNum(n) {
|
|
3438
|
+
if (n < 1e3) return String(n);
|
|
3439
|
+
const k = n / 1e3;
|
|
3440
|
+
return k >= 100 ? `${Math.round(k)}k` : `${k.toFixed(1)}k`;
|
|
3441
|
+
}
|
|
3336
3442
|
function stripOuterQuotes(s) {
|
|
3337
3443
|
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
|
3338
3444
|
return s.slice(1, -1);
|
|
@@ -3388,6 +3494,8 @@ function App({
|
|
|
3388
3494
|
const [ongoingTool, setOngoingTool] = useState2(null);
|
|
3389
3495
|
const lastEditSnapshots = useRef(null);
|
|
3390
3496
|
const pendingEdits = useRef([]);
|
|
3497
|
+
const promptHistory = useRef([]);
|
|
3498
|
+
const historyCursor = useRef(-1);
|
|
3391
3499
|
const [summary, setSummary] = useState2({
|
|
3392
3500
|
turns: 0,
|
|
3393
3501
|
totalCostUsd: 0,
|
|
@@ -3456,11 +3564,28 @@ function App({
|
|
|
3456
3564
|
}
|
|
3457
3565
|
}, [session, loop]);
|
|
3458
3566
|
useInput((_input, key) => {
|
|
3459
|
-
if (
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3567
|
+
if (key.escape && busy) {
|
|
3568
|
+
if (abortedThisTurn.current) return;
|
|
3569
|
+
abortedThisTurn.current = true;
|
|
3570
|
+
loop.abort();
|
|
3571
|
+
return;
|
|
3572
|
+
}
|
|
3573
|
+
if (busy) return;
|
|
3574
|
+
const hist = promptHistory.current;
|
|
3575
|
+
if (key.upArrow) {
|
|
3576
|
+
if (hist.length === 0) return;
|
|
3577
|
+
const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
|
|
3578
|
+
historyCursor.current = nextCursor;
|
|
3579
|
+
setInput(hist[hist.length - 1 - nextCursor] ?? "");
|
|
3580
|
+
return;
|
|
3581
|
+
}
|
|
3582
|
+
if (key.downArrow) {
|
|
3583
|
+
if (historyCursor.current < 0) return;
|
|
3584
|
+
const nextCursor = historyCursor.current - 1;
|
|
3585
|
+
historyCursor.current = nextCursor;
|
|
3586
|
+
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3464
3589
|
});
|
|
3465
3590
|
const codeUndo = useCallback(() => {
|
|
3466
3591
|
if (!codeMode) return "not in code mode";
|
|
@@ -3502,9 +3627,16 @@ function App({
|
|
|
3502
3627
|
);
|
|
3503
3628
|
const handleSubmit = useCallback(
|
|
3504
3629
|
async (raw) => {
|
|
3505
|
-
|
|
3630
|
+
let text = raw.trim();
|
|
3506
3631
|
if (!text || busy) return;
|
|
3507
3632
|
setInput("");
|
|
3633
|
+
historyCursor.current = -1;
|
|
3634
|
+
if (codeMode && pendingEdits.current.length > 0 && (text === "y" || text === "n")) {
|
|
3635
|
+
const out = text === "y" ? codeApply() : codeDiscard();
|
|
3636
|
+
setHistorical((prev) => [...prev, { id: `sys-${Date.now()}`, role: "info", text: out }]);
|
|
3637
|
+
promptHistory.current.push(text);
|
|
3638
|
+
return;
|
|
3639
|
+
}
|
|
3508
3640
|
const slash = parseSlash(text);
|
|
3509
3641
|
if (slash) {
|
|
3510
3642
|
const result = handleSlash(slash.cmd, slash.args, loop, {
|
|
@@ -3512,7 +3644,8 @@ function App({
|
|
|
3512
3644
|
codeUndo: codeMode ? codeUndo : void 0,
|
|
3513
3645
|
codeApply: codeMode ? codeApply : void 0,
|
|
3514
3646
|
codeDiscard: codeMode ? codeDiscard : void 0,
|
|
3515
|
-
codeRoot: codeMode?.rootDir
|
|
3647
|
+
codeRoot: codeMode?.rootDir,
|
|
3648
|
+
pendingEditCount: codeMode ? pendingEdits.current.length : void 0
|
|
3516
3649
|
});
|
|
3517
3650
|
if (result.exit) {
|
|
3518
3651
|
transcriptRef.current?.end();
|
|
@@ -3533,8 +3666,14 @@ function App({
|
|
|
3533
3666
|
}
|
|
3534
3667
|
]);
|
|
3535
3668
|
}
|
|
3536
|
-
|
|
3669
|
+
if (result.resubmit) {
|
|
3670
|
+
text = result.resubmit;
|
|
3671
|
+
} else {
|
|
3672
|
+
promptHistory.current.push(text);
|
|
3673
|
+
return;
|
|
3674
|
+
}
|
|
3537
3675
|
}
|
|
3676
|
+
promptHistory.current.push(text);
|
|
3538
3677
|
setHistorical((prev) => [...prev, { id: `u-${Date.now()}`, role: "user", text }]);
|
|
3539
3678
|
const assistantId = `a-${Date.now()}`;
|
|
3540
3679
|
const streamRef = { id: assistantId, text: "", reasoning: "" };
|
|
@@ -3664,16 +3803,62 @@ function App({
|
|
|
3664
3803
|
}
|
|
3665
3804
|
function OngoingToolRow({ tool }) {
|
|
3666
3805
|
const [tick, setTick] = useState2(0);
|
|
3806
|
+
const [elapsed, setElapsed] = useState2(0);
|
|
3667
3807
|
useEffect2(() => {
|
|
3668
|
-
const
|
|
3669
|
-
|
|
3808
|
+
const start = Date.now();
|
|
3809
|
+
const frameId = setInterval(() => setTick((t) => t + 1), 120);
|
|
3810
|
+
const secId = setInterval(() => setElapsed(Math.floor((Date.now() - start) / 1e3)), 1e3);
|
|
3811
|
+
return () => {
|
|
3812
|
+
clearInterval(frameId);
|
|
3813
|
+
clearInterval(secId);
|
|
3814
|
+
};
|
|
3670
3815
|
}, []);
|
|
3671
3816
|
const frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
3672
|
-
const
|
|
3673
|
-
return /* @__PURE__ */ React6.createElement(Box6, { marginY: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, frames[tick % frames.length]), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, ` tool<${tool.name}> running\u2026`),
|
|
3817
|
+
const summary = summarizeToolArgs(tool.name, tool.args);
|
|
3818
|
+
return /* @__PURE__ */ React6.createElement(Box6, { marginY: 1, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, frames[tick % frames.length]), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, ` tool<${tool.name}> running\u2026`), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, ` ${elapsed}s`)), summary ? /* @__PURE__ */ React6.createElement(Box6, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, summary)) : null);
|
|
3819
|
+
}
|
|
3820
|
+
function summarizeToolArgs(name, args) {
|
|
3821
|
+
if (!args || args === "{}") return "";
|
|
3822
|
+
let parsed;
|
|
3823
|
+
try {
|
|
3824
|
+
parsed = JSON.parse(args);
|
|
3825
|
+
} catch {
|
|
3826
|
+
return args.length > 80 ? `${args.slice(0, 80)}\u2026` : args;
|
|
3827
|
+
}
|
|
3828
|
+
const hasSuffix = (s) => name === s || name.endsWith(`_${s}`);
|
|
3829
|
+
const path = typeof parsed.path === "string" ? parsed.path : void 0;
|
|
3830
|
+
if (hasSuffix("read_file")) {
|
|
3831
|
+
const head = typeof parsed.head === "number" ? `, head=${parsed.head}` : "";
|
|
3832
|
+
const tail = typeof parsed.tail === "number" ? `, tail=${parsed.tail}` : "";
|
|
3833
|
+
return `path: ${path ?? "?"}${head}${tail}`;
|
|
3834
|
+
}
|
|
3835
|
+
if (hasSuffix("write_file")) {
|
|
3836
|
+
const content = typeof parsed.content === "string" ? parsed.content : "";
|
|
3837
|
+
return `path: ${path ?? "?"} (${content.length} chars)`;
|
|
3838
|
+
}
|
|
3839
|
+
if (hasSuffix("edit_file")) {
|
|
3840
|
+
const edits = Array.isArray(parsed.edits) ? parsed.edits.length : 0;
|
|
3841
|
+
return `path: ${path ?? "?"} (${edits} edit${edits === 1 ? "" : "s"})`;
|
|
3842
|
+
}
|
|
3843
|
+
if (hasSuffix("list_directory") || hasSuffix("directory_tree")) {
|
|
3844
|
+
return `path: ${path ?? "?"}`;
|
|
3845
|
+
}
|
|
3846
|
+
if (hasSuffix("search_files")) {
|
|
3847
|
+
const pattern = typeof parsed.pattern === "string" ? parsed.pattern : "?";
|
|
3848
|
+
return `path: ${path ?? "?"} \xB7 pattern: ${pattern}`;
|
|
3849
|
+
}
|
|
3850
|
+
if (hasSuffix("move_file")) {
|
|
3851
|
+
const src = typeof parsed.source === "string" ? parsed.source : "?";
|
|
3852
|
+
const dst = typeof parsed.destination === "string" ? parsed.destination : "?";
|
|
3853
|
+
return `${src} \u2192 ${dst}`;
|
|
3854
|
+
}
|
|
3855
|
+
if (hasSuffix("get_file_info")) {
|
|
3856
|
+
return `path: ${path ?? "?"}`;
|
|
3857
|
+
}
|
|
3858
|
+
return args.length > 80 ? `${args.slice(0, 80)}\u2026` : args;
|
|
3674
3859
|
}
|
|
3675
3860
|
function CommandStrip({ codeMode }) {
|
|
3676
|
-
return /* @__PURE__ */ React6.createElement(Box6, { paddingX: 2, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "/help \xB7 /preset ", "<fast|smart|max>", " \xB7 /mcp \xB7 /compact \xB7 /sessions \xB7 /setup \xB7 /clear \xB7 /exit"), codeMode ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, 'code mode: /apply \xB7 /discard \xB7 /undo \xB7 /commit "msg" \u2014 edits NEVER write without /apply') : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "Esc (while thinking) \u2014 abort & summarize what was found so far"));
|
|
3861
|
+
return /* @__PURE__ */ React6.createElement(Box6, { paddingX: 2, flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "/help \xB7 /preset ", "<fast|smart|max>", " \xB7 /mcp \xB7 /compact \xB7 /sessions \xB7 /setup \xB7 /clear \xB7 /exit"), codeMode ? /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, 'code mode: /apply (y) \xB7 /discard (n) \xB7 /undo \xB7 /commit "msg" \u2014 edits NEVER write without /apply') : null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\u2191/\u2193 recall prompts \xB7 /retry re-send last \xB7 /think see R1 full reasoning"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "Esc (while thinking) \u2014 abort & summarize what was found so far"));
|
|
3677
3862
|
}
|
|
3678
3863
|
function formatEditResults(results) {
|
|
3679
3864
|
const lines = results.map((r) => {
|
|
@@ -3693,7 +3878,7 @@ function formatPendingPreview(blocks) {
|
|
|
3693
3878
|
const tag = b.search === "" ? "NEW " : " ";
|
|
3694
3879
|
return ` ${tag}${b.path} (-${removed} +${added} lines)`;
|
|
3695
3880
|
});
|
|
3696
|
-
const header = `\u25B8 ${blocks.length} pending edit block(s) \u2014 /apply to commit
|
|
3881
|
+
const header = `\u25B8 ${blocks.length} pending edit block(s) \u2014 /apply (or y) to commit \xB7 /discard (or n) to drop`;
|
|
3697
3882
|
return [header, ...lines].join("\n");
|
|
3698
3883
|
}
|
|
3699
3884
|
function countLines2(s) {
|