@oxecli/oxe 1.0.71 → 1.0.73

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { createRequire } from "node:module";
3
3
  import { fileURLToPath } from "node:url";
4
- import { loadOrPrompt, default_reasoning_effort, default_model, max_action_chars, max_resume_history_items, runtimeOsSummary, } from "./config.js";
4
+ import { loadOrPrompt, default_reasoning_effort, max_action_chars, max_resume_history_items, runtimeOsSummary, } 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
7
  import { clearScreen, enableAnsi, askBottomPrompt, userDisplayText, aiMarkdown, mutedMarkdown, messageText, formatToolAction, truncateEllipsis, renderPanel, renderTableString, enableRawStdin, disableRawStdin, waitRawKey, } from "./ui.js";
@@ -24,32 +24,12 @@ export class CLI {
24
24
  this.renderHeader();
25
25
  this.config = null;
26
26
  }
27
- renderHeader(model = default_model) {
27
+ renderHeader() {
28
28
  const version = packageInfo.version ?? "unknown";
29
- const cellWidth = 22;
30
- const centeredCell = (value, render) => {
31
- const left = Math.max(0, Math.floor((cellWidth - value.length) / 2));
32
- const right = Math.max(0, cellWidth - value.length - left);
33
- return " ".repeat(left) + render + " ".repeat(right);
34
- };
35
- const labelCell = (label) => {
36
- return centeredCell(label, `[dim]${label}[/dim]`);
37
- };
38
- const valueCell = (value, color) => {
39
- return centeredCell(value, `[bold ${color}]${value}[/bold ${color}]`);
40
- };
41
- const description = "A focused terminal workspace for building and shipping software.";
29
+ const description = "A focused terminal workspace for building and shipping.";
42
30
  renderPanel("[bold white]Terminal Coding Agent[/bold white]\n" +
43
31
  `[dim]${description}[/dim]\n\n` +
44
- labelCell("") +
45
- labelCell("Model") +
46
- labelCell("Status") +
47
- "\n" +
48
- valueCell("", "cyan") +
49
- valueCell(model, "cyan") +
50
- valueCell("Ready", "green") +
51
- "\n\n" +
52
- `[dim]Environment: ${runtimeOsSummary()}[/dim]`, `\x1b[1;37mOxe\x1b[90m \x1b[1;36mv${version}\x1b[90m`, "Type /help for commands · Ctrl+C to interrupt", false, "90", "left");
32
+ `[dim]Environment: ${runtimeOsSummary()}[/dim]`, `\x1b[1;37mOxe\x1b[90m \x1b[1;36mv${version}\x1b[90m`, "Type /help for commands · Ctrl+C to interrupt", true, "90", "left");
53
33
  }
