@oxecli/oxe 1.0.84 → 1.0.86
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.js +23 -5
- package/dist/engine.js +3 -3
- package/dist/tools.js +1 -1
- package/dist/ui.js +21 -19
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { loadOrPrompt, default_reasoning_effort, max_action_chars, max_resume_history_items, runtimeOsSummary, max_context_tokens, context_overhead_margin, } from "./config.js";
|
|
5
5
|
import { InferenceEngine, estimateTokens } from "./engine.js";
|
|
6
6
|
import { saveSession, loadSession, listSessions, nextSessionId, conversationLabel, COMMAND_HELP, stripOrphanCalls, toolOutputFailed, } from "./sessions.js";
|
|
7
|
-
import { clearScreen, enableAnsi, askBottomPrompt, userDisplayText, aiMarkdown, mutedMarkdown, messageText, toolCallLabel, formatToolResult, truncateEllipsis, stripAnsi, renderPanel, renderTableString, enableRawStdin, disableRawStdin, waitRawKey, } from "./ui.js";
|
|
7
|
+
import { clearScreen, enableAnsi, askBottomPrompt, userDisplayText, aiMarkdown, mutedMarkdown, messageText, toolCallLabel, formatToolResult, truncateEllipsis, stripAnsi, plainLen, truncateStyled, terminalWidth, TOOL_RESULT_MAX_LINES, MAX_COMMAND_DISPLAY_CHARS, renderPanel, renderTableString, enableRawStdin, disableRawStdin, waitRawKey, } from "./ui.js";
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const require = createRequire(import.meta.url);
|
|
10
10
|
const packageInfo = require("../package.json");
|
|
@@ -49,14 +49,32 @@ export class CLI {
|
|
|
49
49
|
const label = started && String(started).trim();
|
|
50
50
|
const body = String(text).trim();
|
|
51
51
|
if (label && /^[⎿╰]/.test(stripAnsi(body))) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// The result body was formatted against the terminal width at tool time,
|
|
53
|
+
// but the window may be narrower on resume — re-truncate defensively so
|
|
54
|
+
// long persisted lines never run off the screen.
|
|
55
|
+
const lineMax = Math.max(terminalWidth() - 4, 20);
|
|
56
|
+
const allLines = body.split("\n");
|
|
57
|
+
const lines = allLines
|
|
58
|
+
.slice(0, TOOL_RESULT_MAX_LINES)
|
|
59
|
+
.map((ln) => plainLen(ln) > lineMax ? truncateStyled(ln, lineMax) + "…\x1b[0m" : ln);
|
|
60
|
+
if (allLines.length > TOOL_RESULT_MAX_LINES) {
|
|
61
|
+
lines.push("\x1b[90m…\x1b[0m");
|
|
62
|
+
}
|
|
63
|
+
const labelLine = plainLen(label) > lineMax ? truncateStyled(label, lineMax) + "…\x1b[0m" : label;
|
|
64
|
+
process.stdout.write(`${labelLine}\n${lines.join("\n")}\n`);
|
|
65
|
+
if (diff) {
|
|
66
|
+
const diffLines = diff.split("\n").map((ln) => plainLen(ln) > lineMax ? truncateStyled(ln, lineMax) + "…\x1b[0m" : ln);
|
|
67
|
+
process.stdout.write(diffLines.join("\n") + "\n\n");
|
|
68
|
+
}
|
|
55
69
|
return;
|
|
56
70
|
}
|
|
57
71
|
const icon = status === "failed" ? "\x1b[31m✗\x1b[0m" : "\x1b[32m✓\x1b[0m";
|
|
58
72
|
const style = status === "failed" ? "\x1b[31m" : "\x1b[32m";
|
|
59
|
-
|
|
73
|
+
const truncated = truncateEllipsis(body, Math.min(max_action_chars, MAX_COMMAND_DISPLAY_CHARS), "text");
|
|
74
|
+
// truncateEllipsis appends a "…(text truncated: N chars total)" suffix, so
|
|
75
|
+
// re-truncate to the current width to keep the legacy action on one row.
|
|
76
|
+
const displayMax = Math.max(terminalWidth() - 6, 20);
|
|
77
|
+
process.stdout.write(`${icon} ${style}${truncateStyled(truncated, displayMax)}\x1b[0m\n`);
|
|
60
78
|
}
|
|
61
79
|
printAssistantBlock(text) {
|
|
62
80
|
const rendered = aiMarkdown(text);
|
package/dist/engine.js
CHANGED
|
@@ -581,10 +581,10 @@ export class InferenceEngine {
|
|
|
581
581
|
this.queryCalledTool = true;
|
|
582
582
|
const started = toolCallLabel(c.name, c.arguments);
|
|
583
583
|
// Print the tool label the instant the command starts, then show a
|
|
584
|
-
// "
|
|
584
|
+
// "╰─ Working..." dots line that swaps to the real result in place.
|
|
585
585
|
process.stdout.write(`${started}\n`);
|
|
586
586
|
const toolSpinner = new Spinner();
|
|
587
|
-
toolSpinner.startDots("\x1b[90m
|
|
587
|
+
toolSpinner.startDots("\x1b[90m╰─\x1b[0m Working");
|
|
588
588
|
const rawResult = await this.runTool(c.name, c.arguments);
|
|
589
589
|
if (this.interrupted) {
|
|
590
590
|
toolSpinner.stop();
|
|
@@ -600,7 +600,7 @@ export class InferenceEngine {
|
|
|
600
600
|
status: failed ? "failed" : "ok",
|
|
601
601
|
diff,
|
|
602
602
|
});
|
|
603
|
-
// Swap the "
|
|
603
|
+
// Swap the "╰─ Working..." line for the real result. If the tool
|
|
604
604
|
// produced a diff it renders directly below the action line with no
|
|
605
605
|
// gap; otherwise a blank line separates the action from what follows.
|
|
606
606
|
toolSpinner.replaceWith(action);
|
package/dist/tools.js
CHANGED
|
@@ -43,7 +43,7 @@ export function takePendingDiffOutput() {
|
|
|
43
43
|
}
|
|
44
44
|
function displayDiff(pathName, oldContent, newContent) {
|
|
45
45
|
// Indent every diff row 3 columns so the diff's left edge lines up with the
|
|
46
|
-
// tool result text above it ("
|
|
46
|
+
// tool result text above it ("╰─ Wrote N chars").
|
|
47
47
|
const ind = " ";
|
|
48
48
|
if (oldContent.length + newContent.length > max_diff_source_chars) {
|
|
49
49
|
pendingDiffOutput.push(`\x1b[90m${ind}${pathName}: ${oldContent.length.toLocaleString()} chars -> ${newContent.length.toLocaleString()} chars ` +
|
package/dist/ui.js
CHANGED
|
@@ -681,10 +681,13 @@ const TOOL_DISPLAY_NAMES = {
|
|
|
681
681
|
grep: "Grep",
|
|
682
682
|
load_skill: "Load",
|
|
683
683
|
};
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
684
|
+
export const TOOL_RESULT_MAX_LINES = 6;
|
|
685
|
+
/** Cap on the visible command/arg shown in a tool label, so the entry always
|
|
686
|
+
* fits on a single row regardless of terminal width. */
|
|
687
|
+
export const MAX_COMMAND_DISPLAY_CHARS = 100;
|
|
688
|
+
/** First line of a tool entry: `Bash(rm -f "…")` — cyan tool name, primary arg
|
|
689
|
+
* in parens. Newlines collapse to spaces and the arg is width-capped so the
|
|
690
|
+
* label never wraps past one row. */
|
|
688
691
|
export function toolCallLabel(name, argumentsJson) {
|
|
689
692
|
let args = {};
|
|
690
693
|
try {
|
|
@@ -713,15 +716,16 @@ export function toolCallLabel(name, argumentsJson) {
|
|
|
713
716
|
arg = String(args["skill_name"] ?? "");
|
|
714
717
|
break;
|
|
715
718
|
}
|
|
716
|
-
arg = arg.trim();
|
|
719
|
+
arg = arg.trim().replace(/\s*\r?\n\s*/g, " ");
|
|
717
720
|
if (!arg)
|
|
718
721
|
return `\x1b[1;36m${display}\x1b[0m`;
|
|
719
|
-
|
|
720
|
-
|
|
722
|
+
const cap = Math.max(Math.min(terminalWidth() - plainLen(display) - 4, MAX_COMMAND_DISPLAY_CHARS), 20);
|
|
723
|
+
if (plainLen(arg) > cap)
|
|
724
|
+
arg = truncateStyled(arg, cap) + "…";
|
|
721
725
|
return `\x1b[1;36m${display}\x1b[0m(${arg})`;
|
|
722
726
|
}
|
|
723
727
|
/**
|
|
724
|
-
* Second line of a tool entry:
|
|
728
|
+
* Second line of a tool entry: `╰─ Done` on a quiet success, otherwise the
|
|
725
729
|
* tool's output / error, collapsed and truncated so it never floods the screen.
|
|
726
730
|
*/
|
|
727
731
|
export function formatToolResult(rawResult, failed) {
|
|
@@ -730,24 +734,22 @@ export function formatToolResult(rawResult, failed) {
|
|
|
730
734
|
.trim();
|
|
731
735
|
const code = raw.match(/^exit code: (\d+)/)?.[1] ?? null;
|
|
732
736
|
const clean = raw.replace(/^exit code: \d+\n?/, "").trim();
|
|
733
|
-
const corner = "\x1b[90m
|
|
737
|
+
const corner = "\x1b[90m╰─\x1b[0m ";
|
|
734
738
|
if (!failed && (!clean || clean === "(no output)")) {
|
|
735
739
|
return `${corner}\x1b[32mDone\x1b[0m`;
|
|
736
740
|
}
|
|
737
741
|
if (failed && (!clean || clean === "(no output)") && code) {
|
|
738
742
|
return `${corner}\x1b[31mexit code: ${code}\x1b[0m`;
|
|
739
743
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
const
|
|
745
|
-
|
|
744
|
+
// Truncate to the terminal width (rows OR per-line length, whichever trips
|
|
745
|
+
// first) so long tool output — e.g. Glob paths — never runs off the screen.
|
|
746
|
+
const termW = terminalWidth();
|
|
747
|
+
const lineMax = Math.max(termW - 4, 20);
|
|
748
|
+
const allLines = clean.split("\n");
|
|
749
|
+
const lines = allLines
|
|
746
750
|
.slice(0, TOOL_RESULT_MAX_LINES)
|
|
747
|
-
.map((ln) => ln.length >
|
|
748
|
-
|
|
749
|
-
: ln);
|
|
750
|
-
if (clipped || body.split("\n").length > TOOL_RESULT_MAX_LINES)
|
|
751
|
+
.map((ln) => (ln.length > lineMax ? ln.slice(0, lineMax) + "…" : ln));
|
|
752
|
+
if (allLines.length > TOOL_RESULT_MAX_LINES)
|
|
751
753
|
lines.push("…");
|
|
752
754
|
const styleOpen = failed ? "\x1b[31m" : "\x1b[90m";
|
|
753
755
|
const inner = lines
|