@oxecli/oxe 1.0.56 → 1.0.58
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/engine.js +4 -4
- package/dist/ui.js +71 -22
- package/package.json +1 -1
package/dist/engine.js
CHANGED
|
@@ -43,7 +43,7 @@ export class InferenceEngine {
|
|
|
43
43
|
keyData;
|
|
44
44
|
client;
|
|
45
45
|
workActive = false;
|
|
46
|
-
workRows =
|
|
46
|
+
workRows = 0;
|
|
47
47
|
inQuery = false;
|
|
48
48
|
activeAbort = null;
|
|
49
49
|
interrupted = false;
|
|
@@ -149,7 +149,7 @@ export class InferenceEngine {
|
|
|
149
149
|
process.stdout.write("\x1b[1A\x1b[2K");
|
|
150
150
|
}
|
|
151
151
|
process.stdout.write(mutedMarkdown(text) + "\n\n");
|
|
152
|
-
this.workRows = displayRows(text) + 1;
|
|
152
|
+
this.workRows = displayRows(mutedMarkdown(text)) + 1;
|
|
153
153
|
}
|
|
154
154
|
clearWorkLine() {
|
|
155
155
|
if (!this.workActive || this.workRows < 1)
|
|
@@ -196,7 +196,7 @@ export class InferenceEngine {
|
|
|
196
196
|
else {
|
|
197
197
|
process.stdout.write(mutedMarkdown(`Worked for ${t}`) + "\n\n");
|
|
198
198
|
this.workActive = true;
|
|
199
|
-
this.workRows = displayRows(`Worked for ${t}`) + 1;
|
|
199
|
+
this.workRows = displayRows(mutedMarkdown(`Worked for ${t}`)) + 1;
|
|
200
200
|
}
|
|
201
201
|
};
|
|
202
202
|
const finishThinking = (report) => {
|
|
@@ -403,7 +403,7 @@ export class InferenceEngine {
|
|
|
403
403
|
return [conversation, false];
|
|
404
404
|
const started = Date.now();
|
|
405
405
|
const comp = new Spinner();
|
|
406
|
-
comp.start(
|
|
406
|
+
comp.start(`Compacting conversation ${tickDuration(0)}`);
|
|
407
407
|
const compTimer = setInterval(() => {
|
|
408
408
|
comp.update(`Compacting conversation ${tickDuration((Date.now() - started) / 1000)}`);
|
|
409
409
|
}, 100);
|
package/dist/ui.js
CHANGED
|
@@ -64,6 +64,38 @@ export function stripAnsi(s) {
|
|
|
64
64
|
export function plainLen(s) {
|
|
65
65
|
return stripAnsi(s).length;
|
|
66
66
|
}
|
|
67
|
+
// Truncate styled text to a max number of visible characters while keeping
|
|
68
|
+
// ANSI escape sequences intact (never cut mid-sequence).
|
|
69
|
+
export function truncateStyled(text, maxVisible) {
|
|
70
|
+
if (maxVisible <= 0)
|
|
71
|
+
return "";
|
|
72
|
+
if (plainLen(text) <= maxVisible)
|
|
73
|
+
return text;
|
|
74
|
+
const re = ANSI_RE;
|
|
75
|
+
re.lastIndex = 0;
|
|
76
|
+
let out = "";
|
|
77
|
+
let visible = 0;
|
|
78
|
+
let last = 0;
|
|
79
|
+
let m;
|
|
80
|
+
while ((m = re.exec(text)) !== null) {
|
|
81
|
+
if (m.index > last) {
|
|
82
|
+
const seg = text.slice(last, m.index);
|
|
83
|
+
const room = maxVisible - visible;
|
|
84
|
+
if (room <= 0)
|
|
85
|
+
return out;
|
|
86
|
+
out += seg.slice(0, room);
|
|
87
|
+
visible += Math.min(seg.length, room);
|
|
88
|
+
if (visible >= maxVisible)
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
out += m[0];
|
|
92
|
+
last = m.index + m[0].length;
|
|
93
|
+
}
|
|
94
|
+
if (visible < maxVisible) {
|
|
95
|
+
out += text.slice(last, last + (maxVisible - visible));
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
67
99
|
// ---------------------------------------------------------------------------
|
|
68
100
|
// Markup tag -> ANSI
|
|
69
101
|
// ---------------------------------------------------------------------------
|
|
@@ -334,11 +366,10 @@ export function aiMarkdown(text) {
|
|
|
334
366
|
return markdownToAnsi(text);
|
|
335
367
|
}
|
|
336
368
|
export function mutedMarkdown(text) {
|
|
337
|
-
|
|
369
|
+
return markdownToAnsi(text)
|
|
338
370
|
.split("\n")
|
|
339
371
|
.map((l) => `\x1b[2m${l}\x1b[0m`)
|
|
340
372
|
.join("\n");
|
|
341
|
-
return markdownToAnsi(dimmed);
|
|
342
373
|
}
|
|
343
374
|
// ---------------------------------------------------------------------------
|
|
344
375
|
// Panel Rendering
|
|
@@ -377,15 +408,9 @@ function panelString(content, title = "", subtitle = "", expand = true, borderSt
|
|
|
377
408
|
for (let i = 0; i < styledLines.length; i++) {
|
|
378
409
|
const line = styledLines[i];
|
|
379
410
|
const plain = plainLines[i] ?? "";
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
out.push(`\x1b[${borderStyle}m│\x1b[0m ${truncated} \x1b[${borderStyle}m│\x1b[0m`);
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
const pad = Math.max(innerW - plain.length, 0);
|
|
387
|
-
out.push(`\x1b[${borderStyle}m│\x1b[0m ${line}${" ".repeat(pad)} \x1b[${borderStyle}m│\x1b[0m`);
|
|
388
|
-
}
|
|
411
|
+
const pad = Math.max(innerW - plain.length, 0);
|
|
412
|
+
const display = plain.length > innerW ? truncateStyled(line, innerW) : line;
|
|
413
|
+
out.push(`\x1b[${borderStyle}m│\x1b[0m ${display}${" ".repeat(pad)} \x1b[${borderStyle}m│\x1b[0m`);
|
|
389
414
|
}
|
|
390
415
|
const bottom = `╰${embed(subtitle, "center")}╯`;
|
|
391
416
|
out.push(`\x1b[${borderStyle}m${bottom}\x1b[0m`);
|
|
@@ -1002,6 +1027,20 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1002
1027
|
}
|
|
1003
1028
|
cursor += text.length;
|
|
1004
1029
|
};
|
|
1030
|
+
// A paste span is treated as a single atomic "block" only when it collapses
|
|
1031
|
+
// to a marker (large pastes). Small inline pastes behave like normal text.
|
|
1032
|
+
const spanCollapsed = (span) => {
|
|
1033
|
+
return shouldCollapsePaste(buffer.slice(span[0], span[1]));
|
|
1034
|
+
};
|
|
1035
|
+
const deleteWholeSpan = (span) => {
|
|
1036
|
+
const [start, end] = span;
|
|
1037
|
+
buffer = buffer.slice(0, start) + buffer.slice(end);
|
|
1038
|
+
const delta = start - end;
|
|
1039
|
+
pasteSpans = pasteSpans
|
|
1040
|
+
.filter(([s, e]) => s !== start || e !== end)
|
|
1041
|
+
.map(([s, e]) => (s >= end ? [s + delta, e + delta] : [s, e]));
|
|
1042
|
+
cursor = start;
|
|
1043
|
+
};
|
|
1005
1044
|
const backspace = () => {
|
|
1006
1045
|
if (cursor <= 0)
|
|
1007
1046
|
return;
|
|
@@ -1010,14 +1049,8 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1010
1049
|
histIdx = hist.length;
|
|
1011
1050
|
}
|
|
1012
1051
|
const containing = pasteSpans.find(([s, e]) => s < cursor && cursor <= e);
|
|
1013
|
-
if (containing) {
|
|
1014
|
-
|
|
1015
|
-
buffer = buffer.slice(0, start) + buffer.slice(end);
|
|
1016
|
-
const delta = start - end;
|
|
1017
|
-
pasteSpans = pasteSpans
|
|
1018
|
-
.filter(([s, e]) => s !== start || e !== end)
|
|
1019
|
-
.map(([s, e]) => (s >= end ? [s + delta, e + delta] : [s, e]));
|
|
1020
|
-
cursor = start;
|
|
1052
|
+
if (containing && spanCollapsed(containing)) {
|
|
1053
|
+
deleteWholeSpan(containing);
|
|
1021
1054
|
return;
|
|
1022
1055
|
}
|
|
1023
1056
|
const before = Array.from(buffer.slice(0, cursor));
|
|
@@ -1049,7 +1082,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1049
1082
|
histIdx = hist.length;
|
|
1050
1083
|
}
|
|
1051
1084
|
const containing = pasteSpans.find(([s, e]) => s <= cursor && cursor < e);
|
|
1052
|
-
if (containing) {
|
|
1085
|
+
if (containing && spanCollapsed(containing)) {
|
|
1053
1086
|
const [start, end] = containing;
|
|
1054
1087
|
buffer = buffer.slice(0, start) + buffer.slice(end);
|
|
1055
1088
|
const delta = start - end;
|
|
@@ -1059,6 +1092,22 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1059
1092
|
return;
|
|
1060
1093
|
}
|
|
1061
1094
|
buffer = buffer.slice(0, cursor) + buffer.slice(cursor + 1);
|
|
1095
|
+
const deletedAt = cursor;
|
|
1096
|
+
const adjusted = [];
|
|
1097
|
+
for (const [s, e] of pasteSpans) {
|
|
1098
|
+
if (deletedAt >= s && deletedAt < e) {
|
|
1099
|
+
const ne = e - 1;
|
|
1100
|
+
if (s < ne)
|
|
1101
|
+
adjusted.push([s, ne]);
|
|
1102
|
+
}
|
|
1103
|
+
else if (deletedAt < s) {
|
|
1104
|
+
adjusted.push([s - 1, e - 1]);
|
|
1105
|
+
}
|
|
1106
|
+
else {
|
|
1107
|
+
adjusted.push([s, e]);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
pasteSpans = adjusted.filter(([s, e]) => s < e);
|
|
1062
1111
|
};
|
|
1063
1112
|
const deleteWordBefore = () => {
|
|
1064
1113
|
if (cursor <= 0)
|
|
@@ -1075,7 +1124,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1075
1124
|
if (cursor <= 0)
|
|
1076
1125
|
return;
|
|
1077
1126
|
for (const [s, e] of pasteSpans) {
|
|
1078
|
-
if (s < cursor && cursor <= e) {
|
|
1127
|
+
if (s < cursor && cursor <= e && spanCollapsed([s, e])) {
|
|
1079
1128
|
cursor = s;
|
|
1080
1129
|
return;
|
|
1081
1130
|
}
|
|
@@ -1086,7 +1135,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = []) {
|
|
|
1086
1135
|
if (cursor >= buffer.length)
|
|
1087
1136
|
return;
|
|
1088
1137
|
for (const [s, e] of pasteSpans) {
|
|
1089
|
-
if (s <= cursor && cursor < e) {
|
|
1138
|
+
if (s <= cursor && cursor < e && spanCollapsed([s, e])) {
|
|
1090
1139
|
cursor = e;
|
|
1091
1140
|
return;
|
|
1092
1141
|
}
|