@oxecli/oxe 1.0.95 → 1.0.97

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/api.js CHANGED
@@ -4,8 +4,7 @@ export async function validateOxeApiKey(apiKey) {
4
4
  if (!key.startsWith(OXE_KEY_PREFIX)) {
5
5
  return {
6
6
  valid: false,
7
- error: "Invalid API key format. Only authentic Oxe API keys (starting with 'oxe_live_') are permitted.\n" +
8
- "Generate your key at: http://localhost:5173/dashboard/api-keys",
7
+ error: "Invalid API key format. Generate your key at: http://localhost:5173/dashboard/api-keys",
9
8
  };
10
9
  }
11
10
  try {
package/dist/config.js CHANGED
@@ -98,7 +98,8 @@ export function detectedShell() {
98
98
  export function osPrefix() {
99
99
  return (`Running environment: ${runtimeOsSummary()}. ` +
100
100
  `Shell commands run via ${detectedShell()} ` +
101
- "with `shell=True`; use commands, quoting, and path separators " +
101
+ `with \`shell=True\`, from the working directory \`${process.cwd()}\`; ` +
102
+ "use commands, quoting, and path separators " +
102
103
  "appropriate to this OS.\n\n");
103
104
  }
104
105
  export const IGNORED_DIRS_BY_CATEGORY = [
package/dist/engine.js CHANGED
@@ -155,10 +155,12 @@ export class InferenceEngine {
155
155
  let sawReasoning = false;
156
156
  let status = null;
157
157
  let thinkingStart = null;
158
- // Only the first API pass in a query shows the "Working…" spinner and a
159
- // committed "Worked for …" block. Subsequent tool iterations run silently
160
- // (the tool labels/results already give feedback) so duplicate working
161
- // blocks never stack; the total worked time lands in the final footer.
158
+ // A "Worked for …" block is committed once per working phase. The flag is
159
+ // reset whenever a tool call runs (in the tool loop below), which is the
160
+ // only way a later phase can begin the loop only continues after a tool
161
+ // call. So unlimited working blocks can appear, but never two in a row
162
+ // without a tool call in between. An answer ends the query. The total
163
+ // worked time also lands in the final footer.
162
164
  const showWorkSpinner = !this.workedCommitted;
163
165
  if (showWorkSpinner)
164
166
  dockTransientStart();
@@ -537,7 +539,13 @@ export class InferenceEngine {
537
539
  conversation.push(rp);
538
540
  inputItems.push(rp);
539
541
  retryPrompts.push(rp);
540
- pending = prevId === null ? conversation : [retryPrompt];
542
+ // Always retry with the full transcript in visible context (which
543
+ // includes the original user prompt), instead of relying solely on
544
+ // previous_response_id continuation. Server-side continuation of a
545
+ // cut-off response can lose the task context, leaving the model with
546
+ // "no context about what was being worked on."
547
+ prevId = null;
548
+ pending = conversation;
541
549
  continue;
542
550
  }
543
551
  dropRetryPrompts(conversation, inputItems, retryPrompts);
@@ -545,6 +553,10 @@ export class InferenceEngine {
545
553
  dockAppendContent(summary() + "\n");
546
554
  return;
547
555
  }
556
+ // A successful turn (text or tool call) after a retry must not leave the
557
+ // cut-off retry prompts in the transcript — they'd pollute the context of
558
+ // later turns. Drop them now that the retry produced real output.
559
+ dropRetryPrompts(conversation, inputItems, retryPrompts);
548
560
  if (!calls.length) {
549
561
  story.push({ type: "footer", text: footerText() });
550
562
  attachFooter(conversation);
@@ -562,6 +574,9 @@ export class InferenceEngine {
562
574
  const toolSpinner = new Spinner();
563
575
  toolSpinner.startDots("\x1b[90m╰─\x1b[0m Working");
564
576
  const rawResult = await this.runTool(c.name, c.arguments);
577
+ // A tool call was made, which interrupts any current working phase,
578
+ // so the next agent iteration may commit a fresh "Worked for …" block.
579
+ this.workedCommitted = false;
565
580
  if (this.interrupted) {
566
581
  toolSpinner.stop();
567
582
  throw new Error("interrupt");
package/dist/ui.js CHANGED
@@ -1299,6 +1299,9 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = [], hin
1299
1299
  if (done)
1300
1300
  return;
1301
1301
  done = true;
1302
+ const sentValue = isErr
1303
+ ? null
1304
+ : value;
1302
1305
  process.stdout.write("\x1b[?2004l");
1303
1306
  process.stdin.setRawMode(false);
1304
1307
  if (pasteBurstTimer)
@@ -1308,10 +1311,30 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = [], hin
1308
1311
  dockSetInactive();
1309
1312
  }
1310
1313
  else {
1314
+ // Clear the sent prompt from the box immediately, so the field shows an
1315
+ // empty prompt as soon as the user sends it while the query streams
1316
+ // above the dock. The resolved value still carries the original sent
1317
+ // buffer/paste spans so the query and draft-restore keep working.
1318
+ const { frame, totalRows } = renderBufferWithCursor("", [], prefix, label, 0, hints);
1319
+ const newLines = frame.split("\n");
1311
1320
  if (lastCursorRow > 0)
1312
1321
  process.stdout.write(`\x1b[${lastCursorRow}A`);
1313
1322
  process.stdout.write("\r");
1314
- dockSetFrame((prevFrameLines ?? []).join("\n"), lastTotalRows);
1323
+ const oldLines = prevFrameLines ?? [];
1324
+ const maxLen = Math.max(oldLines.length, newLines.length);
1325
+ for (let i = 0; i < maxLen; i++) {
1326
+ process.stdout.write("\r\x1b[K" + (newLines[i] ?? ""));
1327
+ if (i < maxLen - 1)
1328
+ process.stdout.write("\n");
1329
+ }
1330
+ // Reposition at the box's top row so the dock can manage it. The erase
1331
+ // loop above ends with the cursor at row (maxLen - 1), so move up by
1332
+ // that many rows — NOT newLines.length - 1, which is too few whenever
1333
+ // the sent (old) box was taller than the emptied box (e.g. a wrapped or
1334
+ // multi-line prompt). Using the wrong count leaves the cursor below the
1335
+ // box top, desyncing the dock and corrupting later redraws.
1336
+ process.stdout.write(`\x1b[${maxLen - 1}A\r`);
1337
+ dockSetFrame(frame, totalRows);
1315
1338
  dockEnterDocked();
1316
1339
  }
1317
1340
  process.stdin.removeListener("keypress", onKeypress);
@@ -1320,7 +1343,7 @@ export function askBottomPrompt(label = "You", prefix = "❯", history = [], hin
1320
1343
  if (isErr)
1321
1344
  reject(value);
1322
1345
  else
1323
- resolve(value);
1346
+ resolve(sentValue);
1324
1347
  };
1325
1348
  const repaint = (isFirst = false) => {
1326
1349
  const { frame, cursorRow, cursorCol, totalRows } = renderBufferWithCursor(buffer, pasteSpans, prefix, label, cursor, hints);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxecli/oxe",
3
- "version": "1.0.95",
3
+ "version": "1.0.97",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },