@oxecli/oxe 1.0.95 → 1.0.96

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,11 @@ 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. Each phase is
159
+ // interrupted (and the flag reset) by either real answer text or a tool
160
+ // call, so unlimited working blocks can appear but never two in a row
161
+ // without an answer or tool call in between. The total worked time also
162
+ // lands in the final footer.
162
163
  const showWorkSpinner = !this.workedCommitted;
163
164
  if (showWorkSpinner)
164
165
  dockTransientStart();
@@ -183,7 +184,10 @@ export class InferenceEngine {
183
184
  const t = tickDuration(elapsed);
184
185
  if (!showWorkSpinner)
185
186
  return;
186
- this.workedCommitted = true;
187
+ // Reset immediately so a later working phase (after an answer or a tool
188
+ // call) may commit a fresh block; the per-streamOnce guard above keeps
189
+ // the current phase from duplicating.
190
+ this.workedCommitted = false;
187
191
  story.push({ type: "worked", text: `Worked for ${t}` });
188
192
  dockReplaceTransient(mutedMarkdown(`Worked for ${t}`) + "\n");
189
193
  };
@@ -537,7 +541,13 @@ export class InferenceEngine {
537
541
  conversation.push(rp);
538
542
  inputItems.push(rp);
539
543
  retryPrompts.push(rp);
540
- pending = prevId === null ? conversation : [retryPrompt];
544
+ // Always retry with the full transcript in visible context (which
545
+ // includes the original user prompt), instead of relying solely on
546
+ // previous_response_id continuation. Server-side continuation of a
547
+ // cut-off response can lose the task context, leaving the model with
548
+ // "no context about what was being worked on."
549
+ prevId = null;
550
+ pending = conversation;
541
551
  continue;
542
552
  }
543
553
  dropRetryPrompts(conversation, inputItems, retryPrompts);
@@ -562,6 +572,9 @@ export class InferenceEngine {
562
572
  const toolSpinner = new Spinner();
563
573
  toolSpinner.startDots("\x1b[90m╰─\x1b[0m Working");
564
574
  const rawResult = await this.runTool(c.name, c.arguments);
575
+ // A tool call was made, which interrupts any current working phase,
576
+ // so the next agent iteration may commit a fresh "Worked for …" block.
577
+ this.workedCommitted = false;
565
578
  if (this.interrupted) {
566
579
  toolSpinner.stop();
567
580
  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.96",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },