@oxecli/oxe 1.0.77 → 1.0.78
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 +8 -4
- package/dist/tools.js +5 -2
- package/dist/ui.js +50 -0
- package/package.json +1 -1
package/dist/engine.js
CHANGED
|
@@ -578,11 +578,12 @@ export class InferenceEngine {
|
|
|
578
578
|
this.workActive = false;
|
|
579
579
|
const started = toolCallLabel(c.name, c.arguments);
|
|
580
580
|
const toolSpinner = new Spinner();
|
|
581
|
-
toolSpinner.
|
|
581
|
+
toolSpinner.startDots("Running");
|
|
582
582
|
const rawResult = await this.runTool(c.name, c.arguments);
|
|
583
|
-
|
|
584
|
-
|
|
583
|
+
if (this.interrupted) {
|
|
584
|
+
toolSpinner.stop();
|
|
585
585
|
throw new Error("interrupt");
|
|
586
|
+
}
|
|
586
587
|
const failed = toolOutputFailed(c.name, rawResult);
|
|
587
588
|
const action = formatToolResult(rawResult, failed);
|
|
588
589
|
story.push({
|
|
@@ -591,7 +592,10 @@ export class InferenceEngine {
|
|
|
591
592
|
text: action,
|
|
592
593
|
status: failed ? "failed" : "ok",
|
|
593
594
|
});
|
|
594
|
-
|
|
595
|
+
// Replace the "Running..." line in place with the tool label so the
|
|
596
|
+
// transition is seamless, then print the result beneath it.
|
|
597
|
+
toolSpinner.replaceWith(started);
|
|
598
|
+
process.stdout.write(`${action}\n\n`);
|
|
595
599
|
// Any diff the tool produced is flushed only now, after the spinner
|
|
596
600
|
// has stopped, so the box renders cleanly below the action line.
|
|
597
601
|
flushPendingDiffOutput();
|
package/dist/tools.js
CHANGED
|
@@ -133,14 +133,17 @@ function displayDiff(pathName, oldContent, newContent) {
|
|
|
133
133
|
const num = v.kind === "+" ? v.newNum : v.oldNum;
|
|
134
134
|
const numStr = num ? String(num).padStart(numW, " ") : gap;
|
|
135
135
|
if (v.kind === "+" || v.kind === "-") {
|
|
136
|
-
const bg = v.kind === "+" ? "\x1b[
|
|
136
|
+
const bg = v.kind === "+" ? "\x1b[48;2;2;40;0m" : "\x1b[48;2;61;1;0m";
|
|
137
137
|
const sign = v.kind === "+" ? "+" : "-";
|
|
138
138
|
const body = truncateStyled(v.body, bodyMax);
|
|
139
139
|
const fill = Math.max(0, termW - numW - 4 - plainLen(body));
|
|
140
140
|
pendingDiffOutput.push(`${bg}\x1b[97m${numStr} ${sign} ${body}${" ".repeat(fill)}\x1b[0m`);
|
|
141
141
|
}
|
|
142
142
|
else {
|
|
143
|
-
const
|
|
143
|
+
const raw = v.kind === "\\" ? v.body : highlightCodeLine(v.body);
|
|
144
|
+
// highlightCodeLine resets to default after each token; re-apply the dim
|
|
145
|
+
// gray base so plain text stays dim and only tokens show color.
|
|
146
|
+
const body = truncateStyled(raw.replace(/\x1b\[0m/g, "\x1b[0m\x1b[90m"), bodyMax);
|
|
144
147
|
pendingDiffOutput.push(`\x1b[90m${numStr} ${body}\x1b[0m`);
|
|
145
148
|
}
|
|
146
149
|
}
|
package/dist/ui.js
CHANGED
|
@@ -512,6 +512,7 @@ export function showCursor() {
|
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
514
|
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
515
|
+
const DOT_FRAMES = [". ", ".. ", "..."];
|
|
515
516
|
export class Spinner {
|
|
516
517
|
timer = null;
|
|
517
518
|
frame = 0;
|
|
@@ -520,6 +521,8 @@ export class Spinner {
|
|
|
520
521
|
enabled;
|
|
521
522
|
lastRendered = "";
|
|
522
523
|
lastLen = 0;
|
|
524
|
+
dotsText = "";
|
|
525
|
+
dotsFrame = 0;
|
|
523
526
|
constructor(enabled = true) {
|
|
524
527
|
this.enabled = enabled;
|
|
525
528
|
}
|
|
@@ -547,6 +550,53 @@ export class Spinner {
|
|
|
547
550
|
}, 80);
|
|
548
551
|
this.draw();
|
|
549
552
|
}
|
|
553
|
+
/** Dots-mode label: renders `Running` + a fixed 3-cell animated dots field.
|
|
554
|
+
* Each tick rewrites ONLY the dots cells via a cursor jump, so the rest of
|
|
555
|
+
* the line never flickers. Swap in the final label with replaceWith(). */
|
|
556
|
+
startDots(text) {
|
|
557
|
+
if (!this.enabled)
|
|
558
|
+
return;
|
|
559
|
+
if (this.timer)
|
|
560
|
+
clearInterval(this.timer);
|
|
561
|
+
this.dotsText = text;
|
|
562
|
+
this.dotsFrame = 0;
|
|
563
|
+
this.rows = 1;
|
|
564
|
+
this.lastRendered = "";
|
|
565
|
+
this.lastLen = text.length + 3;
|
|
566
|
+
this.writeDots(true);
|
|
567
|
+
this.timer = setInterval(() => {
|
|
568
|
+
this.dotsFrame = (this.dotsFrame + 1) % DOT_FRAMES.length;
|
|
569
|
+
this.writeDots(false);
|
|
570
|
+
}, 300);
|
|
571
|
+
}
|
|
572
|
+
writeDots(initial) {
|
|
573
|
+
const label = `\x1b[1;36m${this.dotsText}\x1b[0m`;
|
|
574
|
+
const dots = `\x1b[1;36m${DOT_FRAMES[this.dotsFrame]}\x1b[0m`;
|
|
575
|
+
if (initial) {
|
|
576
|
+
process.stdout.write("\r" + label + dots + "\r");
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
// Jump to the dots column (1-based) and rewrite only the 3-cell field.
|
|
580
|
+
process.stdout.write(`\x1b[${this.dotsText.length + 1}G` + dots + "\r");
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
/** Overwrite the dots line in place with `text` and advance to the next
|
|
584
|
+
* line, without erasing (so there is no flash). */
|
|
585
|
+
replaceWith(text) {
|
|
586
|
+
if (this.timer) {
|
|
587
|
+
clearInterval(this.timer);
|
|
588
|
+
this.timer = null;
|
|
589
|
+
}
|
|
590
|
+
if (!this.enabled) {
|
|
591
|
+
process.stdout.write(`${text}\n`);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
const plain = stripAnsi(text);
|
|
595
|
+
const pad = Math.max(0, this.lastLen - plain.length);
|
|
596
|
+
process.stdout.write("\r" + text + " ".repeat(pad) + "\r\n");
|
|
597
|
+
this.rows = 0;
|
|
598
|
+
this.lastLen = plain.length;
|
|
599
|
+
}
|
|
550
600
|
update(text) {
|
|
551
601
|
if (this.timer) {
|
|
552
602
|
this.render = () => text;
|