mini-coder 0.0.22 → 0.1.0

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/mc.js CHANGED
@@ -3,10 +3,10 @@
3
3
 
4
4
  // src/index.ts
5
5
  import { writeSync } from "fs";
6
- import * as c24 from "yoctocolors";
6
+ import * as c23 from "yoctocolors";
7
7
 
8
8
  // src/agent/agent.ts
9
- import * as c13 from "yoctocolors";
9
+ import * as c12 from "yoctocolors";
10
10
 
11
11
  // src/cli/load-markdown-configs.ts
12
12
  import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
@@ -14,13 +14,13 @@ import { homedir as homedir4 } from "os";
14
14
  import { basename, join as join5 } from "path";
15
15
 
16
16
  // src/cli/config-conflicts.ts
17
- import * as c9 from "yoctocolors";
17
+ import * as c8 from "yoctocolors";
18
18
 
19
19
  // src/cli/output.ts
20
20
  import { existsSync as existsSync3 } from "fs";
21
21
  import { homedir as homedir3 } from "os";
22
22
  import { join as join4 } from "path";
23
- import * as c8 from "yoctocolors";
23
+ import * as c7 from "yoctocolors";
24
24
 
25
25
  // src/cli/custom-commands.ts
26
26
  import { existsSync, readFileSync } from "fs";
@@ -290,159 +290,6 @@ function parseAppError(err) {
290
290
  return { headline: firstLine };
291
291
  }
292
292
 
293
- // src/cli/live-output.ts
294
- import * as c from "yoctocolors";
295
-
296
- // src/cli/terminal-io.ts
297
- class TerminalIO {
298
- rawModeEnabled = false;
299
- interruptHandler = null;
300
- setInterruptHandler(handler) {
301
- this.interruptHandler = handler;
302
- }
303
- beforeWriteCallback = null;
304
- setBeforeWriteCallback(cb) {
305
- this.beforeWriteCallback = cb;
306
- }
307
- skipCallback = false;
308
- stdoutWrite(text) {
309
- if (text && this.beforeWriteCallback && !this.skipCallback) {
310
- this.skipCallback = true;
311
- this.beforeWriteCallback();
312
- this.skipCallback = false;
313
- }
314
- this.doStdoutWrite(text);
315
- }
316
- doStdoutWrite(text) {
317
- process.stdout.write(text);
318
- }
319
- stderrWrite(text) {
320
- if (text && this.beforeWriteCallback && !this.skipCallback) {
321
- this.skipCallback = true;
322
- this.beforeWriteCallback();
323
- this.skipCallback = false;
324
- }
325
- this.doStderrWrite(text);
326
- }
327
- doStderrWrite(text) {
328
- process.stderr.write(text);
329
- }
330
- get isTTY() {
331
- return process.stdin.isTTY;
332
- }
333
- get isStdoutTTY() {
334
- return process.stdout.isTTY;
335
- }
336
- get isStderrTTY() {
337
- return process.stderr.isTTY;
338
- }
339
- get stdoutColumns() {
340
- return process.stdout.columns ?? 0;
341
- }
342
- setRawMode(enable) {
343
- if (this.isTTY) {
344
- process.stdin.setRawMode(enable);
345
- this.rawModeEnabled = enable;
346
- }
347
- }
348
- restoreTerminal() {
349
- try {
350
- if (this.isStderrTTY) {
351
- this.stderrWrite("\x1B[?25h");
352
- this.stderrWrite("\r\x1B[2K");
353
- }
354
- } catch {}
355
- try {
356
- if (this.rawModeEnabled) {
357
- this.setRawMode(false);
358
- }
359
- } catch {}
360
- }
361
- registerCleanup() {
362
- const cleanup = () => this.restoreTerminal();
363
- process.on("exit", cleanup);
364
- process.on("SIGTERM", () => {
365
- cleanup();
366
- process.exit(143);
367
- });
368
- process.on("SIGINT", () => {
369
- if (this.interruptHandler) {
370
- this.interruptHandler();
371
- } else {
372
- cleanup();
373
- process.exit(130);
374
- }
375
- });
376
- process.on("uncaughtException", (err) => {
377
- cleanup();
378
- throw err;
379
- });
380
- process.on("unhandledRejection", (reason) => {
381
- cleanup();
382
- throw reason instanceof Error ? reason : new Error(String(reason));
383
- });
384
- }
385
- onStdinData(handler) {
386
- process.stdin.on("data", handler);
387
- return () => process.stdin.off("data", handler);
388
- }
389
- }
390
- var terminal = new TerminalIO;
391
-
392
- // src/cli/live-output.ts
393
- var LIVE_OUTPUT_PREFIX = ` ${c.dim("\u2502")} `;
394
- function write(text) {
395
- terminal.stdoutWrite(text);
396
- }
397
- function writeln(text = "") {
398
- terminal.stdoutWrite(`${text}
399
- `);
400
- }
401
-
402
- class LiveOutputBlock {
403
- pending = "";
404
- lineOpen = false;
405
- append(chunk) {
406
- if (!chunk)
407
- return;
408
- this.pending += chunk.replace(/\r\n/g, `
409
- `).replace(/\r/g, `
410
- `);
411
- this.flushCompleteLines();
412
- }
413
- finish() {
414
- if (this.pending.length > 0) {
415
- this.openLine();
416
- write(this.pending);
417
- this.pending = "";
418
- }
419
- if (this.lineOpen) {
420
- writeln();
421
- this.lineOpen = false;
422
- }
423
- }
424
- flushCompleteLines() {
425
- let boundary = this.pending.indexOf(`
426
- `);
427
- while (boundary !== -1) {
428
- const line = this.pending.slice(0, boundary);
429
- this.openLine();
430
- write(line);
431
- writeln();
432
- this.lineOpen = false;
433
- this.pending = this.pending.slice(boundary + 1);
434
- boundary = this.pending.indexOf(`
435
- `);
436
- }
437
- }
438
- openLine() {
439
- if (this.lineOpen)
440
- return;
441
- write(LIVE_OUTPUT_PREFIX);
442
- this.lineOpen = true;
443
- }
444
- }
445
-
446
293
  // src/cli/skills.ts
