@oxecli/oxe 1.0.72 → 1.0.74

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
@@ -29,7 +29,7 @@ export class CLI {
29
29
  const description = "A focused terminal workspace for building and shipping.";
30
30
  renderPanel("[bold white]Terminal Coding Agent[/bold white]\n" +
31
31
  `[dim]${description}[/dim]\n\n` +
32
- `[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");
33
33
  }
34
34
  saveSession(engine) {
35
35
  if (!this.inputItems.length)
package/dist/config.js CHANGED
@@ -83,11 +83,21 @@ export const default_reasoning_effort = "low";
83
83
  export function runtimeOsSummary() {
84
84
  return `${os.platform()} ${os.release()} (${os.arch()}, Node ${process.version})`;
85
85
  }
86
+ /**
87
+ * The shell that the bash tool actually launches: `spawn(cmd, { shell: true })`.
88
+ * On Windows Node uses %ComSpec% (cmd.exe by default); on POSIX it uses /bin/sh.
89
+ */
90
+ export function detectedShell() {
91
+ if (process.platform === "win32") {
92
+ const comspec = process.env.ComSpec || process.env.COMSPEC;
93
+ return comspec ? path.basename(comspec) : "cmd.exe";
94
+ }
95
+ const shell = process.env.SHELL;
96
+ return shell ? path.basename(shell) : "sh";
97
+ }
86
98
  export function osPrefix() {
87
- const isWin = process.platform === "win32";
88
- const shell = isWin ? "PowerShell / cmd.exe" : "POSIX sh";
89
99
  return (`Running environment: ${runtimeOsSummary()}. ` +
90
- `Shell commands run via ${shell} ` +
100
+ `Shell commands run via ${detectedShell()} ` +
91
101
  "with `shell=True`; use commands, quoting, and path separators " +
92
102
  "appropriate to this OS.\n\n");
93
103
  }
@@ -157,7 +167,7 @@ export async function loadOrPrompt() {
157
167
  renderPanel("[bold white]Oxe Desktop Authentication[/bold white]\n\n" +
158
168
  `[dim]Only valid Oxe API keys (starting with [bold cyan]${OXE_KEY_PREFIX}[/bold cyan])\n` +
159
169
  "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", "", false, "90", "left");
170
+ "Get your key at: [bold underline]http://localhost:5173/dashboard/api-keys[/bold underline][/dim]", "Oxe Cloud Access", "", true, "90", "left");
161
171
  process.stdout.write("\n");
162
172
  api_key = await promptApiKey("Enter Oxe API Key: ");
163
173
  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.72",
3
+ "version": "1.0.74",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },