mini-coder 0.0.21 → 0.0.23
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/.claude/settings.local.json +9 -1
- package/dist/mc.js +533 -569
- package/package.json +2 -2
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
|
|
6
|
+
import * as c23 from "yoctocolors";
|
|
7
7
|
|
|
8
8
|
// src/agent/agent.ts
|
|
9
|
-
import * as
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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 ?
|
|
679
|
-
terminal.stderrWrite(`\r${
|
|
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
|
|
629
|
+
import * as c2 from "yoctocolors";
|
|
685
630
|
var ANSI_ESCAPE = "\x1B";
|
|
686
|
-
var STATUS_SEP =
|
|
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
|
|
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 ?
|
|
713
|
-
return
|
|
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}${
|
|
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
|
-
|
|
756
|
-
|
|
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(
|
|
705
|
+
optional.push(c2.dim(opts.provider));
|
|
761
706
|
}
|
|
762
707
|
if (opts.activeAgent)
|
|
763
|
-
optional.push(
|
|
708
|
+
optional.push(c2.green(`@${opts.activeAgent}`));
|
|
764
709
|
if (opts.thinkingEffort)
|
|
765
|
-
optional.push(
|
|
710
|
+
optional.push(c2.dim(`\u2726 ${opts.thinkingEffort}`));
|
|
766
711
|
if (opts.gitBranch)
|
|
767
|
-
optional.push(
|
|
712
|
+
optional.push(c2.dim(`\u2387 ${opts.gitBranch}`));
|
|
768
713
|
if (opts.inputTokens > 0 || opts.outputTokens > 0) {
|
|
769
|
-
optional.push(
|
|
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(
|
|
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
|
|
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"
|
|
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
|
|
1129
|
+
import * as c3 from "yoctocolors";
|
|
1185
1130
|
function styleReasoningText(text) {
|
|
1186
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
1164
|
+
writeln(`${G.info} ${c3.dim("reasoning")}`);
|
|
1220
1165
|
this.blockOpen = true;
|
|
1221
1166
|
}
|
|
1222
1167
|
writeText(text) {
|
|
1223
1168
|
if (!this.lineOpen) {
|
|
1224
|
-
|
|
1169
|
+
write(" ");
|
|
1225
1170
|
this.lineOpen = true;
|
|
1226
1171
|
}
|
|
1227
|
-
|
|
1172
|
+
write(styleReasoningText(text));
|
|
1228
1173
|
}
|
|
1229
1174
|
endLine() {
|
|
1230
1175
|
if (!this.lineOpen)
|
|
1231
|
-
|
|
1232
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1298
|
-
|
|
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
|
-
|
|
1261
|
+
write(colored);
|
|
1314
1262
|
}
|
|
1315
1263
|
} else {
|
|
1316
|
-
|
|
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
|
-
|
|
1291
|
+
write(finalColored);
|
|
1344
1292
|
}
|
|
1345
1293
|
}
|
|
1346
|
-
|
|
1294
|
+
writeln();
|
|
1347
1295
|
this.inText = false;
|
|
1348
1296
|
}
|
|
1349
1297
|
}
|
|
1350
1298
|
|
|
1351
1299
|
// src/cli/tool-render.ts
|
|
1352
|
-
import * as
|
|
1300
|
+
import * as c5 from "yoctocolors";
|
|
1353
1301
|
|
|
1354
1302
|
// src/cli/tool-result-renderers.ts
|
|
1355
|
-
import * as
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
@@ -1437,28 +1376,23 @@ function renderShellResult(result, opts) {
|
|
|
1437
1376
|
if (!r || typeof r.stdout !== "string" || typeof r.stderr !== "string") {
|
|
1438
1377
|
return false;
|
|
1439
1378
|
}
|
|
1440
|
-
const streamedOutput = r.streamedOutput === true;
|
|
1441
1379
|
const verboseOutput = opts?.verboseOutput === true;
|
|
1442
1380
|
const stdoutLines = countShellLines(r.stdout);
|
|
1443
1381
|
const stderrLines = countShellLines(r.stderr);
|
|
1444
1382
|
const stdoutSingleLine = getSingleShellLine(r.stdout);
|
|
1445
|
-
const badge = r.timedOut ?
|
|
1383
|
+
const badge = r.timedOut ? c4.yellow("timeout") : r.success ? c4.green("done") : c4.red("error");
|
|
1446
1384
|
const parts = buildShellSummaryParts({
|
|
1447
1385
|
exitCode: r.exitCode,
|
|
1448
1386
|
stdoutLines,
|
|
1449
1387
|
stderrLines,
|
|
1450
1388
|
stdoutSingleLine,
|
|
1451
|
-
streamedOutput,
|
|
1452
1389
|
verboseOutput
|
|
1453
1390
|
});
|
|
1454
|
-
|
|
1455
|
-
if (streamedOutput) {
|
|
1456
|
-
return true;
|
|
1457
|
-
}
|
|
1391
|
+
writeln(` ${badge} ${c4.dim(parts.join(" \xB7 "))}`);
|
|
1458
1392
|
writePreviewLines({
|
|
1459
1393
|
label: "stderr",
|
|
1460
1394
|
value: r.stderr,
|
|
1461
|
-
lineColor:
|
|
1395
|
+
lineColor: c4.red,
|
|
1462
1396
|
maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 10
|
|
1463
1397
|
});
|
|
1464
1398
|
if (shouldPreviewShellStdout({
|
|
@@ -1470,7 +1404,7 @@ function renderShellResult(result, opts) {
|
|
|
1470
1404
|
writePreviewLines({
|
|
1471
1405
|
label: "stdout",
|
|
1472
1406
|
value: r.stdout,
|
|
1473
|
-
lineColor:
|
|
1407
|
+
lineColor: c4.dim,
|
|
1474
1408
|
maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 20
|
|
1475
1409
|
});
|
|
1476
1410
|
}
|
|
@@ -1480,8 +1414,8 @@ function renderSubagentResult(result, _opts) {
|
|
|
1480
1414
|
const r = result;
|
|
1481
1415
|
if (!r || typeof r !== "object")
|
|
1482
1416
|
return false;
|
|
1483
|
-
const label = r.agentName ? ` ${
|
|
1484
|
-
|
|
1417
|
+
const label = r.agentName ? ` ${c4.dim(c4.cyan(`[@${r.agentName}]`))}` : "";
|
|
1418
|
+
writeln(` ${G.agent}${label} ${c4.dim(`subagent done (${r.inputTokens ?? 0}in / ${r.outputTokens ?? 0}out tokens)`)}`);
|
|
1485
1419
|
return true;
|
|
1486
1420
|
}
|
|
1487
1421
|
function buildSkillDescriptionPart(description, verboseOutput = false) {
|
|
@@ -1489,21 +1423,21 @@ function buildSkillDescriptionPart(description, verboseOutput = false) {
|
|
|
1489
1423
|
if (!trimmed)
|
|
1490
1424
|
return "";
|
|
1491
1425
|
if (verboseOutput)
|
|
1492
|
-
return ` ${
|
|
1493
|
-
return ` ${
|
|
1426
|
+
return ` ${c4.dim("\xB7")} ${c4.dim(trimmed)}`;
|
|
1427
|
+
return ` ${c4.dim("\xB7")} ${c4.dim(trimmed.length > 60 ? `${trimmed.slice(0, 57)}\u2026` : trimmed)}`;
|
|
1494
1428
|
}
|
|
1495
1429
|
function renderSkillSummaryLine(skill, opts) {
|
|
1496
1430
|
const name = skill.name ?? "(unknown)";
|
|
1497
1431
|
const source = skill.source ?? "unknown";
|
|
1498
|
-
const labelPrefix = opts?.label ? `${
|
|
1499
|
-
|
|
1432
|
+
const labelPrefix = opts?.label ? `${c4.dim(opts.label)} ` : "";
|
|
1433
|
+
writeln(` ${G.info} ${labelPrefix}${name} ${c4.dim("\xB7")} ${c4.dim(source)}${buildSkillDescriptionPart(skill.description, opts?.verboseOutput === true)}`);
|
|
1500
1434
|
}
|
|
1501
1435
|
function renderListSkillsResult(result, opts) {
|
|
1502
1436
|
const r = result;
|
|
1503
1437
|
if (!Array.isArray(r?.skills))
|
|
1504
1438
|
return false;
|
|
1505
1439
|
if (r.skills.length === 0) {
|
|
1506
|
-
|
|
1440
|
+
writeln(` ${G.info} ${c4.dim("no skills")}`);
|
|
1507
1441
|
return true;
|
|
1508
1442
|
}
|
|
1509
1443
|
const maxSkills = opts?.verboseOutput ? r.skills.length : 6;
|
|
@@ -1513,7 +1447,7 @@ function renderListSkillsResult(result, opts) {
|
|
|
1513
1447
|
});
|
|
1514
1448
|
}
|
|
1515
1449
|
if (r.skills.length > maxSkills) {
|
|
1516
|
-
|
|
1450
|
+
writeln(` ${c4.dim(`+${r.skills.length - maxSkills} more skills`)}`);
|
|
1517
1451
|
}
|
|
1518
1452
|
return true;
|
|
1519
1453
|
}
|
|
@@ -1522,7 +1456,7 @@ function renderReadSkillResult(result, _opts) {
|
|
|
1522
1456
|
if (!r || typeof r !== "object")
|
|
1523
1457
|
return false;
|
|
1524
1458
|
if (!r.skill) {
|
|
1525
|
-
|
|
1459
|
+
writeln(` ${G.info} ${c4.dim("skill")} ${c4.dim("(not found)")}`);
|
|
1526
1460
|
return true;
|
|
1527
1461
|
}
|
|
1528
1462
|
renderSkillSummaryLine(r.skill, {
|
|
@@ -1536,19 +1470,19 @@ function renderWebSearchResult(result, opts) {
|
|
|
1536
1470
|
if (!Array.isArray(r?.results))
|
|
1537
1471
|
return false;
|
|
1538
1472
|
if (r.results.length === 0) {
|
|
1539
|
-
|
|
1473
|
+
writeln(` ${G.info} ${c4.dim("no results")}`);
|
|
1540
1474
|
return true;
|
|
1541
1475
|
}
|
|
1542
1476
|
const maxResults = opts?.verboseOutput ? r.results.length : 5;
|
|
1543
1477
|
for (const item of r.results.slice(0, maxResults)) {
|
|
1544
1478
|
const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
|
|
1545
|
-
const score = typeof item.score === "number" ?
|
|
1546
|
-
|
|
1479
|
+
const score = typeof item.score === "number" ? c4.dim(` (${item.score.toFixed(2)})`) : "";
|
|
1480
|
+
writeln(` ${c4.dim("\u2022")} ${title}${score}`);
|
|
1547
1481
|
if (item.url)
|
|
1548
|
-
|
|
1482
|
+
writeln(` ${c4.dim(item.url)}`);
|
|
1549
1483
|
}
|
|
1550
1484
|
if (r.results.length > maxResults) {
|
|
1551
|
-
|
|
1485
|
+
writeln(` ${c4.dim(` +${r.results.length - maxResults} more`)}`);
|
|
1552
1486
|
}
|
|
1553
1487
|
return true;
|
|
1554
1488
|
}
|
|
@@ -1557,23 +1491,23 @@ function renderWebContentResult(result, opts) {
|
|
|
1557
1491
|
if (!Array.isArray(r?.results))
|
|
1558
1492
|
return false;
|
|
1559
1493
|
if (r.results.length === 0) {
|
|
1560
|
-
|
|
1494
|
+
writeln(` ${G.info} ${c4.dim("no pages")}`);
|
|
1561
1495
|
return true;
|
|
1562
1496
|
}
|
|
1563
1497
|
const maxPages = opts?.verboseOutput ? r.results.length : 3;
|
|
1564
1498
|
for (const item of r.results.slice(0, maxPages)) {
|
|
1565
1499
|
const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
|
|
1566
|
-
|
|
1500
|
+
writeln(` ${c4.dim("\u2022")} ${title}`);
|
|
1567
1501
|
if (item.url)
|
|
1568
|
-
|
|
1502
|
+
writeln(` ${c4.dim(item.url)}`);
|
|
1569
1503
|
const preview = (item.text ?? "").replace(/\s+/g, " ").trim();
|
|
1570
1504
|
if (preview) {
|
|
1571
1505
|
const trimmed = opts?.verboseOutput || preview.length <= 220 ? preview : `${preview.slice(0, 217)}\u2026`;
|
|
1572
|
-
|
|
1506
|
+
writeln(` ${c4.dim(trimmed)}`);
|
|
1573
1507
|
}
|
|
1574
1508
|
}
|
|
1575
1509
|
if (r.results.length > maxPages) {
|
|
1576
|
-
|
|
1510
|
+
writeln(` ${c4.dim(` +${r.results.length - maxPages} more`)}`);
|
|
1577
1511
|
}
|
|
1578
1512
|
return true;
|
|
1579
1513
|
}
|
|
@@ -1586,7 +1520,7 @@ function renderMcpResult(result, opts) {
|
|
|
1586
1520
|
const lines = block.text.split(`
|
|
1587
1521
|
`).slice(0, maxLines);
|
|
1588
1522
|
for (const line of lines)
|
|
1589
|
-
|
|
1523
|
+
writeln(` ${c4.dim("\u2502")} ${line}`);
|
|
1590
1524
|
}
|
|
1591
1525
|
}
|
|
1592
1526
|
return true;
|
|
@@ -1629,40 +1563,40 @@ function buildToolCallLine(name, args) {
|
|
|
1629
1563
|
const prompt = typeof a.prompt === "string" ? a.prompt : "";
|
|
1630
1564
|
const short = prompt.length > 60 ? `${prompt.slice(0, 57)}\u2026` : prompt;
|
|
1631
1565
|
const agentName = typeof a.agentName === "string" && a.agentName ? a.agentName : "";
|
|
1632
|
-
const label = agentName ? ` ${
|
|
1633
|
-
return `${G.agent}${label} ${
|
|
1566
|
+
const label = agentName ? ` ${c5.dim(c5.cyan(`[@${agentName}]`))}` : "";
|
|
1567
|
+
return `${G.agent}${label} ${c5.dim("\u2014")} ${short}`;
|
|
1634
1568
|
}
|
|
1635
1569
|
if (name === "shell") {
|
|
1636
1570
|
const cmd = String(a.command ?? "").trim();
|
|
1637
1571
|
if (!cmd)
|
|
1638
|
-
return `${G.run} ${
|
|
1572
|
+
return `${G.run} ${c5.dim("shell")}`;
|
|
1639
1573
|
const shortCmd = cmd.length > 72 ? `${cmd.slice(0, 69)}\u2026` : cmd;
|
|
1640
1574
|
return `${G.run} ${shortCmd}`;
|
|
1641
1575
|
}
|
|
1642
1576
|
if (name === "listSkills") {
|
|
1643
|
-
return `${G.search} ${
|
|
1577
|
+
return `${G.search} ${c5.dim("list skills")}`;
|
|
1644
1578
|
}
|
|
1645
1579
|
if (name === "readSkill") {
|
|
1646
1580
|
const skillName = typeof a.name === "string" ? a.name : "";
|
|
1647
|
-
return `${G.read} ${
|
|
1581
|
+
return `${G.read} ${c5.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
|
|
1648
1582
|
}
|
|
1649
1583
|
if (name.startsWith("mcp_")) {
|
|
1650
|
-
return `${G.mcp} ${
|
|
1584
|
+
return `${G.mcp} ${c5.dim(name)}`;
|
|
1651
1585
|
}
|
|
1652
|
-
return `${toolGlyph(name)} ${
|
|
1586
|
+
return `${toolGlyph(name)} ${c5.dim(name)}`;
|
|
1653
1587
|
}
|
|
1654
1588
|
function renderToolCall(toolName, args) {
|
|
1655
|
-
|
|
1589
|
+
writeln(` ${buildToolCallLine(toolName, args)}`);
|
|
1656
1590
|
}
|
|
1657
1591
|
function formatErrorBadge(result) {
|
|
1658
1592
|
const msg = typeof result === "string" ? result : result instanceof Error ? result.message : JSON.stringify(result);
|
|
1659
1593
|
const oneLiner = msg.split(`
|
|
1660
1594
|
`)[0] ?? msg;
|
|
1661
|
-
return `${G.err} ${
|
|
1595
|
+
return `${G.err} ${c5.red(oneLiner)}`;
|
|
1662
1596
|
}
|
|
1663
1597
|
function renderToolResult(toolName, result, isError, opts) {
|
|
1664
1598
|
if (isError) {
|
|
1665
|
-
|
|
1599
|
+
writeln(` ${formatErrorBadge(result)}`);
|
|
1666
1600
|
return;
|
|
1667
1601
|
}
|
|
1668
1602
|
if (renderToolResultByName(toolName, result, opts)) {
|
|
@@ -1670,10 +1604,10 @@ function renderToolResult(toolName, result, isError, opts) {
|
|
|
1670
1604
|
}
|
|
1671
1605
|
const text = JSON.stringify(result);
|
|
1672
1606
|
if (opts?.verboseOutput || text.length <= 120) {
|
|
1673
|
-
|
|
1607
|
+
writeln(` ${c5.dim(text)}`);
|
|
1674
1608
|
return;
|
|
1675
1609
|
}
|
|
1676
|
-
|
|
1610
|
+
writeln(` ${c5.dim(`${text.slice(0, 117)}\u2026`)}`);
|
|
1677
1611
|
}
|
|
1678
1612
|
|
|
1679
1613
|
// src/cli/stream-render.ts
|
|
@@ -1702,7 +1636,7 @@ async function renderTurn(events, spinner, opts) {
|
|
|
1702
1636
|
case "text-delta": {
|
|
1703
1637
|
liveReasoning.finish();
|
|
1704
1638
|
content.appendTextDelta(event.delta, renderedVisibleOutput);
|
|
1705
|
-
if (
|
|
1639
|
+
if (content.hasOpenContent())
|
|
1706
1640
|
renderedVisibleOutput = true;
|
|
1707
1641
|
break;
|
|
1708
1642
|
}
|
|
@@ -1713,7 +1647,7 @@ async function renderTurn(events, spinner, opts) {
|
|
|
1713
1647
|
if (showReasoning && delta) {
|
|
1714
1648
|
spinner.stop();
|
|
1715
1649
|
if (renderedVisibleOutput && !liveReasoning.isOpen())
|
|
1716
|
-
|
|
1650
|
+
writeln();
|
|
1717
1651
|
liveReasoning.append(delta);
|
|
1718
1652
|
renderedVisibleOutput = true;
|
|
1719
1653
|
}
|
|
@@ -1728,7 +1662,7 @@ async function renderTurn(events, spinner, opts) {
|
|
|
1728
1662
|
content.flushOpenContent();
|
|
1729
1663
|
spinner.stop();
|
|
1730
1664
|
if (renderedVisibleOutput)
|
|
1731
|
-
|
|
1665
|
+
writeln();
|
|
1732
1666
|
renderToolCall(event.toolName, event.args);
|
|
1733
1667
|
renderedVisibleOutput = true;
|
|
1734
1668
|
spinner.start(event.toolName);
|
|
@@ -1750,7 +1684,7 @@ async function renderTurn(events, spinner, opts) {
|
|
|
1750
1684
|
content.flushOpenContent();
|
|
1751
1685
|
spinner.stop();
|
|
1752
1686
|
const removedKb = (event.removedBytes / 1024).toFixed(1);
|
|
1753
|
-
|
|
1687
|
+
writeln(`${G.info} ${c6.dim("context pruned")} ${c6.dim(event.mode)} ${c6.dim(`\u2013${event.removedMessageCount} messages`)} ${c6.dim(`\u2013${removedKb} KB`)}`);
|
|
1754
1688
|
renderedVisibleOutput = true;
|
|
1755
1689
|
break;
|
|
1756
1690
|
}
|
|
@@ -1759,7 +1693,7 @@ async function renderTurn(events, spinner, opts) {
|
|
|
1759
1693
|
content.flushOpenContent();
|
|
1760
1694
|
spinner.stop();
|
|
1761
1695
|
if (!renderedVisibleOutput)
|
|
1762
|
-
|
|
1696
|
+
writeln();
|
|
1763
1697
|
inputTokens = event.inputTokens;
|
|
1764
1698
|
outputTokens = event.outputTokens;
|
|
1765
1699
|
contextTokens = event.contextTokens;
|
|
@@ -1791,7 +1725,7 @@ async function renderTurn(events, spinner, opts) {
|
|
|
1791
1725
|
|
|
1792
1726
|
// src/cli/output.ts
|
|
1793
1727
|
var HOME = homedir3();
|
|
1794
|
-
var PACKAGE_VERSION = "0.0.
|
|
1728
|
+
var PACKAGE_VERSION = "0.0.23";
|
|
1795
1729
|
function tildePath(p) {
|
|
1796
1730
|
return p.startsWith(HOME) ? `~${p.slice(HOME.length)}` : p;
|
|
1797
1731
|
}
|
|
@@ -1801,38 +1735,38 @@ function restoreTerminal() {
|
|
|
1801
1735
|
function registerTerminalCleanup() {
|
|
1802
1736
|
terminal.registerCleanup();
|
|
1803
1737
|
}
|
|
1804
|
-
function
|
|
1738
|
+
function writeln(text = "") {
|
|
1805
1739
|
terminal.stdoutWrite(`${text}
|
|
1806
1740
|
`);
|
|
1807
1741
|
}
|
|
1808
|
-
function
|
|
1742
|
+
function write(text) {
|
|
1809
1743
|
terminal.stdoutWrite(text);
|
|
1810
1744
|
}
|
|
1811
1745
|
function renderUserMessage(text) {
|
|
1812
1746
|
const lines = text.split(`
|
|
1813
1747
|
`);
|
|
1814
1748
|
if (lines.length === 0) {
|
|
1815
|
-
|
|
1749
|
+
writeln(`${G.prompt}`);
|
|
1816
1750
|
return;
|
|
1817
1751
|
}
|
|
1818
|
-
|
|
1752
|
+
writeln(`${G.prompt} ${lines[0] ?? ""}`);
|
|
1819
1753
|
for (const line of lines.slice(1)) {
|
|
1820
|
-
|
|
1754
|
+
writeln(` ${line}`);
|
|
1821
1755
|
}
|
|
1822
1756
|
}
|
|
1823
1757
|
var G = {
|
|
1824
|
-
prompt:
|
|
1825
|
-
reply:
|
|
1826
|
-
search:
|
|
1827
|
-
read:
|
|
1828
|
-
write:
|
|
1829
|
-
run:
|
|
1830
|
-
agent:
|
|
1831
|
-
mcp:
|
|
1832
|
-
ok:
|
|
1833
|
-
err:
|
|
1834
|
-
warn:
|
|
1835
|
-
info:
|
|
1758
|
+
prompt: c7.green("\u203A"),
|
|
1759
|
+
reply: c7.cyan("\u25C6"),
|
|
1760
|
+
search: c7.yellow("?"),
|
|
1761
|
+
read: c7.dim("\u2190"),
|
|
1762
|
+
write: c7.green("\u270E"),
|
|
1763
|
+
run: c7.dim("$"),
|
|
1764
|
+
agent: c7.cyan("\u21E2"),
|
|
1765
|
+
mcp: c7.yellow("\u2699"),
|
|
1766
|
+
ok: c7.green("\u2714"),
|
|
1767
|
+
err: c7.red("\u2716"),
|
|
1768
|
+
warn: c7.yellow("!"),
|
|
1769
|
+
info: c7.dim("\xB7")
|
|
1836
1770
|
};
|
|
1837
1771
|
var PREFIX = {
|
|
1838
1772
|
user: G.prompt,
|
|
@@ -1854,9 +1788,9 @@ class RenderedError extends Error {
|
|
|
1854
1788
|
function renderError(err, context = "render") {
|
|
1855
1789
|
logError(err, context);
|
|
1856
1790
|
const parsed = parseAppError(err);
|
|
1857
|
-
|
|
1791
|
+
writeln(`${G.err} ${c7.red(parsed.headline)}`);
|
|
1858
1792
|
if (parsed.hint) {
|
|
1859
|
-
|
|
1793
|
+
writeln(` ${c7.dim(parsed.hint)}`);
|
|
1860
1794
|
}
|
|
1861
1795
|
}
|
|
1862
1796
|
function discoverContextFiles(cwd) {
|
|
@@ -1876,11 +1810,11 @@ function discoverContextFiles(cwd) {
|
|
|
1876
1810
|
return found;
|
|
1877
1811
|
}
|
|
1878
1812
|
function renderBanner(model, cwd) {
|
|
1879
|
-
|
|
1813
|
+
writeln();
|
|
1880
1814
|
const title = PACKAGE_VERSION ? `mini-coder \xB7 v${PACKAGE_VERSION}` : "mini-coder";
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1815
|
+
writeln(` ${c7.cyan("mc")} ${c7.dim(title)}`);
|
|
1816
|
+
writeln(` ${c7.dim(model)} ${c7.dim("\xB7")} ${c7.dim(tildePath(cwd))}`);
|
|
1817
|
+
writeln(` ${c7.dim("/help for commands \xB7 esc cancel \xB7 ctrl+c/ctrl+d exit")}`);
|
|
1884
1818
|
const items = [];
|
|
1885
1819
|
const contextFiles = discoverContextFiles(cwd);
|
|
1886
1820
|
if (contextFiles.length > 0)
|
|
@@ -1895,27 +1829,19 @@ function renderBanner(model, cwd) {
|
|
|
1895
1829
|
if (commands.size > 0)
|
|
1896
1830
|
items.push(`${commands.size} custom cmd${commands.size > 1 ? "s" : ""}`);
|
|
1897
1831
|
if (items.length > 0) {
|
|
1898
|
-
|
|
1832
|
+
writeln(` ${c7.dim(items.join(" \xB7 "))}`);
|
|
1899
1833
|
}
|
|
1900
|
-
|
|
1834
|
+
writeln();
|
|
1901
1835
|
}
|
|
1902
1836
|
|
|
1903
1837
|
class CliReporter {
|
|
1904
1838
|
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
1839
|
info(msg) {
|
|
1914
|
-
this.
|
|
1915
|
-
|
|
1840
|
+
this.spinner.stop();
|
|
1841
|
+
writeln(`${G.info} ${c7.dim(msg)}`);
|
|
1916
1842
|
}
|
|
1917
1843
|
error(msg, hint) {
|
|
1918
|
-
this.
|
|
1844
|
+
this.spinner.stop();
|
|
1919
1845
|
if (typeof msg === "string") {
|
|
1920
1846
|
renderError(msg, hint);
|
|
1921
1847
|
} else {
|
|
@@ -1923,29 +1849,23 @@ class CliReporter {
|
|
|
1923
1849
|
}
|
|
1924
1850
|
}
|
|
1925
1851
|
warn(msg) {
|
|
1926
|
-
this.
|
|
1927
|
-
|
|
1852
|
+
this.spinner.stop();
|
|
1853
|
+
writeln(`${G.warn} ${msg}`);
|
|
1928
1854
|
}
|
|
1929
1855
|
writeText(text) {
|
|
1930
|
-
this.
|
|
1931
|
-
|
|
1932
|
-
}
|
|
1933
|
-
streamChunk(text) {
|
|
1934
|
-
this.haltSpinner();
|
|
1935
|
-
this.liveOutput.append(text);
|
|
1856
|
+
this.spinner.stop();
|
|
1857
|
+
writeln(text);
|
|
1936
1858
|
}
|
|
1937
1859
|
startSpinner(label) {
|
|
1938
1860
|
this.spinner.start(label);
|
|
1939
1861
|
}
|
|
1940
1862
|
stopSpinner() {
|
|
1941
|
-
this.
|
|
1863
|
+
this.spinner.stop();
|
|
1942
1864
|
}
|
|
1943
1865
|
async renderTurn(events, opts) {
|
|
1944
|
-
this.liveOutput.finish();
|
|
1945
1866
|
return renderTurn(events, this.spinner, opts);
|
|
1946
1867
|
}
|
|
1947
1868
|
renderStatusBar(data) {
|
|
1948
|
-
this.liveOutput.finish();
|
|
1949
1869
|
renderStatusBar(data);
|
|
1950
1870
|
}
|
|
1951
1871
|
restoreTerminal() {
|
|
@@ -1965,8 +1885,8 @@ function warnConventionConflicts(kind, scope, agentsNames, claudeNames) {
|
|
|
1965
1885
|
if (conflicts.length === 0)
|
|
1966
1886
|
return;
|
|
1967
1887
|
conflicts.sort((a, b) => a.localeCompare(b));
|
|
1968
|
-
const list = conflicts.map((n) =>
|
|
1969
|
-
|
|
1888
|
+
const list = conflicts.map((n) => c8.cyan(n)).join(c8.dim(", "));
|
|
1889
|
+
writeln(`${G.warn} conflicting ${kind} in ${scope} .agents and .claude: ${list} ${c8.dim("\u2014 using .agents version")}`);
|
|
1970
1890
|
}
|
|
1971
1891
|
|
|
1972
1892
|
// src/cli/frontmatter.ts
|
|
@@ -2627,10 +2547,10 @@ function setPreferredGoogleCachedContent(contentId) {
|
|
|
2627
2547
|
}
|
|
2628
2548
|
}
|
|
2629
2549
|
// src/agent/session-runner.ts
|
|
2630
|
-
import * as
|
|
2550
|
+
import * as c11 from "yoctocolors";
|
|
2631
2551
|
|
|
2632
2552
|
// src/cli/input.ts
|
|
2633
|
-
import * as
|
|
2553
|
+
import * as c9 from "yoctocolors";
|
|
2634
2554
|
|
|
2635
2555
|
// src/cli/input-buffer.ts
|
|
2636
2556
|
var PASTE_TOKEN_START = 57344;
|
|
@@ -3064,7 +2984,7 @@ function watchForCancel(abortController, options) {
|
|
|
3064
2984
|
process.stdin.on("data", onData);
|
|
3065
2985
|
return cleanup;
|
|
3066
2986
|
}
|
|
3067
|
-
var PROMPT =
|
|
2987
|
+
var PROMPT = c9.green("\u25B6 ");
|
|
3068
2988
|
var PROMPT_RAW_LEN = 2;
|
|
3069
2989
|
async function readline(opts) {
|
|
3070
2990
|
const cwd = opts.cwd ?? process.cwd();
|
|
@@ -3113,7 +3033,7 @@ async function readline(opts) {
|
|
|
3113
3033
|
process.stdout.write(`${CLEAR_LINE}${prompt}${display}${CSI}${PROMPT_RAW_LEN + displayCursor + 1}G`);
|
|
3114
3034
|
}
|
|
3115
3035
|
function renderSearchPrompt() {
|
|
3116
|
-
process.stdout.write(`${CLEAR_LINE}${
|
|
3036
|
+
process.stdout.write(`${CLEAR_LINE}${c9.cyan("search:")} ${searchQuery}\u2588`);
|
|
3117
3037
|
}
|
|
3118
3038
|
function applyHistory() {
|
|
3119
3039
|
if (histIdx < history.length) {
|
|
@@ -4283,6 +4203,17 @@ var SUPPORTED_PROVIDERS = [
|
|
|
4283
4203
|
"ollama"
|
|
4284
4204
|
];
|
|
4285
4205
|
var ZEN_BASE2 = "https://opencode.ai/zen/v1";
|
|
4206
|
+
var REDACTED_HEADERS = new Set(["authorization"]);
|
|
4207
|
+
function redactHeaders(headers) {
|
|
4208
|
+
if (!headers)
|
|
4209
|
+
return;
|
|
4210
|
+
const h = new Headers(headers);
|
|
4211
|
+
const out = {};
|
|
4212
|
+
h.forEach((v, k) => {
|
|
4213
|
+
out[k] = REDACTED_HEADERS.has(k) ? "[REDACTED]" : v;
|
|
4214
|
+
});
|
|
4215
|
+
return out;
|
|
4216
|
+
}
|
|
4286
4217
|
function createFetchWithLogging() {
|
|
4287
4218
|
const customFetch = async (input, init) => {
|
|
4288
4219
|
if (init?.body) {
|
|
@@ -4292,14 +4223,14 @@ function createFetchWithLogging() {
|
|
|
4292
4223
|
logApiEvent("Provider Request", {
|
|
4293
4224
|
url: input.toString(),
|
|
4294
4225
|
method: init.method,
|
|
4295
|
-
headers: init.headers,
|
|
4226
|
+
headers: redactHeaders(init.headers),
|
|
4296
4227
|
body: bodyJson
|
|
4297
4228
|
});
|
|
4298
4229
|
} catch {
|
|
4299
4230
|
logApiEvent("Provider Request", {
|
|
4300
4231
|
url: input.toString(),
|
|
4301
4232
|
method: init.method,
|
|
4302
|
-
headers: init.headers,
|
|
4233
|
+
headers: redactHeaders(init.headers),
|
|
4303
4234
|
body: init.body
|
|
4304
4235
|
});
|
|
4305
4236
|
}
|
|
@@ -4309,6 +4240,59 @@ function createFetchWithLogging() {
|
|
|
4309
4240
|
return customFetch;
|
|
4310
4241
|
}
|
|
4311
4242
|
var fetchWithLogging = createFetchWithLogging();
|
|
4243
|
+
var OAUTH_STRIP_BETAS = new Set(["structured-outputs-2025-11-13"]);
|
|
4244
|
+
function sanitizeOAuthBody(body) {
|
|
4245
|
+
try {
|
|
4246
|
+
const json = JSON.parse(body);
|
|
4247
|
+
if (Array.isArray(json.tools)) {
|
|
4248
|
+
for (const tool of json.tools) {
|
|
4249
|
+
if (tool.input_schema) {
|
|
4250
|
+
tool.input_schema = {
|
|
4251
|
+
type: "object",
|
|
4252
|
+
properties: tool.input_schema.properties ?? {},
|
|
4253
|
+
required: tool.input_schema.required ?? []
|
|
4254
|
+
};
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
}
|
|
4258
|
+
if (Array.isArray(json.messages)) {
|
|
4259
|
+
for (const msg of json.messages) {
|
|
4260
|
+
if (!Array.isArray(msg.content))
|
|
4261
|
+
continue;
|
|
4262
|
+
for (const block of msg.content) {
|
|
4263
|
+
if (block.type === "tool_use") {
|
|
4264
|
+
delete block.caller;
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
return JSON.stringify(json);
|
|
4270
|
+
} catch {
|
|
4271
|
+
return body;
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
function createOAuthFetch() {
|
|
4275
|
+
const baseFetch = createFetchWithLogging();
|
|
4276
|
+
const oauthFetch = async (input, init) => {
|
|
4277
|
+
let opts = init;
|
|
4278
|
+
if (opts?.headers) {
|
|
4279
|
+
const h = new Headers(opts.headers);
|
|
4280
|
+
const beta = h.get("anthropic-beta");
|
|
4281
|
+
if (beta) {
|
|
4282
|
+
const filtered = beta.split(",").filter((b) => !OAUTH_STRIP_BETAS.has(b)).join(",");
|
|
4283
|
+
h.set("anthropic-beta", filtered);
|
|
4284
|
+
}
|
|
4285
|
+
h.set("user-agent", "claude-cli/2.1.75");
|
|
4286
|
+
h.set("x-app", "cli");
|
|
4287
|
+
opts = { ...opts, headers: Object.fromEntries(h.entries()) };
|
|
4288
|
+
}
|
|
4289
|
+
if (opts?.body) {
|
|
4290
|
+
opts = { ...opts, body: sanitizeOAuthBody(opts.body.toString()) };
|
|
4291
|
+
}
|
|
4292
|
+
return baseFetch(input, opts);
|
|
4293
|
+
};
|
|
4294
|
+
return oauthFetch;
|
|
4295
|
+
}
|
|
4312
4296
|
function requireEnv(name) {
|
|
4313
4297
|
const value = process.env[name];
|
|
4314
4298
|
if (!value)
|
|
@@ -4399,7 +4383,7 @@ async function resolveAnthropicModel(modelId) {
|
|
|
4399
4383
|
oauthAnthropicCache = {
|
|
4400
4384
|
token,
|
|
4401
4385
|
provider: createAnthropic({
|
|
4402
|
-
fetch:
|
|
4386
|
+
fetch: createOAuthFetch(),
|
|
4403
4387
|
authToken: token,
|
|
4404
4388
|
headers: {
|
|
4405
4389
|
"anthropic-beta": "claude-code-20250219,oauth-2025-04-20"
|
|
@@ -4434,6 +4418,9 @@ async function resolveModel(modelString) {
|
|
|
4434
4418
|
}
|
|
4435
4419
|
return PROVIDER_MODEL_RESOLVERS[provider](modelId);
|
|
4436
4420
|
}
|
|
4421
|
+
function isAnthropicOAuth() {
|
|
4422
|
+
return isLoggedIn("anthropic");
|
|
4423
|
+
}
|
|
4437
4424
|
function autoDiscoverModel() {
|
|
4438
4425
|
if (process.env.OPENCODE_API_KEY)
|
|
4439
4426
|
return "zen/claude-sonnet-4-6";
|
|
@@ -4702,11 +4689,11 @@ function annotateAnthropicCacheBreakpoints(turnMessages, systemPrompt) {
|
|
|
4702
4689
|
import { dynamicTool, jsonSchema } from "ai";
|
|
4703
4690
|
|
|
4704
4691
|
// src/llm-api/turn-stream-events.ts
|
|
4705
|
-
function shouldLogStreamChunk(
|
|
4706
|
-
return
|
|
4692
|
+
function shouldLogStreamChunk(c10) {
|
|
4693
|
+
return c10.type !== "text-delta" && c10.type !== "reasoning" && c10.type !== "reasoning-delta";
|
|
4707
4694
|
}
|
|
4708
|
-
function extractToolArgs(
|
|
4709
|
-
return
|
|
4695
|
+
function extractToolArgs(c10) {
|
|
4696
|
+
return c10.input ?? c10.args;
|
|
4710
4697
|
}
|
|
4711
4698
|
function hasRenderableToolArgs(args) {
|
|
4712
4699
|
if (args === null || args === undefined)
|
|
@@ -4719,10 +4706,10 @@ function hasRenderableToolArgs(args) {
|
|
|
4719
4706
|
return Object.keys(args).length > 0;
|
|
4720
4707
|
return true;
|
|
4721
4708
|
}
|
|
4722
|
-
function mapStreamChunkToTurnEvent(
|
|
4723
|
-
switch (
|
|
4709
|
+
function mapStreamChunkToTurnEvent(c10) {
|
|
4710
|
+
switch (c10.type) {
|
|
4724
4711
|
case "text-delta": {
|
|
4725
|
-
const delta = typeof
|
|
4712
|
+
const delta = typeof c10.text === "string" ? c10.text : "";
|
|
4726
4713
|
return {
|
|
4727
4714
|
type: "text-delta",
|
|
4728
4715
|
delta
|
|
@@ -4730,7 +4717,7 @@ function mapStreamChunkToTurnEvent(c11) {
|
|
|
4730
4717
|
}
|
|
4731
4718
|
case "reasoning-delta":
|
|
4732
4719
|
case "reasoning": {
|
|
4733
|
-
const delta = getReasoningDeltaFromStreamChunk(
|
|
4720
|
+
const delta = getReasoningDeltaFromStreamChunk(c10);
|
|
4734
4721
|
if (delta === null)
|
|
4735
4722
|
return null;
|
|
4736
4723
|
return {
|
|
@@ -4739,44 +4726,44 @@ function mapStreamChunkToTurnEvent(c11) {
|
|
|
4739
4726
|
};
|
|
4740
4727
|
}
|
|
4741
4728
|
case "tool-input-start": {
|
|
4742
|
-
const args = extractToolArgs(
|
|
4743
|
-
const hasStableToolCallId = typeof
|
|
4729
|
+
const args = extractToolArgs(c10);
|
|
4730
|
+
const hasStableToolCallId = typeof c10.toolCallId === "string" && c10.toolCallId.trim().length > 0;
|
|
4744
4731
|
if (hasStableToolCallId && !hasRenderableToolArgs(args))
|
|
4745
4732
|
return null;
|
|
4746
4733
|
return {
|
|
4747
4734
|
type: "tool-call-start",
|
|
4748
|
-
toolCallId: String(
|
|
4749
|
-
toolName: String(
|
|
4735
|
+
toolCallId: String(c10.toolCallId ?? ""),
|
|
4736
|
+
toolName: String(c10.toolName ?? ""),
|
|
4750
4737
|
args
|
|
4751
4738
|
};
|
|
4752
4739
|
}
|
|
4753
4740
|
case "tool-call": {
|
|
4754
4741
|
return {
|
|
4755
4742
|
type: "tool-call-start",
|
|
4756
|
-
toolCallId: String(
|
|
4757
|
-
toolName: String(
|
|
4758
|
-
args: extractToolArgs(
|
|
4743
|
+
toolCallId: String(c10.toolCallId ?? ""),
|
|
4744
|
+
toolName: String(c10.toolName ?? ""),
|
|
4745
|
+
args: extractToolArgs(c10)
|
|
4759
4746
|
};
|
|
4760
4747
|
}
|
|
4761
4748
|
case "tool-result": {
|
|
4762
4749
|
return {
|
|
4763
4750
|
type: "tool-result",
|
|
4764
|
-
toolCallId: String(
|
|
4765
|
-
toolName: String(
|
|
4766
|
-
result: "output" in
|
|
4767
|
-
isError: "isError" in
|
|
4751
|
+
toolCallId: String(c10.toolCallId ?? ""),
|
|
4752
|
+
toolName: String(c10.toolName ?? ""),
|
|
4753
|
+
result: "output" in c10 ? c10.output : ("result" in c10) ? c10.result : undefined,
|
|
4754
|
+
isError: "isError" in c10 ? Boolean(c10.isError) : false
|
|
4768
4755
|
};
|
|
4769
4756
|
}
|
|
4770
4757
|
case "tool-error":
|
|
4771
4758
|
return {
|
|
4772
4759
|
type: "tool-result",
|
|
4773
|
-
toolCallId: String(
|
|
4774
|
-
toolName: String(
|
|
4775
|
-
result:
|
|
4760
|
+
toolCallId: String(c10.toolCallId ?? ""),
|
|
4761
|
+
toolName: String(c10.toolName ?? ""),
|
|
4762
|
+
result: c10.error ?? "Tool execution failed",
|
|
4776
4763
|
isError: true
|
|
4777
4764
|
};
|
|
4778
4765
|
case "error": {
|
|
4779
|
-
throw normalizeUnknownError(
|
|
4766
|
+
throw normalizeUnknownError(c10.error);
|
|
4780
4767
|
}
|
|
4781
4768
|
default:
|
|
4782
4769
|
return null;
|
|
@@ -5210,6 +5197,30 @@ function prepareTurnMessages(input) {
|
|
|
5210
5197
|
logApiEvent("Anthropic prompt caching", annotated.diagnostics);
|
|
5211
5198
|
}
|
|
5212
5199
|
}
|
|
5200
|
+
if (isAnthropicModelFamily(modelString) && isAnthropicOAuth()) {
|
|
5201
|
+
const ccIdentity = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
5202
|
+
const ccSystemMsg = {
|
|
5203
|
+
role: "system",
|
|
5204
|
+
content: ccIdentity,
|
|
5205
|
+
providerOptions: {
|
|
5206
|
+
anthropic: { cacheControl: { type: "ephemeral" } }
|
|
5207
|
+
}
|
|
5208
|
+
};
|
|
5209
|
+
if (finalSystemPrompt) {
|
|
5210
|
+
finalMessages = [ccSystemMsg, ...finalMessages];
|
|
5211
|
+
} else {
|
|
5212
|
+
const sysIdx = finalMessages.findIndex((m) => m.role === "system");
|
|
5213
|
+
if (sysIdx >= 0) {
|
|
5214
|
+
finalMessages = [
|
|
5215
|
+
...finalMessages.slice(0, sysIdx),
|
|
5216
|
+
ccSystemMsg,
|
|
5217
|
+
...finalMessages.slice(sysIdx)
|
|
5218
|
+
];
|
|
5219
|
+
} else {
|
|
5220
|
+
finalMessages = [ccSystemMsg, ...finalMessages];
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5213
5224
|
const wasPruned = (pruningMode === "balanced" || pruningMode === "aggressive") && (postStats.messageCount < preStats.messageCount || postStats.totalBytes < preStats.totalBytes);
|
|
5214
5225
|
return {
|
|
5215
5226
|
messages: finalMessages,
|
|
@@ -5298,6 +5309,7 @@ function buildTurnPreparation(input) {
|
|
|
5298
5309
|
function buildStreamTextRequest(input) {
|
|
5299
5310
|
return {
|
|
5300
5311
|
model: input.model,
|
|
5312
|
+
maxOutputTokens: 16384,
|
|
5301
5313
|
messages: input.prepared.messages,
|
|
5302
5314
|
tools: input.toolSet,
|
|
5303
5315
|
stopWhen: stepCountIs(input.maxSteps),
|
|
@@ -5435,7 +5447,7 @@ async function* runTurn(options) {
|
|
|
5435
5447
|
}
|
|
5436
5448
|
|
|
5437
5449
|
// src/session/manager.ts
|
|
5438
|
-
import * as
|
|
5450
|
+
import * as c10 from "yoctocolors";
|
|
5439
5451
|
function newSession(model, cwd) {
|
|
5440
5452
|
const id = generateSessionId();
|
|
5441
5453
|
const row = createSession({ id, cwd, model });
|
|
@@ -5454,19 +5466,19 @@ function touchActiveSession(session) {
|
|
|
5454
5466
|
function printSessionList() {
|
|
5455
5467
|
const sessions = listSessions(20);
|
|
5456
5468
|
if (sessions.length === 0) {
|
|
5457
|
-
|
|
5469
|
+
writeln(c10.dim("No sessions found."));
|
|
5458
5470
|
return;
|
|
5459
5471
|
}
|
|
5460
|
-
|
|
5461
|
-
${
|
|
5472
|
+
writeln(`
|
|
5473
|
+
${c10.bold("Recent sessions:")}`);
|
|
5462
5474
|
for (const s of sessions) {
|
|
5463
5475
|
const date = new Date(s.updated_at).toLocaleString();
|
|
5464
5476
|
const cwd = tildePath(s.cwd);
|
|
5465
|
-
const title = s.title ||
|
|
5466
|
-
|
|
5477
|
+
const title = s.title || c10.dim("(untitled)");
|
|
5478
|
+
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)}`);
|
|
5467
5479
|
}
|
|
5468
|
-
|
|
5469
|
-
${
|
|
5480
|
+
writeln(`
|
|
5481
|
+
${c10.dim("Use")} mc --resume <id> ${c10.dim("to continue a session.")}`);
|
|
5470
5482
|
}
|
|
5471
5483
|
function getMostRecentSession() {
|
|
5472
5484
|
const sessions = listSessions(1);
|
|
@@ -5696,7 +5708,7 @@ class SessionRunner {
|
|
|
5696
5708
|
}
|
|
5697
5709
|
this.session = resumed;
|
|
5698
5710
|
this.currentModel = this.session.model;
|
|
5699
|
-
this.reporter.info(`Resumed session ${this.session.id} (${
|
|
5711
|
+
this.reporter.info(`Resumed session ${this.session.id} (${c11.cyan(this.currentModel)})`);
|
|
5700
5712
|
} else {
|
|
5701
5713
|
this.session = newSession(this.currentModel, this.cwd);
|
|
5702
5714
|
}
|
|
@@ -6160,13 +6172,12 @@ ${input.command}`], {
|
|
|
6160
6172
|
reader.cancel().catch(() => {});
|
|
6161
6173
|
}
|
|
6162
6174
|
}, timeout);
|
|
6163
|
-
async function collectStream(stream
|
|
6175
|
+
async function collectStream(stream) {
|
|
6164
6176
|
const reader = stream.getReader();
|
|
6165
6177
|
readers.push(reader);
|
|
6166
6178
|
const chunks = [];
|
|
6167
6179
|
let totalBytes = 0;
|
|
6168
6180
|
let truncated = false;
|
|
6169
|
-
const decoder = new TextDecoder;
|
|
6170
6181
|
while (true) {
|
|
6171
6182
|
try {
|
|
6172
6183
|
const { done, value } = await reader.read();
|
|
@@ -6174,7 +6185,6 @@ ${input.command}`], {
|
|
|
6174
6185
|
break;
|
|
6175
6186
|
if (!value)
|
|
6176
6187
|
continue;
|
|
6177
|
-
onChunk?.(decoder.decode(value, { stream: true }));
|
|
6178
6188
|
if (totalBytes + value.length > MAX_OUTPUT_BYTES) {
|
|
6179
6189
|
chunks.push(value.slice(0, MAX_OUTPUT_BYTES - totalBytes));
|
|
6180
6190
|
truncated = true;
|
|
@@ -6194,28 +6204,11 @@ ${input.command}`], {
|
|
|
6194
6204
|
let stdout = "";
|
|
6195
6205
|
let stderr = "";
|
|
6196
6206
|
let exitCode = 1;
|
|
6197
|
-
const onOutput = input.onOutput;
|
|
6198
|
-
const hasOutputHandler = typeof onOutput === "function";
|
|
6199
|
-
let streamedAnyOutput = false;
|
|
6200
|
-
let streamedEndsWithNewline = true;
|
|
6201
|
-
const emitOutput = (chunk) => {
|
|
6202
|
-
if (!chunk || !hasOutputHandler)
|
|
6203
|
-
return;
|
|
6204
|
-
const handled = onOutput(chunk);
|
|
6205
|
-
if (handled === false)
|
|
6206
|
-
return;
|
|
6207
|
-
streamedAnyOutput = true;
|
|
6208
|
-
streamedEndsWithNewline = /[\r\n]$/.test(chunk);
|
|
6209
|
-
};
|
|
6210
6207
|
try {
|
|
6211
6208
|
[stdout, stderr] = await Promise.all([
|
|
6212
|
-
collectStream(proc.stdout
|
|
6213
|
-
collectStream(proc.stderr
|
|
6209
|
+
collectStream(proc.stdout),
|
|
6210
|
+
collectStream(proc.stderr)
|
|
6214
6211
|
]);
|
|
6215
|
-
if (streamedAnyOutput && !streamedEndsWithNewline) {
|
|
6216
|
-
emitOutput(`
|
|
6217
|
-
`);
|
|
6218
|
-
}
|
|
6219
6212
|
exitCode = await proc.exited;
|
|
6220
6213
|
} finally {
|
|
6221
6214
|
clearTimeout(timer);
|
|
@@ -6231,8 +6224,7 @@ ${input.command}`], {
|
|
|
6231
6224
|
stderr: stderr.trimEnd(),
|
|
6232
6225
|
exitCode,
|
|
6233
6226
|
success: exitCode === 0,
|
|
6234
|
-
timedOut
|
|
6235
|
-
streamedOutput: streamedAnyOutput
|
|
6227
|
+
timedOut
|
|
6236
6228
|
};
|
|
6237
6229
|
}
|
|
6238
6230
|
var shellTool = {
|
|
@@ -6305,22 +6297,9 @@ function withCwdDefault(tool, cwd) {
|
|
|
6305
6297
|
}
|
|
6306
6298
|
};
|
|
6307
6299
|
}
|
|
6308
|
-
function withShellOutput(tool, onOutput) {
|
|
6309
|
-
const originalExecute = tool.execute;
|
|
6310
|
-
return {
|
|
6311
|
-
...tool,
|
|
6312
|
-
execute: async (input) => {
|
|
6313
|
-
const patched = {
|
|
6314
|
-
...typeof input === "object" && input !== null ? input : {},
|
|
6315
|
-
onOutput
|
|
6316
|
-
};
|
|
6317
|
-
return originalExecute(patched);
|
|
6318
|
-
}
|
|
6319
|
-
};
|
|
6320
|
-
}
|
|
6321
6300
|
function buildToolSet2(opts) {
|
|
6322
|
-
const { cwd
|
|
6323
|
-
const shell =
|
|
6301
|
+
const { cwd } = opts;
|
|
6302
|
+
const shell = withCwdDefault(shellTool, cwd);
|
|
6324
6303
|
const tools = [
|
|
6325
6304
|
shell,
|
|
6326
6305
|
withCwdDefault(listSkillsTool, cwd),
|
|
@@ -6349,17 +6328,10 @@ async function initAgent(opts) {
|
|
|
6349
6328
|
const cwd = opts.cwd;
|
|
6350
6329
|
let currentModel = opts.model;
|
|
6351
6330
|
const { runSubagent, killAll } = createSubagentRunner(cwd, () => currentModel);
|
|
6352
|
-
let verboseOutputEnabled = opts.initialVerboseOutput;
|
|
6353
6331
|
const agents = loadAgents(cwd);
|
|
6354
6332
|
const tools = buildToolSet2({
|
|
6355
6333
|
cwd,
|
|
6356
6334
|
runSubagent,
|
|
6357
|
-
onShellOutput: (chunk) => {
|
|
6358
|
-
if (!verboseOutputEnabled)
|
|
6359
|
-
return false;
|
|
6360
|
-
opts.reporter.streamChunk(chunk);
|
|
6361
|
-
return true;
|
|
6362
|
-
},
|
|
6363
6335
|
availableAgents: subagentAgents(agents)
|
|
6364
6336
|
});
|
|
6365
6337
|
const mcpTools = [];
|
|
@@ -6383,7 +6355,7 @@ async function initAgent(opts) {
|
|
|
6383
6355
|
for (const row of listMcpServers()) {
|
|
6384
6356
|
try {
|
|
6385
6357
|
await connectAndAddMcp(row.name);
|
|
6386
|
-
opts.reporter.info(`MCP: connected ${
|
|
6358
|
+
opts.reporter.info(`MCP: connected ${c12.cyan(row.name)}`);
|
|
6387
6359
|
} catch (e) {
|
|
6388
6360
|
opts.reporter.error(`MCP: failed to connect ${row.name}: ${String(e)}`);
|
|
6389
6361
|
}
|
|
@@ -6448,7 +6420,6 @@ async function initAgent(opts) {
|
|
|
6448
6420
|
},
|
|
6449
6421
|
setVerboseOutput: (verbose) => {
|
|
6450
6422
|
runner.verboseOutput = verbose;
|
|
6451
|
-
verboseOutputEnabled = verbose;
|
|
6452
6423
|
setPreferredVerboseOutput(verbose);
|
|
6453
6424
|
},
|
|
6454
6425
|
get pruningMode() {
|
|
@@ -6506,7 +6477,7 @@ async function initAgent(opts) {
|
|
|
6506
6477
|
}
|
|
6507
6478
|
|
|
6508
6479
|
// src/cli/args.ts
|
|
6509
|
-
import * as
|
|
6480
|
+
import * as c13 from "yoctocolors";
|
|
6510
6481
|
function parseArgs(argv) {
|
|
6511
6482
|
const args = {
|
|
6512
6483
|
model: null,
|
|
@@ -6570,11 +6541,11 @@ function parseArgs(argv) {
|
|
|
6570
6541
|
return args;
|
|
6571
6542
|
}
|
|
6572
6543
|
function printHelp() {
|
|
6573
|
-
|
|
6544
|
+
writeln(`${c13.bold("mini-coder")} \u2014 a small, fast CLI coding agent
|
|
6574
6545
|
`);
|
|
6575
|
-
|
|
6546
|
+
writeln(`${c13.bold("Usage:")} mc [options] [prompt]
|
|
6576
6547
|
`);
|
|
6577
|
-
|
|
6548
|
+
writeln(`${c13.bold("Options:")}`);
|
|
6578
6549
|
const opts = [
|
|
6579
6550
|
["-m, --model <id>", "Model to use (e.g. zen/claude-sonnet-4-6)"],
|
|
6580
6551
|
["-c, --continue", "Continue the most recent session"],
|
|
@@ -6584,10 +6555,10 @@ function printHelp() {
|
|
|
6584
6555
|
["-h, --help", "Show this help"]
|
|
6585
6556
|
];
|
|
6586
6557
|
for (const [flag, desc] of opts) {
|
|
6587
|
-
|
|
6558
|
+
writeln(` ${c13.cyan((flag ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
|
|
6588
6559
|
}
|
|
6589
|
-
|
|
6590
|
-
${
|
|
6560
|
+
writeln(`
|
|
6561
|
+
${c13.bold("Provider env vars:")}`);
|
|
6591
6562
|
const envs = [
|
|
6592
6563
|
["OPENCODE_API_KEY", "OpenCode Zen (recommended)"],
|
|
6593
6564
|
["ANTHROPIC_API_KEY", "Anthropic direct"],
|
|
@@ -6598,22 +6569,22 @@ ${c14.bold("Provider env vars:")}`);
|
|
|
6598
6569
|
["OLLAMA_BASE_URL", "Ollama base URL (default: http://localhost:11434)"]
|
|
6599
6570
|
];
|
|
6600
6571
|
for (const [env, desc] of envs) {
|
|
6601
|
-
|
|
6572
|
+
writeln(` ${c13.yellow((env ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
|
|
6602
6573
|
}
|
|
6603
|
-
|
|
6604
|
-
${
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6574
|
+
writeln(`
|
|
6575
|
+
${c13.bold("Examples:")}`);
|
|
6576
|
+
writeln(` mc ${c13.dim("# interactive session")}`);
|
|
6577
|
+
writeln(` mc "explain this codebase" ${c13.dim("# one-shot prompt then exit")}`);
|
|
6578
|
+
writeln(` mc -c ${c13.dim("# continue last session")}`);
|
|
6579
|
+
writeln(` mc -m ollama/llama3.2 ${c13.dim("# use local Ollama model")}`);
|
|
6580
|
+
writeln(` mc -l ${c13.dim("# list sessions")}`);
|
|
6610
6581
|
}
|
|
6611
6582
|
|
|
6612
6583
|
// src/cli/bootstrap.ts
|
|
6613
6584
|
import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
6614
6585
|
import { homedir as homedir8 } from "os";
|
|
6615
6586
|
import { join as join12 } from "path";
|
|
6616
|
-
import * as
|
|
6587
|
+
import * as c14 from "yoctocolors";
|
|
6617
6588
|
var REVIEW_COMMAND_CONTENT = `---
|
|
6618
6589
|
description: Review recent changes for correctness, code quality, and performance
|
|
6619
6590
|
context: fork
|
|
@@ -6637,7 +6608,7 @@ function bootstrapGlobalDefaults() {
|
|
|
6637
6608
|
if (!existsSync8(reviewPath)) {
|
|
6638
6609
|
mkdirSync4(commandsDir, { recursive: true });
|
|
6639
6610
|
writeFileSync3(reviewPath, REVIEW_COMMAND_CONTENT, "utf-8");
|
|
6640
|
-
|
|
6611
|
+
writeln(`${c14.green("\u2713")} created ${c14.dim("~/.agents/commands/review.md")} ${c14.dim("(edit it to customise your reviews)")}`);
|
|
6641
6612
|
}
|
|
6642
6613
|
}
|
|
6643
6614
|
|
|
@@ -6702,7 +6673,6 @@ class HeadlessReporter {
|
|
|
6702
6673
|
error(_msg, _hint) {}
|
|
6703
6674
|
warn(_msg) {}
|
|
6704
6675
|
writeText(_text) {}
|
|
6705
|
-
streamChunk(_text) {}
|
|
6706
6676
|
startSpinner(_label) {}
|
|
6707
6677
|
stopSpinner() {}
|
|
6708
6678
|
async renderTurn(events, _opts) {
|
|
@@ -6752,7 +6722,7 @@ class HeadlessReporter {
|
|
|
6752
6722
|
}
|
|
6753
6723
|
|
|
6754
6724
|
// src/cli/input-loop.ts
|
|
6755
|
-
import * as
|
|
6725
|
+
import * as c22 from "yoctocolors";
|
|
6756
6726
|
|
|
6757
6727
|
// src/cli/cli-helpers.ts
|
|
6758
6728
|
async function getGitBranch(cwd) {
|
|
@@ -6773,67 +6743,67 @@ async function getGitBranch(cwd) {
|
|
|
6773
6743
|
}
|
|
6774
6744
|
|
|
6775
6745
|
// src/cli/commands.ts
|
|
6776
|
-
import * as
|
|
6746
|
+
import * as c21 from "yoctocolors";
|
|
6777
6747
|
|
|
6778
6748
|
// src/cli/commands-agent.ts
|
|
6779
|
-
import * as
|
|
6749
|
+
import * as c15 from "yoctocolors";
|
|
6780
6750
|
function handleAgentCommand(ctx, args) {
|
|
6781
6751
|
const raw = args.trim();
|
|
6782
6752
|
const agents = loadAgents(ctx.cwd);
|
|
6783
6753
|
if (!raw) {
|
|
6784
6754
|
if (agents.size === 0) {
|
|
6785
|
-
|
|
6786
|
-
|
|
6755
|
+
writeln(c15.dim(" no agents found (~/.agents/agents/ or .agents/agents/)"));
|
|
6756
|
+
writeln(c15.dim(" /agent <name> to activate \xB7 /agent off to deactivate"));
|
|
6787
6757
|
return;
|
|
6788
6758
|
}
|
|
6789
|
-
|
|
6790
|
-
|
|
6759
|
+
writeln();
|
|
6760
|
+
writeln(c15.dim(" agents:"));
|
|
6791
6761
|
for (const agent2 of agents.values()) {
|
|
6792
|
-
const modeTag = agent2.mode ?
|
|
6793
|
-
const srcTag = agent2.source === "local" ?
|
|
6794
|
-
const active = ctx.activeAgent === agent2.name ?
|
|
6795
|
-
|
|
6796
|
-
}
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6762
|
+
const modeTag = agent2.mode ? c15.dim(` [${agent2.mode}]`) : "";
|
|
6763
|
+
const srcTag = agent2.source === "local" ? c15.dim(" (local)") : c15.dim(" (global)");
|
|
6764
|
+
const active = ctx.activeAgent === agent2.name ? c15.cyan(" \u25C0 active") : "";
|
|
6765
|
+
writeln(` ${c15.magenta(`@${agent2.name}`.padEnd(26))} ${c15.dim(agent2.description)}${modeTag}${srcTag}${active}`);
|
|
6766
|
+
}
|
|
6767
|
+
writeln();
|
|
6768
|
+
writeln(c15.dim(" /agent <name> to activate \xB7 /agent off to deactivate"));
|
|
6769
|
+
writeln();
|
|
6800
6770
|
return;
|
|
6801
6771
|
}
|
|
6802
6772
|
if (raw.toLowerCase() === "off" || raw.toLowerCase() === "none") {
|
|
6803
6773
|
ctx.setActiveAgent(null);
|
|
6804
|
-
|
|
6774
|
+
writeln(`${PREFIX.info} ${c15.dim("active agent cleared")}`);
|
|
6805
6775
|
return;
|
|
6806
6776
|
}
|
|
6807
6777
|
const agent = agents.get(raw);
|
|
6808
6778
|
if (!agent) {
|
|
6809
|
-
|
|
6779
|
+
writeln(`${PREFIX.error} agent ${c15.cyan(raw)} not found`);
|
|
6810
6780
|
return;
|
|
6811
6781
|
}
|
|
6812
6782
|
ctx.setActiveAgent(raw, agent.systemPrompt);
|
|
6813
|
-
|
|
6783
|
+
writeln(`${PREFIX.success} active agent \u2192 ${c15.cyan(raw)} ${c15.dim("(instructions appended to system prompt)")}`);
|
|
6814
6784
|
}
|
|
6815
6785
|
|
|
6816
6786
|
// src/cli/commands-config.ts
|
|
6817
|
-
import * as
|
|
6787
|
+
import * as c16 from "yoctocolors";
|
|
6818
6788
|
function handleBooleanToggleCommand(opts) {
|
|
6819
6789
|
const mode = opts.args.trim().toLowerCase();
|
|
6820
6790
|
if (!mode) {
|
|
6821
6791
|
const nextValue = !opts.current;
|
|
6822
6792
|
opts.set(nextValue);
|
|
6823
|
-
|
|
6793
|
+
writeln(`${PREFIX.success} ${opts.label} ${nextValue ? c16.green("on") : c16.dim("off")}`);
|
|
6824
6794
|
return;
|
|
6825
6795
|
}
|
|
6826
6796
|
if (mode === "on") {
|
|
6827
6797
|
opts.set(true);
|
|
6828
|
-
|
|
6798
|
+
writeln(`${PREFIX.success} ${opts.label} ${c16.green("on")}`);
|
|
6829
6799
|
return;
|
|
6830
6800
|
}
|
|
6831
6801
|
if (mode === "off") {
|
|
6832
6802
|
opts.set(false);
|
|
6833
|
-
|
|
6803
|
+
writeln(`${PREFIX.success} ${opts.label} ${c16.dim("off")}`);
|
|
6834
6804
|
return;
|
|
6835
6805
|
}
|
|
6836
|
-
|
|
6806
|
+
writeln(`${PREFIX.error} usage: ${opts.usage}`);
|
|
6837
6807
|
}
|
|
6838
6808
|
function handleReasoningCommand(ctx, args) {
|
|
6839
6809
|
handleBooleanToggleCommand({
|
|
@@ -6857,105 +6827,105 @@ function handleContextCommand(ctx, args) {
|
|
|
6857
6827
|
const [subcommand, value] = args.trim().split(/\s+/, 2);
|
|
6858
6828
|
if (!subcommand) {
|
|
6859
6829
|
const capText = ctx.toolResultPayloadCapBytes <= 0 ? "off" : `${Math.round(ctx.toolResultPayloadCapBytes / 1024)}KB (${ctx.toolResultPayloadCapBytes} bytes)`;
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6830
|
+
writeln(`${PREFIX.info} pruning=${c16.cyan(ctx.pruningMode)} tool-result-cap=${c16.cyan(capText)}`);
|
|
6831
|
+
writeln(c16.dim(" usage: /context prune <off|balanced|aggressive>"));
|
|
6832
|
+
writeln(c16.dim(" /context cap <off|bytes|kb>"));
|
|
6863
6833
|
return;
|
|
6864
6834
|
}
|
|
6865
6835
|
if (subcommand === "prune") {
|
|
6866
6836
|
if (value === "off" || value === "balanced" || value === "aggressive") {
|
|
6867
6837
|
ctx.setPruningMode(value);
|
|
6868
|
-
|
|
6838
|
+
writeln(`${PREFIX.success} context pruning \u2192 ${c16.cyan(value)}`);
|
|
6869
6839
|
return;
|
|
6870
6840
|
}
|
|
6871
|
-
|
|
6841
|
+
writeln(`${PREFIX.error} usage: /context prune <off|balanced|aggressive>`);
|
|
6872
6842
|
return;
|
|
6873
6843
|
}
|
|
6874
6844
|
if (subcommand !== "cap") {
|
|
6875
|
-
|
|
6845
|
+
writeln(`${PREFIX.error} usage: /context <prune|cap> ...`);
|
|
6876
6846
|
return;
|
|
6877
6847
|
}
|
|
6878
6848
|
if (!value) {
|
|
6879
|
-
|
|
6849
|
+
writeln(`${PREFIX.error} usage: /context cap <off|bytes|kb>`);
|
|
6880
6850
|
return;
|
|
6881
6851
|
}
|
|
6882
6852
|
if (value === "off") {
|
|
6883
6853
|
ctx.setToolResultPayloadCapBytes(0);
|
|
6884
|
-
|
|
6854
|
+
writeln(`${PREFIX.success} tool-result payload cap disabled`);
|
|
6885
6855
|
return;
|
|
6886
6856
|
}
|
|
6887
6857
|
const capMatch = value.match(/^(\d+)(kb)?$/i);
|
|
6888
6858
|
if (!capMatch) {
|
|
6889
|
-
|
|
6859
|
+
writeln(`${PREFIX.error} invalid cap: ${c16.cyan(value)}`);
|
|
6890
6860
|
return;
|
|
6891
6861
|
}
|
|
6892
6862
|
const base = Number.parseInt(capMatch[1] ?? "", 10);
|
|
6893
6863
|
const capBytes = (capMatch[2] ?? "").toLowerCase() === "kb" ? base * 1024 : base;
|
|
6894
6864
|
if (!Number.isFinite(capBytes) || capBytes < 0) {
|
|
6895
|
-
|
|
6865
|
+
writeln(`${PREFIX.error} invalid cap: ${c16.cyan(value)}`);
|
|
6896
6866
|
return;
|
|
6897
6867
|
}
|
|
6898
6868
|
ctx.setToolResultPayloadCapBytes(capBytes);
|
|
6899
|
-
|
|
6869
|
+
writeln(`${PREFIX.success} tool-result payload cap \u2192 ${c16.cyan(`${capBytes} bytes`)}`);
|
|
6900
6870
|
}
|
|
6901
6871
|
function handleCacheCommand(ctx, args) {
|
|
6902
6872
|
const [subcommand, value] = args.trim().split(/\s+/, 2);
|
|
6903
6873
|
if (!subcommand) {
|
|
6904
|
-
const geminiCache = ctx.googleCachedContent ?
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6874
|
+
const geminiCache = ctx.googleCachedContent ? c16.cyan(ctx.googleCachedContent) : "off";
|
|
6875
|
+
writeln(`${PREFIX.info} prompt-caching=${ctx.promptCachingEnabled ? c16.green("on") : c16.dim("off")} openai-retention=${c16.cyan(ctx.openaiPromptCacheRetention)} gemini-cache=${geminiCache}`);
|
|
6876
|
+
writeln(c16.dim(" usage: /cache <on|off>"));
|
|
6877
|
+
writeln(c16.dim(" /cache openai <in_memory|24h>"));
|
|
6878
|
+
writeln(c16.dim(" /cache gemini <off|cachedContents/...>"));
|
|
6909
6879
|
return;
|
|
6910
6880
|
}
|
|
6911
6881
|
if (subcommand === "on" || subcommand === "off") {
|
|
6912
6882
|
ctx.setPromptCachingEnabled(subcommand === "on");
|
|
6913
|
-
|
|
6883
|
+
writeln(`${PREFIX.success} prompt caching \u2192 ${subcommand === "on" ? c16.green("on") : c16.dim("off")}`);
|
|
6914
6884
|
return;
|
|
6915
6885
|
}
|
|
6916
6886
|
if (subcommand === "openai") {
|
|
6917
6887
|
if (value === "in_memory" || value === "24h") {
|
|
6918
6888
|
ctx.setOpenAIPromptCacheRetention(value);
|
|
6919
|
-
|
|
6889
|
+
writeln(`${PREFIX.success} openai prompt cache retention \u2192 ${c16.cyan(value)}`);
|
|
6920
6890
|
return;
|
|
6921
6891
|
}
|
|
6922
|
-
|
|
6892
|
+
writeln(`${PREFIX.error} usage: /cache openai <in_memory|24h>`);
|
|
6923
6893
|
return;
|
|
6924
6894
|
}
|
|
6925
6895
|
if (subcommand !== "gemini") {
|
|
6926
|
-
|
|
6896
|
+
writeln(`${PREFIX.error} usage: /cache <on|off|openai|gemini> ...`);
|
|
6927
6897
|
return;
|
|
6928
6898
|
}
|
|
6929
6899
|
if (!value) {
|
|
6930
|
-
|
|
6900
|
+
writeln(`${PREFIX.error} usage: /cache gemini <off|cachedContents/...>`);
|
|
6931
6901
|
return;
|
|
6932
6902
|
}
|
|
6933
6903
|
if (value === "off") {
|
|
6934
6904
|
ctx.setGoogleCachedContent(null);
|
|
6935
|
-
|
|
6905
|
+
writeln(`${PREFIX.success} gemini cached content \u2192 ${c16.dim("off")}`);
|
|
6936
6906
|
return;
|
|
6937
6907
|
}
|
|
6938
6908
|
ctx.setGoogleCachedContent(value);
|
|
6939
|
-
|
|
6909
|
+
writeln(`${PREFIX.success} gemini cached content \u2192 ${c16.cyan(value)}`);
|
|
6940
6910
|
}
|
|
6941
6911
|
|
|
6942
6912
|
// src/cli/commands-help.ts
|
|
6943
|
-
import * as
|
|
6913
|
+
import * as c17 from "yoctocolors";
|
|
6944
6914
|
function renderEntries(entries) {
|
|
6945
6915
|
for (const [label, description] of entries) {
|
|
6946
|
-
|
|
6916
|
+
writeln(` ${c17.cyan(label.padEnd(28))} ${c17.dim(description)}`);
|
|
6947
6917
|
}
|
|
6948
6918
|
}
|
|
6949
6919
|
function renderHelpCommand(ctx, custom) {
|
|
6950
|
-
|
|
6951
|
-
|
|
6920
|
+
writeln();
|
|
6921
|
+
writeln(` ${c17.dim("session")}`);
|
|
6952
6922
|
renderEntries([
|
|
6953
6923
|
["/new", "start a fresh session"],
|
|
6954
6924
|
["/undo", "remove the last conversation turn"],
|
|
6955
6925
|
["/exit", "quit"]
|
|
6956
6926
|
]);
|
|
6957
|
-
|
|
6958
|
-
|
|
6927
|
+
writeln();
|
|
6928
|
+
writeln(` ${c17.dim("model + context")}`);
|
|
6959
6929
|
renderEntries([
|
|
6960
6930
|
["/model [id]", "list or switch models"],
|
|
6961
6931
|
["/reasoning [on|off]", "toggle reasoning display"],
|
|
@@ -6970,8 +6940,8 @@ function renderHelpCommand(ctx, custom) {
|
|
|
6970
6940
|
["/logout <provider>", "clear OAuth tokens"],
|
|
6971
6941
|
["/help", "show this help"]
|
|
6972
6942
|
]);
|
|
6973
|
-
|
|
6974
|
-
|
|
6943
|
+
writeln();
|
|
6944
|
+
writeln(` ${c17.dim("prompt")}`);
|
|
6975
6945
|
renderEntries([
|
|
6976
6946
|
["ask normally", "send a prompt to the current agent"],
|
|
6977
6947
|
["!cmd", "run a shell command and keep the result in context"],
|
|
@@ -6979,63 +6949,63 @@ function renderHelpCommand(ctx, custom) {
|
|
|
6979
6949
|
["@skill", "inject a skill into the prompt (Tab to complete)"]
|
|
6980
6950
|
]);
|
|
6981
6951
|
if (custom.size > 0) {
|
|
6982
|
-
|
|
6983
|
-
|
|
6952
|
+
writeln();
|
|
6953
|
+
writeln(` ${c17.dim("custom commands")}`);
|
|
6984
6954
|
for (const cmd of custom.values()) {
|
|
6985
|
-
const source = cmd.source === "local" ?
|
|
6986
|
-
|
|
6955
|
+
const source = cmd.source === "local" ? c17.dim("local") : c17.dim("global");
|
|
6956
|
+
writeln(` ${c17.green(`/${cmd.name}`.padEnd(28))} ${c17.dim(cmd.description)} ${c17.dim("\xB7")} ${source}`);
|
|
6987
6957
|
}
|
|
6988
6958
|
}
|
|
6989
6959
|
const agents = loadAgents(ctx.cwd);
|
|
6990
6960
|
if (agents.size > 0) {
|
|
6991
|
-
|
|
6992
|
-
|
|
6961
|
+
writeln();
|
|
6962
|
+
writeln(` ${c17.dim("agents")}`);
|
|
6993
6963
|
for (const agent of agents.values()) {
|
|
6994
|
-
const mode = agent.mode ?
|
|
6995
|
-
const source = agent.source === "local" ?
|
|
6996
|
-
|
|
6964
|
+
const mode = agent.mode ? c17.dim(agent.mode) : c17.dim("agent");
|
|
6965
|
+
const source = agent.source === "local" ? c17.dim("local") : c17.dim("global");
|
|
6966
|
+
writeln(` ${c17.magenta(agent.name.padEnd(28))} ${c17.dim(agent.description)} ${c17.dim("\xB7")} ${mode} ${c17.dim("\xB7")} ${source}`);
|
|
6997
6967
|
}
|
|
6998
6968
|
}
|
|
6999
6969
|
const skills = loadSkillsIndex(ctx.cwd);
|
|
7000
6970
|
if (skills.size > 0) {
|
|
7001
|
-
|
|
7002
|
-
|
|
6971
|
+
writeln();
|
|
6972
|
+
writeln(` ${c17.dim("skills")}`);
|
|
7003
6973
|
for (const skill of skills.values()) {
|
|
7004
|
-
const source = skill.source === "local" ?
|
|
7005
|
-
|
|
6974
|
+
const source = skill.source === "local" ? c17.dim("local") : c17.dim("global");
|
|
6975
|
+
writeln(` ${c17.yellow(`@${skill.name}`.padEnd(28))} ${c17.dim(skill.description)} ${c17.dim("\xB7")} ${source}`);
|
|
7006
6976
|
}
|
|
7007
6977
|
}
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
6978
|
+
writeln();
|
|
6979
|
+
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`);
|
|
6980
|
+
writeln();
|
|
7011
6981
|
}
|
|
7012
6982
|
|
|
7013
6983
|
// src/cli/commands-login.ts
|
|
7014
|
-
import * as
|
|
6984
|
+
import * as c18 from "yoctocolors";
|
|
7015
6985
|
function renderLoginHelp() {
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
6986
|
+
writeln();
|
|
6987
|
+
writeln(` ${c18.dim("usage:")}`);
|
|
6988
|
+
writeln(` /login ${c18.dim("show login status")}`);
|
|
6989
|
+
writeln(` /login <provider> ${c18.dim("login via OAuth")}`);
|
|
6990
|
+
writeln(` /logout <provider> ${c18.dim("clear saved tokens")}`);
|
|
6991
|
+
writeln();
|
|
6992
|
+
writeln(` ${c18.dim("providers:")}`);
|
|
7023
6993
|
for (const p of getOAuthProviders()) {
|
|
7024
|
-
const status = isLoggedIn(p.id) ?
|
|
7025
|
-
|
|
6994
|
+
const status = isLoggedIn(p.id) ? c18.green("logged in") : c18.dim("not logged in");
|
|
6995
|
+
writeln(` ${c18.cyan(p.id.padEnd(20))} ${p.name} ${c18.dim("\xB7")} ${status}`);
|
|
7026
6996
|
}
|
|
7027
|
-
|
|
6997
|
+
writeln();
|
|
7028
6998
|
}
|
|
7029
6999
|
function renderStatus() {
|
|
7030
7000
|
const loggedIn = listLoggedInProviders();
|
|
7031
7001
|
if (loggedIn.length === 0) {
|
|
7032
|
-
|
|
7002
|
+
writeln(`${PREFIX.info} ${c18.dim("no OAuth logins \u2014 use")} /login <provider>`);
|
|
7033
7003
|
return;
|
|
7034
7004
|
}
|
|
7035
7005
|
for (const id of loggedIn) {
|
|
7036
7006
|
const provider = getOAuthProvider(id);
|
|
7037
7007
|
const name = provider?.name ?? id;
|
|
7038
|
-
|
|
7008
|
+
writeln(`${PREFIX.success} ${c18.cyan(id)} ${c18.dim(name)}`);
|
|
7039
7009
|
}
|
|
7040
7010
|
}
|
|
7041
7011
|
async function handleLoginCommand(ctx, args) {
|
|
@@ -7050,13 +7020,13 @@ async function handleLoginCommand(ctx, args) {
|
|
|
7050
7020
|
}
|
|
7051
7021
|
const provider = getOAuthProvider(providerId);
|
|
7052
7022
|
if (!provider) {
|
|
7053
|
-
|
|
7023
|
+
writeln(`${PREFIX.error} unknown provider "${providerId}" \u2014 available: ${getOAuthProviders().map((p) => p.id).join(", ")}`);
|
|
7054
7024
|
return;
|
|
7055
7025
|
}
|
|
7056
7026
|
if (isLoggedIn(providerId)) {
|
|
7057
7027
|
const token = await getAccessToken(providerId);
|
|
7058
7028
|
if (token) {
|
|
7059
|
-
|
|
7029
|
+
writeln(`${PREFIX.success} already logged in to ${c18.cyan(provider.name)}`);
|
|
7060
7030
|
return;
|
|
7061
7031
|
}
|
|
7062
7032
|
}
|
|
@@ -7065,43 +7035,43 @@ async function handleLoginCommand(ctx, args) {
|
|
|
7065
7035
|
await login(providerId, {
|
|
7066
7036
|
onOpenUrl: (url, instructions) => {
|
|
7067
7037
|
ctx.stopSpinner();
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7038
|
+
writeln(`${PREFIX.info} ${instructions}`);
|
|
7039
|
+
writeln();
|
|
7040
|
+
writeln(` ${c18.cyan(url)}`);
|
|
7041
|
+
writeln();
|
|
7072
7042
|
const open = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
7073
7043
|
Bun.spawn([open, url], { stdout: "ignore", stderr: "ignore" });
|
|
7074
7044
|
ctx.startSpinner("waiting for browser callback");
|
|
7075
7045
|
},
|
|
7076
7046
|
onProgress: (msg) => {
|
|
7077
7047
|
ctx.stopSpinner();
|
|
7078
|
-
|
|
7048
|
+
writeln(`${PREFIX.info} ${c18.dim(msg)}`);
|
|
7079
7049
|
ctx.startSpinner("exchanging tokens");
|
|
7080
7050
|
}
|
|
7081
7051
|
});
|
|
7082
7052
|
ctx.stopSpinner();
|
|
7083
|
-
|
|
7053
|
+
writeln(`${PREFIX.success} logged in to ${c18.cyan(provider.name)}`);
|
|
7084
7054
|
} catch (err) {
|
|
7085
7055
|
ctx.stopSpinner();
|
|
7086
|
-
|
|
7056
|
+
writeln(`${PREFIX.error} login failed: ${err.message}`);
|
|
7087
7057
|
}
|
|
7088
7058
|
}
|
|
7089
7059
|
function handleLogoutCommand(_ctx, args) {
|
|
7090
7060
|
const providerId = args.trim().toLowerCase();
|
|
7091
7061
|
if (!providerId) {
|
|
7092
|
-
|
|
7062
|
+
writeln(`${PREFIX.error} usage: /logout <provider>`);
|
|
7093
7063
|
return;
|
|
7094
7064
|
}
|
|
7095
7065
|
if (!isLoggedIn(providerId)) {
|
|
7096
|
-
|
|
7066
|
+
writeln(`${PREFIX.info} ${c18.dim("not logged in to")} ${providerId}`);
|
|
7097
7067
|
return;
|
|
7098
7068
|
}
|
|
7099
7069
|
logout(providerId);
|
|
7100
|
-
|
|
7070
|
+
writeln(`${PREFIX.success} logged out of ${c18.cyan(providerId)}`);
|
|
7101
7071
|
}
|
|
7102
7072
|
|
|
7103
7073
|
// src/cli/commands-mcp.ts
|
|
7104
|
-
import * as
|
|
7074
|
+
import * as c19 from "yoctocolors";
|
|
7105
7075
|
async function handleMcpCommand(ctx, args) {
|
|
7106
7076
|
const parts = args.trim().split(/\s+/);
|
|
7107
7077
|
const sub = parts[0] ?? "list";
|
|
@@ -7109,28 +7079,28 @@ async function handleMcpCommand(ctx, args) {
|
|
|
7109
7079
|
case "list": {
|
|
7110
7080
|
const servers = listMcpServers();
|
|
7111
7081
|
if (servers.length === 0) {
|
|
7112
|
-
|
|
7113
|
-
|
|
7082
|
+
writeln(c19.dim(" no MCP servers configured"));
|
|
7083
|
+
writeln(c19.dim(" /mcp add <name> http <url> \xB7 /mcp add <name> stdio <cmd> [args...]"));
|
|
7114
7084
|
return;
|
|
7115
7085
|
}
|
|
7116
|
-
|
|
7086
|
+
writeln();
|
|
7117
7087
|
for (const s of servers) {
|
|
7118
|
-
const detail = s.url ?
|
|
7119
|
-
|
|
7088
|
+
const detail = s.url ? c19.dim(` ${s.url}`) : s.command ? c19.dim(` ${s.command}`) : "";
|
|
7089
|
+
writeln(` ${c19.yellow("\u2699")} ${c19.bold(s.name)} ${c19.dim(s.transport)}${detail}`);
|
|
7120
7090
|
}
|
|
7121
7091
|
return;
|
|
7122
7092
|
}
|
|
7123
7093
|
case "add": {
|
|
7124
7094
|
const [, name, transport, ...rest] = parts;
|
|
7125
7095
|
if (!name || !transport || rest.length === 0) {
|
|
7126
|
-
|
|
7127
|
-
|
|
7096
|
+
writeln(`${PREFIX.error} usage: /mcp add <name> http <url>`);
|
|
7097
|
+
writeln(`${PREFIX.error} /mcp add <name> stdio <cmd> [args...]`);
|
|
7128
7098
|
return;
|
|
7129
7099
|
}
|
|
7130
7100
|
if (transport === "http") {
|
|
7131
7101
|
const url = rest[0];
|
|
7132
7102
|
if (!url) {
|
|
7133
|
-
|
|
7103
|
+
writeln(`${PREFIX.error} usage: /mcp add <name> http <url>`);
|
|
7134
7104
|
return;
|
|
7135
7105
|
}
|
|
7136
7106
|
upsertMcpServer({
|
|
@@ -7144,7 +7114,7 @@ async function handleMcpCommand(ctx, args) {
|
|
|
7144
7114
|
} else if (transport === "stdio") {
|
|
7145
7115
|
const [command, ...cmdArgs] = rest;
|
|
7146
7116
|
if (!command) {
|
|
7147
|
-
|
|
7117
|
+
writeln(`${PREFIX.error} usage: /mcp add <name> stdio <cmd> [args...]`);
|
|
7148
7118
|
return;
|
|
7149
7119
|
}
|
|
7150
7120
|
upsertMcpServer({
|
|
@@ -7156,14 +7126,14 @@ async function handleMcpCommand(ctx, args) {
|
|
|
7156
7126
|
env: null
|
|
7157
7127
|
});
|
|
7158
7128
|
} else {
|
|
7159
|
-
|
|
7129
|
+
writeln(`${PREFIX.error} unknown transport: ${transport} (use http or stdio)`);
|
|
7160
7130
|
return;
|
|
7161
7131
|
}
|
|
7162
7132
|
try {
|
|
7163
7133
|
await ctx.connectMcpServer(name);
|
|
7164
|
-
|
|
7134
|
+
writeln(`${PREFIX.success} mcp server ${c19.cyan(name)} added and connected`);
|
|
7165
7135
|
} catch (e) {
|
|
7166
|
-
|
|
7136
|
+
writeln(`${PREFIX.success} mcp server ${c19.cyan(name)} saved ${c19.dim(`(connection failed: ${String(e)})`)}`);
|
|
7167
7137
|
}
|
|
7168
7138
|
return;
|
|
7169
7139
|
}
|
|
@@ -7171,21 +7141,21 @@ async function handleMcpCommand(ctx, args) {
|
|
|
7171
7141
|
case "rm": {
|
|
7172
7142
|
const [, name] = parts;
|
|
7173
7143
|
if (!name) {
|
|
7174
|
-
|
|
7144
|
+
writeln(`${PREFIX.error} usage: /mcp remove <name>`);
|
|
7175
7145
|
return;
|
|
7176
7146
|
}
|
|
7177
7147
|
deleteMcpServer(name);
|
|
7178
|
-
|
|
7148
|
+
writeln(`${PREFIX.success} mcp server ${c19.cyan(name)} removed`);
|
|
7179
7149
|
return;
|
|
7180
7150
|
}
|
|
7181
7151
|
default:
|
|
7182
|
-
|
|
7183
|
-
|
|
7152
|
+
writeln(`${PREFIX.error} unknown: /mcp ${sub}`);
|
|
7153
|
+
writeln(c19.dim(" subcommands: list \xB7 add \xB7 remove"));
|
|
7184
7154
|
}
|
|
7185
7155
|
}
|
|
7186
7156
|
|
|
7187
7157
|
// src/cli/commands-model.ts
|
|
7188
|
-
import * as
|
|
7158
|
+
import * as c20 from "yoctocolors";
|
|
7189
7159
|
var THINKING_EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
7190
7160
|
function parseThinkingEffort(value) {
|
|
7191
7161
|
return THINKING_EFFORTS.includes(value) ? value : null;
|
|
@@ -7204,21 +7174,21 @@ function renderModelUpdatedMessage(ctx, modelId, effortArg) {
|
|
|
7204
7174
|
if (effortArg) {
|
|
7205
7175
|
if (effortArg === "off") {
|
|
7206
7176
|
ctx.setThinkingEffort(null);
|
|
7207
|
-
|
|
7177
|
+
writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)} ${c20.dim("(thinking disabled)")}`);
|
|
7208
7178
|
return;
|
|
7209
7179
|
}
|
|
7210
7180
|
const effort = parseThinkingEffort(effortArg);
|
|
7211
7181
|
if (effort) {
|
|
7212
7182
|
ctx.setThinkingEffort(effort);
|
|
7213
|
-
|
|
7183
|
+
writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)} ${c20.dim(`(\u2726 ${effort})`)}`);
|
|
7214
7184
|
return;
|
|
7215
7185
|
}
|
|
7216
|
-
|
|
7217
|
-
|
|
7186
|
+
writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)}`);
|
|
7187
|
+
writeln(`${PREFIX.error} unknown effort level ${c20.cyan(effortArg)} (use low, medium, high, xhigh, off)`);
|
|
7218
7188
|
return;
|
|
7219
7189
|
}
|
|
7220
|
-
const effortTag = ctx.thinkingEffort ?
|
|
7221
|
-
|
|
7190
|
+
const effortTag = ctx.thinkingEffort ? c20.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
|
|
7191
|
+
writeln(`${PREFIX.success} model \u2192 ${c20.cyan(modelId)}${effortTag}`);
|
|
7222
7192
|
}
|
|
7223
7193
|
async function handleModelSet(ctx, args) {
|
|
7224
7194
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
@@ -7231,7 +7201,7 @@ async function handleModelSet(ctx, args) {
|
|
|
7231
7201
|
const snapshot = await fetchAvailableModels();
|
|
7232
7202
|
const match = findModelIdByAlias(idArg, snapshot.models.map((model) => model.id));
|
|
7233
7203
|
if (!match) {
|
|
7234
|
-
|
|
7204
|
+
writeln(`${PREFIX.error} unknown model ${c20.cyan(idArg)} ${c20.dim("\u2014 run /models for the full list")}`);
|
|
7235
7205
|
return;
|
|
7236
7206
|
}
|
|
7237
7207
|
modelId = match;
|
|
@@ -7242,30 +7212,30 @@ async function handleModelSet(ctx, args) {
|
|
|
7242
7212
|
function handleModelEffort(ctx, effortArg) {
|
|
7243
7213
|
if (effortArg === "off") {
|
|
7244
7214
|
ctx.setThinkingEffort(null);
|
|
7245
|
-
|
|
7215
|
+
writeln(`${PREFIX.success} thinking effort disabled`);
|
|
7246
7216
|
return;
|
|
7247
7217
|
}
|
|
7248
7218
|
const effort = parseThinkingEffort(effortArg);
|
|
7249
7219
|
if (!effort) {
|
|
7250
|
-
|
|
7220
|
+
writeln(`${PREFIX.error} usage: /model effort <low|medium|high|xhigh|off>`);
|
|
7251
7221
|
return;
|
|
7252
7222
|
}
|
|
7253
7223
|
ctx.setThinkingEffort(effort);
|
|
7254
|
-
|
|
7224
|
+
writeln(`${PREFIX.success} thinking effort \u2192 ${c20.cyan(effort)}`);
|
|
7255
7225
|
}
|
|
7256
7226
|
async function renderModelList(ctx) {
|
|
7257
7227
|
ctx.startSpinner("fetching models");
|
|
7258
7228
|
const snapshot = await fetchAvailableModels();
|
|
7259
7229
|
ctx.stopSpinner();
|
|
7260
7230
|
if (snapshot.models.length === 0) {
|
|
7261
|
-
|
|
7262
|
-
|
|
7231
|
+
writeln(`${PREFIX.error} No models found. Check your API keys or Ollama connection.`);
|
|
7232
|
+
writeln(c20.dim(" Set OPENCODE_API_KEY for Zen, or start Ollama for local models."));
|
|
7263
7233
|
return;
|
|
7264
7234
|
}
|
|
7265
7235
|
if (snapshot.stale) {
|
|
7266
7236
|
const lastSync = snapshot.lastSyncAt ? new Date(snapshot.lastSyncAt).toLocaleString() : "never";
|
|
7267
7237
|
const refreshTag = snapshot.refreshing ? " (refreshing in background)" : "";
|
|
7268
|
-
|
|
7238
|
+
writeln(c20.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
|
|
7269
7239
|
}
|
|
7270
7240
|
const modelsByProvider = new Map;
|
|
7271
7241
|
for (const model of snapshot.models) {
|
|
@@ -7276,22 +7246,22 @@ async function renderModelList(ctx) {
|
|
|
7276
7246
|
modelsByProvider.set(model.provider, [model]);
|
|
7277
7247
|
}
|
|
7278
7248
|
}
|
|
7279
|
-
|
|
7249
|
+
writeln();
|
|
7280
7250
|
for (const [provider, providerModels] of modelsByProvider) {
|
|
7281
|
-
|
|
7251
|
+
writeln(c20.bold(` ${provider}`));
|
|
7282
7252
|
for (const model of providerModels) {
|
|
7283
7253
|
const isCurrent = ctx.currentModel === model.id;
|
|
7284
|
-
const freeTag = model.free ?
|
|
7285
|
-
const contextTag = model.context ?
|
|
7286
|
-
const effortTag = isCurrent && ctx.thinkingEffort ?
|
|
7287
|
-
const currentTag = isCurrent ?
|
|
7288
|
-
|
|
7289
|
-
|
|
7254
|
+
const freeTag = model.free ? c20.green(" free") : "";
|
|
7255
|
+
const contextTag = model.context ? c20.dim(` ${Math.round(model.context / 1000)}k`) : "";
|
|
7256
|
+
const effortTag = isCurrent && ctx.thinkingEffort ? c20.dim(` \u2726 ${ctx.thinkingEffort}`) : "";
|
|
7257
|
+
const currentTag = isCurrent ? c20.cyan(" \u25C0") : "";
|
|
7258
|
+
writeln(` ${c20.dim("\xB7")} ${model.displayName}${freeTag}${contextTag}${currentTag}${effortTag}`);
|
|
7259
|
+
writeln(` ${c20.dim(model.id)}`);
|
|
7290
7260
|
}
|
|
7291
7261
|
}
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7262
|
+
writeln();
|
|
7263
|
+
writeln(c20.dim(" /model <id> to switch \xB7 e.g. /model zen/claude-sonnet-4-6"));
|
|
7264
|
+
writeln(c20.dim(" /model effort <low|medium|high|xhigh|off> to set thinking effort"));
|
|
7295
7265
|
}
|
|
7296
7266
|
async function handleModelCommand(ctx, args) {
|
|
7297
7267
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
@@ -7312,9 +7282,9 @@ async function handleUndo(ctx) {
|
|
|
7312
7282
|
try {
|
|
7313
7283
|
const ok = await ctx.undoLastTurn();
|
|
7314
7284
|
if (ok) {
|
|
7315
|
-
|
|
7285
|
+
writeln(`${PREFIX.success} ${c21.dim("last conversation turn removed")}`);
|
|
7316
7286
|
} else {
|
|
7317
|
-
|
|
7287
|
+
writeln(`${PREFIX.info} ${c21.dim("nothing to undo")}`);
|
|
7318
7288
|
}
|
|
7319
7289
|
} finally {
|
|
7320
7290
|
ctx.stopSpinner();
|
|
@@ -7327,11 +7297,11 @@ function handleNew(ctx) {
|
|
|
7327
7297
|
}
|
|
7328
7298
|
async function handleCustomCommand(cmd, args, ctx) {
|
|
7329
7299
|
const prompt = await expandTemplate(cmd.template, args, ctx.cwd);
|
|
7330
|
-
const label =
|
|
7300
|
+
const label = c21.cyan(cmd.name);
|
|
7331
7301
|
const srcPath = cmd.source === "local" ? `.agents/commands/${cmd.name}.md` : `~/.agents/commands/${cmd.name}.md`;
|
|
7332
|
-
const src =
|
|
7333
|
-
|
|
7334
|
-
|
|
7302
|
+
const src = c21.dim(`[${srcPath}]`);
|
|
7303
|
+
writeln(`${PREFIX.info} ${label} ${src}`);
|
|
7304
|
+
writeln();
|
|
7335
7305
|
const fork = cmd.context === "fork" || cmd.subtask === true;
|
|
7336
7306
|
if (!fork) {
|
|
7337
7307
|
return { type: "inject-user-message", text: prompt };
|
|
@@ -7343,8 +7313,8 @@ async function handleCustomCommand(cmd, args, ctx) {
|
|
|
7343
7313
|
try {
|
|
7344
7314
|
ctx.startSpinner("subagent");
|
|
7345
7315
|
const output = await ctx.runSubagent(prompt, cmd.agent, cmd.model, abortController.signal);
|
|
7346
|
-
|
|
7347
|
-
|
|
7316
|
+
write(output.result);
|
|
7317
|
+
writeln();
|
|
7348
7318
|
return {
|
|
7349
7319
|
type: "inject-user-message",
|
|
7350
7320
|
text: `/${cmd.name} output:
|
|
@@ -7357,7 +7327,7 @@ ${output.result}
|
|
|
7357
7327
|
if (isAbortError(e)) {
|
|
7358
7328
|
return { type: "handled" };
|
|
7359
7329
|
}
|
|
7360
|
-
|
|
7330
|
+
writeln(`${PREFIX.error} /${cmd.name} failed: ${String(e)}`);
|
|
7361
7331
|
return { type: "handled" };
|
|
7362
7332
|
} finally {
|
|
7363
7333
|
stopWatcher();
|
|
@@ -7414,7 +7384,7 @@ async function handleCommand(command, args, ctx) {
|
|
|
7414
7384
|
case "q":
|
|
7415
7385
|
return { type: "exit" };
|
|
7416
7386
|
default: {
|
|
7417
|
-
|
|
7387
|
+
writeln(`${PREFIX.error} unknown: /${command} ${c21.dim("\u2014 /help for commands")}`);
|
|
7418
7388
|
return { type: "unknown", command };
|
|
7419
7389
|
}
|
|
7420
7390
|
}
|
|
@@ -7510,7 +7480,7 @@ async function runInputLoop(opts) {
|
|
|
7510
7480
|
}
|
|
7511
7481
|
switch (input.type) {
|
|
7512
7482
|
case "eof":
|
|
7513
|
-
reporter.writeText(
|
|
7483
|
+
reporter.writeText(c22.dim("Goodbye."));
|
|
7514
7484
|
return;
|
|
7515
7485
|
case "interrupt":
|
|
7516
7486
|
gitBranchCache.refreshInBackground();
|
|
@@ -7518,7 +7488,7 @@ async function runInputLoop(opts) {
|
|
|
7518
7488
|
case "command": {
|
|
7519
7489
|
const result = await handleCommand(input.command, input.args, cmdCtx);
|
|
7520
7490
|
if (result.type === "exit") {
|
|
7521
|
-
reporter.writeText(
|
|
7491
|
+
reporter.writeText(c22.dim("Goodbye."));
|
|
7522
7492
|
return;
|
|
7523
7493
|
}
|
|
7524
7494
|
if (result.type === "inject-user-message") {
|
|
@@ -7536,13 +7506,7 @@ async function runInputLoop(opts) {
|
|
|
7536
7506
|
const result = await runShellCommand({
|
|
7537
7507
|
command: input.command,
|
|
7538
7508
|
timeout: 30000,
|
|
7539
|
-
cwd
|
|
7540
|
-
...cmdCtx.verboseOutput ? {
|
|
7541
|
-
onOutput: (chunk) => {
|
|
7542
|
-
reporter.streamChunk(chunk);
|
|
7543
|
-
return true;
|
|
7544
|
-
}
|
|
7545
|
-
} : {}
|
|
7509
|
+
cwd
|
|
7546
7510
|
});
|
|
7547
7511
|
renderToolResult("shell", result, false, {
|
|
7548
7512
|
verboseOutput: cmdCtx.verboseOutput
|
|
@@ -7597,8 +7561,8 @@ async function resolvePromptInput(promptArg, opts) {
|
|
|
7597
7561
|
|
|
7598
7562
|
// src/cli/structured-output.ts
|
|
7599
7563
|
import { createTwoFilesPatch } from "diff";
|
|
7600
|
-
function writeJsonLine(
|
|
7601
|
-
|
|
7564
|
+
function writeJsonLine(write2, payload) {
|
|
7565
|
+
write2(`${JSON.stringify(payload)}
|
|
7602
7566
|
`);
|
|
7603
7567
|
}
|
|
7604
7568
|
|
|
@@ -7654,7 +7618,7 @@ async function main() {
|
|
|
7654
7618
|
if (last) {
|
|
7655
7619
|
sessionId = last.id;
|
|
7656
7620
|
} else {
|
|
7657
|
-
|
|
7621
|
+
writeln(c23.dim("No previous session found, starting fresh."));
|
|
7658
7622
|
}
|
|
7659
7623
|
} else if (args.sessionId) {
|
|
7660
7624
|
sessionId = args.sessionId;
|
|
@@ -7721,7 +7685,7 @@ async function main() {
|
|
|
7721
7685
|
const { text: resolvedText, images: refImages } = await resolveFileRefs(prompt, args.cwd);
|
|
7722
7686
|
await runner.processUserInput(resolvedText, refImages);
|
|
7723
7687
|
const { totalIn, totalOut } = runner.getStatusInfo();
|
|
7724
|
-
|
|
7688
|
+
writeln(`${G.info} ${c23.dim(`${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out tokens`)}`);
|
|
7725
7689
|
return;
|
|
7726
7690
|
}
|
|
7727
7691
|
await runInputLoop({
|