447
294
  import {
448
295
  closeSync,
@@ -567,7 +414,7 @@ function warnInvalidSkill(filePath, reason) {
567
414
  if (warnedInvalidSkills.has(key))
568
415
  return;
569
416
  warnedInvalidSkills.add(key);
570
- writeln2(`${G.warn} skipping invalid skill ${filePath}: ${reason}`);
417
+ writeln(`${G.warn} skipping invalid skill ${filePath}: ${reason}`);
571
418
  }
572
419
  function validateSkill(candidate) {
573
420
  const meta = getCandidateFrontmatter(candidate);
@@ -639,7 +486,105 @@ function loadSkillContent(name, cwd, homeDir) {
639
486
  }
640
487
 
641
488
  // src/cli/spinner.ts
642
- import * as c2 from "yoctocolors";
489
+ import * as c from "yoctocolors";
490
+
491
+ // src/cli/terminal-io.ts
492
+ class TerminalIO {
493
+ rawModeEnabled = false;
494
+ interruptHandler = null;
495
+ setInterruptHandler(handler) {
496
+ this.interruptHandler = handler;
497
+ }
498
+ beforeWriteCallback = null;
499
+ setBeforeWriteCallback(cb) {
500
+ this.beforeWriteCallback = cb;
501
+ }
502
+ skipCallback = false;
503
+ stdoutWrite(text) {
504
+ if (text && this.beforeWriteCallback && !this.skipCallback) {
505
+ this.skipCallback = true;
506
+ this.beforeWriteCallback();
507
+ this.skipCallback = false;
508
+ }
509
+ this.doStdoutWrite(text);
510
+ }
511
+ doStdoutWrite(text) {
512
+ process.stdout.write(text);
513
+ }
514
+ stderrWrite(text) {
515
+ if (text && this.beforeWriteCallback && !this.skipCallback) {
516
+ this.skipCallback = true;
517
+ this.beforeWriteCallback();
518
+ this.skipCallback = false;
519
+ }
520
+ this.doStderrWrite(text);
521
+ }
522
+ doStderrWrite(text) {
523
+ process.stderr.write(text);
524
+ }
525
+ get isTTY() {
526
+ return process.stdin.isTTY;
527
+ }
528
+ get isStdoutTTY() {
529
+ return process.stdout.isTTY;
530
+ }
531
+ get isStderrTTY() {
532
+ return process.stderr.isTTY;
533
+ }
534
+ get stdoutColumns() {
535
+ return process.stdout.columns ?? 0;
536
+ }
537
+ setRawMode(enable) {
538
+ if (this.isTTY) {
539
+ process.stdin.setRawMode(enable);
540
+ this.rawModeEnabled = enable;
541
+ }
542
+ }
543
+ restoreTerminal() {
544
+ try {
545
+ if (this.isStderrTTY) {
546
+ this.stderrWrite("\x1B[?25h");
547
+ this.stderrWrite("\r\x1B[2K");
548
+ }
549
+ } catch {}
550
+ try {
551
+ if (this.rawModeEnabled) {
552
+ this.setRawMode(false);
553
+ }
554
+ } catch {}
555
+ }
556
+ registerCleanup() {
557
+ const cleanup = () => this.restoreTerminal();
558
+ process.on("exit", cleanup);
559
+ process.on("SIGTERM", () => {
560
+ cleanup();
561
+ process.exit(143);
562
+ });
563
+ process.on("SIGINT", () => {
564
+ if (this.interruptHandler) {
565
+ this.interruptHandler();
566
+ } else {
567
+ cleanup();
568
+ process.exit(130);
569
+ }
570
+ });
571
+ process.on("uncaughtException", (err) => {
572
+ cleanup();
573
+ throw err;
574
+ });
575
+ process.on("unhandledRejection", (reason) => {
576
+ cleanup();
577
+ throw reason instanceof Error ? reason : new Error(String(reason));
578
+ });
579
+ }
580
+ onStdinData(handler) {
581
+ process.stdin.on("data", handler);
582
+ return () => process.stdin.off("data", handler);
583
+ }
584
+ }
585
+ var terminal = new TerminalIO;
586
+
587
+ // src/cli/spinner.ts
643
588
  var SPINNER_FRAMES = ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"];
644
589
 
645
590
  class Spinner {
@@ -675,15 +620,15 @@ class Spinner {
675
620
  }
676
621
  _tick() {
677
622
  const f = SPINNER_FRAMES[this.frame++ % SPINNER_FRAMES.length] ?? "\u28FE";
678
- const label = this.label ? c2.dim(` ${this.label}`) : "";
679
- terminal.stderrWrite(`\r${c2.dim(f)}${label}`);
623
+ const label = this.label ? c.dim(` ${this.label}`) : "";
624
+ terminal.stderrWrite(`\r${c.dim(f)}${label}`);
680
625
  }
681
626
  }
682
627
 
683
628
  // src/cli/status-bar.ts
684
- import * as c3 from "yoctocolors";
629
+ import * as c2 from "yoctocolors";
685
630
  var ANSI_ESCAPE = "\x1B";
686
- var STATUS_SEP = c3.dim(" \xB7 ");
631
+ var STATUS_SEP = c2.dim(" \xB7 ");
687
632
  function stripAnsi(s) {
688
633
  if (!s.includes(ANSI_ESCAPE))
689
634
  return s;
@@ -705,12 +650,12 @@ function buildContextSegment(opts) {
705
650
  if (opts.contextTokens <= 0)
706
651
  return null;
707
652
  if (opts.contextWindow === null) {
708
- return c3.dim(`ctx ${fmtTokens(opts.contextTokens)}`);
653
+ return c2.dim(`ctx ${fmtTokens(opts.contextTokens)}`);
709
654
  }
710
655
  const pct = Math.round(opts.contextTokens / opts.contextWindow * 100);
711
656
  const pctStr = `${pct}%`;
712
- const pctColored = pct >= 90 ? c3.red(pctStr) : pct >= 75 ? c3.yellow(pctStr) : c3.dim(pctStr);
713
- return c3.dim(`ctx ${fmtTokens(opts.contextTokens)}/${fmtTokens(opts.contextWindow)} `) + pctColored;
657
+ const pctColored = pct >= 90 ? c2.red(pctStr) : pct >= 75 ? c2.yellow(pctStr) : c2.dim(pctStr);
658
+ return c2.dim(`ctx ${fmtTokens(opts.contextTokens)}/${fmtTokens(opts.contextWindow)} `) + pctColored;
714
659
  }
715
660
  function renderStatusLine(segments) {
716
661
  return segments.join(STATUS_SEP);
@@ -747,26 +692,26 @@ function fitStatusSegments(required, optional, cols) {
747
692
  return truncatePlainText(fixedPrefix, cols);
748
693
  const maxTailLen = Math.max(8, cols - fixedPrefix.length - sepLen);
749
694
  const truncatedTail = truncatePlainText(plainRequired[1] ?? "", maxTailLen);
750
- return `${required[0]}${STATUS_SEP}${c3.dim(truncatedTail)}`;
695
+ return `${required[0]}${STATUS_SEP}${c2.dim(truncatedTail)}`;
751
696
  }
752
697
  function renderStatusBar(opts) {
753
698
  const cols = Math.max(20, terminal.stdoutColumns || 80);
754
699
  const required = [
755
- c3.cyan(opts.model),
756
- c3.dim(`#${opts.sessionId.slice(0, 8)}`)
700
+ c2.cyan(opts.model),
701
+ c2.dim(`#${opts.sessionId.slice(0, 8)}`)
757
702
  ];
758
703
  const optional = [];
759
704
  if (opts.provider && opts.provider !== "zen") {
760
- optional.push(c3.dim(opts.provider));
705
+ optional.push(c2.dim(opts.provider));
761
706
  }
762
707
  if (opts.activeAgent)
763
- optional.push(c3.green(`@${opts.activeAgent}`));
708
+ optional.push(c2.green(`@${opts.activeAgent}`));
764
709
  if (opts.thinkingEffort)
765
- optional.push(c3.dim(`\u2726 ${opts.thinkingEffort}`));
710
+ optional.push(c2.dim(`\u2726 ${opts.thinkingEffort}`));
766
711
  if (opts.gitBranch)
767
- optional.push(c3.dim(`\u2387 ${opts.gitBranch}`));
712
+ optional.push(c2.dim(`\u2387 ${opts.gitBranch}`));
768
713
  if (opts.inputTokens > 0 || opts.outputTokens > 0) {
769
- optional.push(c3.dim(`tok ${fmtTokens(opts.inputTokens)}/${fmtTokens(opts.outputTokens)}`));
714
+ optional.push(c2.dim(`tok ${fmtTokens(opts.inputTokens)}/${fmtTokens(opts.outputTokens)}`));
770
715
  }
771
716
  const contextSegment = buildContextSegment({
772
717
  contextTokens: opts.contextTokens,
@@ -774,14 +719,14 @@ function renderStatusBar(opts) {
774
719
  });
775
720
  if (contextSegment)
776
721
  optional.push(contextSegment);
777
- optional.push(c3.dim(opts.cwd));
722
+ optional.push(c2.dim(opts.cwd));
778
723
  const out = fitStatusSegments(required, optional, cols);
779
724
  terminal.stdoutWrite(`${out}
780
725
  `);
781
726
  }
782
727
 
783
728
  // src/cli/stream-render.ts
784
- import * as c7 from "yoctocolors";
729
+ import * as c6 from "yoctocolors";
785
730
 
786
731
  // src/llm-api/model-routing.ts
787
732
  function parseModelString(modelString) {
@@ -866,7 +811,7 @@ function isToolCallPart(part) {
866
811
  function hasObjectToolCallInput(part) {
867
812
  return isToolCallPart(part) && "input" in part && isRecord(part.input) && !Array.isArray(part.input);
868
813
  }
869
- var TOOL_RUNTIME_INPUT_KEYS = new Set(["cwd", "onOutput"]);
814
+ var TOOL_RUNTIME_INPUT_KEYS = new Set(["cwd"]);
870
815
  function stripToolRuntimeInputFields(messages) {
871
816
  let mutated = false;
872
817
  const result = messages.map((message) => {
@@ -1181,9 +1126,9 @@ function extractAssistantText(newMessages) {
1181
1126
  }
1182
1127
 
1183
1128
  // src/cli/live-reasoning.ts
1184
- import * as c4 from "yoctocolors";
1129
+ import * as c3 from "yoctocolors";
1185
1130
  function styleReasoningText(text) {
1186
- return c4.italic(c4.dim(text));
1131
+ return c3.italic(c3.dim(text));
1187
1132
  }
1188
1133
 
1189
1134
  class LiveReasoningBlock {
@@ -1209,27 +1154,27 @@ class LiveReasoningBlock {
1209
1154
  if (!this.blockOpen)
1210
1155
  return;
1211
1156
  if (this.lineOpen)
1212
- writeln2();
1157
+ writeln();
1213
1158
  this.blockOpen = false;
1214
1159
  this.lineOpen = false;
1215
1160
  }
1216
1161
  openBlock() {
1217
1162
  if (this.blockOpen)
1218
1163
  return;
1219
- writeln2(`${G.info} ${c4.dim("reasoning")}`);
1164
+ writeln(`${G.info} ${c3.dim("reasoning")}`);
1220
1165
  this.blockOpen = true;
1221
1166
  }
1222
1167
  writeText(text) {
1223
1168
  if (!this.lineOpen) {
1224
- write2(" ");
1169
+ write(" ");
1225
1170
  this.lineOpen = true;
1226
1171
  }
1227
- write2(styleReasoningText(text));
1172
+ write(styleReasoningText(text));
1228
1173
  }
1229
1174
  endLine() {
1230
1175
  if (!this.lineOpen)
1231
- write2(" ");
1232
- writeln2();
1176
+ write(" ");
1177
+ writeln();
1233
1178
  this.lineOpen = false;
1234
1179
  }
1235
1180
  }
@@ -1288,14 +1233,17 @@ class StreamRenderContent {
1288
1233
  return this.inText;
1289
1234
  }
1290
1235
  appendTextDelta(delta, renderedVisibleOutput) {
1291
- const text = delta ?? "";
1236
+ let text = delta ?? "";
1292
1237
  if (!text)
1293
1238
  return;
1294
1239
  if (!this.inText) {
1240
+ text = text.trimStart();
1241
+ if (!text)
1242
+ return;
1295
1243
  this.spinner.stop();
1296
1244
  if (renderedVisibleOutput)
1297
- writeln2();
1298
- write2(`${G.reply} `);
1245
+ writeln();
1246
+ write(`${G.reply} `);
1299
1247
  this.inText = true;
1300
1248
  if (terminal.isStdoutTTY)
1301
1249
  this.highlighter = createHighlighter();
@@ -1310,10 +1258,10 @@ class StreamRenderContent {
1310
1258
  if (isFirstLine && colored.startsWith("\x1B[2K\r")) {
1311
1259
  colored = `\x1B[2K\r${G.reply} ${colored.slice(5)}`;
1312
1260
  }
1313
- write2(colored);
1261
+ write(colored);
1314
1262
  }
1315
1263
  } else {
1316
- write2(text);
1264
+ write(text);
1317
1265
  }
1318
1266
  }
1319
1267
  appendReasoningDelta(delta) {
@@ -1340,43 +1288,43 @@ ${text}`;
1340
1288
  if (isFirstLine && finalColored.startsWith("\x1B[2K\r")) {
1341
1289
  finalColored = `\x1B[2K\r${G.reply} ${finalColored.slice(5)}`;
1342
1290
  }
1343
- write2(finalColored);
1291
+ write(finalColored);
1344
1292
  }
1345
1293
  }
1346
- writeln2();
1294
+ writeln();
1347
1295
  this.inText = false;
1348
1296
  }
1349
1297
  }
1350
1298
 
1351
1299
  // src/cli/tool-render.ts
1352
- import * as c6 from "yoctocolors";
1300
+ import * as c5 from "yoctocolors";
1353
1301
 
1354
1302
  // src/cli/tool-result-renderers.ts
1355
- import * as c5 from "yoctocolors";
1303
+ import * as c4 from "yoctocolors";
1356
1304
  function writePreviewLines(opts) {
1357
1305
  if (!opts.value.trim())
1358
1306
  return;
1359
1307
  const lines = opts.value.split(`
1360
1308
  `);
1361
- writeln2(` ${c5.dim(opts.label)} ${c5.dim(`(${lines.length} lines)`)}`);
1309
+ writeln(` ${c4.dim(opts.label)} ${c4.dim(`(${lines.length} lines)`)}`);
1362
1310
  if (!Number.isFinite(opts.maxLines) || lines.length <= opts.maxLines) {
1363
1311
  for (const line of lines) {
1364
- writeln2(` ${opts.lineColor("\u2502")} ${line}`);
1312
+ writeln(` ${opts.lineColor("\u2502")} ${line}`);
1365
1313
  }
1366
1314
  return;
1367
1315
  }
1368
1316
  const headCount = Math.max(1, Math.ceil(opts.maxLines / 2));
1369
1317
  const tailCount = Math.max(0, Math.floor(opts.maxLines / 2));
1370
1318
  for (const line of lines.slice(0, headCount)) {
1371
- writeln2(` ${opts.lineColor("\u2502")} ${line}`);
1319
+ writeln(` ${opts.lineColor("\u2502")} ${line}`);
1372
1320
  }
1373
1321
  const hiddenLines = Math.max(0, lines.length - (headCount + tailCount));
1374
1322
  if (hiddenLines > 0) {
1375
- writeln2(` ${opts.lineColor("\u2502")} ${c5.dim(`\u2026 +${hiddenLines} lines`)}`);
1323
+ writeln(` ${opts.lineColor("\u2502")} ${c4.dim(`\u2026 +${hiddenLines} lines`)}`);
1376
1324
  }
1377
1325
  if (tailCount > 0) {
1378
1326
  for (const line of lines.slice(-tailCount)) {
1379
- writeln2(` ${opts.lineColor("\u2502")} ${line}`);
1327
+ writeln(` ${opts.lineColor("\u2502")} ${line}`);
1380
1328
  }
1381
1329
  }
1382
1330
  }
@@ -1401,15 +1349,6 @@ function getSingleShellLine(value) {
1401
1349
  }
1402
1350
  function buildShellSummaryParts(opts) {
1403
1351
  const parts = [`exit ${opts.exitCode}`];
1404
- if (opts.streamedOutput) {
1405
- if (opts.stdoutLines === 0 && opts.stderrLines === 0) {
1406
- parts.push("no output");
1407
- }
1408
- if (opts.stderrLines > 0) {
1409
- parts.push(`stderr ${opts.stderrLines}L`);
1410
- }
1411
- return parts;
1412
- }
1413
1352
  if (opts.stderrLines === 0 && opts.stdoutSingleLine !== null && opts.stdoutSingleLine.length > 0) {
1414
1353
  parts.push(`out: ${truncateOneLine(opts.stdoutSingleLine, 100, opts.verboseOutput)}`);
1415
1354
  return parts;
@@ -1428,6 +1367,8 @@ function buildShellSummaryParts(opts) {
1428
1367
  function shouldPreviewShellStdout(opts) {
1429
1368
  if (opts.stdoutLines === 0)
1430
1369
  return false;
1370
+ if (opts.stdoutSingleLine !== null && opts.stderrLines === 0)
1371
+ return false;
1431
1372
  if (!opts.success || opts.stderrLines > 0)
1432
1373
  return true;
1433
1374
  return opts.stdoutSingleLine === null;
@@ -1437,28 +1378,23 @@ function renderShellResult(result, opts) {
1437
1378
  if (!r || typeof r.stdout !== "string" || typeof r.stderr !== "string") {
1438
1379
  return false;
1439
1380
  }
1440
- const streamedOutput = r.streamedOutput === true;
1441
1381
  const verboseOutput = opts?.verboseOutput === true;
1442
1382
  const stdoutLines = countShellLines(r.stdout);
1443
1383
  const stderrLines = countShellLines(r.stderr);
1444
1384
  const stdoutSingleLine = getSingleShellLine(r.stdout);
1445
- const badge = r.timedOut ? c5.yellow("timeout") : r.success ? c5.green("done") : c5.red("error");
1385
+ const badge = r.timedOut ? c4.yellow("timeout") : r.success ? c4.green("done") : c4.red("error");
1446
1386
  const parts = buildShellSummaryParts({
1447
1387
  exitCode: r.exitCode,
1448
1388
  stdoutLines,
1449
1389
  stderrLines,
1450
1390
  stdoutSingleLine,
1451
- streamedOutput,
1452
1391
  verboseOutput
1453
1392
  });
1454
- writeln2(` ${badge} ${c5.dim(parts.join(" \xB7 "))}`);
1455
- if (streamedOutput) {
1456
- return true;
1457
- }
1393
+ writeln(` ${badge} ${c4.dim(parts.join(" \xB7 "))}`);
1458
1394
  writePreviewLines({
1459
1395
  label: "stderr",
1460
1396
  value: r.stderr,
1461
- lineColor: c5.red,
1397
+ lineColor: c4.red,
1462
1398
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 10
1463
1399
  });
1464
1400
  if (shouldPreviewShellStdout({
@@ -1470,7 +1406,7 @@ function renderShellResult(result, opts) {
1470
1406
  writePreviewLines({
1471
1407
  label: "stdout",
1472
1408
  value: r.stdout,
1473
- lineColor: c5.dim,
1409
+ lineColor: c4.dim,
1474
1410
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 20
1475
1411
  });
1476
1412
  }
@@ -1480,8 +1416,8 @@ function renderSubagentResult(result, _opts) {
1480
1416
  const r = result;
1481
1417
  if (!r || typeof r !== "object")
1482
1418
  return false;
1483
- const label = r.agentName ? ` ${c5.dim(c5.cyan(`[@${r.agentName}]`))}` : "";
1484
- writeln2(` ${G.agent}${label} ${c5.dim(`subagent done (${r.inputTokens ?? 0}in / ${r.outputTokens ?? 0}out tokens)`)}`);
1419
+ const label = r.agentName ? ` ${c4.dim(c4.cyan(`[@${r.agentName}]`))}` : "";
1420
+ writeln(` ${G.agent}${label} ${c4.dim(`subagent done (${r.inputTokens ?? 0}in / ${r.outputTokens ?? 0}out tokens)`)}`);
1485
1421
  return true;
1486
1422
  }
1487
1423
  function buildSkillDescriptionPart(description, verboseOutput = false) {
@@ -1489,21 +1425,21 @@ function buildSkillDescriptionPart(description, verboseOutput = false) {
1489
1425
  if (!trimmed)
1490
1426
  return "";
1491
1427
  if (verboseOutput)
1492
- return ` ${c5.dim("\xB7")} ${c5.dim(trimmed)}`;
1493
- return ` ${c5.dim("\xB7")} ${c5.dim(trimmed.length > 60 ? `${trimmed.slice(0, 57)}\u2026` : trimmed)}`;
1428
+ return ` ${c4.dim("\xB7")} ${c4.dim(trimmed)}`;
1429
+ return ` ${c4.dim("\xB7")} ${c4.dim(trimmed.length > 60 ? `${trimmed.slice(0, 57)}\u2026` : trimmed)}`;
1494
1430
  }
1495
1431
  function renderSkillSummaryLine(skill, opts) {
1496
1432
  const name = skill.name ?? "(unknown)";
1497
1433
  const source = skill.source ?? "unknown";
1498
- const labelPrefix = opts?.label ? `${c5.dim(opts.label)} ` : "";
1499
- writeln2(` ${G.info} ${labelPrefix}${name} ${c5.dim("\xB7")} ${c5.dim(source)}${buildSkillDescriptionPart(skill.description, opts?.verboseOutput === true)}`);
1434
+ const labelPrefix = opts?.label ? `${c4.dim(opts.label)} ` : "";
1435
+ writeln(` ${G.info} ${labelPrefix}${name} ${c4.dim("\xB7")} ${c4.dim(source)}${buildSkillDescriptionPart(skill.description, opts?.verboseOutput === true)}`);
1500
1436
  }
1501
1437
  function renderListSkillsResult(result, opts) {
1502
1438
  const r = result;
1503
1439
  if (!Array.isArray(r?.skills))
1504
1440
  return false;
1505
1441
  if (r.skills.length === 0) {
1506
- writeln2(` ${G.info} ${c5.dim("no skills")}`);
1442
+ writeln(` ${G.info} ${c4.dim("no skills")}`);
1507
1443
  return true;
1508
1444
  }
1509
1445
  const maxSkills = opts?.verboseOutput ? r.skills.length : 6;
@@ -1513,7 +1449,7 @@ function renderListSkillsResult(result, opts) {
1513
1449
  });
1514
1450
  }
1515
1451
  if (r.skills.length > maxSkills) {
1516
- writeln2(` ${c5.dim(`+${r.skills.length - maxSkills} more skills`)}`);
1452
+ writeln(` ${c4.dim(`+${r.skills.length - maxSkills} more skills`)}`);
1517
1453
  }
1518
1454
  return true;
1519
1455
  }
@@ -1522,7 +1458,7 @@ function renderReadSkillResult(result, _opts) {
1522
1458
  if (!r || typeof r !== "object")
1523
1459
  return false;
1524
1460
  if (!r.skill) {
1525
- writeln2(` ${G.info} ${c5.dim("skill")} ${c5.dim("(not found)")}`);
1461
+ writeln(` ${G.info} ${c4.dim("skill")} ${c4.dim("(not found)")}`);
1526
1462
  return true;
1527
1463
  }
1528
1464
  renderSkillSummaryLine(r.skill, {
@@ -1536,19 +1472,19 @@ function renderWebSearchResult(result, opts) {
1536
1472
  if (!Array.isArray(r?.results))
1537
1473
  return false;
1538
1474
  if (r.results.length === 0) {
1539
- writeln2(` ${G.info} ${c5.dim("no results")}`);
1475
+ writeln(` ${G.info} ${c4.dim("no results")}`);
1540
1476
  return true;
1541
1477
  }
1542
1478
  const maxResults = opts?.verboseOutput ? r.results.length : 5;
1543
1479
  for (const item of r.results.slice(0, maxResults)) {
1544
1480
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
1545
- const score = typeof item.score === "number" ? c5.dim(` (${item.score.toFixed(2)})`) : "";
1546
- writeln2(` ${c5.dim("\u2022")} ${title}${score}`);
1481
+ const score = typeof item.score === "number" ? c4.dim(` (${item.score.toFixed(2)})`) : "";
1482
+ writeln(` ${c4.dim("\u2022")} ${title}${score}`);
1547
1483
  if (item.url)
1548
- writeln2(` ${c5.dim(item.url)}`);
1484
+ writeln(` ${c4.dim(item.url)}`);
1549
1485
  }
1550
1486
  if (r.results.length > maxResults) {
1551
- writeln2(` ${c5.dim(` +${r.results.length - maxResults} more`)}`);
1487
+ writeln(` ${c4.dim(` +${r.results.length - maxResults} more`)}`);
1552
1488
  }
1553
1489
  return true;
1554
1490
  }
@@ -1557,39 +1493,41 @@ function renderWebContentResult(result, opts) {
1557
1493
  if (!Array.isArray(r?.results))
1558
1494
  return false;
1559
1495
  if (r.results.length === 0) {
1560
- writeln2(` ${G.info} ${c5.dim("no pages")}`);
1496
+ writeln(` ${G.info} ${c4.dim("no pages")}`);
1561
1497
  return true;
1562
1498
  }
1563
1499
  const maxPages = opts?.verboseOutput ? r.results.length : 3;
1564
1500
  for (const item of r.results.slice(0, maxPages)) {
1565
1501
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
1566
- writeln2(` ${c5.dim("\u2022")} ${title}`);
1502
+ writeln(` ${c4.dim("\u2022")} ${title}`);
1567
1503
  if (item.url)
1568
- writeln2(` ${c5.dim(item.url)}`);
1504
+ writeln(` ${c4.dim(item.url)}`);
1569
1505
  const preview = (item.text ?? "").replace(/\s+/g, " ").trim();
1570
1506
  if (preview) {
1571
1507
  const trimmed = opts?.verboseOutput || preview.length <= 220 ? preview : `${preview.slice(0, 217)}\u2026`;
1572
- writeln2(` ${c5.dim(trimmed)}`);
1508
+ writeln(` ${c4.dim(trimmed)}`);
1573
1509
  }
1574
1510
  }
1575
1511
  if (r.results.length > maxPages) {
1576
- writeln2(` ${c5.dim(` +${r.results.length - maxPages} more`)}`);
1512
+ writeln(` ${c4.dim(` +${r.results.length - maxPages} more`)}`);
1577
1513
  }
1578
1514
  return true;
1579
1515
  }
1580
1516
  function renderMcpResult(result, opts) {
1581
1517
  const content = Array.isArray(result) ? result : [result];
1582
1518
  const maxBlocks = opts?.verboseOutput ? content.length : 5;
1519
+ let rendered = false;
1583
1520
  for (const block of content.slice(0, maxBlocks)) {
1584
1521
  if (block?.type === "text" && block.text) {
1585
1522
  const maxLines = opts?.verboseOutput ? Number.POSITIVE_INFINITY : 6;
1586
1523
  const lines = block.text.split(`
1587
1524
  `).slice(0, maxLines);
1588
1525
  for (const line of lines)
1589
- writeln2(` ${c5.dim("\u2502")} ${line}`);
1526
+ writeln(` ${c4.dim("\u2502")} ${line}`);
1527
+ rendered = true;
1590
1528
  }
1591
1529
  }
1592
- return true;
1530
+ return rendered;
1593
1531
  }
1594
1532
  var TOOL_RESULT_RENDERERS = {
1595
1533
  shell: renderShellResult,
@@ -1619,6 +1557,10 @@ function toolGlyph(name) {
1619
1557
  return G.read;
1620
1558
  if (name === "listSkills")
1621
1559
  return G.search;
1560
+ if (name === "webSearch")
1561
+ return G.search;
1562
+ if (name === "webContent")
1563
+ return G.read;
1622
1564
  if (name.startsWith("mcp_"))
1623
1565
  return G.mcp;
1624
1566
  return G.info;
@@ -1629,40 +1571,51 @@ function buildToolCallLine(name, args) {
1629
1571
  const prompt = typeof a.prompt === "string" ? a.prompt : "";
1630
1572
  const short = prompt.length > 60 ? `${prompt.slice(0, 57)}\u2026` : prompt;
1631
1573
  const agentName = typeof a.agentName === "string" && a.agentName ? a.agentName : "";
1632
- const label = agentName ? ` ${c6.dim(c6.cyan(`[@${agentName}]`))}` : "";
1633
- return `${G.agent}${label} ${c6.dim("\u2014")} ${short}`;
1574
+ const label = agentName ? ` ${c5.dim(c5.cyan(`[@${agentName}]`))}` : "";
1575
+ return `${G.agent}${label} ${c5.dim("\u2014")} ${short}`;
1634
1576
  }
1635
1577
  if (name === "shell") {
1636
1578
  const cmd = String(a.command ?? "").trim();
1637
1579
  if (!cmd)
1638
- return `${G.run} ${c6.dim("shell")}`;
1580
+ return `${G.run} ${c5.dim("shell")}`;
1639
1581
  const shortCmd = cmd.length > 72 ? `${cmd.slice(0, 69)}\u2026` : cmd;
1640
1582
  return `${G.run} ${shortCmd}`;
1641
1583
  }
1642
1584
  if (name === "listSkills") {
1643
- return `${G.search} ${c6.dim("list skills")}`;
1585
+ return `${G.search} ${c5.dim("list skills")}`;
1644
1586
  }
1645
1587
  if (name === "readSkill") {
1646
1588
  const skillName = typeof a.name === "string" ? a.name : "";
1647
- return `${G.read} ${c6.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
1589
+ return `${G.read} ${c5.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
1648
1590
  }
1649
- if (name.startsWith("mcp_")) {
1650
- return `${G.mcp} ${c6.dim(name)}`;
1591
+ if (name === "webSearch") {
1592
+ const query = typeof a.query === "string" ? a.query : "";
1593
+ const short = query.length > 60 ? `${query.slice(0, 57)}\u2026` : query;
1594
+ return `${G.search} ${c5.dim("search")}${short ? ` ${short}` : ""}`;
1651
1595
  }
1652
- return `${toolGlyph(name)} ${c6.dim(name)}`;
1596
+ if (name === "webContent") {
1597
+ const urls = Array.isArray(a.urls) ? a.urls : [];
1598
+ const label = urls.length === 1 ? String(urls[0]) : `${urls.length} url${urls.length !== 1 ? "s" : ""}`;
1599
+ const short = label.length > 60 ? `${label.slice(0, 57)}\u2026` : label;
1600
+ return `${G.read} ${c5.dim("fetch")} ${short}`;
1601
+ }
1602
+ if (name.startsWith("mcp_")) {
1603
+ return `${G.mcp} ${c5.dim(name)}`;
1604
+ }
1605
+ return `${toolGlyph(name)} ${c5.dim(name)}`;
1653
1606
  }
1654
1607
  function renderToolCall(toolName, args) {
1655
- writeln2(` ${buildToolCallLine(toolName, args)}`);
1608
+ writeln(` ${buildToolCallLine(toolName, args)}`);
1656
1609
  }
1657
1610
  function formatErrorBadge(result) {
1658
1611
  const msg = typeof result === "string" ? result : result instanceof Error ? result.message : JSON.stringify(result);
1659
1612
  const oneLiner = msg.split(`
1660
1613
  `)[0] ?? msg;
1661
- return `${G.err} ${c6.red(oneLiner)}`;
1614
+ return `${G.err} ${c5.red(oneLiner)}`;
1662
1615
  }
1663
1616
  function renderToolResult(toolName, result, isError, opts) {
1664
1617
  if (isError) {
1665
- writeln2(` ${formatErrorBadge(result)}`);
1618
+ writeln(` ${formatErrorBadge(result)}`);
1666
1619
  return;
1667
1620
  }
1668
1621
  if (renderToolResultByName(toolName, result, opts)) {
@@ -1670,10 +1623,10 @@ function renderToolResult(toolName, result, isError, opts) {
1670
1623
  }
1671
1624
  const text = JSON.stringify(result);
1672
1625
  if (opts?.verboseOutput || text.length <= 120) {
1673
- writeln2(` ${c6.dim(text)}`);
1626
+ writeln(` ${c5.dim(text)}`);
1674
1627
  return;
1675
1628
  }
1676
- writeln2(` ${c6.dim(`${text.slice(0, 117)}\u2026`)}`);
1629
+ writeln(` ${c5.dim(`${text.slice(0, 117)}\u2026`)}`);
1677
1630
  }
1678
1631
 
1679
1632
  // src/cli/stream-render.ts
@@ -1687,6 +1640,8 @@ async function renderTurn(events, spinner, opts) {
1687
1640
  let contextTokens = 0;
1688
1641
  let newMessages = [];
1689
1642
  const startedToolCalls = new Set;
1643
+ const toolCallInfo = new Map;
1644
+ let parallelCallCount = 0;
1690
1645
  let renderedVisibleOutput = false;
1691
1646
  let reasoningComputed = false;
1692
1647
  let reasoningText = "";
@@ -1702,7 +1657,7 @@ async function renderTurn(events, spinner, opts) {
1702
1657
  case "text-delta": {
1703
1658
  liveReasoning.finish();
1704
1659
  content.appendTextDelta(event.delta, renderedVisibleOutput);
1705
- if (event.delta)
1660
+ if (content.hasOpenContent())
1706
1661
  renderedVisibleOutput = true;
1707
1662
  break;
1708
1663
  }
@@ -1713,7 +1668,7 @@ async function renderTurn(events, spinner, opts) {
1713
1668
  if (showReasoning && delta) {
1714
1669
  spinner.stop();
1715
1670
  if (renderedVisibleOutput && !liveReasoning.isOpen())
1716
- writeln2();
1671
+ writeln();
1717
1672
  liveReasoning.append(delta);
1718
1673
  renderedVisibleOutput = true;
1719
1674
  }
@@ -1723,12 +1678,20 @@ async function renderTurn(events, spinner, opts) {
1723
1678
  if (startedToolCalls.has(event.toolCallId)) {
1724
1679
  break;
1725
1680
  }
1681
+ const isConsecutiveToolCall = startedToolCalls.size > 0 && toolCallInfo.size > 0;
1726
1682
  startedToolCalls.add(event.toolCallId);
1683
+ toolCallInfo.set(event.toolCallId, {
1684
+ toolName: event.toolName,
1685
+ label: buildToolCallLine(event.toolName, event.args)
1686
+ });
1687
+ if (toolCallInfo.size > 1) {
1688
+ parallelCallCount = toolCallInfo.size;
1689
+ }
1727
1690
  liveReasoning.finish();
1728
1691
  content.flushOpenContent();
1729
1692
  spinner.stop();
1730
- if (renderedVisibleOutput)
1731
- writeln2();
1693
+ if (renderedVisibleOutput && !isConsecutiveToolCall)
1694
+ writeln();
1732
1695
  renderToolCall(event.toolName, event.args);
1733
1696
  renderedVisibleOutput = true;
1734
1697
  spinner.start(event.toolName);
@@ -1736,8 +1699,15 @@ async function renderTurn(events, spinner, opts) {
1736
1699
  }
1737
1700
  case "tool-result": {
1738
1701
  startedToolCalls.delete(event.toolCallId);
1702
+ const callInfo = toolCallInfo.get(event.toolCallId);
1703
+ toolCallInfo.delete(event.toolCallId);
1739
1704
  liveReasoning.finish();
1740
1705
  spinner.stop();
1706
+ if (parallelCallCount > 1 && callInfo) {
1707
+ writeln(` ${c6.dim("\u21B3")} ${callInfo.label}`);
1708
+ }
1709
+ if (toolCallInfo.size === 0)
1710
+ parallelCallCount = 0;
1741
1711
  renderToolResult(event.toolName, event.result, event.isError, {
1742
1712
  verboseOutput
1743
1713
  });
@@ -1750,7 +1720,7 @@ async function renderTurn(events, spinner, opts) {
1750
1720
  content.flushOpenContent();
1751
1721
  spinner.stop();
1752
1722
  const removedKb = (event.removedBytes / 1024).toFixed(1);
1753
- writeln2(`${G.info} ${c7.dim("context pruned")} ${c7.dim(event.mode)} ${c7.dim(`\u2013${event.removedMessageCount} messages`)} ${c7.dim(`\u2013${removedKb} KB`)}`);
1723
+ writeln(`${G.info} ${c6.dim("context pruned")} ${c6.dim(event.mode)} ${c6.dim(`\u2013${event.removedMessageCount} messages`)} ${c6.dim(`\u2013${removedKb} KB`)}`);
1754
1724
  renderedVisibleOutput = true;
1755
1725
  break;
1756
1726
  }
@@ -1759,7 +1729,7 @@ async function renderTurn(events, spinner, opts) {
1759
1729
  content.flushOpenContent();
1760
1730
  spinner.stop();
1761
1731
  if (!renderedVisibleOutput)
1762
- writeln2();
1732
+ writeln();
1763
1733
  inputTokens = event.inputTokens;
1764
1734
  outputTokens = event.outputTokens;
1765
1735
  contextTokens = event.contextTokens;
@@ -1791,7 +1761,7 @@ async function renderTurn(events, spinner, opts) {
1791
1761
 
1792
1762
  // src/cli/output.ts
1793
1763
  var HOME = homedir3();
1794
- var PACKAGE_VERSION = "0.0.22";
1764
+ var PACKAGE_VERSION = "0.1.0";
1795
1765
  function tildePath(p) {
1796
1766
  return p.startsWith(HOME) ? `~${p.slice(HOME.length)}` : p;
1797
1767
  }
@@ -1801,38 +1771,38 @@ function restoreTerminal() {
1801
1771
  function registerTerminalCleanup() {
1802
1772
  terminal.registerCleanup();
1803
1773
  }
1804
- function writeln2(text = "") {
1774
+ function writeln(text = "") {
1805
1775
  terminal.stdoutWrite(`${text}
1806
1776
  `);
1807
1777
  }
1808
- function write2(text) {
1778
+ function write(text) {
1809
1779
  terminal.stdoutWrite(text);
1810
1780
  }
1811
1781
  function renderUserMessage(text) {
1812
1782
  const lines = text.split(`
1813
1783
  `);
1814
1784
  if (lines.length === 0) {
1815
- writeln2(`${G.prompt}`);
1785
+ writeln(`${G.prompt}`);
1816
1786
  return;
1817
1787
  }
1818
- writeln2(`${G.prompt} ${lines[0] ?? ""}`);
1788
+ writeln(`${G.prompt} ${lines[0] ?? ""}`);
1819
1789
  for (const line of lines.slice(1)) {
1820
- writeln2(` ${line}`);
1790
+ writeln(` ${line}`);
1821
1791
  }
1822
1792
  }
1823
1793
  var G = {
1824
- prompt: c8.green("\u203A"),
1825
- reply: c8.cyan("\u25C6"),
1826
- search: c8.yellow("?"),
1827
- read: c8.dim("\u2190"),
1828
- write: c8.green("\u270E"),
1829
- run: c8.dim("$"),
1830
- agent: c8.cyan("\u21E2"),
1831
- mcp: c8.yellow("\u2699"),
1832
- ok: c8.green("\u2714"),
1833
- err: c8.red("\u2716"),
1834
- warn: c8.yellow("!"),
1835
- info: c8.dim("\xB7")
1794
+ prompt: c7.green("\u203A"),
1795
+ reply: c7.cyan("\u25C6"),
1796
+ search: c7.yellow("?"),
1797
+ read: c7.dim("\u2190"),
1798
+ write: c7.green("\u270E"),
1799
+ run: c7.dim("$"),
1800
+ agent: c7.cyan("\u21E2"),
1801
+ mcp: c7.yellow("\u2699"),
1802
+ ok: c7.green("\u2714"),
1803
+ err: c7.red("\u2716"),
1804
+ warn: c7.yellow("!"),
1805
+ info: c7.dim("\xB7")
1836
1806
  };
1837
1807
  var PREFIX = {
1838
1808
  user: G.prompt,
@@ -1854,9 +1824,9 @@ class RenderedError extends Error {
1854
1824
  function renderError(err, context = "render") {
1855
1825
  logError(err, context);
1856
1826
  const parsed = parseAppError(err);
1857
- writeln2(`${G.err} ${c8.red(parsed.headline)}`);
1827
+ writeln(`${G.err} ${c7.red(parsed.headline)}`);
1858
1828
  if (parsed.hint) {
1859
- writeln2(` ${c8.dim(parsed.hint)}`);
1829
+ writeln(` ${c7.dim(parsed.hint)}`);
1860
1830
  }
1861
1831
  }
1862
1832
  function discoverContextFiles(cwd) {
@@ -1876,11 +1846,11 @@ function discoverContextFiles(cwd) {
1876
1846
  return found;
1877
1847
  }
1878
1848
  function renderBanner(model, cwd) {
1879
- writeln2();
1849
+ writeln();
1880
1850
  const title = PACKAGE_VERSION ? `mini-coder \xB7 v${PACKAGE_VERSION}` : "mini-coder";
1881
- writeln2(` ${c8.cyan("mc")} ${c8.dim(title)}`);
1882
- writeln2(` ${c8.dim(model)} ${c8.dim("\xB7")} ${c8.dim(tildePath(cwd))}`);
1883
- writeln2(` ${c8.dim("/help for commands \xB7 esc cancel \xB7 ctrl+c/ctrl+d exit")}`);
1851
+ writeln(` ${c7.cyan("mc")} ${c7.dim(title)}`);
1852
+ writeln(` ${c7.dim(model)} ${c7.dim("\xB7")} ${c7.dim(tildePath(cwd))}`);
1853
+ writeln(` ${c7.dim("/help for commands \xB7 esc cancel \xB7 ctrl+c/ctrl+d exit")}`);
1884
1854
  const items = [];
1885
1855
  const contextFiles = discoverContextFiles(cwd);
1886
1856
  if (contextFiles.length > 0)
@@ -1895,27 +1865,19 @@ function renderBanner(model, cwd) {
1895
1865
  if (commands.size > 0)
1896
1866
  items.push(`${commands.size} custom cmd${commands.size > 1 ? "s" : ""}`);
1897
1867
  if (items.length > 0) {
1898
- writeln2(` ${c8.dim(items.join(" \xB7 "))}`);
1868
+ writeln(` ${c7.dim(items.join(" \xB7 "))}`);
1899
1869
  }
1900
- writeln2();
1870
+ writeln();
1901
1871
  }
1902
1872
 
1903
1873
  class CliReporter {
1904
1874
  spinner = new Spinner;
1905
- liveOutput = new LiveOutputBlock;
1906
- haltSpinner() {
1907
- this.spinner.stop();
1908
- }
1909
- haltSpinnerAndFlushLiveOutput() {
1910
- this.spinner.stop();
1911
- this.liveOutput.finish();
1912
- }
1913
1875
  info(msg) {
1914
- this.haltSpinnerAndFlushLiveOutput();
1915
- writeln2(`${G.info} ${c8.dim(msg)}`);
1876
+ this.spinner.stop();
1877
+ writeln(`${G.info} ${c7.dim(msg)}`);
1916
1878
  }
1917
1879
  error(msg, hint) {
1918
- this.haltSpinnerAndFlushLiveOutput();
1880
+ this.spinner.stop();
1919
1881
  if (typeof msg === "string") {
1920
1882
  renderError(msg, hint);
1921
1883
  } else {
@@ -1923,29 +1885,23 @@ class CliReporter {
1923
1885
  }
1924
1886
  }
1925
1887
  warn(msg) {
1926
- this.haltSpinnerAndFlushLiveOutput();
1927
- writeln2(`${G.warn} ${msg}`);
1888
+ this.spinner.stop();
1889
+ writeln(`${G.warn} ${msg}`);
1928
1890
  }
1929
1891
  writeText(text) {
1930
- this.haltSpinnerAndFlushLiveOutput();
1931
- writeln2(text);
1932
- }
1933
- streamChunk(text) {
1934
- this.haltSpinner();
1935
- this.liveOutput.append(text);
1892
+ this.spinner.stop();
1893
+ writeln(text);
1936
1894
  }
1937
1895
  startSpinner(label) {
1938
1896
  this.spinner.start(label);
1939
1897
  }
1940
1898
  stopSpinner() {
1941
- this.haltSpinner();
1899
+ this.spinner.stop();
1942
1900
  }
1943
1901
  async renderTurn(events, opts) {
1944
- this.liveOutput.finish();
1945
1902
  return renderTurn(events, this.spinner, opts);
1946
1903
  }
1947
1904
  renderStatusBar(data) {
1948
- this.liveOutput.finish();
1949
1905
  renderStatusBar(data);
1950
1906
  }
1951
1907
  restoreTerminal() {
@@ -1965,8 +1921,8 @@ function warnConventionConflicts(kind, scope, agentsNames, claudeNames) {
1965
1921
  if (conflicts.length === 0)
1966
1922
  return;
1967
1923
  conflicts.sort((a, b) => a.localeCompare(b));
1968
- const list = conflicts.map((n) => c9.cyan(n)).join(c9.dim(", "));
1969
- writeln2(`${G.warn} conflicting ${kind} in ${scope} .agents and .claude: ${list} ${c9.dim("\u2014 using .agents version")}`);
1924
+ const list = conflicts.map((n) => c8.cyan(n)).join(c8.dim(", "));
1925
+ writeln(`${G.warn} conflicting ${kind} in ${scope} .agents and .claude: ${list} ${c8.dim("\u2014 using .agents version")}`);
1970
1926
  }
1971
1927
 
1972
1928
  // src/cli/frontmatter.ts
@@ -2627,10 +2583,10 @@ function setPreferredGoogleCachedContent(contentId) {
2627
2583
  }
2628
2584
  }
2629
2585
  // src/agent/session-runner.ts
2630
- import * as c12 from "yoctocolors";
2586
+ import * as c11 from "yoctocolors";
2631
2587
 
2632
2588
  // src/cli/input.ts
2633
- import * as c10 from "yoctocolors";
2589
+ import * as c9 from "yoctocolors";
2634
2590
 
2635
2591
  // src/cli/input-buffer.ts
2636
2592
  var PASTE_TOKEN_START = 57344;
@@ -3064,7 +3020,7 @@ function watchForCancel(abortController, options) {
3064
3020
  process.stdin.on("data", onData);
3065
3021
  return cleanup;
3066
3022
  }
3067
- var PROMPT = c10.green("\u25B6 ");
3023
+ var PROMPT = c9.green("\u25B6 ");
3068
3024
  var PROMPT_RAW_LEN = 2;
3069
3025
  async function readline(opts) {
3070
3026
  const cwd = opts.cwd ?? process.cwd();
@@ -3113,7 +3069,7 @@ async function readline(opts) {
3113
3069
  process.stdout.write(`${CLEAR_LINE}${prompt}${display}${CSI}${PROMPT_RAW_LEN + displayCursor + 1}G`);
3114
3070
  }
3115
3071
  function renderSearchPrompt() {
3116
- process.stdout.write(`${CLEAR_LINE}${c10.cyan("search:")} ${searchQuery}\u2588`);
3072
+ process.stdout.write(`${CLEAR_LINE}${c9.cyan("search:")} ${searchQuery}\u2588`);
3117
3073
  }
3118
3074
  function applyHistory() {
3119
3075
  if (histIdx < history.length) {
@@ -4565,10 +4521,6 @@ function normalizeUnknownError(error) {
4565
4521
  return new Error(stringifyUnknown(error));
4566
4522
  }
4567
4523
 
4568
- // src/llm-api/turn-anthropic-oauth.ts
4569
- import Anthropic from "@anthropic-ai/sdk";
4570
- import { zodSchema } from "ai";
4571
-
4572
4524
  // src/llm-api/turn-context.ts
4573
4525
  import { pruneMessages } from "ai";
4574
4526
  var DEFAULT_TOOL_RESULT_PAYLOAD_CAP_BYTES = 16 * 1024;
@@ -4769,994 +4721,184 @@ function annotateAnthropicCacheBreakpoints(turnMessages, systemPrompt) {
4769
4721
  };
4770
4722
  }
4771
4723
 
4772
- // src/llm-api/turn-request.ts
4773
- import { stepCountIs } from "ai";
4724
+ // src/llm-api/turn-execution.ts
4725
+ import { dynamicTool, jsonSchema } from "ai";
4774
4726
 
4775
- // src/llm-api/provider-options.ts
4776
- var ANTHROPIC_BUDGET = {
4777
- low: 4096,
4778
- medium: 8192,
4779
- high: 16384,
4780
- xhigh: 32768
4781
- };
4782
- var GEMINI_BUDGET = {
4783
- low: 4096,
4784
- medium: 8192,
4785
- high: 16384,
4786
- xhigh: 24575
4787
- };
4788
- function clampEffort(effort, max) {
4789
- const ORDER = ["low", "medium", "high", "xhigh"];
4790
- const effortIdx = ORDER.indexOf(effort);
4791
- const maxIdx = ORDER.indexOf(max);
4792
- return ORDER[Math.min(effortIdx, maxIdx)];
4727
+ // src/llm-api/turn-stream-events.ts
4728
+ function shouldLogStreamChunk(c10) {
4729
+ return c10.type !== "text-delta" && c10.type !== "reasoning" && c10.type !== "reasoning-delta";
4793
4730
  }
4794
- function getAnthropicThinkingOptions(modelId, effort) {
4795
- const isAdaptive = /^claude-3-7/.test(modelId) || /^claude-sonnet-4/.test(modelId) || /^claude-opus-4/.test(modelId);
4796
- if (isAdaptive) {
4797
- const isOpus = /^claude-opus-4/.test(modelId);
4798
- const mapped = effort === "xhigh" ? isOpus ? "max" : "high" : effort;
4799
- return { anthropic: { thinking: { type: "adaptive" }, effort: mapped } };
4800
- }
4801
- return {
4802
- anthropic: {
4803
- thinking: { type: "enabled", budgetTokens: ANTHROPIC_BUDGET[effort] },
4804
- betas: ["interleaved-thinking-2025-05-14"]
4731
+ function extractToolArgs(c10) {
4732
+ return c10.input ?? c10.args;
4733
+ }
4734
+ function hasRenderableToolArgs(args) {
4735
+ if (args === null || args === undefined)
4736
+ return false;
4737
+ if (typeof args === "string")
4738
+ return args.trim().length > 0;
4739
+ if (Array.isArray(args))
4740
+ return args.length > 0;
4741
+ if (typeof args === "object")
4742
+ return Object.keys(args).length > 0;
4743
+ return true;
4744
+ }
4745
+ function mapStreamChunkToTurnEvent(c10) {
4746
+ switch (c10.type) {
4747
+ case "text-delta": {
4748
+ const delta = typeof c10.text === "string" ? c10.text : "";
4749
+ return {
4750
+ type: "text-delta",
4751
+ delta
4752
+ };
4805
4753
  }
4806
- };
4754
+ case "reasoning-delta":
4755
+ case "reasoning": {
4756
+ const delta = getReasoningDeltaFromStreamChunk(c10);
4757
+ if (delta === null)
4758
+ return null;
4759
+ return {
4760
+ type: "reasoning-delta",
4761
+ delta
4762
+ };
4763
+ }
4764
+ case "tool-input-start": {
4765
+ const args = extractToolArgs(c10);
4766
+ const hasStableToolCallId = typeof c10.toolCallId === "string" && c10.toolCallId.trim().length > 0;
4767
+ if (hasStableToolCallId && !hasRenderableToolArgs(args))
4768
+ return null;
4769
+ return {
4770
+ type: "tool-call-start",
4771
+ toolCallId: String(c10.toolCallId ?? ""),
4772
+ toolName: String(c10.toolName ?? ""),
4773
+ args
4774
+ };
4775
+ }
4776
+ case "tool-call": {
4777
+ return {
4778
+ type: "tool-call-start",
4779
+ toolCallId: String(c10.toolCallId ?? ""),
4780
+ toolName: String(c10.toolName ?? ""),
4781
+ args: extractToolArgs(c10)
4782
+ };
4783
+ }
4784
+ case "tool-result": {
4785
+ return {
4786
+ type: "tool-result",
4787
+ toolCallId: String(c10.toolCallId ?? ""),
4788
+ toolName: String(c10.toolName ?? ""),
4789
+ result: "output" in c10 ? c10.output : ("result" in c10) ? c10.result : undefined,
4790
+ isError: "isError" in c10 ? Boolean(c10.isError) : false
4791
+ };
4792
+ }
4793
+ case "tool-error":
4794
+ return {
4795
+ type: "tool-result",
4796
+ toolCallId: String(c10.toolCallId ?? ""),
4797
+ toolName: String(c10.toolName ?? ""),
4798
+ result: c10.error ?? "Tool execution failed",
4799
+ isError: true
4800
+ };
4801
+ case "error": {
4802
+ throw normalizeUnknownError(c10.error);
4803
+ }
4804
+ default:
4805
+ return null;
4806
+ }
4807
4807
  }
4808
- function getOpenAIThinkingOptions(modelId, effort) {
4809
- const supportsXhigh = /^gpt-5\.[2-9]/.test(modelId) || /^o4/.test(modelId);
4810
- const clamped = supportsXhigh ? effort : clampEffort(effort, "high");
4811
- return { openai: { reasoningEffort: clamped, reasoningSummary: "auto" } };
4808
+
4809
+ // src/llm-api/turn-execution.ts
4810
+ function isZodSchema(s) {
4811
+ return s !== null && typeof s === "object" && "_def" in s;
4812
4812
  }
4813
- function getGeminiThinkingOptions(modelId, effort) {
4814
- if (/^gemini-3/.test(modelId)) {
4815
- return {
4816
- google: {
4817
- thinkingConfig: {
4818
- includeThoughts: true,
4819
- thinkingLevel: clampEffort(effort, "high")
4820
- }
4813
+ function toCoreTool(def) {
4814
+ const schema = isZodSchema(def.schema) ? def.schema : jsonSchema(def.schema);
4815
+ return dynamicTool({
4816
+ description: def.description,
4817
+ inputSchema: schema,
4818
+ execute: async (input) => {
4819
+ try {
4820
+ return await def.execute(input);
4821
+ } catch (err) {
4822
+ throw normalizeUnknownError(err);
4821
4823
  }
4822
- };
4824
+ }
4825
+ });
4826
+ }
4827
+ function buildToolSet(tools) {
4828
+ const toolSet = {};
4829
+ for (const def of tools) {
4830
+ toolSet[def.name] = toCoreTool(def);
4823
4831
  }
4832
+ return toolSet;
4833
+ }
4834
+ function createTurnStepTracker(opts) {
4835
+ let stepCount = 0;
4836
+ let inputTokens = 0;
4837
+ let outputTokens = 0;
4838
+ let contextTokens = 0;
4839
+ let partialMessages = [];
4824
4840
  return {
4825
- google: {
4826
- thinkingConfig: {
4827
- includeThoughts: true,
4828
- thinkingBudget: GEMINI_BUDGET[effort]
4829
- }
4830
- }
4841
+ onStepFinish: (step) => {
4842
+ opts.onStepLog({
4843
+ stepNumber: stepCount + 1,
4844
+ finishReason: step.finishReason,
4845
+ usage: step.usage
4846
+ });
4847
+ inputTokens += step.usage?.inputTokens ?? 0;
4848
+ outputTokens += step.usage?.outputTokens ?? 0;
4849
+ contextTokens = step.usage?.inputTokens ?? contextTokens;
4850
+ stepCount += 1;
4851
+ const s = step;
4852
+ partialMessages = s.response?.messages ?? s.messages ?? partialMessages;
4853
+ },
4854
+ getState: () => ({
4855
+ stepCount,
4856
+ inputTokens,
4857
+ outputTokens,
4858
+ contextTokens,
4859
+ partialMessages
4860
+ })
4831
4861
  };
4832
4862
  }
4833
- var THINKING_STRATEGIES = [
4834
- {
4835
- supports: isAnthropicModelFamily,
4836
- build: getAnthropicThinkingOptions
4837
- },
4838
- {
4839
- supports: isOpenAIReasoningModelFamily,
4840
- build: getOpenAIThinkingOptions
4841
- },
4842
- {
4843
- supports: isGeminiModelFamily,
4844
- build: getGeminiThinkingOptions
4845
- }
4846
- ];
4847
- function getThinkingProviderOptions(modelString, effort) {
4848
- if (!supportsThinking(modelString))
4863
+ var TOOL_RESULT_CHUNK_TYPES = new Set(["tool-result", "tool-error"]);
4864
+ function normalizeToolCallId(raw) {
4865
+ if (typeof raw !== "string")
4849
4866
  return null;
4850
- const { modelId } = parseModelString(modelString);
4851
- for (const strategy of THINKING_STRATEGIES) {
4852
- if (!strategy.supports(modelString))
4853
- continue;
4854
- return strategy.build(modelId, effort);
4855
- }
4856
- return null;
4867
+ const trimmed = raw.trim();
4868
+ return trimmed ? trimmed : null;
4857
4869
  }
4858
- var CACHE_FAMILY_RULES = [
4859
- [isAnthropicModelFamily, "anthropic"],
4860
- [isGeminiModelFamily, "google"]
4861
- ];
4862
- function getCacheFamily(modelString) {
4863
- for (const [match, family] of CACHE_FAMILY_RULES) {
4864
- if (match(modelString))
4865
- return family;
4866
- }
4867
- return "none";
4870
+ function normalizeToolName(raw) {
4871
+ if (typeof raw !== "string")
4872
+ return "tool";
4873
+ const trimmed = raw.trim();
4874
+ return trimmed || "tool";
4868
4875
  }
4869
- function getCachingProviderOptions(modelString, opts) {
4870
- if (!opts.enabled)
4876
+ function isRecord5(value) {
4877
+ return value !== null && typeof value === "object";
4878
+ }
4879
+ function normalizeTextPartId(raw) {
4880
+ if (typeof raw !== "string")
4871
4881
  return null;
4872
- const family = getCacheFamily(modelString);
4873
- if (family === "google" && opts.googleCachedContent && opts.googleExplicitCachingCompatible !== false) {
4874
- return { google: { cachedContent: opts.googleCachedContent } };
4875
- }
4876
- return null;
4877
- }
4878
-
4879
- // src/llm-api/turn-prepare-messages.ts
4880
- function prepareTurnMessages(input) {
4881
- const {
4882
- messages,
4883
- modelString,
4884
- toolCount,
4885
- systemPrompt,
4886
- pruningMode,
4887
- toolResultPayloadCapBytes,
4888
- promptCachingEnabled
4889
- } = input;
4890
- const apiLogOn = isApiLogEnabled();
4891
- const strippedRuntimeToolFields = stripToolRuntimeInputFields(messages);
4892
- if (strippedRuntimeToolFields !== messages && apiLogOn) {
4893
- logApiEvent("runtime tool input fields stripped", { modelString });
4894
- }
4895
- const geminiResult = sanitizeGeminiToolMessagesWithMetadata(strippedRuntimeToolFields, modelString, toolCount > 0);
4896
- if (geminiResult.repaired && apiLogOn) {
4897
- logApiEvent("gemini tool history repaired", {
4898
- modelString,
4899
- reason: geminiResult.reason,
4900
- repairedFromIndex: geminiResult.repairedFromIndex,
4901
- droppedMessageCount: geminiResult.droppedMessageCount,
4902
- tailOnlyAffected: geminiResult.tailOnlyAffected
4903
- });
4904
- }
4905
- const openaiStripped = stripOpenAIHistoryTransforms(geminiResult.messages, modelString);
4906
- if (openaiStripped !== geminiResult.messages && apiLogOn) {
4907
- logApiEvent("openai history transforms applied", { modelString });
4908
- }
4909
- const normalised = normalizeOpenAICompatibleToolCallInputs(openaiStripped, modelString);
4910
- if (normalised !== openaiStripped && apiLogOn) {
4911
- logApiEvent("openai-compatible tool input normalized", { modelString });
4912
- }
4913
- const preStats = apiLogOn ? getMessageDiagnostics(normalised) : getMessageStats(normalised);
4914
- if (apiLogOn)
4915
- logApiEvent("turn context pre-prune", preStats);
4916
- const pruned = applyContextPruning(normalised, pruningMode);
4917
- const postStats = apiLogOn ? getMessageDiagnostics(pruned) : getMessageStats(pruned);
4918
- if (apiLogOn)
4919
- logApiEvent("turn context post-prune", postStats);
4920
- const compacted = compactToolResultPayloads(pruned, toolResultPayloadCapBytes);
4921
- if (compacted !== pruned && apiLogOn) {
4922
- logApiEvent("turn context post-compaction", {
4923
- capBytes: toolResultPayloadCapBytes,
4924
- diagnostics: getMessageDiagnostics(compacted)
4925
- });
4926
- }
4927
- let finalMessages = compacted;
4928
- let finalSystemPrompt = systemPrompt;
4929
- const cacheFamily = getCacheFamily(modelString);
4930
- if (cacheFamily === "anthropic" && promptCachingEnabled) {
4931
- const annotated = annotateAnthropicCacheBreakpoints(compacted, systemPrompt);
4932
- finalMessages = annotated.messages;
4933
- finalSystemPrompt = annotated.systemPrompt;
4934
- if (apiLogOn) {
4935
- logApiEvent("Anthropic prompt caching", annotated.diagnostics);
4936
- }
4937
- }
4938
- if (isAnthropicModelFamily(modelString) && isAnthropicOAuth()) {
4939
- const prefix = `You are Claude Code, Anthropic's official CLI for Claude.
4940
- `;
4941
- if (finalSystemPrompt) {
4942
- finalSystemPrompt = prefix + finalSystemPrompt;
4943
- } else {
4944
- const sysMsg = finalMessages.find((m) => m.role === "system");
4945
- if (sysMsg && typeof sysMsg.content === "string") {
4946
- const idx = finalMessages.indexOf(sysMsg);
4947
- finalMessages[idx] = { ...sysMsg, content: prefix + sysMsg.content };
4948
- }
4949
- }
4950
- }
4951
- const wasPruned = (pruningMode === "balanced" || pruningMode === "aggressive") && (postStats.messageCount < preStats.messageCount || postStats.totalBytes < preStats.totalBytes);
4952
- return {
4953
- messages: finalMessages,
4954
- systemPrompt: finalSystemPrompt,
4955
- pruned: wasPruned,
4956
- prePruneMessageCount: preStats.messageCount,
4957
- prePruneTotalBytes: preStats.totalBytes,
4958
- postPruneMessageCount: postStats.messageCount,
4959
- postPruneTotalBytes: postStats.totalBytes
4960
- };
4961
- }
4962
-
4963
- // src/llm-api/turn-provider-options.ts
4964
- function isRecord5(value) {
4965
- return value !== null && typeof value === "object";
4966
- }
4967
- function mergeDeep(target, source) {
4968
- const output = { ...target };
4969
- for (const key in source) {
4970
- const sVal = source[key];
4971
- const tVal = target[key];
4972
- output[key] = isRecord5(sVal) && isRecord5(tVal) ? { ...tVal, ...sVal } : sVal;
4973
- }
4974
- return output;
4975
- }
4976
- function buildTurnProviderOptions(input) {
4977
- const {
4978
- modelString,
4979
- thinkingEffort,
4980
- promptCachingEnabled,
4981
- openaiPromptCacheRetention,
4982
- googleCachedContent,
4983
- toolCount,
4984
- hasSystemPrompt
4985
- } = input;
4986
- const thinkingOpts = thinkingEffort ? getThinkingProviderOptions(modelString, thinkingEffort) : null;
4987
- const reasoningSummaryRequested = isRecord5(thinkingOpts) && isRecord5(thinkingOpts.openai) && typeof thinkingOpts.openai.reasoningSummary === "string";
4988
- const cacheFamily = getCacheFamily(modelString);
4989
- const cacheOpts = getCachingProviderOptions(modelString, {
4990
- enabled: promptCachingEnabled,
4991
- openaiRetention: openaiPromptCacheRetention,
4992
- googleCachedContent,
4993
- googleExplicitCachingCompatible: toolCount === 0 && !hasSystemPrompt
4994
- });
4995
- const baseProviderOpts = {
4996
- ...thinkingOpts ?? {},
4997
- ...isOpenAIGPT(modelString) ? {
4998
- openai: {
4999
- store: false,
5000
- ...isRecord5(thinkingOpts?.openai) ? thinkingOpts.openai : {}
5001
- }
5002
- } : {}
5003
- };
5004
- const providerOptions = cacheOpts ? mergeDeep(baseProviderOpts, cacheOpts) : baseProviderOpts;
5005
- return {
5006
- cacheFamily,
5007
- thinkingOpts,
5008
- cacheOpts,
5009
- providerOptions,
5010
- reasoningSummaryRequested
5011
- };
5012
- }
5013
-
5014
- // src/llm-api/turn-request.ts
5015
- function buildTurnPreparation(input) {
5016
- const providerOptionsResult = buildTurnProviderOptions({
5017
- modelString: input.modelString,
5018
- thinkingEffort: input.thinkingEffort,
5019
- promptCachingEnabled: input.promptCachingEnabled,
5020
- openaiPromptCacheRetention: input.openaiPromptCacheRetention,
5021
- googleCachedContent: input.googleCachedContent,
5022
- toolCount: input.toolCount,
5023
- hasSystemPrompt: Boolean(input.systemPrompt)
5024
- });
5025
- const prepared = prepareTurnMessages({
5026
- messages: input.messages,
5027
- modelString: input.modelString,
5028
- toolCount: input.toolCount,
5029
- systemPrompt: input.systemPrompt,
5030
- pruningMode: input.pruningMode,
5031
- toolResultPayloadCapBytes: input.toolResultPayloadCapBytes,
5032
- promptCachingEnabled: input.promptCachingEnabled
5033
- });
5034
- return { providerOptionsResult, prepared };
5035
- }
5036
- function buildStreamTextRequest(input) {
5037
- return {
5038
- model: input.model,
5039
- maxOutputTokens: 16384,
5040
- messages: input.prepared.messages,
5041
- tools: input.toolSet,
5042
- stopWhen: stepCountIs(input.maxSteps),
5043
- onStepFinish: input.onStepFinish,
5044
- prepareStep: ({ stepNumber }) => {
5045
- if (stepNumber >= input.maxSteps - 1) {
5046
- return { activeTools: [] };
5047
- }
5048
- return;
5049
- },
5050
- ...input.prepared.systemPrompt ? { system: input.prepared.systemPrompt } : {},
5051
- ...Object.keys(input.providerOptions).length > 0 ? {
5052
- providerOptions: input.providerOptions
5053
- } : {},
5054
- ...input.signal ? { abortSignal: input.signal } : {},
5055
- onError: () => {},
5056
- timeout: { chunkMs: 120000 }
5057
- };
5058
- }
5059
-
5060
- // src/llm-api/turn-anthropic-oauth.ts
5061
- var MAX_STEPS = 50;
5062
- var MAX_OUTPUT_TOKENS = 16384;
5063
- var CC_VERSION = "2.1.75";
5064
- var cachedClient = null;
5065
- function getClient(token) {
5066
- if (cachedClient?.token === token && cachedClient.client)
5067
- return cachedClient.client;
5068
- const client = new Anthropic({
5069
- apiKey: null,
5070
- authToken: token,
5071
- maxRetries: 5,
5072
- dangerouslyAllowBrowser: true,
5073
- defaultHeaders: {
5074
- accept: "application/json",
5075
- "anthropic-dangerous-direct-browser-access": "true",
5076
- "anthropic-beta": "claude-code-20250219,oauth-2025-04-20",
5077
- "user-agent": `claude-cli/${CC_VERSION}`,
5078
- "x-app": "cli"
5079
- }
5080
- });
5081
- cachedClient = { token, client };
5082
- return client;
5083
- }
5084
- function supportsAdaptiveThinking(modelId) {
5085
- return modelId.includes("opus-4-6") || modelId.includes("sonnet-4-6");
5086
- }
5087
- function mapEffort(effort, modelId) {
5088
- if (!effort)
5089
- return;
5090
- const map = {
5091
- low: "low",
5092
- medium: "medium",
5093
- high: "high",
5094
- xhigh: modelId.includes("opus-4-6") ? "max" : "high"
5095
- };
5096
- return map[effort];
5097
- }
5098
- function coreToAnthropicMessages(messages) {
5099
- let systemPrompt;
5100
- const params = [];
5101
- const toolUseIds = new Set;
5102
- for (const msg of messages) {
5103
- if (msg.role !== "assistant" || !Array.isArray(msg.content))
5104
- continue;
5105
- for (const part of msg.content) {
5106
- if (part.type === "tool-call" && part.toolCallId) {
5107
- toolUseIds.add(part.toolCallId);
5108
- }
5109
- }
5110
- }
5111
- for (const msg of messages) {
5112
- if (msg.role === "system") {
5113
- systemPrompt = typeof msg.content === "string" ? msg.content : Array.isArray(msg.content) ? msg.content.filter((p) => p.type === "text").map((p) => p.text).join(`
5114
- `) : undefined;
5115
- continue;
5116
- }
5117
- if (msg.role === "user") {
5118
- if (typeof msg.content === "string") {
5119
- if (msg.content.trim())
5120
- params.push({ role: "user", content: msg.content });
5121
- continue;
5122
- }
5123
- if (Array.isArray(msg.content)) {
5124
- const blocks = [];
5125
- for (const part of msg.content) {
5126
- if (part.type === "text" && part.text?.trim()) {
5127
- blocks.push({ type: "text", text: part.text });
5128
- } else if (part.type === "tool-result") {
5129
- if (!toolUseIds.has(part.toolCallId))
5130
- continue;
5131
- blocks.push({
5132
- type: "tool_result",
5133
- tool_use_id: part.toolCallId,
5134
- content: typeof part.result === "string" ? part.result : JSON.stringify(part.result ?? part.output ?? ""),
5135
- is_error: part.isError ?? false
5136
- });
5137
- } else if (part.type === "image") {
5138
- blocks.push({
5139
- type: "image",
5140
- source: {
5141
- type: "base64",
5142
- media_type: part.mimeType ?? "image/png",
5143
- data: part.data
5144
- }
5145
- });
5146
- }
5147
- }
5148
- if (blocks.length > 0)
5149
- params.push({ role: "user", content: blocks });
5150
- }
5151
- continue;
5152
- }
5153
- if (msg.role === "assistant") {
5154
- if (typeof msg.content === "string") {
5155
- if (msg.content.trim())
5156
- params.push({ role: "assistant", content: msg.content });
5157
- continue;
5158
- }
5159
- if (Array.isArray(msg.content)) {
5160
- const blocks = [];
5161
- for (const part of msg.content) {
5162
- if (part.type === "text" && part.text?.trim()) {
5163
- blocks.push({ type: "text", text: part.text });
5164
- } else if (part.type === "tool-call") {
5165
- blocks.push({
5166
- type: "tool_use",
5167
- id: part.toolCallId,
5168
- name: part.toolName,
5169
- input: part.args ?? {}
5170
- });
5171
- } else if (part.type === "thinking") {
5172
- if (part.redacted && part.signature) {
5173
- blocks.push({
5174
- type: "redacted_thinking",
5175
- data: part.signature
5176
- });
5177
- } else if (part.text?.trim() && part.signature?.trim()) {
5178
- blocks.push({
5179
- type: "thinking",
5180
- thinking: part.text,
5181
- signature: part.signature
5182
- });
5183
- }
5184
- }
5185
- }
5186
- if (blocks.length > 0)
5187
- params.push({ role: "assistant", content: blocks });
5188
- }
5189
- }
5190
- }
5191
- return { system: systemPrompt, params };
5192
- }
5193
- function convertTools(tools) {
5194
- return tools.map((tool) => {
5195
- const schema = zodSchema(tool.schema).jsonSchema;
5196
- return {
5197
- name: tool.name,
5198
- description: tool.description,
5199
- input_schema: {
5200
- type: "object",
5201
- properties: schema.properties ?? {},
5202
- required: schema.required ?? []
5203
- }
5204
- };
5205
- });
5206
- }
5207
- function buildCoreMessages(assistantText, thinkingBlocks, toolCalls, toolResults) {
5208
- const messages = [];
5209
- const parts = [];
5210
- for (const tb of thinkingBlocks) {
5211
- if (tb.redacted) {
5212
- parts.push({
5213
- type: "thinking",
5214
- text: "[Reasoning redacted]",
5215
- signature: tb.signature,
5216
- redacted: true
5217
- });
5218
- } else {
5219
- parts.push({
5220
- type: "thinking",
5221
- text: tb.text,
5222
- signature: tb.signature
5223
- });
5224
- }
5225
- }
5226
- if (assistantText.trim()) {
5227
- parts.push({ type: "text", text: assistantText });
5228
- }
5229
- for (const tc of toolCalls) {
5230
- parts.push({
5231
- type: "tool-call",
5232
- toolCallId: tc.id,
5233
- toolName: tc.name,
5234
- args: tc.args
5235
- });
5236
- }
5237
- if (parts.length > 0) {
5238
- messages.push({
5239
- role: "assistant",
5240
- content: parts
5241
- });
5242
- }
5243
- if (toolResults.length > 0) {
5244
- const resultParts = toolResults.map((tr) => ({
5245
- type: "tool-result",
5246
- toolCallId: tr.toolCallId,
5247
- toolName: tr.toolName,
5248
- result: tr.result,
5249
- isError: tr.isError
5250
- }));
5251
- messages.push({
5252
- role: "user",
5253
- content: resultParts
5254
- });
5255
- }
5256
- return messages;
5257
- }
5258
- function parseStreamingJson(partial) {
5259
- try {
5260
- return JSON.parse(partial);
5261
- } catch {
5262
- try {
5263
- let fixed = partial;
5264
- const opens = (fixed.match(/{/g) || []).length;
5265
- const closes = (fixed.match(/}/g) || []).length;
5266
- for (let i = 0;i < opens - closes; i++)
5267
- fixed += "}";
5268
- return JSON.parse(fixed);
5269
- } catch {
5270
- return {};
5271
- }
5272
- }
5273
- }
5274
- async function* runTurnAnthropicOAuth(options) {
5275
- const {
5276
- token,
5277
- modelString,
5278
- messages,
5279
- tools,
5280
- systemPrompt,
5281
- signal,
5282
- thinkingEffort,
5283
- pruningMode = "balanced",
5284
- promptCachingEnabled = true,
5285
- toolResultPayloadCapBytes = DEFAULT_TOOL_RESULT_PAYLOAD_CAP_BYTES
5286
- } = options;
5287
- const modelId = modelString.replace(/^anthropic\//, "");
5288
- const client = getClient(token);
5289
- const anthropicTools = convertTools(tools);
5290
- const toolExecutors = new Map(tools.map((t) => [t.name, t.execute]));
5291
- let totalInputTokens = 0;
5292
- let totalOutputTokens = 0;
5293
- let contextTokens = 0;
5294
- let stepCount = 0;
5295
- const allNewMessages = [];
5296
- try {
5297
- const { prepared } = buildTurnPreparation({
5298
- modelString,
5299
- messages,
5300
- thinkingEffort,
5301
- promptCachingEnabled,
5302
- openaiPromptCacheRetention: "in_memory",
5303
- googleCachedContent: null,
5304
- toolCount: tools.length,
5305
- systemPrompt,
5306
- pruningMode,
5307
- toolResultPayloadCapBytes
5308
- });
5309
- logApiEvent("turn start", {
5310
- modelString,
5311
- messageCount: messages.length,
5312
- reasoningSummaryRequested: false,
5313
- pruningMode,
5314
- toolResultPayloadCapBytes
5315
- });
5316
- if (prepared.pruned) {
5317
- yield {
5318
- type: "context-pruned",
5319
- mode: pruningMode,
5320
- beforeMessageCount: prepared.prePruneMessageCount,
5321
- afterMessageCount: prepared.postPruneMessageCount,
5322
- removedMessageCount: prepared.prePruneMessageCount - prepared.postPruneMessageCount,
5323
- beforeTotalBytes: prepared.prePruneTotalBytes,
5324
- afterTotalBytes: prepared.postPruneTotalBytes,
5325
- removedBytes: prepared.prePruneTotalBytes - prepared.postPruneTotalBytes
5326
- };
5327
- }
5328
- const { system: extractedSystem, params: anthropicMessages } = coreToAnthropicMessages(prepared.messages);
5329
- const ccPrefix = "You are Claude Code, Anthropic's official CLI for Claude.";
5330
- const sysText = prepared.systemPrompt ?? extractedSystem;
5331
- const systemBlocks = [
5332
- {
5333
- type: "text",
5334
- text: ccPrefix,
5335
- cache_control: { type: "ephemeral" }
5336
- }
5337
- ];
5338
- if (sysText) {
5339
- const clean = sysText.startsWith(ccPrefix) ? sysText.slice(ccPrefix.length).replace(/^\n/, "") : sysText;
5340
- if (clean.trim()) {
5341
- systemBlocks.push({
5342
- type: "text",
5343
- text: clean,
5344
- cache_control: { type: "ephemeral" }
5345
- });
5346
- }
5347
- }
5348
- const currentMessages = [...anthropicMessages];
5349
- while (stepCount < MAX_STEPS) {
5350
- stepCount++;
5351
- const isLastStep = stepCount >= MAX_STEPS;
5352
- const params = {
5353
- model: modelId,
5354
- max_tokens: MAX_OUTPUT_TOKENS,
5355
- system: systemBlocks,
5356
- messages: currentMessages,
5357
- tools: isLastStep ? [] : anthropicTools,
5358
- stream: true
5359
- };
5360
- if (thinkingEffort && supportsAdaptiveThinking(modelId)) {
5361
- params.thinking = { type: "adaptive" };
5362
- const effort = mapEffort(thinkingEffort, modelId);
5363
- if (effort) {
5364
- params.output_config = {
5365
- effort
5366
- };
5367
- }
5368
- }
5369
- for (const m of currentMessages) {
5370
- if (!Array.isArray(m.content))
5371
- continue;
5372
- for (const block of m.content) {
5373
- if (typeof block === "object" && block !== null) {
5374
- delete block.cache_control;
5375
- }
5376
- }
5377
- }
5378
- const lastMsg = currentMessages.length > 0 ? currentMessages[currentMessages.length - 1] : undefined;
5379
- if (lastMsg && lastMsg.role === "user" && Array.isArray(lastMsg.content)) {
5380
- const lastBlock = lastMsg.content[lastMsg.content.length - 1];
5381
- if (lastBlock && typeof lastBlock === "object") {
5382
- lastBlock.cache_control = {
5383
- type: "ephemeral"
5384
- };
5385
- }
5386
- }
5387
- if (isApiLogEnabled()) {
5388
- logApiEvent("Provider Request", {
5389
- url: "https://api.anthropic.com/v1/messages",
5390
- method: "POST",
5391
- model: modelId,
5392
- messageCount: currentMessages.length,
5393
- toolCount: params.tools?.length ?? 0
5394
- });
5395
- }
5396
- const stream = client.messages.stream(params, { signal });
5397
- let assistantText = "";
5398
- const thinkingBlocks = [];
5399
- const toolCalls = [];
5400
- let partialJson = "";
5401
- let currentToolId = "";
5402
- let currentToolName = "";
5403
- let stepInputTokens = 0;
5404
- let stepOutputTokens = 0;
5405
- let stopReason;
5406
- for await (const event of stream) {
5407
- if (event.type === "message_start") {
5408
- stepInputTokens = event.message.usage.input_tokens || 0;
5409
- stepOutputTokens = event.message.usage.output_tokens || 0;
5410
- } else if (event.type === "content_block_start") {
5411
- if (event.content_block.type === "text") {} else if (event.content_block.type === "thinking") {
5412
- thinkingBlocks.push({
5413
- text: "",
5414
- signature: ""
5415
- });
5416
- } else if (event.content_block.type === "redacted_thinking") {
5417
- thinkingBlocks.push({
5418
- text: "[Reasoning redacted]",
5419
- signature: event.content_block.data,
5420
- redacted: true
5421
- });
5422
- } else if (event.content_block.type === "tool_use") {
5423
- currentToolId = event.content_block.id;
5424
- currentToolName = event.content_block.name;
5425
- partialJson = "";
5426
- }
5427
- } else if (event.type === "content_block_delta") {
5428
- if (event.delta.type === "text_delta") {
5429
- assistantText += event.delta.text;
5430
- yield { type: "text-delta", delta: event.delta.text };
5431
- } else if (event.delta.type === "thinking_delta") {
5432
- const tb = thinkingBlocks[thinkingBlocks.length - 1];
5433
- if (tb)
5434
- tb.text += event.delta.thinking;
5435
- yield {
5436
- type: "reasoning-delta",
5437
- delta: event.delta.thinking
5438
- };
5439
- } else if (event.delta.type === "input_json_delta") {
5440
- partialJson += event.delta.partial_json;
5441
- } else if (event.delta.type === "signature_delta") {
5442
- const tb = thinkingBlocks[thinkingBlocks.length - 1];
5443
- if (tb)
5444
- tb.signature += event.delta.signature;
5445
- }
5446
- } else if (event.type === "content_block_stop") {
5447
- if (currentToolId && currentToolName) {
5448
- const args = parseStreamingJson(partialJson);
5449
- toolCalls.push({
5450
- id: currentToolId,
5451
- name: currentToolName,
5452
- args
5453
- });
5454
- yield {
5455
- type: "tool-call-start",
5456
- toolCallId: currentToolId,
5457
- toolName: currentToolName,
5458
- args
5459
- };
5460
- currentToolId = "";
5461
- currentToolName = "";
5462
- partialJson = "";
5463
- }
5464
- } else if (event.type === "message_delta") {
5465
- if (event.delta.stop_reason) {
5466
- stopReason = event.delta.stop_reason;
5467
- }
5468
- if (event.usage.output_tokens != null) {
5469
- stepOutputTokens = event.usage.output_tokens;
5470
- }
5471
- }
5472
- }
5473
- totalInputTokens += stepInputTokens;
5474
- totalOutputTokens += stepOutputTokens;
5475
- contextTokens = stepInputTokens;
5476
- logApiEvent("step finish", {
5477
- stepNumber: stepCount,
5478
- finishReason: stopReason,
5479
- usage: {
5480
- inputTokens: stepInputTokens,
5481
- outputTokens: stepOutputTokens
5482
- }
5483
- });
5484
- const toolResults = [];
5485
- if (stopReason === "tool_use" && toolCalls.length > 0) {
5486
- for (const tc of toolCalls) {
5487
- const executor = toolExecutors.get(tc.name);
5488
- let result;
5489
- let isError = false;
5490
- if (!executor) {
5491
- result = `Unknown tool: ${tc.name}`;
5492
- isError = true;
5493
- } else {
5494
- try {
5495
- result = await executor(tc.args);
5496
- } catch (err) {
5497
- result = normalizeUnknownError(err).message;
5498
- isError = true;
5499
- }
5500
- }
5501
- toolResults.push({
5502
- toolCallId: tc.id,
5503
- toolName: tc.name,
5504
- result,
5505
- isError
5506
- });
5507
- yield {
5508
- type: "tool-result",
5509
- toolCallId: tc.id,
5510
- toolName: tc.name,
5511
- result,
5512
- isError
5513
- };
5514
- }
5515
- }
5516
- const stepMessages = buildCoreMessages(assistantText, thinkingBlocks, toolCalls, toolResults);
5517
- allNewMessages.push(...stepMessages);
5518
- if (stopReason !== "tool_use" || toolCalls.length === 0) {
5519
- break;
5520
- }
5521
- const assistantBlocks = [];
5522
- for (const tb of thinkingBlocks) {
5523
- if (tb.redacted) {
5524
- assistantBlocks.push({
5525
- type: "redacted_thinking",
5526
- data: tb.signature
5527
- });
5528
- } else if (tb.text.trim() && tb.signature.trim()) {
5529
- assistantBlocks.push({
5530
- type: "thinking",
5531
- thinking: tb.text,
5532
- signature: tb.signature
5533
- });
5534
- }
5535
- }
5536
- if (assistantText.trim()) {
5537
- assistantBlocks.push({ type: "text", text: assistantText });
5538
- }
5539
- for (const tc of toolCalls) {
5540
- assistantBlocks.push({
5541
- type: "tool_use",
5542
- id: tc.id,
5543
- name: tc.name,
5544
- input: tc.args
5545
- });
5546
- }
5547
- currentMessages.push({
5548
- role: "assistant",
5549
- content: assistantBlocks
5550
- });
5551
- const resultBlocks = toolResults.map((tr) => ({
5552
- type: "tool_result",
5553
- tool_use_id: tr.toolCallId,
5554
- content: typeof tr.result === "string" ? tr.result : JSON.stringify(tr.result ?? ""),
5555
- is_error: tr.isError
5556
- }));
5557
- currentMessages.push({ role: "user", content: resultBlocks });
5558
- }
5559
- logApiEvent("turn complete", {
5560
- newMessagesCount: allNewMessages.length,
5561
- inputTokens: totalInputTokens,
5562
- outputTokens: totalOutputTokens
5563
- });
5564
- yield {
5565
- type: "turn-complete",
5566
- inputTokens: totalInputTokens,
5567
- outputTokens: totalOutputTokens,
5568
- contextTokens,
5569
- messages: allNewMessages
5570
- };
5571
- } catch (err) {
5572
- const normalizedError = normalizeUnknownError(err);
5573
- logApiEvent("turn error", normalizedError);
5574
- yield {
5575
- type: "turn-error",
5576
- error: normalizedError,
5577
- partialMessages: allNewMessages
5578
- };
5579
- }
5580
- }
5581
-
5582
- // src/llm-api/turn-execution.ts
5583
- import { dynamicTool, jsonSchema } from "ai";
5584
-
5585
- // src/llm-api/turn-stream-events.ts
5586
- function shouldLogStreamChunk(c11) {
5587
- return c11.type !== "text-delta" && c11.type !== "reasoning" && c11.type !== "reasoning-delta";
5588
- }
5589
- function extractToolArgs(c11) {
5590
- return c11.input ?? c11.args;
5591
- }
5592
- function hasRenderableToolArgs(args) {
5593
- if (args === null || args === undefined)
5594
- return false;
5595
- if (typeof args === "string")
5596
- return args.trim().length > 0;
5597
- if (Array.isArray(args))
5598
- return args.length > 0;
5599
- if (typeof args === "object")
5600
- return Object.keys(args).length > 0;
5601
- return true;
5602
- }
5603
- function mapStreamChunkToTurnEvent(c11) {
5604
- switch (c11.type) {
5605
- case "text-delta": {
5606
- const delta = typeof c11.text === "string" ? c11.text : "";
5607
- return {
5608
- type: "text-delta",
5609
- delta
5610
- };
5611
- }
5612
- case "reasoning-delta":
5613
- case "reasoning": {
5614
- const delta = getReasoningDeltaFromStreamChunk(c11);
5615
- if (delta === null)
5616
- return null;
5617
- return {
5618
- type: "reasoning-delta",
5619
- delta
5620
- };
5621
- }
5622
- case "tool-input-start": {
5623
- const args = extractToolArgs(c11);
5624
- const hasStableToolCallId = typeof c11.toolCallId === "string" && c11.toolCallId.trim().length > 0;
5625
- if (hasStableToolCallId && !hasRenderableToolArgs(args))
5626
- return null;
5627
- return {
5628
- type: "tool-call-start",
5629
- toolCallId: String(c11.toolCallId ?? ""),
5630
- toolName: String(c11.toolName ?? ""),
5631
- args
5632
- };
5633
- }
5634
- case "tool-call": {
5635
- return {
5636
- type: "tool-call-start",
5637
- toolCallId: String(c11.toolCallId ?? ""),
5638
- toolName: String(c11.toolName ?? ""),
5639
- args: extractToolArgs(c11)
5640
- };
5641
- }
5642
- case "tool-result": {
5643
- return {
5644
- type: "tool-result",
5645
- toolCallId: String(c11.toolCallId ?? ""),
5646
- toolName: String(c11.toolName ?? ""),
5647
- result: "output" in c11 ? c11.output : ("result" in c11) ? c11.result : undefined,
5648
- isError: "isError" in c11 ? Boolean(c11.isError) : false
5649
- };
5650
- }
5651
- case "tool-error":
5652
- return {
5653
- type: "tool-result",
5654
- toolCallId: String(c11.toolCallId ?? ""),
5655
- toolName: String(c11.toolName ?? ""),
5656
- result: c11.error ?? "Tool execution failed",
5657
- isError: true
5658
- };
5659
- case "error": {
5660
- throw normalizeUnknownError(c11.error);
5661
- }
5662
- default:
5663
- return null;
5664
- }
5665
- }
5666
-
5667
- // src/llm-api/turn-execution.ts
5668
- function isZodSchema(s) {
5669
- return s !== null && typeof s === "object" && "_def" in s;
5670
- }
5671
- function toCoreTool(def) {
5672
- const schema = isZodSchema(def.schema) ? def.schema : jsonSchema(def.schema);
5673
- return dynamicTool({
5674
- description: def.description,
5675
- inputSchema: schema,
5676
- execute: async (input) => {
5677
- try {
5678
- return await def.execute(input);
5679
- } catch (err) {
5680
- throw normalizeUnknownError(err);
5681
- }
5682
- }
5683
- });
5684
- }
5685
- function buildToolSet(tools) {
5686
- const toolSet = {};
5687
- for (const def of tools) {
5688
- toolSet[def.name] = toCoreTool(def);
5689
- }
5690
- return toolSet;
5691
- }
5692
- function createTurnStepTracker(opts) {
5693
- let stepCount = 0;
5694
- let inputTokens = 0;
5695
- let outputTokens = 0;
5696
- let contextTokens = 0;
5697
- let partialMessages = [];
5698
- return {
5699
- onStepFinish: (step) => {
5700
- opts.onStepLog({
5701
- stepNumber: stepCount + 1,
5702
- finishReason: step.finishReason,
5703
- usage: step.usage
5704
- });
5705
- inputTokens += step.usage?.inputTokens ?? 0;
5706
- outputTokens += step.usage?.outputTokens ?? 0;
5707
- contextTokens = step.usage?.inputTokens ?? contextTokens;
5708
- stepCount += 1;
5709
- const s = step;
5710
- partialMessages = s.response?.messages ?? s.messages ?? partialMessages;
5711
- },
5712
- getState: () => ({
5713
- stepCount,
5714
- inputTokens,
5715
- outputTokens,
5716
- contextTokens,
5717
- partialMessages
5718
- })
5719
- };
5720
- }
5721
- var TOOL_RESULT_CHUNK_TYPES = new Set(["tool-result", "tool-error"]);
5722
- function normalizeToolCallId(raw) {
5723
- if (typeof raw !== "string")
5724
- return null;
5725
- const trimmed = raw.trim();
5726
- return trimmed ? trimmed : null;
5727
- }
5728
- function normalizeToolName(raw) {
5729
- if (typeof raw !== "string")
5730
- return "tool";
5731
- const trimmed = raw.trim();
5732
- return trimmed || "tool";
5733
- }
5734
- function isRecord6(value) {
5735
- return value !== null && typeof value === "object";
5736
- }
5737
- function normalizeTextPartId(raw) {
5738
- if (typeof raw !== "string")
5739
- return null;
5740
- const trimmed = raw.trim();
5741
- return trimmed ? trimmed : null;
5742
- }
5743
- function getOpenAITextPhase2(chunk) {
5744
- const providerData = isRecord6(chunk.providerMetadata) ? chunk.providerMetadata : isRecord6(chunk.providerOptions) ? chunk.providerOptions : null;
5745
- if (!providerData)
5746
- return null;
5747
- const openai = providerData.openai;
5748
- if (!isRecord6(openai))
5749
- return null;
5750
- return openai.phase === "commentary" || openai.phase === "final_answer" ? openai.phase : null;
5751
- }
5752
- function extractTextDelta(chunk) {
5753
- if (typeof chunk.text === "string")
5754
- return chunk.text;
5755
- if (typeof chunk.textDelta === "string")
5756
- return chunk.textDelta;
5757
- if (typeof chunk.delta === "string")
5758
- return chunk.delta;
5759
- return "";
4882
+ const trimmed = raw.trim();
4883
+ return trimmed ? trimmed : null;
4884
+ }
4885
+ function getOpenAITextPhase2(chunk) {
4886
+ const providerData = isRecord5(chunk.providerMetadata) ? chunk.providerMetadata : isRecord5(chunk.providerOptions) ? chunk.providerOptions : null;
4887
+ if (!providerData)
4888
+ return null;
4889
+ const openai = providerData.openai;
4890
+ if (!isRecord5(openai))
4891
+ return null;
4892
+ return openai.phase === "commentary" || openai.phase === "final_answer" ? openai.phase : null;
4893
+ }
4894
+ function extractTextDelta(chunk) {
4895
+ if (typeof chunk.text === "string")
4896
+ return chunk.text;
4897
+ if (typeof chunk.textDelta === "string")
4898
+ return chunk.textDelta;
4899
+ if (typeof chunk.delta === "string")
4900
+ return chunk.delta;
4901
+ return "";
5760
4902
  }
5761
4903
 
5762
4904
  class StreamTextPhaseTracker {
@@ -5857,84 +4999,376 @@ class StreamToolCallTracker {
5857
4999
  }
5858
5000
  return { chunk, suppressTurnEvent: false };
5859
5001
  }
5860
- trackRenderableStart(chunk, toolName, existingToolCallId) {
5861
- const toolCallId = existingToolCallId ?? this.nextSyntheticToolCallId();
5862
- this.trackStart(toolName, toolCallId);
5863
- if (toolCallId === chunk.toolCallId)
5864
- return chunk;
5865
- return { ...chunk, toolCallId };
5002
+ trackRenderableStart(chunk, toolName, existingToolCallId) {
5003
+ const toolCallId = existingToolCallId ?? this.nextSyntheticToolCallId();
5004
+ this.trackStart(toolName, toolCallId);
5005
+ if (toolCallId === chunk.toolCallId)
5006
+ return chunk;
5007
+ return { ...chunk, toolCallId };
5008
+ }
5009
+ nextSyntheticToolCallId() {
5010
+ this.syntheticCount += 1;
5011
+ return `synthetic-tool-call-${this.syntheticCount}`;
5012
+ }
5013
+ trackStart(toolName, toolCallId) {
5014
+ const pending = this.pendingByTool.get(toolName) ?? [];
5015
+ pending.push(toolCallId);
5016
+ this.pendingByTool.set(toolName, pending);
5017
+ }
5018
+ trackDeferredStart(toolName) {
5019
+ this.deferredStartsByTool.set(toolName, (this.deferredStartsByTool.get(toolName) ?? 0) + 1);
5020
+ }
5021
+ consumeDeferredStart(toolName) {
5022
+ const count = this.deferredStartsByTool.get(toolName) ?? 0;
5023
+ if (count <= 0)
5024
+ return;
5025
+ if (count === 1) {
5026
+ this.deferredStartsByTool.delete(toolName);
5027
+ return;
5028
+ }
5029
+ this.deferredStartsByTool.set(toolName, count - 1);
5030
+ }
5031
+ consumeTracked(toolName, toolCallId) {
5032
+ const pending = this.pendingByTool.get(toolName);
5033
+ if (!pending || pending.length === 0)
5034
+ return;
5035
+ const idx = pending.indexOf(toolCallId);
5036
+ if (idx === -1)
5037
+ return;
5038
+ pending.splice(idx, 1);
5039
+ if (pending.length === 0)
5040
+ this.pendingByTool.delete(toolName);
5041
+ }
5042
+ consumeNextTracked(toolName) {
5043
+ const pending = this.pendingByTool.get(toolName);
5044
+ if (!pending || pending.length === 0)
5045
+ return null;
5046
+ const toolCallId = pending.shift() ?? null;
5047
+ if (pending.length === 0)
5048
+ this.pendingByTool.delete(toolName);
5049
+ return toolCallId;
5050
+ }
5051
+ }
5052
+ async function* mapFullStreamToTurnEvents(stream, opts) {
5053
+ const toolCallTracker = new StreamToolCallTracker;
5054
+ const textPhaseTracker = new StreamTextPhaseTracker;
5055
+ for await (const originalChunk of stream) {
5056
+ const prepared = toolCallTracker.prepare(originalChunk);
5057
+ const chunk = prepared.chunk;
5058
+ const route = textPhaseTracker.route(chunk);
5059
+ if (!prepared.suppressTurnEvent && route !== "skip" && shouldLogStreamChunk(chunk)) {
5060
+ opts.onChunk?.(chunk);
5061
+ }
5062
+ if (prepared.suppressTurnEvent || route === "skip")
5063
+ continue;
5064
+ const event = route === "reasoning" ? mapCommentaryChunkToTurnEvent(chunk) : mapStreamChunkToTurnEvent(chunk);
5065
+ if (event)
5066
+ yield event;
5067
+ }
5068
+ }
5069
+
5070
+ // src/llm-api/turn-request.ts
5071
+ import { stepCountIs } from "ai";
5072
+
5073
+ // src/llm-api/provider-options.ts
5074
+ var ANTHROPIC_BUDGET = {
5075
+ low: 4096,
5076
+ medium: 8192,
5077
+ high: 16384,
5078
+ xhigh: 32768
5079
+ };
5080
+ var GEMINI_BUDGET = {
5081
+ low: 4096,
5082
+ medium: 8192,
5083
+ high: 16384,
5084
+ xhigh: 24575
5085
+ };
5086
+ function clampEffort(effort, max) {
5087
+ const ORDER = ["low", "medium", "high", "xhigh"];
5088
+ const effortIdx = ORDER.indexOf(effort);
5089
+ const maxIdx = ORDER.indexOf(max);
5090
+ return ORDER[Math.min(effortIdx, maxIdx)];
5091
+ }
5092
+ function getAnthropicThinkingOptions(modelId, effort) {
5093
+ const isAdaptive = /^claude-3-7/.test(modelId) || /^claude-sonnet-4/.test(modelId) || /^claude-opus-4/.test(modelId);
5094
+ if (isAdaptive) {
5095
+ const isOpus = /^claude-opus-4/.test(modelId);
5096
+ const mapped = effort === "xhigh" ? isOpus ? "max" : "high" : effort;
5097
+ return { anthropic: { thinking: { type: "adaptive" }, effort: mapped } };
5098
+ }
5099
+ return {
5100
+ anthropic: {
5101
+ thinking: { type: "enabled", budgetTokens: ANTHROPIC_BUDGET[effort] },
5102
+ betas: ["interleaved-thinking-2025-05-14"]
5103
+ }
5104
+ };
5105
+ }
5106
+ function getOpenAIThinkingOptions(modelId, effort) {
5107
+ const supportsXhigh = /^gpt-5\.[2-9]/.test(modelId) || /^o4/.test(modelId);
5108
+ const clamped = supportsXhigh ? effort : clampEffort(effort, "high");
5109
+ return { openai: { reasoningEffort: clamped, reasoningSummary: "auto" } };
5110
+ }
5111
+ function getGeminiThinkingOptions(modelId, effort) {
5112
+ if (/^gemini-3/.test(modelId)) {
5113
+ return {
5114
+ google: {
5115
+ thinkingConfig: {
5116
+ includeThoughts: true,
5117
+ thinkingLevel: clampEffort(effort, "high")
5118
+ }
5119
+ }
5120
+ };
5121
+ }
5122
+ return {
5123
+ google: {
5124
+ thinkingConfig: {
5125
+ includeThoughts: true,
5126
+ thinkingBudget: GEMINI_BUDGET[effort]
5127
+ }
5128
+ }
5129
+ };
5130
+ }
5131
+ var THINKING_STRATEGIES = [
5132
+ {
5133
+ supports: isAnthropicModelFamily,
5134
+ build: getAnthropicThinkingOptions
5135
+ },
5136
+ {
5137
+ supports: isOpenAIReasoningModelFamily,
5138
+ build: getOpenAIThinkingOptions
5139
+ },
5140
+ {
5141
+ supports: isGeminiModelFamily,
5142
+ build: getGeminiThinkingOptions
5143
+ }
5144
+ ];
5145
+ function getThinkingProviderOptions(modelString, effort) {
5146
+ if (!supportsThinking(modelString))
5147
+ return null;
5148
+ const { modelId } = parseModelString(modelString);
5149
+ for (const strategy of THINKING_STRATEGIES) {
5150
+ if (!strategy.supports(modelString))
5151
+ continue;
5152
+ return strategy.build(modelId, effort);
5153
+ }
5154
+ return null;
5155
+ }
5156
+ var CACHE_FAMILY_RULES = [
5157
+ [isAnthropicModelFamily, "anthropic"],
5158
+ [isGeminiModelFamily, "google"]
5159
+ ];
5160
+ function getCacheFamily(modelString) {
5161
+ for (const [match, family] of CACHE_FAMILY_RULES) {
5162
+ if (match(modelString))
5163
+ return family;
5164
+ }
5165
+ return "none";
5166
+ }
5167
+ function getCachingProviderOptions(modelString, opts) {
5168
+ if (!opts.enabled)
5169
+ return null;
5170
+ const family = getCacheFamily(modelString);
5171
+ if (family === "google" && opts.googleCachedContent && opts.googleExplicitCachingCompatible !== false) {
5172
+ return { google: { cachedContent: opts.googleCachedContent } };
5173
+ }
5174
+ return null;
5175
+ }
5176
+
5177
+ // src/llm-api/turn-prepare-messages.ts
5178
+ function prepareTurnMessages(input) {
5179
+ const {
5180
+ messages,
5181
+ modelString,
5182
+ toolCount,
5183
+ systemPrompt,
5184
+ pruningMode,
5185
+ toolResultPayloadCapBytes,
5186
+ promptCachingEnabled
5187
+ } = input;
5188
+ const apiLogOn = isApiLogEnabled();
5189
+ const strippedRuntimeToolFields = stripToolRuntimeInputFields(messages);
5190
+ if (strippedRuntimeToolFields !== messages && apiLogOn) {
5191
+ logApiEvent("runtime tool input fields stripped", { modelString });
5192
+ }
5193
+ const geminiResult = sanitizeGeminiToolMessagesWithMetadata(strippedRuntimeToolFields, modelString, toolCount > 0);
5194
+ if (geminiResult.repaired && apiLogOn) {
5195
+ logApiEvent("gemini tool history repaired", {
5196
+ modelString,
5197
+ reason: geminiResult.reason,
5198
+ repairedFromIndex: geminiResult.repairedFromIndex,
5199
+ droppedMessageCount: geminiResult.droppedMessageCount,
5200
+ tailOnlyAffected: geminiResult.tailOnlyAffected
5201
+ });
5866
5202
  }
5867
- nextSyntheticToolCallId() {
5868
- this.syntheticCount += 1;
5869
- return `synthetic-tool-call-${this.syntheticCount}`;
5203
+ const openaiStripped = stripOpenAIHistoryTransforms(geminiResult.messages, modelString);
5204
+ if (openaiStripped !== geminiResult.messages && apiLogOn) {
5205
+ logApiEvent("openai history transforms applied", { modelString });
5870
5206
  }
5871
- trackStart(toolName, toolCallId) {
5872
- const pending = this.pendingByTool.get(toolName) ?? [];
5873
- pending.push(toolCallId);
5874
- this.pendingByTool.set(toolName, pending);
5207
+ const normalised = normalizeOpenAICompatibleToolCallInputs(openaiStripped, modelString);
5208
+ if (normalised !== openaiStripped && apiLogOn) {
5209
+ logApiEvent("openai-compatible tool input normalized", { modelString });
5875
5210
  }
5876
- trackDeferredStart(toolName) {
5877
- this.deferredStartsByTool.set(toolName, (this.deferredStartsByTool.get(toolName) ?? 0) + 1);
5211
+ const preStats = apiLogOn ? getMessageDiagnostics(normalised) : getMessageStats(normalised);
5212
+ if (apiLogOn)
5213
+ logApiEvent("turn context pre-prune", preStats);
5214
+ const pruned = applyContextPruning(normalised, pruningMode);
5215
+ const postStats = apiLogOn ? getMessageDiagnostics(pruned) : getMessageStats(pruned);
5216
+ if (apiLogOn)
5217
+ logApiEvent("turn context post-prune", postStats);
5218
+ const compacted = compactToolResultPayloads(pruned, toolResultPayloadCapBytes);
5219
+ if (compacted !== pruned && apiLogOn) {
5220
+ logApiEvent("turn context post-compaction", {
5221
+ capBytes: toolResultPayloadCapBytes,
5222
+ diagnostics: getMessageDiagnostics(compacted)
5223
+ });
5878
5224
  }
5879
- consumeDeferredStart(toolName) {
5880
- const count = this.deferredStartsByTool.get(toolName) ?? 0;
5881
- if (count <= 0)
5882
- return;
5883
- if (count === 1) {
5884
- this.deferredStartsByTool.delete(toolName);
5885
- return;
5225
+ let finalMessages = compacted;
5226
+ let finalSystemPrompt = systemPrompt;
5227
+ const cacheFamily = getCacheFamily(modelString);
5228
+ if (cacheFamily === "anthropic" && promptCachingEnabled) {
5229
+ const annotated = annotateAnthropicCacheBreakpoints(compacted, systemPrompt);
5230
+ finalMessages = annotated.messages;
5231
+ finalSystemPrompt = annotated.systemPrompt;
5232
+ if (apiLogOn) {
5233
+ logApiEvent("Anthropic prompt caching", annotated.diagnostics);
5886
5234
  }
5887
- this.deferredStartsByTool.set(toolName, count - 1);
5888
- }
5889
- consumeTracked(toolName, toolCallId) {
5890
- const pending = this.pendingByTool.get(toolName);
5891
- if (!pending || pending.length === 0)
5892
- return;
5893
- const idx = pending.indexOf(toolCallId);
5894
- if (idx === -1)
5895
- return;
5896
- pending.splice(idx, 1);
5897
- if (pending.length === 0)
5898
- this.pendingByTool.delete(toolName);
5899
5235
  }
5900
- consumeNextTracked(toolName) {
5901
- const pending = this.pendingByTool.get(toolName);
5902
- if (!pending || pending.length === 0)
5903
- return null;
5904
- const toolCallId = pending.shift() ?? null;
5905
- if (pending.length === 0)
5906
- this.pendingByTool.delete(toolName);
5907
- return toolCallId;
5236
+ if (isAnthropicModelFamily(modelString) && isAnthropicOAuth()) {
5237
+ const ccIdentity = "You are Claude Code, Anthropic's official CLI for Claude.";
5238
+ const ccSystemMsg = {
5239
+ role: "system",
5240
+ content: ccIdentity,
5241
+ providerOptions: {
5242
+ anthropic: { cacheControl: { type: "ephemeral" } }
5243
+ }
5244
+ };
5245
+ if (finalSystemPrompt) {
5246
+ finalMessages = [ccSystemMsg, ...finalMessages];
5247
+ } else {
5248
+ const sysIdx = finalMessages.findIndex((m) => m.role === "system");
5249
+ if (sysIdx >= 0) {
5250
+ finalMessages = [
5251
+ ...finalMessages.slice(0, sysIdx),
5252
+ ccSystemMsg,
5253
+ ...finalMessages.slice(sysIdx)
5254
+ ];
5255
+ } else {
5256
+ finalMessages = [ccSystemMsg, ...finalMessages];
5257
+ }
5258
+ }
5908
5259
  }
5260
+ const wasPruned = (pruningMode === "balanced" || pruningMode === "aggressive") && (postStats.messageCount < preStats.messageCount || postStats.totalBytes < preStats.totalBytes);
5261
+ return {
5262
+ messages: finalMessages,
5263
+ systemPrompt: finalSystemPrompt,
5264
+ pruned: wasPruned,
5265
+ prePruneMessageCount: preStats.messageCount,
5266
+ prePruneTotalBytes: preStats.totalBytes,
5267
+ postPruneMessageCount: postStats.messageCount,
5268
+ postPruneTotalBytes: postStats.totalBytes
5269
+ };
5909
5270
  }
5910
- async function* mapFullStreamToTurnEvents(stream, opts) {
5911
- const toolCallTracker = new StreamToolCallTracker;
5912
- const textPhaseTracker = new StreamTextPhaseTracker;
5913
- for await (const originalChunk of stream) {
5914
- const prepared = toolCallTracker.prepare(originalChunk);
5915
- const chunk = prepared.chunk;
5916
- const route = textPhaseTracker.route(chunk);
5917
- if (!prepared.suppressTurnEvent && route !== "skip" && shouldLogStreamChunk(chunk)) {
5918
- opts.onChunk?.(chunk);
5919
- }
5920
- if (prepared.suppressTurnEvent || route === "skip")
5921
- continue;
5922
- const event = route === "reasoning" ? mapCommentaryChunkToTurnEvent(chunk) : mapStreamChunkToTurnEvent(chunk);
5923
- if (event)
5924
- yield event;
5271
+
5272
+ // src/llm-api/turn-provider-options.ts
5273
+ function isRecord6(value) {
5274
+ return value !== null && typeof value === "object";
5275
+ }
5276
+ function mergeDeep(target, source) {
5277
+ const output = { ...target };
5278
+ for (const key in source) {
5279
+ const sVal = source[key];
5280
+ const tVal = target[key];
5281
+ output[key] = isRecord6(sVal) && isRecord6(tVal) ? { ...tVal, ...sVal } : sVal;
5925
5282
  }
5283
+ return output;
5284
+ }
5285
+ function buildTurnProviderOptions(input) {
5286
+ const {
5287
+ modelString,
5288
+ thinkingEffort,
5289
+ promptCachingEnabled,
5290
+ openaiPromptCacheRetention,
5291
+ googleCachedContent,
5292
+ toolCount,
5293
+ hasSystemPrompt
5294
+ } = input;
5295
+ const thinkingOpts = thinkingEffort ? getThinkingProviderOptions(modelString, thinkingEffort) : null;
5296
+ const reasoningSummaryRequested = isRecord6(thinkingOpts) && isRecord6(thinkingOpts.openai) && typeof thinkingOpts.openai.reasoningSummary === "string";
5297
+ const cacheFamily = getCacheFamily(modelString);
5298
+ const cacheOpts = getCachingProviderOptions(modelString, {
5299
+ enabled: promptCachingEnabled,
5300
+ openaiRetention: openaiPromptCacheRetention,
5301
+ googleCachedContent,
5302
+ googleExplicitCachingCompatible: toolCount === 0 && !hasSystemPrompt
5303
+ });
5304
+ const baseProviderOpts = {
5305
+ ...thinkingOpts ?? {},
5306
+ ...isOpenAIGPT(modelString) ? {
5307
+ openai: {
5308
+ store: false,
5309
+ ...isRecord6(thinkingOpts?.openai) ? thinkingOpts.openai : {}
5310
+ }
5311
+ } : {}
5312
+ };
5313
+ const providerOptions = cacheOpts ? mergeDeep(baseProviderOpts, cacheOpts) : baseProviderOpts;
5314
+ return {
5315
+ cacheFamily,
5316
+ thinkingOpts,
5317
+ cacheOpts,
5318
+ providerOptions,
5319
+ reasoningSummaryRequested
5320
+ };
5321
+ }
5322
+
5323
+ // src/llm-api/turn-request.ts
5324
+ function buildTurnPreparation(input) {
5325
+ const providerOptionsResult = buildTurnProviderOptions({
5326
+ modelString: input.modelString,
5327
+ thinkingEffort: input.thinkingEffort,
5328
+ promptCachingEnabled: input.promptCachingEnabled,
5329
+ openaiPromptCacheRetention: input.openaiPromptCacheRetention,
5330
+ googleCachedContent: input.googleCachedContent,
5331
+ toolCount: input.toolCount,
5332
+ hasSystemPrompt: Boolean(input.systemPrompt)
5333
+ });
5334
+ const prepared = prepareTurnMessages({
5335
+ messages: input.messages,
5336
+ modelString: input.modelString,
5337
+ toolCount: input.toolCount,
5338
+ systemPrompt: input.systemPrompt,
5339
+ pruningMode: input.pruningMode,
5340
+ toolResultPayloadCapBytes: input.toolResultPayloadCapBytes,
5341
+ promptCachingEnabled: input.promptCachingEnabled
5342
+ });
5343
+ return { providerOptionsResult, prepared };
5344
+ }
5345
+ function buildStreamTextRequest(input) {
5346
+ return {
5347
+ model: input.model,
5348
+ maxOutputTokens: 16384,
5349
+ messages: input.prepared.messages,
5350
+ tools: input.toolSet,
5351
+ stopWhen: stepCountIs(input.maxSteps),
5352
+ onStepFinish: input.onStepFinish,
5353
+ prepareStep: ({ stepNumber }) => {
5354
+ if (stepNumber >= input.maxSteps - 1) {
5355
+ return { activeTools: [] };
5356
+ }
5357
+ return;
5358
+ },
5359
+ ...input.prepared.systemPrompt ? { system: input.prepared.systemPrompt } : {},
5360
+ ...Object.keys(input.providerOptions).length > 0 ? {
5361
+ providerOptions: input.providerOptions
5362
+ } : {},
5363
+ ...input.signal ? { abortSignal: input.signal } : {},
5364
+ onError: () => {},
5365
+ timeout: { chunkMs: 120000 }
5366
+ };
5926
5367
  }
5927
5368
 
5928
5369
  // src/llm-api/turn.ts
5929
- var MAX_STEPS2 = 50;
5370
+ var MAX_STEPS = 50;
5930
5371
  async function* runTurn(options) {
5931
- if (options.modelString.startsWith("anthropic/") && isLoggedIn("anthropic")) {
5932
- const token = await getAccessToken("anthropic");
5933
- if (token) {
5934
- yield* runTurnAnthropicOAuth({ ...options, token });
5935
- return;
5936
- }
5937
- }
5938
5372
  const {
5939
5373
  model,
5940
5374
  modelString,
@@ -6006,7 +5440,7 @@ async function* runTurn(options) {
6006
5440
  onStepFinish: stepTracker.onStepFinish,
6007
5441
  signal,
6008
5442
  providerOptions: providerOptionsResult.providerOptions,
6009
- maxSteps: MAX_STEPS2
5443
+ maxSteps: MAX_STEPS
6010
5444
  }));
6011
5445
  result.response.catch(() => {});
6012
5446
  for await (const event of mapFullStreamToTurnEvents(result.fullStream, {
@@ -6049,7 +5483,7 @@ async function* runTurn(options) {
6049
5483
  }
6050
5484
 
6051
5485
  // src/session/manager.ts
6052
- import * as c11 from "yoctocolors";
5486
+ import * as c10 from "yoctocolors";
6053
5487
  function newSession(model, cwd) {
6054
5488
  const id = generateSessionId();
6055
5489
  const row = createSession({ id, cwd, model });
@@ -6068,19 +5502,19 @@ function touchActiveSession(session) {
6068
5502
  function printSessionList() {
6069
5503
  const sessions = listSessions(20);
6070
5504
  if (sessions.length === 0) {
6071
- writeln2(c11.dim("No sessions found."));
5505
+ writeln(c10.dim("No sessions found."));
6072
5506
  return;
6073
5507
  }
6074
- writeln2(`
6075
- ${c11.bold("Recent sessions:")}`);
5508
+ writeln(`
5509
+ ${c10.bold("Recent sessions:")}`);
6076
5510
  for (const s of sessions) {
6077
5511
  const date = new Date(s.updated_at).toLocaleString();
6078
5512
  const cwd = tildePath(s.cwd);
6079
- const title = s.title || c11.dim("(untitled)");
6080
- writeln2(` ${c11.dim(s.id.padEnd(14))} ${title.padEnd(30)} ${c11.cyan(s.model.split("/").pop() ?? s.model).padEnd(20)} ${c11.dim(cwd)} ${c11.dim(date)}`);
5513
+ const title = s.title || c10.dim("(untitled)");
5514
+ writeln(` ${c10.dim(s.id.padEnd(14))} ${title.padEnd(30)} ${c10.cyan(s.model.split("/").pop() ?? s.model).padEnd(20)} ${c10.dim(cwd)} ${c10.dim(date)}`);
6081
5515
  }
6082
- writeln2(`
6083
- ${c11.dim("Use")} mc --resume <id> ${c11.dim("to continue a session.")}`);
5516
+ writeln(`
5517
+ ${c10.dim("Use")} mc --resume <id> ${c10.dim("to continue a session.")}`);
6084
5518
  }
6085
5519
  function getMostRecentSession() {
6086
5520
  const sessions = listSessions(1);
@@ -6310,7 +5744,7 @@ class SessionRunner {
6310
5744
  }
6311
5745
  this.session = resumed;
6312
5746
  this.currentModel = this.session.model;
6313
- this.reporter.info(`Resumed session ${this.session.id} (${c12.cyan(this.currentModel)})`);
5747
+ this.reporter.info(`Resumed session ${this.session.id} (${c11.cyan(this.currentModel)})`);
6314
5748
  } else {
6315
5749
  this.session = newSession(this.currentModel, this.cwd);
6316
5750
  }
@@ -6774,13 +6208,12 @@ ${input.command}`], {
6774
6208
  reader.cancel().catch(() => {});
6775
6209
  }
6776
6210
  }, timeout);
6777
- async function collectStream(stream, onChunk) {
6211
+ async function collectStream(stream) {
6778
6212
  const reader = stream.getReader();
6779
6213
  readers.push(reader);
6780
6214
  const chunks = [];
6781
6215
  let totalBytes = 0;
6782
6216
  let truncated = false;
6783
- const decoder = new TextDecoder;
6784
6217
  while (true) {
6785
6218
  try {
6786
6219
  const { done, value } = await reader.read();
@@ -6788,7 +6221,6 @@ ${input.command}`], {
6788
6221
  break;
6789
6222
  if (!value)
6790
6223
  continue;
6791
- onChunk?.(decoder.decode(value, { stream: true }));
6792
6224
  if (totalBytes + value.length > MAX_OUTPUT_BYTES) {
6793
6225
  chunks.push(value.slice(0, MAX_OUTPUT_BYTES - totalBytes));
6794
6226
  truncated = true;
@@ -6808,28 +6240,11 @@ ${input.command}`], {
6808
6240
  let stdout = "";
6809
6241
  let stderr = "";
6810
6242
  let exitCode = 1;
6811
- const onOutput = input.onOutput;
6812
- const hasOutputHandler = typeof onOutput === "function";
6813
- let streamedAnyOutput = false;
6814
- let streamedEndsWithNewline = true;
6815
- const emitOutput = (chunk) => {
6816
- if (!chunk || !hasOutputHandler)
6817
- return;
6818
- const handled = onOutput(chunk);
6819
- if (handled === false)
6820
- return;
6821
- streamedAnyOutput = true;
6822
- streamedEndsWithNewline = /[\r\n]$/.test(chunk);
6823
- };
6824
6243
  try {
6825
6244
  [stdout, stderr] = await Promise.all([
6826
- collectStream(proc.stdout, hasOutputHandler ? emitOutput : undefined),
6827
- collectStream(proc.stderr, hasOutputHandler ? emitOutput : undefined)
6245
+ collectStream(proc.stdout),
6246
+ collectStream(proc.stderr)
6828
6247
  ]);
6829
- if (streamedAnyOutput && !streamedEndsWithNewline) {
6830
- emitOutput(`
6831
- `);
6832
- }
6833
6248
  exitCode = await proc.exited;
6834
6249
  } finally {
6835
6250
  clearTimeout(timer);
@@ -6845,8 +6260,7 @@ ${input.command}`], {
6845
6260
  stderr: stderr.trimEnd(),
6846
6261
  exitCode,
6847
6262
  success: exitCode === 0,
6848
- timedOut,
6849
- streamedOutput: streamedAnyOutput
6263
+ timedOut
6850
6264
  };
6851
6265
  }
6852
6266
  var shellTool = {
@@ -6919,22 +6333,9 @@ function withCwdDefault(tool, cwd) {
6919
6333
  }
6920
6334
  };
6921
6335
  }
6922
- function withShellOutput(tool, onOutput) {
6923
- const originalExecute = tool.execute;
6924
- return {
6925
- ...tool,
6926
- execute: async (input) => {
6927
- const patched = {
6928
- ...typeof input === "object" && input !== null ? input : {},
6929
- onOutput
6930
- };
6931
- return originalExecute(patched);
6932
- }
6933
- };
6934
- }
6935
6336
  function buildToolSet2(opts) {
6936
- const { cwd, onShellOutput } = opts;
6937
- const shell = onShellOutput ? withShellOutput(withCwdDefault(shellTool, cwd), onShellOutput) : withCwdDefault(shellTool, cwd);
6337
+ const { cwd } = opts;
6338
+ const shell = withCwdDefault(shellTool, cwd);
6938
6339
  const tools = [
6939
6340
  shell,
6940
6341
  withCwdDefault(listSkillsTool, cwd),
@@ -6963,17 +6364,10 @@ async function initAgent(opts) {
6963
6364
  const cwd = opts.cwd;
6964
6365
  let currentModel = opts.model;
6965
6366
  const { runSubagent, killAll } = createSubagentRunner(cwd, () => currentModel);
6966
- let verboseOutputEnabled = opts.initialVerboseOutput;
6967
6367
  const agents = loadAgents(cwd);
6968
6368
  const tools = buildToolSet2({
6969
6369
  cwd,
6970
6370
  runSubagent,
6971
- onShellOutput: (chunk) => {
6972
- if (!verboseOutputEnabled)
6973
- return false;
6974
- opts.reporter.streamChunk(chunk);
6975
- return true;
6976
- },
6977
6371
  availableAgents: subagentAgents(agents)
6978
6372
  });
6979
6373
  const mcpTools = [];
@@ -6997,7 +6391,7 @@ async function initAgent(opts) {
6997
6391
  for (const row of listMcpServers()) {
6998
6392
  try {
6999
6393
  await connectAndAddMcp(row.name);
7000
- opts.reporter.info(`MCP: connected ${c13.cyan(row.name)}`);
6394
+ opts.reporter.info(`MCP: connected ${c12.cyan(row.name)}`);
7001
6395
  } catch (e) {
7002
6396
  opts.reporter.error(`MCP: failed to connect ${row.name}: ${String(e)}`);
7003
6397
  }
@@ -7062,7 +6456,6 @@ async function initAgent(opts) {
7062
6456
  },
7063
6457
  setVerboseOutput: (verbose) => {
7064
6458
  runner.verboseOutput = verbose;
7065
- verboseOutputEnabled = verbose;
7066
6459
  setPreferredVerboseOutput(verbose);
7067
6460
  },
7068
6461
  get pruningMode() {
@@ -7120,12 +6513,12 @@ async function initAgent(opts) {
7120
6513
  }
7121
6514
 
7122
6515
  // src/cli/args.ts
7123
- import * as c14 from "yoctocolors";
6516
+ import * as c13 from "yoctocolors";
7124
6517
  function parseArgs(argv) {
7125
6518
  const args = {
7126
6519
  model: null,
7127
6520
  sessionId: null,
7128
- listSessions: false,
6521
+ list: false,
7129
6522
  resumeLast: false,
7130
6523
  prompt: null,
7131
6524
  cwd: process.cwd(),
@@ -7152,7 +6545,7 @@ function parseArgs(argv) {
7152
6545
  break;
7153
6546
  case "--list":
7154
6547
  case "-l":
7155
- args.listSessions = true;
6548
+ args.list = true;
7156
6549
  break;
7157
6550
  case "--cwd":
7158
6551
  args.cwd = argv[++i] ?? process.cwd();
@@ -7184,11 +6577,11 @@ function parseArgs(argv) {
7184
6577
  return args;
7185
6578
  }
7186
6579
  function printHelp() {
7187
- writeln2(`${c14.bold("mini-coder")} \u2014 a small, fast CLI coding agent
6580
+ writeln(`${c13.bold("mini-coder")} \u2014 a small, fast CLI coding agent
7188
6581
  `);
7189
- writeln2(`${c14.bold("Usage:")} mc [options] [prompt]
6582
+ writeln(`${c13.bold("Usage:")} mc [options] [prompt]
7190
6583
  `);
7191
- writeln2(`${c14.bold("Options:")}`);
6584
+ writeln(`${c13.bold("Options:")}`);
7192
6585
  const opts = [
7193
6586
  ["-m, --model <id>", "Model to use (e.g. zen/claude-sonnet-4-6)"],
7194
6587
  ["-c, --continue", "Continue the most recent session"],
@@ -7198,10 +6591,10 @@ function printHelp() {
7198
6591
  ["-h, --help", "Show this help"]
7199
6592
  ];
7200
6593
  for (const [flag, desc] of opts) {
7201
- writeln2(` ${c14.cyan((flag ?? "").padEnd(22))} ${c14.dim(desc ?? "")}`);
6594
+ writeln(` ${c13.cyan((flag ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
7202
6595
  }
7203
- writeln2(`
7204
- ${c14.bold("Provider env vars:")}`);
6596
+ writeln(`
6597
+ ${c13.bold("Provider env vars:")}`);
7205
6598
  const envs = [
7206
6599
  ["OPENCODE_API_KEY", "OpenCode Zen (recommended)"],
7207
6600
  ["ANTHROPIC_API_KEY", "Anthropic direct"],
@@ -7212,22 +6605,22 @@ ${c14.bold("Provider env vars:")}`);
7212
6605
  ["OLLAMA_BASE_URL", "Ollama base URL (default: http://localhost:11434)"]
7213
6606
  ];
7214
6607
  for (const [env, desc] of envs) {
7215
- writeln2(` ${c14.yellow((env ?? "").padEnd(22))} ${c14.dim(desc ?? "")}`);
6608
+ writeln(` ${c13.yellow((env ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
7216
6609
  }
7217
- writeln2(`
7218
- ${c14.bold("Examples:")}`);
7219
- writeln2(` mc ${c14.dim("# interactive session")}`);
7220
- writeln2(` mc "explain this codebase" ${c14.dim("# one-shot prompt then exit")}`);
7221
- writeln2(` mc -c ${c14.dim("# continue last session")}`);
7222
- writeln2(` mc -m ollama/llama3.2 ${c14.dim("# use local Ollama model")}`);
7223
- writeln2(` mc -l ${c14.dim("# list sessions")}`);
6610
+ writeln(`
6611
+ ${c13.bold("Examples:")}`);
6612
+ writeln(` mc ${c13.dim("# interactive session")}`);
6613
+ writeln(` mc "explain this codebase" ${c13.dim("# one-shot prompt then exit")}`);
6614
+ writeln(` mc -c ${c13.dim("# continue last session")}`);
6615
+ writeln(` mc -m ollama/llama3.2 ${c13.dim("# use local Ollama model")}`);
6616
+ writeln(` mc -l ${c13.dim("# list sessions")}`);
7224
6617
  }
7225
6618
 
7226
6619
  // src/cli/bootstrap.ts
7227
6620
  import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
7228
6621
  import { homedir as homedir8 } from "os";
7229
6622
  import { join as join12 } from "path";
7230
- import * as c15 from "yoctocolors";
6623
+ import * as c14 from "yoctocolors";
7231
6624
  var REVIEW_COMMAND_CONTENT = `---
7232
6625
  description: Review recent changes for correctness, code quality, and performance
7233
6626
  context: fork
@@ -7251,7 +6644,7 @@ function bootstrapGlobalDefaults() {
7251
6644
  if (!existsSync8(reviewPath)) {
7252
6645
  mkdirSync4(commandsDir, { recursive: true });
7253
6646
  writeFileSync3(reviewPath, REVIEW_COMMAND_CONTENT, "utf-8");
7254
- writeln2(`${c15.green("\u2713")} created ${c15.dim("~/.agents/commands/review.md")} ${c15.dim("(edit it to customise your reviews)")}`);
6647
+ writeln(`${c14.green("\u2713")} created ${c14.dim("~/.agents/commands/review.md")} ${c14.dim("(edit it to customise your reviews)")}`);
7255
6648
  }
7256
6649
  }
7257
6650
 
@@ -7316,7 +6709,6 @@ class HeadlessReporter {
7316
6709
  error(_msg, _hint) {}
7317
6710
  warn(_msg) {}
7318
6711
  writeText(_text) {}
7319
- streamChunk(_text) {}
7320
6712
  startSpinner(_label) {}
7321
6713
  stopSpinner() {}
7322
6714
  async renderTurn(events, _opts) {
@@ -7366,7 +6758,7 @@ class HeadlessReporter {
7366
6758
  }
7367
6759
 
7368
6760
  // src/cli/input-loop.ts
7369
- import * as c23 from "yoctocolors";
6761
+ import * as c22 from "yoctocolors";
7370
6762
 
7371
6763
  // src/cli/cli-helpers.ts
7372
6764
  async function getGitBranch(cwd) {
@@ -7387,67 +6779,67 @@ async function getGitBranch(cwd) {
7387
6779
  }
7388
6780
 
7389
6781
  // src/cli/commands.ts
7390
- import * as c22 from "yoctocolors";
6782
+ import * as c21 from "yoctocolors";
7391
6783
 
7392
6784
  // src/cli/commands-agent.ts
7393
- import * as c16 from "yoctocolors";
6785
+ import * as c15 from "yoctocolors";
7394
6786
  function handleAgentCommand(ctx, args) {
7395
6787
  const raw = args.trim();
7396
6788
  const agents = loadAgents(ctx.cwd);
7397
6789
  if (!raw) {
7398
6790
  if (agents.size === 0) {
7399
- writeln2(c16.dim(" no agents found (~/.agents/agents/ or .agents/agents/)"));
7400
- writeln2(c16.dim(" /agent <name> to activate \xB7 /agent off to deactivate"));
6791
+ writeln(c15.dim(" no agents found (~/.agents/agents/ or .agents/agents/)"));
6792
+ writeln(c15.dim(" /agent <name> to activate \xB7 /agent off to deactivate"));
7401
6793
  return;
7402
6794
  }
7403
- writeln2();
7404
- writeln2(c16.dim(" agents:"));
6795
+ writeln();
6796
+ writeln(c15.dim(" agents:"));
7405
6797
  for (const agent2 of agents.values()) {
7406
- const modeTag = agent2.mode ? c16.dim(` [${agent2.mode}]`) : "";
7407
- const srcTag = agent2.source === "local" ? c16.dim(" (local)") : c16.dim(" (global)");
7408
- const active = ctx.activeAgent === agent2.name ? c16.cyan(" \u25C0 active") : "";
7409
- writeln2(` ${c16.magenta(`@${agent2.name}`.padEnd(26))} ${c16.dim(agent2.description)}${modeTag}${srcTag}${active}`);
7410
- }
7411
- writeln2();
7412
- writeln2(c16.dim(" /agent <name> to activate \xB7 /agent off to deactivate"));
7413
- writeln2();
6798
+ const modeTag = agent2.mode ? c15.dim(` [${agent2.mode}]`) : "";
6799
+ const srcTag = agent2.source === "local" ? c15.dim(" (local)") : c15.dim(" (global)");
6800
+ const active = ctx.activeAgent === agent2.name ? c15.cyan(" \u25C0 active") : "";
6801
+ writeln(` ${c15.magenta(`@${agent2.name}`.padEnd(26))} ${c15.dim(agent2.description)}${modeTag}${srcTag}${active}`);
6802
+ }
6803
+ writeln();
6804
+ writeln(c15.dim(" /agent <name> to activate \xB7 /agent off to deactivate"));
6805
+ writeln();
7414
6806
  return;
7415
6807
  }
7416
6808
  if (raw.toLowerCase() === "off" || raw.toLowerCase() === "none") {
7417
6809
  ctx.setActiveAgent(null);
7418
- writeln2(`${PREFIX.info} ${c16.dim("active agent cleared")}`);
6810
+ writeln(`${PREFIX.info} ${c15.dim("active agent cleared")}`);
7419
6811
  return;
7420
6812
  }
7421
6813
  const agent = agents.get(raw);
7422
6814
  if (!agent) {
7423
- writeln2(`${PREFIX.error} agent ${c16.cyan(raw)} not found`);
6815
+ writeln(`${PREFIX.error} agent ${c15.cyan(raw)} not found`);
7424
6816
  return;
7425
6817
  }
7426
6818
  ctx.setActiveAgent(raw, agent.systemPrompt);
7427
- writeln2(`${PREFIX.success} active agent \u2192 ${c16.cyan(raw)} ${c16.dim("(instructions appended to system prompt)")}`);
6819
+ writeln(`${PREFIX.success} active agent \u2192 ${c15.cyan(raw)} ${c15.dim("(instructions appended to system prompt)")}`);
7428
6820
  }
7429
6821
 
7430
6822
  // src/cli/commands-config.ts
7431
- import * as c17 from "yoctocolors";
6823
+ import * as c16 from "yoctocolors";
7432
6824
  function handleBooleanToggleCommand(opts) {
7433
6825
  const mode = opts.args.trim().toLowerCase();
7434
6826
  if (!mode) {
7435
6827
  const nextValue = !opts.current;
7436
6828
  opts.set(nextValue);
7437
- writeln2(`${PREFIX.success} ${opts.label} ${nextValue ? c17.green("on") : c17.dim("off")}`);
6829
+ writeln(`${PREFIX.success} ${opts.label} ${nextValue ? c16.green("on") : c16.dim("off")}`);
7438
6830
  return;
7439
6831
  }
7440
6832
  if (mode === "on") {
7441
6833
  opts.set(true);
7442
- writeln2(`${PREFIX.success} ${opts.label} ${c17.green("on")}`);
6834
+ writeln(`${PREFIX.success} ${opts.label} ${c16.green("on")}`);
7443
6835
  return;
7444
6836
  }
7445
6837
  if (mode === "off") {
7446
6838
  opts.set(false);
7447
- writeln2(`${PREFIX.success} ${opts.label} ${c17.dim("off")}`);
6839
+ writeln(`${PREFIX.success} ${opts.label} ${c16.dim("off")}`);
7448
6840
  return;
7449
6841
  }
7450
- writeln2(`${PREFIX.error} usage: ${opts.usage}`);
6842
+ writeln(`${PREFIX.error} usage: ${opts.usage}`);
7451
6843
  }
7452
6844
  function handleReasoningCommand(ctx, args) {
7453
6845
  handleBooleanToggleCommand({
@@ -7471,105 +6863,105 @@ function handleContextCommand(ctx, args) {
7471
6863
  const [subcommand, value] = args.trim().split(/\s+/, 2);
7472
6864
  if (!subcommand) {
7473
6865
  const capText = ctx.toolResultPayloadCapBytes <= 0 ? "off" : `${Math.round(ctx.toolResultPayloadCapBytes / 1024)}KB (${ctx.toolResultPayloadCapBytes} bytes)`;
7474
- writeln2(`${PREFIX.info} pruning=${c17.cyan(ctx.pruningMode)} tool-result-cap=${c17.cyan(capText)}`);
7475
- writeln2(c17.dim(" usage: /context prune <off|balanced|aggressive>"));
7476
- writeln2(c17.dim(" /context cap <off|bytes|kb>"));
6866
+ writeln(`${PREFIX.info} pruning=${c16.cyan(ctx.pruningMode)} tool-result-cap=${c16.cyan(capText)}`);
6867
+ writeln(c16.dim(" usage: /context prune <off|balanced|aggressive>"));
6868
+ writeln(c16.dim(" /context cap <off|bytes|kb>"));
7477
6869
  return;
7478
6870
  }
7479
6871
  if (subcommand === "prune") {
7480
6872
  if (value === "off" || value === "balanced" || value === "aggressive") {
7481
6873
  ctx.setPruningMode(value);
7482
- writeln2(`${PREFIX.success} context pruning \u2192 ${c17.cyan(value)}`);
6874
+ writeln(`${PREFIX.success} context pruning \u2192 ${c16.cyan(value)}`);
7483
6875
  return;
7484
6876
  }
7485
- writeln2(`${PREFIX.error} usage: /context prune <off|balanced|aggressive>`);
6877
+ writeln(`${PREFIX.error} usage: /context prune <off|balanced|aggressive>`);
7486
6878
  return;
7487
6879
  }
7488
6880
  if (subcommand !== "cap") {
7489
- writeln2(`${PREFIX.error} usage: /context <prune|cap> ...`);
6881
+ writeln(`${PREFIX.error} usage: /context <prune|cap> ...`);
7490
6882
  return;
7491
6883
  }
7492
6884
  if (!value) {
7493
- writeln2(`${PREFIX.error} usage: /context cap <off|bytes|kb>`);
6885
+ writeln(`${PREFIX.error} usage: /context cap <off|bytes|kb>`);
7494
6886
  return;
7495
6887
  }
7496
6888
  if (value === "off") {
7497
6889
  ctx.setToolResultPayloadCapBytes(0);
7498
- writeln2(`${PREFIX.success} tool-result payload cap disabled`);
6890
+ writeln(`${PREFIX.success} tool-result payload cap disabled`);
7499
6891
  return;
7500
6892
  }
7501
6893
  const capMatch = value.match(/^(\d+)(kb)?$/i);
7502
6894
  if (!capMatch) {
7503
- writeln2(`${PREFIX.error} invalid cap: ${c17.cyan(value)}`);
6895
+ writeln(`${PREFIX.error} invalid cap: ${c16.cyan(value)}`);
7504
6896
  return;
7505
6897
  }
7506
6898
  const base = Number.parseInt(capMatch[1] ?? "", 10);
7507
6899
  const capBytes = (capMatch[2] ?? "").toLowerCase() === "kb" ? base * 1024 : base;
7508
6900
  if (!Number.isFinite(capBytes) || capBytes < 0) {
7509
- writeln2(`${PREFIX.error} invalid cap: ${c17.cyan(value)}`);
6901
+ writeln(`${PREFIX.error} invalid cap: ${c16.cyan(value)}`);
7510
6902
  return;
7511
6903
  }
7512
6904
  ctx.setToolResultPayloadCapBytes(capBytes);
7513
- writeln2(`${PREFIX.success} tool-result payload cap \u2192 ${c17.cyan(`${capBytes} bytes`)}`);
6905
+ writeln(`${PREFIX.success} tool-result payload cap \u2192 ${c16.cyan(`${capBytes} bytes`)}`);
7514
6906
  }
7515
6907
  function handleCacheCommand(ctx, args) {
7516
6908
  const [subcommand, value] = args.trim().split(/\s+/, 2);
7517
6909
  if (!subcommand) {
7518
- const geminiCache = ctx.googleCachedContent ? c17.cyan(ctx.googleCachedContent) : "off";
7519
- writeln2(`${PREFIX.info} prompt-caching=${ctx.promptCachingEnabled ? c17.green("on") : c17.dim("off")} openai-retention=${c17.cyan(ctx.openaiPromptCacheRetention)} gemini-cache=${geminiCache}`);
7520
- writeln2(c17.dim(" usage: /cache <on|off>"));
7521
- writeln2(c17.dim(" /cache openai <in_memory|24h>"));
7522
- writeln2(c17.dim(" /cache gemini <off|cachedContents/...>"));
6910
+ const geminiCache = ctx.googleCachedContent ? c16.cyan(ctx.googleCachedContent) : "off";
6911
+ writeln(`${PREFIX.info} prompt-caching=${ctx.promptCachingEnabled ? c16.green("on") : c16.dim("off")} openai-retention=${c16.cyan(ctx.openaiPromptCacheRetention)} gemini-cache=${geminiCache}`);
6912
+ writeln(c16.dim(" usage: /cache <on|off>"));
6913
+ writeln(c16.dim(" /cache openai <in_memory|24h>"));
6914
+ writeln(c16.dim(" /cache gemini <off|cachedContents/...>"));
7523
6915
  return;
7524
6916
  }
7525
6917
  if (subcommand === "on" || subcommand === "off") {
7526
6918
  ctx.setPromptCachingEnabled(subcommand === "on");
7527
- writeln2(`${PREFIX.success} prompt caching \u2192 ${subcommand === "on" ? c17.green("on") : c17.dim("off")}`);
6919
+ writeln(`${PREFIX.success} prompt caching \u2192 ${subcommand === "on" ? c16.green("on") : c16.dim("off")}`);
7528
6920
  return;
7529
6921
  }
7530
6922
  if (subcommand === "openai") {
7531
6923
  if (value === "in_memory" || value === "24h") {
7532
6924
  ctx.setOpenAIPromptCacheRetention(value);
7533
- writeln2(`${PREFIX.success} openai prompt cache retention \u2192 ${c17.cyan(value)}`);
6925
+ writeln(`${PREFIX.success} openai prompt cache retention \u2192 ${c16.cyan(value)}`);
7534
6926
  return;
7535
6927
  }
7536
- writeln2(`${PREFIX.error} usage: /cache openai <in_memory|24h>`);
6928
+ writeln(`${PREFIX.error} usage: /cache openai <in_memory|24h>`);
7537
6929
  return;
7538
6930
  }
7539
6931
  if (subcommand !== "gemini") {
7540
- writeln2(`${PREFIX.error} usage: /cache <on|off|openai|gemini> ...`);
6932
+ writeln(`${PREFIX.error} usage: /cache <on|off|openai|gemini> ...`);
7541
6933
  return;
7542
6934
  }
7543
6935
  if (!value) {
7544
- writeln2(`${PREFIX.error} usage: /cache gemini <off|cachedContents/...>`);
6936
+ writeln(`${PREFIX.error} usage: /cache gemini <off|cachedContents/...>`);
7545
6937
  return;
7546
6938
  }
7547
6939
  if (value === "off") {
7548
6940
  ctx.setGoogleCachedContent(null);
7549
- writeln2(`${PREFIX.success} gemini cached content \u2192 ${c17.dim("off")}`);
6941
+ writeln(`${PREFIX.success} gemini cached content \u2192 ${c16.dim("off")}`);
7550
6942
  return;
7551
6943
  }
7552
6944
  ctx.setGoogleCachedContent(value);
7553
- writeln2(`${PREFIX.success} gemini cached content \u2192 ${c17.cyan(value)}`);
6945
+ writeln(`${PREFIX.success} gemini cached content \u2192 ${c16.cyan(value)}`);
7554
6946
  }
7555
6947
 
7556
6948
  // src/cli/commands-help.ts
7557
- import * as c18 from "yoctocolors";
6949
+ import * as c17 from "yoctocolors";
7558
6950
  function renderEntries(entries) {
7559
6951
  for (const [label, description] of entries) {
7560
- writeln2(` ${c18.cyan(label.padEnd(28))} ${c18.dim(description)}`);
6952
+ writeln(` ${c17.cyan(label.padEnd(28))} ${c17.dim(description)}`);
7561
6953
  }
7562
6954
  }
7563
6955
  function renderHelpCommand(ctx, custom) {
7564
- writeln2();
7565
- writeln2(` ${c18.dim("session")}`);
6956
+ writeln();
6957
+ writeln(` ${c17.dim("session")}`);
7566
6958
  renderEntries([
7567
6959
  ["/new", "start a fresh session"],
7568
6960
  ["/undo", "remove the last conversation turn"],
7569
6961
  ["/exit", "quit"]
7570
6962
  ]);
7571
- writeln2();
7572
- writeln2(` ${c18.dim("model + context")}`);
6963
+ writeln();
6964
+ writeln(` ${c17.dim("model + context")}`);
7573
6965
  renderEntries([
7574
6966
  ["/model [id]", "list or switch models"],
7575
6967
  ["/reasoning [on|off]", "toggle reasoning display"],
@@ -7584,8 +6976,8 @@ function renderHelpCommand(ctx, custom) {
7584
6976
  ["/logout <provider>", "clear OAuth tokens"],
7585
6977
  ["/help", "show this help"]
7586
6978
  ]);
7587
- writeln2();
7588
- writeln2(` ${c18.dim("prompt")}`);
6979
+ writeln();
6980
+ writeln(` ${c17.dim("prompt")}`);
7589
6981
  renderEntries([
7590
6982
  ["ask normally", "send a prompt to the current agent"],
7591
6983
  ["!cmd", "run a shell command and keep the result in context"],
@@ -7593,63 +6985,63 @@ function renderHelpCommand(ctx, custom) {
7593
6985
  ["@skill", "inject a skill into the prompt (Tab to complete)"]
7594
6986
  ]);
7595
6987
  if (custom.size > 0) {
7596
- writeln2();
7597
- writeln2(` ${c18.dim("custom commands")}`);
6988
+ writeln();
6989
+ writeln(` ${c17.dim("custom commands")}`);
7598
6990
  for (const cmd of custom.values()) {
7599
- const source = cmd.source === "local" ? c18.dim("local") : c18.dim("global");
7600
- writeln2(` ${c18.green(`/${cmd.name}`.padEnd(28))} ${c18.dim(cmd.description)} ${c18.dim("\xB7")} ${source}`);
6991
+ const source = cmd.source === "local" ? c17.dim("local") : c17.dim("global");
6992
+ writeln(` ${c17.green(`/${cmd.name}`.padEnd(28))} ${c17.dim(cmd.description)} ${c17.dim("\xB7")} ${source}`);
7601
6993
  }
7602
6994
  }
7603
6995
  const agents = loadAgents(ctx.cwd);
7604
6996
  if (agents.size > 0) {
7605
- writeln2();
7606
- writeln2(` ${c18.dim("agents")}`);
6997
+ writeln();
6998
+ writeln(` ${c17.dim("agents")}`);
7607
6999
  for (const agent of agents.values()) {
7608
- const mode = agent.mode ? c18.dim(agent.mode) : c18.dim("agent");
7609
- const source = agent.source === "local" ? c18.dim("local") : c18.dim("global");
7610
- writeln2(` ${c18.magenta(agent.name.padEnd(28))} ${c18.dim(agent.description)} ${c18.dim("\xB7")} ${mode} ${c18.dim("\xB7")} ${source}`);
7000
+ const mode = agent.mode ? c17.dim(agent.mode) : c17.dim("agent");
7001
+ const source = agent.source === "local" ? c17.dim("local") : c17.dim("global");
7002
+ writeln(` ${c17.magenta(agent.name.padEnd(28))} ${c17.dim(agent.description)} ${c17.dim("\xB7")} ${mode} ${c17.dim("\xB7")} ${source}`);
7611
7003
  }
7612
7004
  }
7613
7005
  const skills = loadSkillsIndex(ctx.cwd);
7614
7006
  if (skills.size > 0) {
7615
- writeln2();
7616
- writeln2(` ${c18.dim("skills")}`);
7007
+ writeln();
7008
+ writeln(` ${c17.dim("skills")}`);
7617
7009
  for (const skill of skills.values()) {
7618
- const source = skill.source === "local" ? c18.dim("local") : c18.dim("global");
7619
- writeln2(` ${c18.yellow(`@${skill.name}`.padEnd(28))} ${c18.dim(skill.description)} ${c18.dim("\xB7")} ${source}`);
7010
+ const source = skill.source === "local" ? c17.dim("local") : c17.dim("global");
7011
+ writeln(` ${c17.yellow(`@${skill.name}`.padEnd(28))} ${c17.dim(skill.description)} ${c17.dim("\xB7")} ${source}`);
7620
7012
  }
7621
7013
  }
7622
- writeln2();
7623
- writeln2(` ${c18.dim("keys")} ${c18.dim("esc")} cancel response ${c18.dim("\xB7")} ${c18.dim("ctrl+c / ctrl+d")} exit ${c18.dim("\xB7")} ${c18.dim("ctrl+r")} history search ${c18.dim("\xB7")} ${c18.dim("\u2191\u2193")} history`);
7624
- writeln2();
7014
+ writeln();
7015
+ writeln(` ${c17.dim("keys")} ${c17.dim("esc")} cancel response ${c17.dim("\xB7")} ${c17.dim("ctrl+c / ctrl+d")} exit ${c17.dim("\xB7")} ${c17.dim("ctrl+r")} history search ${c17.dim("\xB7")} ${c17.dim("\u2191\u2193")} history`);
7016
+ writeln();
7625
7017
  }
7626
7018
 
7627
7019
  // src/cli/commands-login.ts
7628
- import * as c19 from "yoctocolors";
7020
+ import * as c18 from "yoctocolors";
7629
7021
  function renderLoginHelp() {
7630
- writeln2();
7631
- writeln2(` ${c19.dim("usage:")}`);
7632
- writeln2(` /login ${c19.dim("show login status")}`);
7633
- writeln2(` /login <provider> ${c19.dim("login via OAuth")}`);
7634
- writeln2(` /logout <provider> ${c19.dim("clear saved tokens")}`);
7635
- writeln2();
7636
- writeln2(` ${c19.dim("providers:")}`);
7022
+ writeln();
7023
+ writeln(` ${c18.dim("usage:")}`);
7024
+ writeln(` /login ${c18.dim("show login status")}`);
7025
+ writeln(` /login <provider> ${c18.dim("login via OAuth")}`);
7026
+ writeln(` /logout <provider> ${c18.dim("clear saved tokens")}`);
7027
+ writeln();
7028
+ writeln(` ${c18.dim("providers:")}`);
7637
7029
  for (const p of getOAuthProviders()) {
7638
- const status = isLoggedIn(p.id) ? c19.green("logged in") : c19.dim("not logged in");
7639
- writeln2(` ${c19.cyan(p.id.padEnd(20))} ${p.name} ${c19.dim("\xB7")} ${status}`);
7030
+ const status = isLoggedIn(p.id) ? c18.green("logged in") : c18.dim("not logged in");
7031
+ writeln(` ${c18.cyan(p.id.padEnd(20))} ${p.name} ${c18.dim("\xB7")} ${status}`);
7640
7032
  }
7641
- writeln2();
7033
+ writeln();
7642
7034
  }
7643
7035
  function renderStatus() {
7644
7036
  const loggedIn = listLoggedInProviders();
7645
7037
  if (loggedIn.length === 0) {
7646
- writeln2(`${PREFIX.info} ${c19.dim("no OAuth logins \u2014 use")} /login <provider>`);
7038
+ writeln(`${PREFIX.info} ${c18.dim("no OAuth logins \u2014 use")} /login <provider>`);
7647
7039
  return;
7648
7040
  }
7649
7041
  for (const id of loggedIn) {
7650
7042
  const provider = getOAuthProvider(id);
7651
7043
  const name = provider?.name ?? id;
7652
- writeln2(`${PREFIX.success} ${c19.cyan(id)} ${c19.dim(name)}`);
7044
+ writeln(`${PREFIX.success} ${c18.cyan(id)} ${c18.dim(name)}`);
7653
7045
  }
7654
7046
  }
7655
7047
  async function handleLoginCommand(ctx, args) {
@@ -7664,13 +7056,13 @@ async function handleLoginCommand(ctx, args) {
7664
7056
  }
7665
7057
  const provider = getOAuthProvider(providerId);
7666
7058
  if (!provider) {
7667
- writeln2(`${PREFIX.error} unknown provider "${providerId}" \u2014 available: ${getOAuthProviders().map((p) => p.id).join(", ")}`);
7059
+ writeln(`${PREFIX.error} unknown provider "${providerId}" \u2014 available: ${getOAuthProviders().map((p) => p.id).join(", ")}`);
7668
7060
  return;
7669
7061
  }
7670
7062
  if (isLoggedIn(providerId)) {
7671
7063
  const token = await getAccessToken(providerId);
7672
7064
  if (token) {
7673
- writeln2(`${PREFIX.success} already logged in to ${c19.cyan(provider.name)}`);
7065
+ writeln(`${PREFIX.success} already logged in to ${c18.cyan(provider.name)}`);
7674
7066
  return;
7675
7067
  }
7676
7068
  }
@@ -7679,43 +7071,43 @@ async function handleLoginCommand(ctx, args) {
7679
7071
  await login(providerId, {
7680
7072
  onOpenUrl: (url, instructions) => {
7681
7073
  ctx.stopSpinner();
7682
- writeln2(`${PREFIX.info} ${instructions}`);
7683
- writeln2();
7684
- writeln2(` ${c19.cyan(url)}`);
7685
- writeln2();
7074
+ writeln(`${PREFIX.info} ${instructions}`);
7075
+ writeln();
7076
+ writeln(` ${c18.cyan(url)}`);
7077
+ writeln();
7686
7078
  const open = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
7687
7079
  Bun.spawn([open, url], { stdout: "ignore", stderr: "ignore" });
7688
7080
  ctx.startSpinner("waiting for browser callback");
7689
7081
  },
7690
7082
  onProgress: (msg) => {
7691
7083
  ctx.stopSpinner();
7692
- writeln2(`${PREFIX.info} ${c19.dim(msg)}`);
7084
+ writeln(`${PREFIX.info} ${c18.dim(msg)}`);
7693
7085
  ctx.startSpinner("exchanging tokens");
7694
7086
  }
7695
7087
  });
7696
7088
  ctx.stopSpinner();
7697
- writeln2(`${PREFIX.success} logged in to ${c19.cyan(provider.name)}`);
7089
+ writeln(`${PREFIX.success} logged in to ${c18.cyan(provider.name)}`);
7698
7090
  } catch (err) {
7699
7091
  ctx.stopSpinner();
7700
- writeln2(`${PREFIX.error} login failed: ${err.message}`);
7092
+ writeln(`${PREFIX.error} login failed: ${err.message}`);
7701
7093
  }
7702
7094
  }
7703
7095
  function handleLogoutCommand(_ctx, args) {
7704
7096
  const providerId = args.trim().toLowerCase();
7705
7097
  if (!providerId) {
7706
- writeln2(`${PREFIX.error} usage: /logout <provider>`);
7098
+ writeln(`${PREFIX.error} usage: /logout <provider>`);
7707
7099
  return;
7708
7100
  }
7709
7101
  if (!isLoggedIn(providerId)) {
7710
- writeln2(`${PREFIX.info} ${c19.dim("not logged in to")} ${providerId}`);
7102
+ writeln(`${PREFIX.info} ${c18.dim("not logged in to")} ${providerId}`);
7711
7103
  return;
7712
7104
  }
7713
7105
  logout(providerId);
7714
- writeln2(`${PREFIX.success} logged out of ${c19.cyan(providerId)}`);
7106
+ writeln(`${PREFIX.success} logged out of ${c18.cyan(providerId)}`);
7715
7107
  }
7716
7108
 
7717
7109
  // src/cli/commands-mcp.ts
7718
- import * as c20 from "yoctocolors";
7110
+ import * as c19 from "yoctocolors";
7719
7111
  async function handleMcpCommand(ctx, args) {
7720
7112
  const parts = args.trim().split(/\s+/);
7721
7113
  const sub = parts[0] ?? "list";
@@ -7723,28 +7115,28 @@ async function handleMcpCommand(ctx, args) {
7723
7115
  case "list": {
7724
7116
  const servers = listMcpServers();
7725
7117
  if (servers.length === 0) {
7726
- writeln2(c20.dim(" no MCP servers configured"));
7727
- writeln2(c20.dim(" /mcp add <name> http <url> \xB7 /mcp add <name> stdio <cmd> [args...]"));
7118
+ writeln(c19.dim(" no MCP servers configured"));
7119
+ writeln(c19.dim(" /mcp add <name> http <url> \xB7 /mcp add <name> stdio <cmd> [args...]"));
7728
7120
  return;
7729
7121
  }
7730
- writeln2();
7122
+ writeln();
7731
7123
  for (const s of servers) {
7732
- const detail = s.url ? c20.dim(` ${s.url}`) : s.command ? c20.dim(` ${s.command}`) : "";
7733
- writeln2(` ${c20.yellow("\u2699")} ${c20.bold(s.name)} ${c20.dim(s.transport)}${detail}`);
7124
+ const detail = s.url ? c19.dim(` ${s.url}`) : s.command ? c19.dim(` ${s.command}`) : "";
7125
+ writeln(` ${c19.yellow("\u2699")} ${c19.bold(s.name)} ${c19.dim(s.transport)}${detail}`);
7734
7126
  }
7735
7127
  return;
7736
7128
  }
7737
7129
  case "add": {
7738
7130
  const [, name, transport, ...rest] = parts;
7739
7131
  if (!name || !transport || rest.length === 0) {
7740
- writeln2(`${PREFIX.error} usage: /mcp add <name> http <url>`);
7741
- writeln2(`${PREFIX.error} /mcp add <name> stdio <cmd> [args...]`);
7132
+ writeln(`${PREFIX.error} usage: /mcp add <name> http <url>`);
7133
+ writeln(`${PREFIX.error} /mcp add <name> stdio <cmd> [args...]`);
7742
7134
  return;
7743
7135
  }
7744
7136
  if (transport === "http") {
7745
7137
  const url = rest[0];
7746
7138
  if (!url) {
7747
- writeln2(`${PREFIX.error} usage: /mcp add <name> http <url>`);
7139
+ writeln(`${PREFIX.error} usage: /mcp add <name> http <url>`);
7748
7140
  return;
7749
7141
  }
7750
7142
  upsertMcpServer({
@@ -7758,7 +7150,7 @@ async function handleMcpCommand(ctx, args) {
7758
7150
  } else if (transport === "stdio") {
7759
7151
  const [command, ...cmdArgs] = rest;
7760
7152
  if (!command) {
7761
- writeln2(`${PREFIX.error} usage: /mcp add <name> stdio <cmd> [args...]`);
7153
+ writeln(`${PREFIX.error} usage: /mcp add <name> stdio <cmd> [args...]`);
7762
7154
  return;
7763
7155
  }
7764
7156
  upsertMcpServer({
@@ -7770,14 +7162,14 @@ async function handleMcpCommand(ctx, args) {
7770
7162
  env: null
7771
7163
  });
7772
7164
  } else {
7773
- writeln2(`${PREFIX.error} unknown transport: ${transport} (use http or stdio)`);
7165
+ writeln(`${PREFIX.error} unknown transport: ${transport} (use http or stdio)`);
7774
7166
  return;
7775
7167
  }
7776
7168
  try {
7777
7169
  await ctx.connectMcpServer(name);
7778
- writeln2(`${PREFIX.success} mcp server ${c20.cyan(name)} added and connected`);
7170
+ writeln(`${PREFIX.success} mcp server ${c19.cyan(name)} added and connected`);
7779
7171
  } catch (e) {
7780
- writeln2(`${PREFIX.success} mcp server ${c20.cyan(name)} saved ${c20.dim(`(connection failed: ${String(e)})`)}`);
7172
+ writeln(`${PREFIX.success} mcp server ${c19.cyan(name)} saved ${c19.dim(`(connection failed: ${String(e)})`)}`);
7781
7173
  }
7782
7174
  return;
7783
7175
  }
@@ -7785,21 +7177,21 @@ async function handleMcpCommand(ctx, args) {
7785
7177
  case "rm": {
7786
7178
  const [, name] = parts;
7787
7179
  if (!name) {
7788
- writeln2(`${PREFIX.error} usage: /mcp remove <name>`);
7180
+ writeln(`${PREFIX.error} usage: /mcp remove <name>`);
7789
7181
  return;
7790
7182
  }
7791
7183
  deleteMcpServer(name);
7792
- writeln2(`${PREFIX.success} mcp server ${c20.cyan(name)} removed`);
7184
+ writeln(`${PREFIX.success} mcp server ${c19.cyan(name)} removed`);
7793
7185
  return;
7794
7186
  }
7795
7187
  default:
7796
- writeln2(`${PREFIX.error} unknown: /mcp ${sub}`);
7797
- writeln2(c20.dim(" subcommands: list \xB7 add \xB7 remove"));
7188
+ writeln(`${PREFIX.error} unknown: /mcp ${sub}`);
7189
+ writeln(c19.dim(" subcommands: list \xB7 add \xB7 remove"));
7798
7190
  }
7799
7191
  }
7800
7192
 
7801
7193
  // src/cli/commands-model.ts
7802
- import * as c21 from "yoctocolors";
7194
+ import * as c20 from "yoctocolors";
7803
7195
  var THINKING_EFFORTS = ["low", "medium", "high", "xhigh"];
7804
7196
  function parseThinkingEffort(value) {
7805
7197
  return THINKING_EFFORTS.includes(value) ? value : null;
@@ -7818,21 +7210,21 @@ function renderModelUpdatedMessage(ctx, modelId, effortArg) {
7818
7210
  if (effortArg) {
7819
7211
  if (effortArg === "off") {
7820
7212
  ctx.setThinkingEffort(null);
7821
- writeln2(`${PREFIX.success} model \u2192 ${c21.cyan(modelId)} ${c21.dim("(thinking disabled)")}`);
7213
+ writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)} ${c20.dim("(thinking disabled)")}`);
7822
7214
  return;
7823
7215
  }
7824
7216
  const effort = parseThinkingEffort(effortArg);
7825
7217
  if (effort) {
7826
7218
  ctx.setThinkingEffort(effort);
7827
- writeln2(`${PREFIX.success} model \u2192 ${c21.cyan(modelId)} ${c21.dim(`(\u2726 ${effort})`)}`);
7219
+ writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)} ${c20.dim(`(\u2726 ${effort})`)}`);
7828
7220
  return;
7829
7221
  }
7830
- writeln2(`${PREFIX.success} model \u2192 ${c21.cyan(modelId)}`);
7831
- writeln2(`${PREFIX.error} unknown effort level ${c21.cyan(effortArg)} (use low, medium, high, xhigh, off)`);
7222
+ writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)}`);
7223
+ writeln(`${PREFIX.error} unknown effort level ${c20.cyan(effortArg)} (use low, medium, high, xhigh, off)`);
7832
7224
  return;
7833
7225
  }
7834
- const effortTag = ctx.thinkingEffort ? c21.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
7835
- writeln2(`${PREFIX.success} model \u2192 ${c21.cyan(modelId)}${effortTag}`);
7226
+ const effortTag = ctx.thinkingEffort ? c20.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
7227
+ writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)}${effortTag}`);
7836
7228
  }
7837
7229
  async function handleModelSet(ctx, args) {
7838
7230
  const parts = args.trim().split(/\s+/).filter(Boolean);
@@ -7845,7 +7237,7 @@ async function handleModelSet(ctx, args) {
7845
7237
  const snapshot = await fetchAvailableModels();
7846
7238
  const match = findModelIdByAlias(idArg, snapshot.models.map((model) => model.id));
7847
7239
  if (!match) {
7848
- writeln2(`${PREFIX.error} unknown model ${c21.cyan(idArg)} ${c21.dim("\u2014 run /models for the full list")}`);
7240
+ writeln(`${PREFIX.error} unknown model ${c20.cyan(idArg)} ${c20.dim("\u2014 run /models for the full list")}`);
7849
7241
  return;
7850
7242
  }
7851
7243
  modelId = match;
@@ -7856,30 +7248,30 @@ async function handleModelSet(ctx, args) {
7856
7248
  function handleModelEffort(ctx, effortArg) {
7857
7249
  if (effortArg === "off") {
7858
7250
  ctx.setThinkingEffort(null);
7859
- writeln2(`${PREFIX.success} thinking effort disabled`);
7251
+ writeln(`${PREFIX.success} thinking effort disabled`);
7860
7252
  return;
7861
7253
  }
7862
7254
  const effort = parseThinkingEffort(effortArg);
7863
7255
  if (!effort) {
7864
- writeln2(`${PREFIX.error} usage: /model effort <low|medium|high|xhigh|off>`);
7256
+ writeln(`${PREFIX.error} usage: /model effort <low|medium|high|xhigh|off>`);
7865
7257
  return;
7866
7258
  }
7867
7259
  ctx.setThinkingEffort(effort);
7868
- writeln2(`${PREFIX.success} thinking effort \u2192 ${c21.cyan(effort)}`);
7260
+ writeln(`${PREFIX.success} thinking effort \u2192 ${c20.cyan(effort)}`);
7869
7261
  }
7870
7262
  async function renderModelList(ctx) {
7871
7263
  ctx.startSpinner("fetching models");
7872
7264
  const snapshot = await fetchAvailableModels();
7873
7265
  ctx.stopSpinner();
7874
7266
  if (snapshot.models.length === 0) {
7875
- writeln2(`${PREFIX.error} No models found. Check your API keys or Ollama connection.`);
7876
- writeln2(c21.dim(" Set OPENCODE_API_KEY for Zen, or start Ollama for local models."));
7267
+ writeln(`${PREFIX.error} No models found. Check your API keys or Ollama connection.`);
7268
+ writeln(c20.dim(" Set OPENCODE_API_KEY for Zen, or start Ollama for local models."));
7877
7269
  return;
7878
7270
  }
7879
7271
  if (snapshot.stale) {
7880
7272
  const lastSync = snapshot.lastSyncAt ? new Date(snapshot.lastSyncAt).toLocaleString() : "never";
7881
7273
  const refreshTag = snapshot.refreshing ? " (refreshing in background)" : "";
7882
- writeln2(c21.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
7274
+ writeln(c20.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
7883
7275
  }
7884
7276
  const modelsByProvider = new Map;
7885
7277
  for (const model of snapshot.models) {
@@ -7890,22 +7282,22 @@ async function renderModelList(ctx) {
7890
7282
  modelsByProvider.set(model.provider, [model]);
7891
7283
  }
7892
7284
  }
7893
- writeln2();
7285
+ writeln();
7894
7286
  for (const [provider, providerModels] of modelsByProvider) {
7895
- writeln2(c21.bold(` ${provider}`));
7287
+ writeln(c20.bold(` ${provider}`));
7896
7288
  for (const model of providerModels) {
7897
7289
  const isCurrent = ctx.currentModel === model.id;
7898
- const freeTag = model.free ? c21.green(" free") : "";
7899
- const contextTag = model.context ? c21.dim(` ${Math.round(model.context / 1000)}k`) : "";
7900
- const effortTag = isCurrent && ctx.thinkingEffort ? c21.dim(` \u2726 ${ctx.thinkingEffort}`) : "";
7901
- const currentTag = isCurrent ? c21.cyan(" \u25C0") : "";
7902
- writeln2(` ${c21.dim("\xB7")} ${model.displayName}${freeTag}${contextTag}${currentTag}${effortTag}`);
7903
- writeln2(` ${c21.dim(model.id)}`);
7290
+ const freeTag = model.free ? c20.green(" free") : "";
7291
+ const contextTag = model.context ? c20.dim(` ${Math.round(model.context / 1000)}k`) : "";
7292
+ const effortTag = isCurrent && ctx.thinkingEffort ? c20.dim(` \u2726 ${ctx.thinkingEffort}`) : "";
7293
+ const currentTag = isCurrent ? c20.cyan(" \u25C0") : "";
7294
+ writeln(` ${c20.dim("\xB7")} ${model.displayName}${freeTag}${contextTag}${currentTag}${effortTag}`);
7295
+ writeln(` ${c20.dim(model.id)}`);
7904
7296
  }
7905
7297
  }
7906
- writeln2();
7907
- writeln2(c21.dim(" /model <id> to switch \xB7 e.g. /model zen/claude-sonnet-4-6"));
7908
- writeln2(c21.dim(" /model effort <low|medium|high|xhigh|off> to set thinking effort"));
7298
+ writeln();
7299
+ writeln(c20.dim(" /model <id> to switch \xB7 e.g. /model zen/claude-sonnet-4-6"));
7300
+ writeln(c20.dim(" /model effort <low|medium|high|xhigh|off> to set thinking effort"));
7909
7301
  }
7910
7302
  async function handleModelCommand(ctx, args) {
7911
7303
  const parts = args.trim().split(/\s+/).filter(Boolean);
@@ -7926,9 +7318,9 @@ async function handleUndo(ctx) {
7926
7318
  try {
7927
7319
  const ok = await ctx.undoLastTurn();
7928
7320
  if (ok) {
7929
- writeln2(`${PREFIX.success} ${c22.dim("last conversation turn removed")}`);
7321
+ writeln(`${PREFIX.success} ${c21.dim("last conversation turn removed")}`);
7930
7322
  } else {
7931
- writeln2(`${PREFIX.info} ${c22.dim("nothing to undo")}`);
7323
+ writeln(`${PREFIX.info} ${c21.dim("nothing to undo")}`);
7932
7324
  }
7933
7325
  } finally {
7934
7326
  ctx.stopSpinner();
@@ -7941,11 +7333,11 @@ function handleNew(ctx) {
7941
7333
  }
7942
7334
  async function handleCustomCommand(cmd, args, ctx) {
7943
7335
  const prompt = await expandTemplate(cmd.template, args, ctx.cwd);
7944
- const label = c22.cyan(cmd.name);
7336
+ const label = c21.cyan(cmd.name);
7945
7337
  const srcPath = cmd.source === "local" ? `.agents/commands/${cmd.name}.md` : `~/.agents/commands/${cmd.name}.md`;
7946
- const src = c22.dim(`[${srcPath}]`);
7947
- writeln2(`${PREFIX.info} ${label} ${src}`);
7948
- writeln2();
7338
+ const src = c21.dim(`[${srcPath}]`);
7339
+ writeln(`${PREFIX.info} ${label} ${src}`);
7340
+ writeln();
7949
7341
  const fork = cmd.context === "fork" || cmd.subtask === true;
7950
7342
  if (!fork) {
7951
7343
  return { type: "inject-user-message", text: prompt };
@@ -7957,8 +7349,8 @@ async function handleCustomCommand(cmd, args, ctx) {
7957
7349
  try {
7958
7350
  ctx.startSpinner("subagent");
7959
7351
  const output = await ctx.runSubagent(prompt, cmd.agent, cmd.model, abortController.signal);
7960
- write2(output.result);
7961
- writeln2();
7352
+ write(output.result);
7353
+ writeln();
7962
7354
  return {
7963
7355
  type: "inject-user-message",
7964
7356
  text: `/${cmd.name} output:
@@ -7971,7 +7363,7 @@ ${output.result}
7971
7363
  if (isAbortError(e)) {
7972
7364
  return { type: "handled" };
7973
7365
  }
7974
- writeln2(`${PREFIX.error} /${cmd.name} failed: ${String(e)}`);
7366
+ writeln(`${PREFIX.error} /${cmd.name} failed: ${String(e)}`);
7975
7367
  return { type: "handled" };
7976
7368
  } finally {
7977
7369
  stopWatcher();
@@ -8028,7 +7420,7 @@ async function handleCommand(command, args, ctx) {
8028
7420
  case "q":
8029
7421
  return { type: "exit" };
8030
7422
  default: {
8031
- writeln2(`${PREFIX.error} unknown: /${command} ${c22.dim("\u2014 /help for commands")}`);
7423
+ writeln(`${PREFIX.error} unknown: /${command} ${c21.dim("\u2014 /help for commands")}`);
8032
7424
  return { type: "unknown", command };
8033
7425
  }
8034
7426
  }
@@ -8124,7 +7516,7 @@ async function runInputLoop(opts) {
8124
7516
  }
8125
7517
  switch (input.type) {
8126
7518
  case "eof":
8127
- reporter.writeText(c23.dim("Goodbye."));
7519
+ reporter.writeText(c22.dim("Goodbye."));
8128
7520
  return;
8129
7521
  case "interrupt":
8130
7522
  gitBranchCache.refreshInBackground();
@@ -8132,7 +7524,7 @@ async function runInputLoop(opts) {
8132
7524
  case "command": {
8133
7525
  const result = await handleCommand(input.command, input.args, cmdCtx);
8134
7526
  if (result.type === "exit") {
8135
- reporter.writeText(c23.dim("Goodbye."));
7527
+ reporter.writeText(c22.dim("Goodbye."));
8136
7528
  return;
8137
7529
  }
8138
7530
  if (result.type === "inject-user-message") {
@@ -8150,13 +7542,7 @@ async function runInputLoop(opts) {
8150
7542
  const result = await runShellCommand({
8151
7543
  command: input.command,
8152
7544
  timeout: 30000,
8153
- cwd,
8154
- ...cmdCtx.verboseOutput ? {
8155
- onOutput: (chunk) => {
8156
- reporter.streamChunk(chunk);
8157
- return true;
8158
- }
8159
- } : {}
7545
+ cwd
8160
7546
  });
8161
7547
  renderToolResult("shell", result, false, {
8162
7548
  verboseOutput: cmdCtx.verboseOutput
@@ -8211,8 +7597,8 @@ async function resolvePromptInput(promptArg, opts) {
8211
7597
 
8212
7598
  // src/cli/structured-output.ts
8213
7599
  import { createTwoFilesPatch } from "diff";
8214
- function writeJsonLine(write3, payload) {
8215
- write3(`${JSON.stringify(payload)}
7600
+ function writeJsonLine(write2, payload) {
7601
+ write2(`${JSON.stringify(payload)}
8216
7602
  `);
8217
7603
  }
8218
7604
 
@@ -8253,7 +7639,7 @@ async function main() {
8253
7639
  printHelp();
8254
7640
  process.exit(0);
8255
7641
  }
8256
- if (args.listSessions) {
7642
+ if (args.list) {
8257
7643
  printSessionList();
8258
7644
  process.exit(0);
8259
7645
  }
@@ -8268,7 +7654,7 @@ async function main() {
8268
7654
  if (last) {
8269
7655
  sessionId = last.id;
8270
7656
  } else {
8271
- writeln2(c24.dim("No previous session found, starting fresh."));
7657
+ writeln(c23.dim("No previous session found, starting fresh."));
8272
7658
  }
8273
7659
  } else if (args.sessionId) {
8274
7660
  sessionId = args.sessionId;
@@ -8335,7 +7721,7 @@ async function main() {
8335
7721
  const { text: resolvedText, images: refImages } = await resolveFileRefs(prompt, args.cwd);
8336
7722
  await runner.processUserInput(resolvedText, refImages);
8337
7723
  const { totalIn, totalOut } = runner.getStatusInfo();
8338
- writeln2(`${G.info} ${c24.dim(`${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out tokens`)}`);
7724
+ writeln(`${G.info} ${c23.dim(`${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out tokens`)}`);
8339
7725
  return;
8340
7726
  }
8341
7727
  await runInputLoop({