54
34
  saveSession(engine) {
55
35
  if (!this.inputItems.length)
@@ -370,7 +350,7 @@ export class CLI {
370
350
  this.sessionId = sid;
371
351
  engine.reasoningEffort = String(rec["reasoning_effort"] ?? default_reasoning_effort);
372
352
  clearScreen();
373
- this.renderHeader(engine.modelName);
353
+ this.renderHeader();
374
354
  process.stdout.write("\n");
375
355
  process.stdout.write(`\x1b[90mResumed:\x1b[0m \x1b[1m${truncateLabel(rec["label"])}\x1b[0m\n`);
376
356
  process.stdout.write(`\x1b[90m(${this.inputItems.length} items · ${estimateTokens(this.inputItems).toLocaleString()} tokens)\x1b[0m\n\n`);
@@ -409,7 +389,7 @@ export class CLI {
409
389
  this.story = [];
410
390
  this.sessionId = null;
411
391
  clearScreen();
412
- this.renderHeader(engine.modelName);
392
+ this.renderHeader();
413
393
  continue;
414
394
  }
415
395
  if (lower.startsWith("/resume")) {
package/dist/config.js CHANGED
@@ -156,8 +156,8 @@ export async function loadOrPrompt() {
156
156
  process.stdout.write("\n");
157
157
  renderPanel("[bold white]Oxe Desktop Authentication[/bold white]\n\n" +
158
158
  `[dim]Only valid Oxe API keys (starting with [bold cyan]${OXE_KEY_PREFIX}[/bold cyan])\n` +
159
- "generated on your Oxe dashboard are authorized to run this agent.\n\n" +
160
- "Get your key at: [bold underline]http://localhost:5173/dashboard/api-keys[/bold underline][/dim]", "Oxe Cloud Access", "", false, "90", "left");
159
+ "generated on your Oxe dashboard are authorized.\n\n" +
160
+ "Get your key at: [bold underline]http://localhost:5173/dashboard/api-keys[/bold underline][/dim]", "Oxe Cloud Access", "", true, "90", "left");
161
161
  process.stdout.write("\n");
162
162
  api_key = await promptApiKey("Enter Oxe API Key: ");
163
163
  if (!api_key) {
package/dist/tools.js CHANGED
@@ -4,7 +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
+ import { truncateStyled, plainLen, terminalWidth, highlightCodeLine } from "./ui.js";
8
8
  export { toolLoadSkill };
9
9
  // ---------------------------------------------------------------------------
10
10
  // Path sanitization helper
@@ -49,13 +49,26 @@ function displayDiff(pathName, oldContent, newContent) {
49
49
  const patch = structuredPatch(pathName, pathName, oldContent, newContent, "", "", { context: max_diff_context_lines });
50
50
  const contentLines = [];
51
51
  for (const hunk of patch.hunks) {
52
+ let oldNum = hunk.oldStart;
53
+ let newNum = hunk.newStart;
52
54
  for (const l of hunk.lines) {
53
- if (l.startsWith("+"))
54
- contentLines.push({ line: l, kind: "+" });
55
- else if (l.startsWith("-"))
56
- contentLines.push({ line: l, kind: "-" });
57
- else
58
- contentLines.push({ line: l, kind: " " });
55
+ if (l.startsWith("\\")) {
56
+ // "" meta line: no line numbers.
57
+ contentLines.push({ line: l, kind: "\\", oldNum: null, newNum: null });
58
+ }
59
+ else if (l.startsWith("+")) {
60
+ contentLines.push({ line: l, kind: "+", oldNum: null, newNum });
61
+ newNum++;
62
+ }
63
+ else if (l.startsWith("-")) {
64
+ contentLines.push({ line: l, kind: "-", oldNum, newNum: null });
65
+ oldNum++;
66
+ }
67
+ else {
68
+ contentLines.push({ line: l, kind: " ", oldNum, newNum });
69
+ oldNum++;
70
+ newNum++;
71
+ }
59
72
  }
60
73
  }
61
74
  const added = contentLines.filter((c) => c.kind === "+").length;
@@ -69,14 +82,17 @@ function displayDiff(pathName, oldContent, newContent) {
69
82
  if (!run.length)
70
83
  return;
71
84
  const kind = run[0].kind;
72
- const limit = kind === " " ? max_diff_context_lines : max_diff_lines;
85
+ const limit = kind === " " || kind === "\\" ? max_diff_context_lines : max_diff_lines;
73
86
  const hidden = run.length - limit;
74
- for (const r of run.slice(0, limit))
75
- shown.push({ kind, line: truncateDiffLine(r.line) });
87
+ for (const r of run.slice(0, limit)) {
88
+ shown.push({ kind, line: truncateDiffLine(r.line), oldNum: r.oldNum, newNum: r.newNum });
89
+ }
76
90
  if (hidden > 0) {
77
91
  shown.push({
78
92
  kind: "~",
79
93
  line: `… (${hidden} ${hidden === 1 ? "line" : "lines"} of diff hidden) …`,
94
+ oldNum: null,
95
+ newNum: null,
80
96
  });
81
97
  }
82
98
  run = [];
@@ -91,20 +107,28 @@ function displayDiff(pathName, oldContent, newContent) {
91
107
  flush();
92
108
  // Build the lines, stripping the leading + / - / space marker for display.
93
109
  // Summary lines ("~") are already plain text and are kept whole.
94
- const visible = shown.map(({ kind, line }) => {
110
+ const visible = shown.map(({ kind, line, oldNum, newNum }) => {
95
111
  if (kind === "~")
96
- return { kind, body: line };
97
- const k = line[0] === "+" ? "+" : line[0] === "-" ? "-" : " ";
98
- return { kind: k, body: line.slice(1) };
112
+ return { kind, body: line, oldNum, newNum };
113
+ const k = line[0] === "+" ? "+" : line[0] === "-" ? "-" : line[0] === "\\" ? "\\" : " ";
114
+ return { kind: k, body: line.slice(1), oldNum, newNum };
99
115
  });
100
- // A "… (N lines hidden) …" summary line is neutral context.
101
116
  const termW = terminalWidth();
117
+ let maxNum = 1;
118
+ for (const v of visible) {
119
+ if (v.oldNum)
120
+ maxNum = Math.max(maxNum, v.oldNum);
121
+ if (v.newNum)
122
+ maxNum = Math.max(maxNum, v.newNum);
123
+ }
124
+ const numW = Math.max(String(maxNum).length, 2);
102
125
  let contentW = 0;
103
126
  for (const v of visible) {
104
- contentW = Math.max(contentW, plainLen(v.body));
127
+ const len = v.kind === "~" ? plainLen(v.body) : numW + 1 + 2 + plainLen(v.body);
128
+ contentW = Math.max(contentW, len);
105
129
  }
106
130
  const headerPlain = `${pathName} +${added} -${removed}`;
107
- const boxW = Math.min(Math.max(contentW, plainLen(headerPlain)) + 6, Math.max(termW - 2, 20));
131
+ const boxW = Math.min(Math.max(contentW + 6, plainLen(headerPlain) + 6), Math.max(termW - 2, 20));
108
132
  const innerW = Math.max(boxW - 4, 1);
109
133
  const maxPath = Math.max(10, boxW - 2 - plainLen(` +${added} -${removed}`) - 3);
110
134
  let pathDisp = pathName;
@@ -114,26 +138,32 @@ function displayDiff(pathName, oldContent, newContent) {
114
138
  const headerStr = `─ ${header} `;
115
139
  const top = `╭${headerStr}${"─".repeat(Math.max(0, boxW - 2 - plainLen(headerStr)))}╮`;
116
140
  pendingDiffOutput.push(`\x1b[90m${top}\x1b[0m`);
141
+ const bodyMax = Math.max(innerW - numW - 3, 1);
142
+ const gap = " ".repeat(numW);
117
143
  for (const v of visible) {
118
- let line;
119
144
  if (v.kind === "~") {
120
145
  const body = truncateStyled(v.body, innerW - 2);
121
- line = `\x1b[90m ${body}\x1b[0m`;
122
- }
123
- else if (v.kind === "+") {
124
- const body = truncateStyled(v.body, innerW - 2);
125
- line = `\x1b[32m+ ${body}\x1b[0m`;
146
+ const text = `\x1b[90m${gap} ${body}\x1b[0m`;
147
+ const fill = Math.max(0, innerW - plainLen(text));
148
+ pendingDiffOutput.push(`\x1b[90m│\x1b[0m ${text}${" ".repeat(fill)} \x1b[90m│\x1b[0m`);
149
+ continue;
126
150
  }
127
- else if (v.kind === "-") {
128
- const body = truncateStyled(v.body, innerW - 2);
129
- line = `\x1b[31m- ${body}\x1b[0m`;
151
+ const num = v.kind === "+" ? v.newNum : v.oldNum;
152
+ const numStr = num ? String(num).padStart(numW, " ") : gap;
153
+ if (v.kind === "+" || v.kind === "-") {
154
+ const color = v.kind === "+" ? "\x1b[32m" : "\x1b[31m";
155
+ const body = truncateStyled(v.body, bodyMax);
156
+ const text = `${numStr} ${v.kind === "+" ? "+ " : "- "}${body}`;
157
+ const fill = Math.max(0, innerW - plainLen(text));
158
+ // Whole line is painted green/red, filling to the right edge.
159
+ pendingDiffOutput.push(`\x1b[90m│\x1b[0m ${color}${text}${" ".repeat(fill)}\x1b[0m \x1b[90m│\x1b[0m`);
130
160
  }
131
161
  else {
132
- const body = truncateStyled(v.body, innerW - 2);
133
- line = `\x1b[90m ${body}\x1b[0m`;
162
+ const body = truncateStyled(v.kind === "\\" ? v.body : highlightCodeLine(v.body), bodyMax);
163
+ const text = `\x1b[90m${numStr} ${body}\x1b[0m`;
164
+ const fill = Math.max(0, innerW - plainLen(text));
165
+ pendingDiffOutput.push(`\x1b[90m│\x1b[0m ${text}${" ".repeat(fill)} \x1b[90m│\x1b[0m`);
134
166
  }
135
- const fill = Math.max(0, innerW - plainLen(line));
136
- pendingDiffOutput.push(`\x1b[90m│\x1b[0m ${line}${" ".repeat(fill)} \x1b[90m│\x1b[0m`);
137
167
  }
138
168
  pendingDiffOutput.push(`\x1b[90m╰${"─".repeat(boxW - 2)}╯\x1b[0m`);
139
169
  }
package/dist/ui.js CHANGED
@@ -153,7 +153,7 @@ const KEYWORDS = new Set([
153
153
  "lambda", "with", "as", "yield", "pass", "None", "True", "False", "null",
154
154
  "undefined", "true", "false", "fn", "struct", "pub", "impl", "mut", "use",
155
155
  ]);
156
- function highlightCodeLine(line, _lang = "") {
156
+ export function highlightCodeLine(line, _lang = "") {
157
157
  if (!line)
158
158
  return "";
159
159
  if (/^\s*(\/\/|#|\/\*)/.test(line)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxecli/oxe",
3
- "version": "1.0.71",
3
+ "version": "1.0.73",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },