@oxecli/oxe 1.0.78 → 1.0.79

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 CHANGED
@@ -577,8 +577,11 @@ export class InferenceEngine {
577
577
  for (const c of calls) {
578
578
  this.workActive = false;
579
579
  const started = toolCallLabel(c.name, c.arguments);
580
+ // Print the tool label the instant the command starts, then show a
581
+ // "⎿ Working..." dots line that swaps to the real result in place.
582
+ process.stdout.write(`${started}\n`);
580
583
  const toolSpinner = new Spinner();
581
- toolSpinner.startDots("Running");
584
+ toolSpinner.startDots("\x1b[90m⎿\x1b[0m Working");
582
585
  const rawResult = await this.runTool(c.name, c.arguments);
583
586
  if (this.interrupted) {
584
587
  toolSpinner.stop();
@@ -592,10 +595,9 @@ export class InferenceEngine {
592
595
  text: action,
593
596
  status: failed ? "failed" : "ok",
594
597
  });
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`);
598
+ // Swap the "⎿ Working..." line for the real result, then a blank line.
599
+ toolSpinner.replaceWith(action);
600
+ process.stdout.write(`\n`);
599
601
  // Any diff the tool produced is flushed only now, after the spinner
600
602
  // has stopped, so the box renders cleanly below the action line.
601
603
  flushPendingDiffOutput();
package/dist/tools.js CHANGED
@@ -133,11 +133,16 @@ 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[48;2;2;40;0m" : "\x1b[48;2;61;1;0m";
137
- const sign = v.kind === "+" ? "+" : "-";
138
- const body = truncateStyled(v.body, bodyMax);
136
+ const isAdd = v.kind === "+";
137
+ const bg = isAdd ? "\x1b[48;2;2;40;0m" : "\x1b[48;2;61;1;0m";
138
+ const fg = isAdd ? "\x1b[38;2;80;200;80m" : "\x1b[38;2;220;90;90m";
139
+ const sign = isAdd ? "+" : "-";
140
+ // Changed content renders normal white with syntax highlighting;
141
+ // re-apply the white base after each token reset.
142
+ const raw = highlightCodeLine(v.body);
143
+ const body = truncateStyled(raw.replace(/\x1b\[0m/g, "\x1b[0m\x1b[97m"), bodyMax);
139
144
  const fill = Math.max(0, termW - numW - 4 - plainLen(body));
140
- pendingDiffOutput.push(`${bg}\x1b[97m${numStr} ${sign} ${body}${" ".repeat(fill)}\x1b[0m`);
145
+ pendingDiffOutput.push(`${bg}${fg}${numStr} ${sign} \x1b[0m\x1b[97m${body}${" ".repeat(fill)}\x1b[0m`);
141
146
  }
142
147
  else {
143
148
  const raw = v.kind === "\\" ? v.body : highlightCodeLine(v.body);
package/dist/ui.js CHANGED
@@ -550,9 +550,10 @@ export class Spinner {
550
550
  }, 80);
551
551
  this.draw();
552
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(). */
553
+ /** Dots-mode label: renders `text` (ANSI pre-colored by the caller) + a
554
+ * fixed 3-cell animated dots field. Each tick rewrites ONLY the dots cells
555
+ * via a cursor jump, so the rest of the line never flickers. Swap in the
556
+ * final label with replaceWith(). */
556
557
  startDots(text) {
557
558
  if (!this.enabled)
558
559
  return;
@@ -562,7 +563,7 @@ export class Spinner {
562
563
  this.dotsFrame = 0;
563
564
  this.rows = 1;
564
565
  this.lastRendered = "";
565
- this.lastLen = text.length + 3;
566
+ this.lastLen = plainLen(text) + 3;
566
567
  this.writeDots(true);
567
568
  this.timer = setInterval(() => {
568
569
  this.dotsFrame = (this.dotsFrame + 1) % DOT_FRAMES.length;
@@ -570,18 +571,18 @@ export class Spinner {
570
571
  }, 300);
571
572
  }
572
573
  writeDots(initial) {
573
- const label = `\x1b[1;36m${this.dotsText}\x1b[0m`;
574
574
  const dots = `\x1b[1;36m${DOT_FRAMES[this.dotsFrame]}\x1b[0m`;
575
575
  if (initial) {
576
- process.stdout.write("\r" + label + dots + "\r");
576
+ process.stdout.write("\r" + this.dotsText + dots + "\r");
577
577
  }
578
578
  else {
579
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");
580
+ process.stdout.write(`\x1b[${plainLen(this.dotsText) + 1}G` + dots + "\r");
581
581
  }
582
582
  }
583
583
  /** Overwrite the dots line in place with `text` and advance to the next
584
- * line, without erasing (so there is no flash). */
584
+ * line, without erasing (so there is no flash). Multi-line text replaces
585
+ * the first line in place and prints the remaining lines below it. */
585
586
  replaceWith(text) {
586
587
  if (this.timer) {
587
588
  clearInterval(this.timer);
@@ -591,9 +592,14 @@ export class Spinner {
591
592
  process.stdout.write(`${text}\n`);
592
593
  return;
593
594
  }
594
- const plain = stripAnsi(text);
595
+ const parts = text.split("\n");
596
+ const first = parts[0];
597
+ const rest = parts.slice(1);
598
+ const plain = stripAnsi(first);
595
599
  const pad = Math.max(0, this.lastLen - plain.length);
596
- process.stdout.write("\r" + text + " ".repeat(pad) + "\r\n");
600
+ process.stdout.write("\r" + first + " ".repeat(pad) + "\r\n");
601
+ if (rest.length)
602
+ process.stdout.write(rest.join("\n") + "\n");
597
603
  this.rows = 0;
598
604
  this.lastLen = plain.length;
599
605
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxecli/oxe",
3
- "version": "1.0.78",
3
+ "version": "1.0.79",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },