@oxecli/oxe 1.0.59 → 1.0.60
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/tools.js +37 -9
- package/dist/ui.js +25 -11
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -4,6 +4,7 @@ import { execFile, spawn } from "node:child_process";
|
|
|
4
4
|
import { structuredPatch } from "diff";
|
|
5
5
|
import { max_diff_source_chars, max_diff_lines, max_diff_context_lines, max_diff_line_chars, max_read_line_chars, max_read_file_bytes, max_read_lines, max_output_chars, max_bash_timeout_seconds, max_grep_file_bytes, strict_max_properties, ignoredDirs, } from "./config.js";
|
|
6
6
|
import { toolLoadSkill } from "./skills.js";
|
|
7
|
+
import { truncateStyled, plainLen, terminalWidth } from "./ui.js";
|
|
7
8
|
export { toolLoadSkill };
|
|
8
9
|
// ---------------------------------------------------------------------------
|
|
9
10
|
// Path sanitization helper
|
|
@@ -52,7 +53,6 @@ function displayDiff(pathName, oldContent, newContent) {
|
|
|
52
53
|
const removed = contentLines.filter((c) => c.kind === "-").length;
|
|
53
54
|
if (!added && !removed)
|
|
54
55
|
return;
|
|
55
|
-
process.stdout.write(`\x1b[90m┌─\x1b[0m \x1b[1m${pathName}\x1b[0m \x1b[32m+${added}\x1b[0m \x1b[31m-${removed}\x1b[0m\n`);
|
|
56
56
|
const shown = [];
|
|
57
57
|
let run = [];
|
|
58
58
|
let lastKind = null;
|
|
@@ -77,18 +77,46 @@ function displayDiff(pathName, oldContent, newContent) {
|
|
|
77
77
|
run.push(c);
|
|
78
78
|
}
|
|
79
79
|
flush();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
// Build the lines, stripping the leading + / - / space marker for display.
|
|
81
|
+
const visible = shown.map((l) => {
|
|
82
|
+
const kind = l[0] === "+" ? "+" : l[0] === "-" ? "-" : " ";
|
|
83
|
+
return { kind, body: l.slice(1) };
|
|
84
|
+
});
|
|
85
|
+
// A "… (N lines hidden) …" summary line is neutral context.
|
|
86
|
+
const termW = terminalWidth();
|
|
87
|
+
let contentW = 0;
|
|
88
|
+
for (const v of visible) {
|
|
89
|
+
contentW = Math.max(contentW, plainLen(v.body));
|
|
90
|
+
}
|
|
91
|
+
const headerPlain = `${pathName} +${added} -${removed}`;
|
|
92
|
+
const boxW = Math.min(Math.max(contentW, plainLen(headerPlain)) + 6, Math.max(termW - 2, 20));
|
|
93
|
+
const innerW = Math.max(boxW - 4, 1);
|
|
94
|
+
const maxPath = Math.max(10, boxW - 2 - plainLen(` +${added} -${removed}`) - 3);
|
|
95
|
+
let pathDisp = pathName;
|
|
96
|
+
if (plainLen(pathDisp) > maxPath)
|
|
97
|
+
pathDisp = truncateStyled(pathDisp, Math.max(maxPath - 1, 1)) + "…";
|
|
98
|
+
const header = `\x1b[1m${pathDisp}\x1b[0m \x1b[32m+${added}\x1b[0m \x1b[31m-${removed}\x1b[0m`;
|
|
99
|
+
const headerStr = `─ ${header} `;
|
|
100
|
+
const top = `╭${headerStr}${"─".repeat(Math.max(0, boxW - 2 - plainLen(headerStr)))}╮`;
|
|
101
|
+
process.stdout.write(`\x1b[90m${top}\x1b[0m\n`);
|
|
102
|
+
for (const v of visible) {
|
|
103
|
+
let line;
|
|
104
|
+
if (v.kind === "+") {
|
|
105
|
+
const body = truncateStyled(v.body, innerW - 2);
|
|
106
|
+
line = `\x1b[32m+ ${body}\x1b[0m`;
|
|
107
|
+
}
|
|
108
|
+
else if (v.kind === "-") {
|
|
109
|
+
const body = truncateStyled(v.body, innerW - 2);
|
|
110
|
+
line = `\x1b[31m- ${body}\x1b[0m`;
|
|
86
111
|
}
|
|
87
112
|
else {
|
|
88
|
-
|
|
113
|
+
const body = truncateStyled(v.body, innerW - 2);
|
|
114
|
+
line = `\x1b[2m ${body}\x1b[0m`;
|
|
89
115
|
}
|
|
116
|
+
const fill = Math.max(0, innerW - plainLen(line));
|
|
117
|
+
process.stdout.write(`\x1b[90m│\x1b[0m ${line}${" ".repeat(fill)} \x1b[90m│\x1b[0m\n`);
|
|
90
118
|
}
|
|
91
|
-
process.stdout.write(`\x1b[90m
|
|
119
|
+
process.stdout.write(`\x1b[90m╰${"─".repeat(boxW - 2)}╯\x1b[0m\n`);
|
|
92
120
|
}
|
|
93
121
|
export function truncateToolOutput(output, maxChars = max_output_chars) {
|
|
94
122
|
if (output.length > maxChars) {
|
package/dist/ui.js
CHANGED
|
@@ -213,9 +213,9 @@ function formatMarkdownTable(tableLines) {
|
|
|
213
213
|
colWidths.push(Math.max(mw, 3));
|
|
214
214
|
}
|
|
215
215
|
const out = [];
|
|
216
|
-
const topBorder = `\x1b[90m
|
|
216
|
+
const topBorder = `\x1b[90m╭${colWidths.map((w) => "─".repeat(w + 2)).join("┬")}╮\x1b[0m`;
|
|
217
217
|
const midBorder = `\x1b[90m├${colWidths.map((w) => "─".repeat(w + 2)).join("┼")}┤\x1b[0m`;
|
|
218
|
-
const botBorder = `\x1b[90m
|
|
218
|
+
const botBorder = `\x1b[90m╰${colWidths.map((w) => "─".repeat(w + 2)).join("┴")}╯\x1b[0m`;
|
|
219
219
|
out.push(topBorder);
|
|
220
220
|
const headCells = header.map((h, i) => {
|
|
221
221
|
const formatted = `\x1b[1;37m${formatInlineMarkdown(h)}\x1b[0m`;
|
|
@@ -302,20 +302,20 @@ export function markdownToAnsi(text) {
|
|
|
302
302
|
continue;
|
|
303
303
|
}
|
|
304
304
|
let line = raw;
|
|
305
|
-
// Headers
|
|
305
|
+
// Headers (render as styled headings with the '#' markers stripped)
|
|
306
306
|
const h1 = line.match(/^#\s+(.+)$/);
|
|
307
307
|
if (h1) {
|
|
308
|
-
out.push(`\x1b[1;36m
|
|
308
|
+
out.push(`\x1b[1;36m${formatInlineMarkdown(h1[1])}\x1b[0m`);
|
|
309
309
|
continue;
|
|
310
310
|
}
|
|
311
311
|
const h2 = line.match(/^##\s+(.+)$/);
|
|
312
312
|
if (h2) {
|
|
313
|
-
out.push(`\x1b[1;34m
|
|
313
|
+
out.push(`\x1b[1;34m${formatInlineMarkdown(h2[1])}\x1b[0m`);
|
|
314
314
|
continue;
|
|
315
315
|
}
|
|
316
316
|
const h3 = line.match(/^###\s+(.+)$/);
|
|
317
317
|
if (h3) {
|
|
318
|
-
out.push(`\x1b[1;37m
|
|
318
|
+
out.push(`\x1b[1;37m${formatInlineMarkdown(h3[1])}\x1b[0m`);
|
|
319
319
|
continue;
|
|
320
320
|
}
|
|
321
321
|
// Blockquote
|
|
@@ -728,11 +728,25 @@ function wrapRuns(runs, width) {
|
|
|
728
728
|
while (rest.length > 0) {
|
|
729
729
|
if (curLen >= width)
|
|
730
730
|
flush();
|
|
731
|
-
let take
|
|
732
|
-
if (
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
731
|
+
let take;
|
|
732
|
+
if (curLen === 0) {
|
|
733
|
+
// Start of a line: take a whole word (or one char for a lone space,
|
|
734
|
+
// or a full-width chunk for an overlong word).
|
|
735
|
+
const sp = rest.indexOf(" ");
|
|
736
|
+
take = sp === -1 ? rest.length : sp;
|
|
737
|
+
if (take === 0)
|
|
738
|
+
take = 1;
|
|
739
|
+
take = Math.min(take, width);
|
|
740
|
+
}
|
|
741
|
+
else {
|
|
742
|
+
// Mid-line: append the next whole word (plus its trailing space) only
|
|
743
|
+
// if it fits; otherwise move the entire word to the next line.
|
|
744
|
+
const sp = rest.indexOf(" ");
|
|
745
|
+
take = sp === -1 ? rest.length : sp + 1;
|
|
746
|
+
if (take > width - curLen) {
|
|
747
|
+
flush();
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
736
750
|
}
|
|
737
751
|
const chunk = rest.slice(0, take);
|
|
738
752
|
cur += run.style ? run.style + chunk + "\x1b[0m" : chunk;
|