agent.libx.js 0.93.27 → 0.93.29

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/cli/cli.ts CHANGED
@@ -314,14 +314,19 @@ function makeHost(format: 'text' | 'json' | 'stream-json' = 'text', opts?: { str
314
314
  const md = format === 'text' && useColor && opts?.stream ? new MarkdownStream({ bold, dim, cyan }, process.stdout.columns ?? 80) : null;
315
315
  if (md) process.on('SIGWINCH', () => md.resize(process.stdout.columns ?? 80)); // reflow streamed markdown on resize
316
316
  const flushText = () => { if (md && md.pending()) process.stdout.write(md.flush()); };
317
+ // `thinking_delta` streams to stderr WITHOUT a trailing newline (a continuous dimmed reasoning flow).
318
+ // Any other output that follows (the answer on stdout, a `· notice`, the next step header) must first
319
+ // close that open line — else it collides mid-word into the reasoning tail (`· step 2` → `step ya`).
320
+ let openReasonLine = false;
321
+ const closeReasonLine = () => { if (openReasonLine) { process.stderr.write('\n'); openReasonLine = false; } };
317
322
  return {
318
323
  flushText,
319
324
  notify(e) {
320
325
  spinner.stop(); // real output arriving → clear the spinner first
321
326
  if (e.kind === 'text_delta') {
322
327
  if (streamJson) process.stdout.write(JSON.stringify({ type: 'text', text: e.message }) + '\n');
323
- else if (md) process.stdout.write(md.feed(e.message)); // line-buffered markdown render
324
- else (cleanStdout ? process.stderr : process.stdout).write(e.message); // json keeps stdout clean → stderr
328
+ else if (md) { closeReasonLine(); process.stdout.write(md.feed(e.message)); } // line-buffered markdown render
329
+ else { if (!cleanStdout) closeReasonLine(); (cleanStdout ? process.stderr : process.stdout).write(e.message); } // json keeps stdout clean → stderr
325
330
  return;
326
331
  }
327
332
  // extended-thinking (reasoning-native models): a dimmed stderr flow in text mode; a typed event in
@@ -333,12 +338,17 @@ function makeHost(format: 'text' | 'json' | 'stream-json' = 'text', opts?: { str
333
338
  // stay in order — otherwise late-flushed markdown lands after the thinking it preceded.
334
339
  if (md && md.pending()) process.stdout.write(md.flush() + '\n');
335
340
  process.stderr.write(dim(e.message));
341
+ openReasonLine = true; // unterminated reasoning line — next output must close it
336
342
  }
337
343
  return;
338
344
  }
345
+ // Structural events (tool_use/tool_result/tool_result_image/turn_start) have dedicated renderers
346
+ // (displayHooks ⚙ chrome, the step header) — never dump their raw `kind` as a `· notice`, or the
347
+ // result preview gets sandwiched between junk `· tool_use`/`· tool_result` labels.
348
+ if (!('message' in e)) return;
349
+ closeReasonLine(); // close an open reasoning line so the notice starts fresh (not glued mid-word)
339
350
  if (md && md.pending()) process.stdout.write(md.flush() + '\n'); // finish the in-progress line before a notice
340
- const notice = 'message' in e ? e.message : e.kind; // not every HostEvent variant carries `message`
341
- err(dim(` · ${notice}\n`)); // tool-activity notices stay on stderr (human chrome) for every format
351
+ err(dim(` · ${e.message}\n`)); // tool-activity notices stay on stderr (human chrome) for every format
342
352
  },
343
353
  async confirm(prompt) {
344
354
  // arrow-select on a TTY; fall back to a typed y/N when piped (selectMenu → null)
package/dist/cli.js CHANGED
@@ -3468,9 +3468,11 @@ init_tools_structured();
3468
3468
  init_todo();
3469
3469
  init_tools_web();
3470
3470
 
3471
- // src/artifacts.ts
3471
+ // src/scratch.ts
3472
+ init_tools();
3473
+ init_tools_structured();
3472
3474
  init_logging();
3473
- var log4 = forComponent("artifacts");
3475
+ var log4 = forComponent("scratch");
3474
3476
 
3475
3477
  // src/lessons.ts
3476
3478
  init_logging();
@@ -5427,6 +5429,7 @@ function defaultOpenBrowser(url) {
5427
5429
  }
5428
5430
 
5429
5431
  // cli/core.ts
5432
+ import { randomUUID } from "crypto";
5430
5433
  import { resolve, basename, join as join3 } from "path";
5431
5434
  import { existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
5432
5435
  import { platform, arch, release, userInfo, homedir } from "os";
@@ -5571,7 +5574,9 @@ Reference files in them by their mount path (the left side).`;
5571
5574
  // host's MCP servers so the delegated cursor agent runs in the same environment. Gated to cursor:
5572
5575
  // openai/google adapters Object.assign providerOptions into the request body, so a blanket cwd
5573
5576
  // would corrupt those calls.
5574
- ...isCursor ? { providerOptions: { cwd, ...toCursorMcp(o.mcpServers) ?? {} } } : {},
5577
+ // Warm cursor session (default on; CURSOR_WARM=0 to disable): one long-lived agent reused across
5578
+ // turns, amortising the ~2s Agent.create + h2 handshake. Keyed per agentx launch.
5579
+ ...isCursor ? { providerOptions: { cwd, ...toCursorMcp(o.mcpServers) ?? {}, ...process.env.CURSOR_WARM === "0" ? {} : { cursorSession: randomUUID() } } } : {},
5575
5580
  ...(() => {
5576
5581
  const now5 = /* @__PURE__ */ new Date();
5577
5582
  const platformNames = { darwin: "macOS", linux: "Linux", win32: "Windows" };
@@ -7988,14 +7993,26 @@ function makeHost(format = "text", opts) {
7988
7993
  const flushText = () => {
7989
7994
  if (md && md.pending()) process.stdout.write(md.flush());
7990
7995
  };
7996
+ let openReasonLine = false;
7997
+ const closeReasonLine = () => {
7998
+ if (openReasonLine) {
7999
+ process.stderr.write("\n");
8000
+ openReasonLine = false;
8001
+ }
8002
+ };
7991
8003
  return {
7992
8004
  flushText,
7993
8005
  notify(e) {
7994
8006
  spinner.stop();
7995
8007
  if (e.kind === "text_delta") {
7996
8008
  if (streamJson) process.stdout.write(JSON.stringify({ type: "text", text: e.message }) + "\n");
7997
- else if (md) process.stdout.write(md.feed(e.message));
7998
- else (cleanStdout ? process.stderr : process.stdout).write(e.message);
8009
+ else if (md) {
8010
+ closeReasonLine();
8011
+ process.stdout.write(md.feed(e.message));
8012
+ } else {
8013
+ if (!cleanStdout) closeReasonLine();
8014
+ (cleanStdout ? process.stderr : process.stdout).write(e.message);
8015
+ }
7999
8016
  return;
8000
8017
  }
8001
8018
  if (e.kind === "thinking_delta") {
@@ -8003,12 +8020,14 @@ function makeHost(format = "text", opts) {
8003
8020
  else if (!cleanStdout) {
8004
8021
  if (md && md.pending()) process.stdout.write(md.flush() + "\n");
8005
8022
  process.stderr.write(dim(e.message));
8023
+ openReasonLine = true;
8006
8024
  }
8007
8025
  return;
8008
8026
  }
8027
+ if (!("message" in e)) return;
8028
+ closeReasonLine();
8009
8029
  if (md && md.pending()) process.stdout.write(md.flush() + "\n");
8010
- const notice = "message" in e ? e.message : e.kind;
8011
- err(dim(` \xB7 ${notice}
8030
+ err(dim(` \xB7 ${e.message}
8012
8031
  `));
8013
8032
  },
8014
8033
  async confirm(prompt) {