mini-coder 0.2.2 → 0.3.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
@@ -2,10 +2,10 @@
2
2
  // @bun
3
3
 
4
4
  // src/index.ts
5
- import * as c22 from "yoctocolors";
5
+ import * as c21 from "yoctocolors";
6
6
 
7
7
  // src/agent/agent.ts
8
- import * as c12 from "yoctocolors";
8
+ import * as c11 from "yoctocolors";
9
9
 
10
10
  // src/mcp/client.ts
11
11
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
@@ -13,7 +13,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
13
13
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
14
14
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
15
15
  // src/internal/version.ts
16
- var PACKAGE_VERSION = "0.2.2";
16
+ var PACKAGE_VERSION = "0.3.0";
17
17
 
18
18
  // src/mcp/client.ts
19
19
  async function connectMcpServer(config) {
@@ -339,7 +339,7 @@ function deleteMcpServer(name) {
339
339
  }
340
340
  // src/cli/output.ts
341
341
  import { homedir as homedir4 } from "os";
342
- import * as c8 from "yoctocolors";
342
+ import * as c7 from "yoctocolors";
343
343
 
344
344
  // src/agent/context-files.ts
345
345
  import { existsSync as existsSync2, readFileSync } from "fs";
@@ -577,9 +577,153 @@ var anthropicOAuth = {
577
577
  refreshToken: refreshAnthropicToken
578
578
  };
579
579
 
580
+ // src/session/oauth/openai.ts
581
+ import { createServer as createServer2 } from "http";
582
+ var CLIENT_ID2 = "app_EMoamEEZ73f0CkXaXp7hrann";
583
+ var AUTHORIZE_URL2 = "https://auth.openai.com/oauth/authorize";
584
+ var TOKEN_URL2 = "https://auth.openai.com/oauth/token";
585
+ var CALLBACK_HOST2 = "127.0.0.1";
586
+ var CALLBACK_PORT2 = 1455;
587
+ var CALLBACK_PATH2 = "/auth/callback";
588
+ var REDIRECT_URI2 = `http://localhost:${CALLBACK_PORT2}${CALLBACK_PATH2}`;
589
+ var SCOPES2 = "openid profile email offline_access";
590
+ var LOGIN_TIMEOUT_MS2 = 5 * 60 * 1000;
591
+ var SUCCESS_HTML2 = `<!doctype html>
592
+ <html lang="en"><head><meta charset="utf-8"><title>Authenticated</title></head>
593
+ <body><p>OpenAI authentication successful. Return to your terminal.</p></body></html>`;
594
+ function createState() {
595
+ const bytes = new Uint8Array(16);
596
+ crypto.getRandomValues(bytes);
597
+ let hex = "";
598
+ for (const b of bytes)
599
+ hex += b.toString(16).padStart(2, "0");
600
+ return hex;
601
+ }
602
+ function startCallbackServer2(expectedState) {
603
+ return new Promise((resolve2, reject) => {
604
+ let result = null;
605
+ let cancelled = false;
606
+ const server = createServer2((req, res) => {
607
+ const url = new URL(req.url ?? "", "http://localhost");
608
+ if (url.pathname !== CALLBACK_PATH2) {
609
+ res.writeHead(404).end("Not found");
610
+ return;
611
+ }
612
+ const code = url.searchParams.get("code");
613
+ const state = url.searchParams.get("state");
614
+ const error = url.searchParams.get("error");
615
+ if (error || !code || !state || state !== expectedState) {
616
+ res.writeHead(400).end("Authentication failed.");
617
+ return;
618
+ }
619
+ res.writeHead(200, { "Content-Type": "text/html" }).end(SUCCESS_HTML2);
620
+ result = { code };
621
+ });
622
+ server.on("error", reject);
623
+ server.listen(CALLBACK_PORT2, CALLBACK_HOST2, () => {
624
+ resolve2({
625
+ server,
626
+ cancel: () => {
627
+ cancelled = true;
628
+ },
629
+ waitForCode: async () => {
630
+ const deadline = Date.now() + LOGIN_TIMEOUT_MS2;
631
+ while (!result && !cancelled && Date.now() < deadline) {
632
+ await new Promise((r) => setTimeout(r, 100));
633
+ }
634
+ return result;
635
+ }
636
+ });
637
+ });
638
+ });
639
+ }
640
+ async function postTokenRequest2(body, label) {
641
+ const res = await fetch(TOKEN_URL2, {
642
+ method: "POST",
643
+ headers: {
644
+ "Content-Type": "application/x-www-form-urlencoded"
645
+ },
646
+ body,
647
+ signal: AbortSignal.timeout(30000)
648
+ });
649
+ if (!res.ok) {
650
+ const text = await res.text();
651
+ throw new Error(`${label} failed (${res.status}): ${text}`);
652
+ }
653
+ const data = await res.json();
654
+ return {
655
+ access: data.access_token,
656
+ refresh: data.refresh_token,
657
+ expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000
658
+ };
659
+ }
660
+ function exchangeCode2(code, verifier) {
661
+ return postTokenRequest2(new URLSearchParams({
662
+ grant_type: "authorization_code",
663
+ client_id: CLIENT_ID2,
664
+ code,
665
+ code_verifier: verifier,
666
+ redirect_uri: REDIRECT_URI2
667
+ }), "Token exchange");
668
+ }
669
+ function refreshOpenAIToken(refreshToken) {
670
+ return postTokenRequest2(new URLSearchParams({
671
+ grant_type: "refresh_token",
672
+ refresh_token: refreshToken,
673
+ client_id: CLIENT_ID2
674
+ }), "Token refresh");
675
+ }
676
+ async function loginOpenAI(callbacks) {
677
+ const { verifier, challenge } = await generatePKCE();
678
+ const state = createState();
679
+ const cb = await startCallbackServer2(state);
680
+ try {
681
+ const params = new URLSearchParams({
682
+ response_type: "code",
683
+ client_id: CLIENT_ID2,
684
+ redirect_uri: REDIRECT_URI2,
685
+ scope: SCOPES2,
686
+ code_challenge: challenge,
687
+ code_challenge_method: "S256",
688
+ state,
689
+ id_token_add_organizations: "true",
690
+ codex_cli_simplified_flow: "true",
691
+ originator: "mc"
692
+ });
693
+ callbacks.onOpenUrl(`${AUTHORIZE_URL2}?${params}`, "Complete login in your browser.");
694
+ const result = await cb.waitForCode();
695
+ if (!result)
696
+ throw new Error("Login cancelled or no code received");
697
+ callbacks.onProgress("Exchanging authorization code for tokens\u2026");
698
+ return exchangeCode2(result.code, verifier);
699
+ } finally {
700
+ cb.server.close();
701
+ }
702
+ }
703
+ function extractAccountId(accessToken) {
704
+ try {
705
+ const parts = accessToken.split(".");
706
+ const jwt = parts[1];
707
+ if (parts.length !== 3 || !jwt)
708
+ return null;
709
+ const payload = JSON.parse(atob(jwt));
710
+ const auth = payload["https://api.openai.com/auth"];
711
+ return auth?.chatgpt_account_id ?? null;
712
+ } catch {
713
+ return null;
714
+ }
715
+ }
716
+ var openaiOAuth = {
717
+ id: "openai",
718
+ name: "OpenAI (ChatGPT Plus/Pro)",
719
+ login: loginOpenAI,
720
+ refreshToken: refreshOpenAIToken
721
+ };
722
+
580
723
  // src/session/oauth/auth-storage.ts
581
724
  var PROVIDERS = new Map([
582
- [anthropicOAuth.id, anthropicOAuth]
725
+ [anthropicOAuth.id, anthropicOAuth],
726
+ [openaiOAuth.id, openaiOAuth]
583
727
  ]);
584
728
  function getOAuthProviders() {
585
729
  return [...PROVIDERS.values()];
@@ -1140,15 +1284,42 @@ async function fetchZenModels() {
1140
1284
  });
1141
1285
  }
1142
1286
  async function fetchOpenAIModels() {
1143
- const key = process.env.OPENAI_API_KEY;
1144
- if (!key)
1287
+ const envKey = process.env.OPENAI_API_KEY;
1288
+ if (envKey) {
1289
+ return fetchPaginatedModelsList(`${OPENAI_BASE}/v1/models`, { headers: { Authorization: `Bearer ${envKey}` } }, 6000, "data", "id", (_item, modelId) => ({
1290
+ providerModelId: modelId,
1291
+ displayName: modelId,
1292
+ contextWindow: null,
1293
+ free: false
1294
+ }));
1295
+ }
1296
+ if (isLoggedIn("openai")) {
1297
+ const token = await getAccessToken("openai");
1298
+ if (!token)
1299
+ return null;
1300
+ return fetchCodexOAuthModels(token);
1301
+ }
1302
+ return null;
1303
+ }
1304
+ var CODEX_MODELS_URL = "https://chatgpt.com/backend-api/codex/models?client_version=1.0.0";
1305
+ async function fetchCodexOAuthModels(token) {
1306
+ try {
1307
+ const res = await fetch(CODEX_MODELS_URL, {
1308
+ headers: { Authorization: `Bearer ${token}` },
1309
+ signal: AbortSignal.timeout(6000)
1310
+ });
1311
+ if (!res.ok)
1312
+ return null;
1313
+ const data = await res.json();
1314
+ return (data.models ?? []).filter((m) => m.visibility === "list").map((m) => ({
1315
+ providerModelId: m.slug,
1316
+ displayName: m.display_name || m.slug,
1317
+ contextWindow: m.context_window,
1318
+ free: false
1319
+ }));
1320
+ } catch {
1145
1321
  return null;
1146
- return fetchPaginatedModelsList(`${OPENAI_BASE}/v1/models`, { headers: { Authorization: `Bearer ${key}` } }, 6000, "data", "id", (_item, modelId) => ({
1147
- providerModelId: modelId,
1148
- displayName: modelId,
1149
- contextWindow: null,
1150
- free: false
1151
- }));
1322
+ }
1152
1323
  }
1153
1324
  async function getAnthropicAuth() {
1154
1325
  const envKey = process.env.ANTHROPIC_API_KEY;
@@ -1236,7 +1407,7 @@ async function fetchProviderCandidates(provider) {
1236
1407
  var MODELS_DEV_SYNC_KEY = "last_models_dev_sync_at";
1237
1408
  var PROVIDER_SYNC_KEY_PREFIX = "last_provider_sync_at:";
1238
1409
  var CACHE_VERSION_KEY = "model_info_cache_version";
1239
- var CACHE_VERSION = 3;
1410
+ var CACHE_VERSION = 5;
1240
1411
  var MODEL_INFO_TTL_MS = 24 * 60 * 60 * 1000;
1241
1412
  var REMOTE_PROVIDER_ENV_KEYS = [
1242
1413
  { provider: "zen", envKeys: ["OPENCODE_API_KEY"] },
@@ -1281,8 +1452,10 @@ function hasAnyEnvKey(env, keys) {
1281
1452
  }
1282
1453
  function getRemoteProvidersFromEnv(env) {
1283
1454
  const providers = REMOTE_PROVIDER_ENV_KEYS.filter((entry) => hasAnyEnvKey(env, entry.envKeys)).map((entry) => entry.provider);
1284
- if (!providers.includes("anthropic") && isLoggedIn("anthropic")) {
1285
- providers.push("anthropic");
1455
+ for (const p of ["anthropic", "openai"]) {
1456
+ if (!providers.includes(p) && isLoggedIn(p)) {
1457
+ providers.push(p);
1458
+ }
1286
1459
  }
1287
1460
  return providers;
1288
1461
  }
@@ -1586,10 +1759,64 @@ var ZEN_BACKEND_RESOLVERS = {
1586
1759
  function resolveZenModel(modelId) {
1587
1760
  return ZEN_BACKEND_RESOLVERS[getZenBackend(modelId)](modelId);
1588
1761
  }
1589
- function resolveOpenAIModel(modelId) {
1762
+ function createOAuthOpenAIProvider(token) {
1763
+ const accountId = extractAccountId(token);
1764
+ return createOpenAI({
1765
+ apiKey: "oauth",
1766
+ baseURL: OPENAI_CODEX_BASE_URL,
1767
+ fetch: (input, init) => {
1768
+ const h = new Headers(init?.headers);
1769
+ h.delete("OpenAI-Organization");
1770
+ h.delete("OpenAI-Project");
1771
+ h.set("Authorization", `Bearer ${token}`);
1772
+ if (accountId)
1773
+ h.set("chatgpt-account-id", accountId);
1774
+ let body = init?.body;
1775
+ if (typeof body === "string") {
1776
+ try {
1777
+ const parsed = JSON.parse(body);
1778
+ if (parsed.input && Array.isArray(parsed.input)) {
1779
+ if (!parsed.instructions) {
1780
+ const sysIdx = parsed.input.findIndex((m) => m.role === "developer" || m.role === "system");
1781
+ if (sysIdx !== -1) {
1782
+ const sysMsg = parsed.input[sysIdx];
1783
+ parsed.instructions = typeof sysMsg.content === "string" ? sysMsg.content : JSON.stringify(sysMsg.content);
1784
+ parsed.input.splice(sysIdx, 1);
1785
+ }
1786
+ }
1787
+ delete parsed.max_output_tokens;
1788
+ parsed.store = false;
1789
+ parsed.stream = true;
1790
+ body = JSON.stringify(parsed);
1791
+ }
1792
+ } catch {}
1793
+ }
1794
+ return fetch(input, {
1795
+ ...init,
1796
+ body,
1797
+ headers: Object.fromEntries(h.entries())
1798
+ });
1799
+ }
1800
+ });
1801
+ }
1802
+ async function resolveOpenAIModel(modelId) {
1803
+ if (isLoggedIn("openai")) {
1804
+ const token = await getAccessToken("openai");
1805
+ if (token) {
1806
+ if (!oauthOpenAICache || oauthOpenAICache.token !== token) {
1807
+ oauthOpenAICache = {
1808
+ token,
1809
+ provider: createOAuthOpenAIProvider(token)
1810
+ };
1811
+ }
1812
+ return oauthOpenAICache.provider.responses(modelId);
1813
+ }
1814
+ }
1590
1815
  return modelId.startsWith("gpt-") ? directProviders.openai().responses(modelId) : directProviders.openai()(modelId);
1591
1816
  }
1817
+ var OPENAI_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex";
1592
1818
  var oauthAnthropicCache = null;
1819
+ var oauthOpenAICache = null;
1593
1820
  function createOAuthAnthropicProvider(token) {
1594
1821
  return createAnthropic({
1595
1822
  apiKey: "",
@@ -1647,7 +1874,9 @@ function discoverConnectedProviders() {
1647
1874
  result.push({ name: "anthropic", via: "oauth" });
1648
1875
  else if (process.env.ANTHROPIC_API_KEY)
1649
1876
  result.push({ name: "anthropic", via: "env" });
1650
- if (process.env.OPENAI_API_KEY)
1877
+ if (isLoggedIn("openai"))
1878
+ result.push({ name: "openai", via: "oauth" });
1879
+ else if (process.env.OPENAI_API_KEY)
1651
1880
  result.push({ name: "openai", via: "env" });
1652
1881
  if (process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY)
1653
1882
  result.push({ name: "google", via: "env" });
@@ -1660,7 +1889,7 @@ function autoDiscoverModel() {
1660
1889
  return "zen/claude-sonnet-4-6";
1661
1890
  if (process.env.ANTHROPIC_API_KEY || isLoggedIn("anthropic"))
1662
1891
  return "anthropic/claude-sonnet-4-6";
1663
- if (process.env.OPENAI_API_KEY)
1892
+ if (process.env.OPENAI_API_KEY || isLoggedIn("openai"))
1664
1893
  return "openai/gpt-5.4";
1665
1894
  if (process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY)
1666
1895
  return "google/gemini-3.1-pro";
@@ -2290,9 +2519,6 @@ class Spinner {
2290
2519
  terminal.setBeforeWriteCallback(null);
2291
2520
  terminal.stderrWrite("\r\x1B[2K\x1B[?25h");
2292
2521
  }
2293
- update(label) {
2294
- this.label = label;
2295
- }
2296
2522
  _tick() {
2297
2523
  const f = SPINNER_FRAMES[this.frame++ % SPINNER_FRAMES.length] ?? "\u28FE";
2298
2524
  const label = this.label ? c2.dim(` ${this.label}`) : "";
@@ -2346,19 +2572,6 @@ function buildContextSegment(opts) {
2346
2572
  function renderStatusLine(segments) {
2347
2573
  return segments.join(STATUS_SEP);
2348
2574
  }
2349
- function buildStatusBarSignature(opts) {
2350
- return JSON.stringify({
2351
- model: opts.model,
2352
- cwd: opts.cwd,
2353
- gitBranch: opts.gitBranch,
2354
- sessionId: opts.sessionId,
2355
- inputTokens: opts.inputTokens,
2356
- outputTokens: opts.outputTokens,
2357
- contextTokens: opts.contextTokens,
2358
- contextWindow: opts.contextWindow,
2359
- thinkingEffort: opts.thinkingEffort ?? null
2360
- });
2361
- }
2362
2575
  function fitStatusSegments(required, optional, cols) {
2363
2576
  const fittedOptional = [...optional];
2364
2577
  let line = renderStatusLine([...required, ...fittedOptional]);
@@ -2400,7 +2613,8 @@ function renderStatusBar(opts) {
2400
2613
  }
2401
2614
 
2402
2615
  // src/cli/stream-render.ts
2403
- import * as c7 from "yoctocolors";
2616
+ import * as c6 from "yoctocolors";
2617
+ import { createHighlighter } from "yoctomarkdown";
2404
2618
 
2405
2619
  // src/llm-api/history/gemini.ts
2406
2620
  function getGeminiThoughtSignature(part) {
@@ -2658,60 +2872,6 @@ function extractAssistantText(newMessages) {
2658
2872
  `);
2659
2873
  }
2660
2874
 
2661
- // src/cli/live-reasoning.ts
2662
- import * as c4 from "yoctocolors";
2663
- function styleReasoningText(text) {
2664
- return c4.italic(c4.dim(text));
2665
- }
2666
-
2667
- class LiveReasoningBlock {
2668
- blockOpen = false;
2669
- lineOpen = false;
2670
- append(delta) {
2671
- if (!delta)
2672
- return;
2673
- this.openBlock();
2674
- const lines = delta.split(`
2675
- `);
2676
- for (const [index, line] of lines.entries()) {
2677
- if (line)
2678
- this.writeText(line);
2679
- if (index < lines.length - 1)
2680
- this.endLine();
2681
- }
2682
- }
2683
- isOpen() {
2684
- return this.blockOpen;
2685
- }
2686
- finish() {
2687
- if (!this.blockOpen)
2688
- return;
2689
- if (this.lineOpen)
2690
- writeln();
2691
- this.blockOpen = false;
2692
- this.lineOpen = false;
2693
- }
2694
- openBlock() {
2695
- if (this.blockOpen)
2696
- return;
2697
- writeln(`${G.info} ${c4.dim("reasoning")}`);
2698
- this.blockOpen = true;
2699
- }
2700
- writeText(text) {
2701
- if (!this.lineOpen) {
2702
- write(" ");
2703
- this.lineOpen = true;
2704
- }
2705
- write(styleReasoningText(text));
2706
- }
2707
- endLine() {
2708
- if (!this.lineOpen)
2709
- write(" ");
2710
- writeln();
2711
- this.lineOpen = false;
2712
- }
2713
- }
2714
-
2715
2875
  // src/cli/reasoning.ts
2716
2876
  function normalizeReasoningDelta(delta) {
2717
2877
  return delta.replace(/\r\n?/g, `
@@ -2745,130 +2905,34 @@ function normalizeReasoningText(text) {
2745
2905
  `);
2746
2906
  }
2747
2907
 
2748
- // src/cli/stream-render-content.ts
2749
- import { createHighlighter } from "yoctomarkdown";
2750
- class StreamRenderContent {
2751
- spinner;
2752
- quiet;
2753
- inText = false;
2754
- accumulatedText = "";
2755
- accumulatedReasoning = "";
2756
- highlighter;
2757
- constructor(spinner, quiet = false) {
2758
- this.spinner = spinner;
2759
- this.quiet = quiet;
2760
- }
2761
- getText() {
2762
- return this.accumulatedText;
2763
- }
2764
- getReasoning() {
2765
- return this.accumulatedReasoning;
2766
- }
2767
- hasOpenContent() {
2768
- return this.inText;
2769
- }
2770
- appendTextDelta(delta, renderedVisibleOutput) {
2771
- let text = delta ?? "";
2772
- if (!text)
2773
- return;
2774
- if (!this.inText) {
2775
- text = text.trimStart();
2776
- if (!text)
2777
- return;
2778
- if (!this.quiet) {
2779
- this.spinner.stop();
2780
- if (renderedVisibleOutput)
2781
- writeln();
2782
- write(`${G.reply} `);
2783
- }
2784
- this.inText = true;
2785
- if (!this.quiet && terminal.isStdoutTTY)
2786
- this.highlighter = createHighlighter();
2787
- }
2788
- const isFirstLine = !this.accumulatedText.includes(`
2789
- `);
2790
- this.accumulatedText += text;
2791
- if (this.quiet)
2792
- return;
2793
- this.spinner.stop();
2794
- if (this.highlighter) {
2795
- let colored = this.highlighter.write(text);
2796
- if (colored) {
2797
- if (isFirstLine && colored.startsWith("\x1B[2K\r")) {
2798
- colored = `\x1B[2K\r${G.reply} ${colored.slice(5)}`;
2799
- }
2800
- write(colored);
2801
- }
2802
- } else {
2803
- write(text);
2804
- }
2805
- }
2806
- appendReasoningDelta(delta) {
2807
- const text = delta ?? "";
2808
- if (!text)
2809
- return "";
2810
- let appended = text;
2811
- if (this.accumulatedReasoning.endsWith("**") && text.startsWith("**") && !this.accumulatedReasoning.endsWith(`
2812
- `)) {
2813
- appended = `
2814
- ${text}`;
2815
- }
2816
- this.accumulatedReasoning += appended;
2817
- return appended;
2818
- }
2819
- flushOpenContent() {
2820
- if (!this.inText)
2821
- return;
2822
- if (this.quiet) {
2823
- this.inText = false;
2824
- return;
2825
- }
2826
- if (this.highlighter) {
2827
- let finalColored = this.highlighter.end();
2828
- if (finalColored) {
2829
- const isFirstLine = !this.accumulatedText.includes(`
2830
- `);
2831
- if (isFirstLine && finalColored.startsWith("\x1B[2K\r")) {
2832
- finalColored = `\x1B[2K\r${G.reply} ${finalColored.slice(5)}`;
2833
- }
2834
- write(finalColored);
2835
- }
2836
- }
2837
- writeln();
2838
- this.inText = false;
2839
- }
2840
- }
2841
-
2842
2908
  // src/cli/tool-render.ts
2843
- import * as c6 from "yoctocolors";
2909
+ import * as c5 from "yoctocolors";
2844
2910
 
2845
2911
  // src/cli/tool-result-renderers.ts
2846
- import * as c5 from "yoctocolors";
2912
+ import * as c4 from "yoctocolors";
2847
2913
  function writePreviewLines(opts) {
2848
2914
  if (!opts.value.trim())
2849
2915
  return;
2850
2916
  const lines = opts.value.split(`
2851
2917
  `);
2852
- writeln(` ${c5.dim(opts.label)} ${c5.dim(`(${lines.length} lines)`)}`);
2918
+ if (opts.label)
2919
+ writeln(`${c4.dim(opts.label)} ${c4.dim(`(${lines.length} lines)`)}`);
2853
2920
  if (!Number.isFinite(opts.maxLines) || lines.length <= opts.maxLines) {
2854
- for (const line of lines) {
2855
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2856
- }
2921
+ for (const line of lines)
2922
+ writeln(line);
2857
2923
  return;
2858
2924
  }
2859
2925
  const headCount = Math.max(1, Math.ceil(opts.maxLines / 2));
2860
2926
  const tailCount = Math.max(0, Math.floor(opts.maxLines / 2));
2861
- for (const line of lines.slice(0, headCount)) {
2862
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2863
- }
2927
+ for (const line of lines.slice(0, headCount))
2928
+ writeln(line);
2864
2929
  const hiddenLines = Math.max(0, lines.length - (headCount + tailCount));
2865
2930
  if (hiddenLines > 0) {
2866
- writeln(` ${opts.lineColor("\u2502")} ${c5.dim(`\u2026 +${hiddenLines} lines`)}`);
2931
+ writeln(c4.dim(`\u2026 +${hiddenLines} lines`));
2867
2932
  }
2868
2933
  if (tailCount > 0) {
2869
- for (const line of lines.slice(-tailCount)) {
2870
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2871
- }
2934
+ for (const line of lines.slice(-tailCount))
2935
+ writeln(line);
2872
2936
  }
2873
2937
  }
2874
2938
  function truncateOneLine(value, max = 100, verboseOutput = false) {
@@ -2927,11 +2991,11 @@ function renderShellResult(result, opts) {
2927
2991
  const stdoutLines = countShellLines(r.stdout);
2928
2992
  const stderrLines = countShellLines(r.stderr);
2929
2993
  const stdoutSingleLine = getSingleShellLine(r.stdout);
2930
- let badge = c5.red("error");
2994
+ let badge = c4.red("error");
2931
2995
  if (r.timedOut)
2932
- badge = c5.yellow("timeout");
2996
+ badge = c4.yellow("timeout");
2933
2997
  else if (r.success)
2934
- badge = c5.green("done");
2998
+ badge = c4.green("done");
2935
2999
  const parts = buildShellSummaryParts({
2936
3000
  exitCode: r.exitCode,
2937
3001
  stdoutLines,
@@ -2939,11 +3003,10 @@ function renderShellResult(result, opts) {
2939
3003
  stdoutSingleLine,
2940
3004
  verboseOutput
2941
3005
  });
2942
- writeln(` ${badge} ${c5.dim(parts.join(" \xB7 "))}`);
3006
+ writeln(`${badge} ${c4.dim(parts.join(" \xB7 "))}`);
2943
3007
  writePreviewLines({
2944
3008
  label: "stderr",
2945
3009
  value: displayStderr,
2946
- lineColor: c5.red,
2947
3010
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 10
2948
3011
  });
2949
3012
  if (shouldPreviewShellStdout({
@@ -2955,7 +3018,6 @@ function renderShellResult(result, opts) {
2955
3018
  writePreviewLines({
2956
3019
  label: "stdout",
2957
3020
  value: displayStdout,
2958
- lineColor: c5.dim,
2959
3021
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 20
2960
3022
  });
2961
3023
  }
@@ -2966,21 +3028,21 @@ function buildSkillDescriptionPart(description, verboseOutput = false) {
2966
3028
  if (!trimmed)
2967
3029
  return "";
2968
3030
  if (verboseOutput)
2969
- return ` ${c5.dim("\xB7")} ${c5.dim(trimmed)}`;
2970
- return ` ${c5.dim("\xB7")} ${c5.dim(trimmed.length > 60 ? `${trimmed.slice(0, 57)}\u2026` : trimmed)}`;
3031
+ return ` ${c4.dim("\xB7")} ${c4.dim(trimmed)}`;
3032
+ return ` ${c4.dim("\xB7")} ${c4.dim(trimmed.length > 60 ? `${trimmed.slice(0, 57)}\u2026` : trimmed)}`;
2971
3033
  }
2972
3034
  function renderSkillSummaryLine(skill, opts) {
2973
3035
  const name = skill.name ?? "(unknown)";
2974
3036
  const source = skill.source ?? "unknown";
2975
- const labelPrefix = opts?.label ? `${c5.dim(opts.label)} ` : "";
2976
- writeln(` ${G.info} ${labelPrefix}${name} ${c5.dim("\xB7")} ${c5.dim(source)}${buildSkillDescriptionPart(skill.description, opts?.verboseOutput === true)}`);
3037
+ const labelPrefix = opts?.label ? `${c4.dim(opts.label)} ` : "";
3038
+ writeln(`${G.info} ${labelPrefix}${name} ${c4.dim("\xB7")} ${c4.dim(source)}${buildSkillDescriptionPart(skill.description, opts?.verboseOutput === true)}`);
2977
3039
  }
2978
3040
  function renderListSkillsResult(result, opts) {
2979
3041
  const r = result;
2980
3042
  if (!Array.isArray(r?.skills))
2981
3043
  return false;
2982
3044
  if (r.skills.length === 0) {
2983
- writeln(` ${G.info} ${c5.dim("no skills")}`);
3045
+ writeln(`${G.info} ${c4.dim("no skills")}`);
2984
3046
  return true;
2985
3047
  }
2986
3048
  const maxSkills = opts?.verboseOutput ? r.skills.length : 6;
@@ -2990,7 +3052,7 @@ function renderListSkillsResult(result, opts) {
2990
3052
  });
2991
3053
  }
2992
3054
  if (r.skills.length > maxSkills) {
2993
- writeln(` ${c5.dim(`+${r.skills.length - maxSkills} more skills`)}`);
3055
+ writeln(`${c4.dim(`+${r.skills.length - maxSkills} more skills`)}`);
2994
3056
  }
2995
3057
  return true;
2996
3058
  }
@@ -2999,7 +3061,7 @@ function renderReadSkillResult(result, _opts) {
2999
3061
  if (!r || typeof r !== "object")
3000
3062
  return false;
3001
3063
  if (!r.skill) {
3002
- writeln(` ${G.info} ${c5.dim("skill")} ${c5.dim("(not found)")}`);
3064
+ writeln(`${G.info} ${c4.dim("skill")} ${c4.dim("(not found)")}`);
3003
3065
  return true;
3004
3066
  }
3005
3067
  renderSkillSummaryLine(r.skill, {
@@ -3013,19 +3075,19 @@ function renderWebSearchResult(result, opts) {
3013
3075
  if (!Array.isArray(r?.results))
3014
3076
  return false;
3015
3077
  if (r.results.length === 0) {
3016
- writeln(` ${G.info} ${c5.dim("no results")}`);
3078
+ writeln(`${G.info} ${c4.dim("no results")}`);
3017
3079
  return true;
3018
3080
  }
3019
3081
  const maxResults = opts?.verboseOutput ? r.results.length : 5;
3020
3082
  for (const item of r.results.slice(0, maxResults)) {
3021
3083
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
3022
- const score = typeof item.score === "number" ? c5.dim(` (${item.score.toFixed(2)})`) : "";
3023
- writeln(` ${c5.dim("\u2022")} ${title}${score}`);
3084
+ const score = typeof item.score === "number" ? c4.dim(` (${item.score.toFixed(2)})`) : "";
3085
+ writeln(`${c4.dim("\u2022")} ${title}${score}`);
3024
3086
  if (item.url)
3025
- writeln(` ${c5.dim(item.url)}`);
3087
+ writeln(` ${c4.dim(item.url)}`);
3026
3088
  }
3027
3089
  if (r.results.length > maxResults) {
3028
- writeln(` ${c5.dim(` +${r.results.length - maxResults} more`)}`);
3090
+ writeln(`${c4.dim(`+${r.results.length - maxResults} more`)}`);
3029
3091
  }
3030
3092
  return true;
3031
3093
  }
@@ -3034,23 +3096,23 @@ function renderWebContentResult(result, opts) {
3034
3096
  if (!Array.isArray(r?.results))
3035
3097
  return false;
3036
3098
  if (r.results.length === 0) {
3037
- writeln(` ${G.info} ${c5.dim("no pages")}`);
3099
+ writeln(`${G.info} ${c4.dim("no pages")}`);
3038
3100
  return true;
3039
3101
  }
3040
3102
  const maxPages = opts?.verboseOutput ? r.results.length : 3;
3041
3103
  for (const item of r.results.slice(0, maxPages)) {
3042
3104
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
3043
- writeln(` ${c5.dim("\u2022")} ${title}`);
3105
+ writeln(`${c4.dim("\u2022")} ${title}`);
3044
3106
  if (item.url)
3045
- writeln(` ${c5.dim(item.url)}`);
3107
+ writeln(` ${c4.dim(item.url)}`);
3046
3108
  const preview = (item.text ?? "").replace(/\s+/g, " ").trim();
3047
3109
  if (preview) {
3048
3110
  const trimmed = opts?.verboseOutput || preview.length <= 220 ? preview : `${preview.slice(0, 217)}\u2026`;
3049
- writeln(` ${c5.dim(trimmed)}`);
3111
+ writeln(` ${c4.dim(trimmed)}`);
3050
3112
  }
3051
3113
  }
3052
3114
  if (r.results.length > maxPages) {
3053
- writeln(` ${c5.dim(` +${r.results.length - maxPages} more`)}`);
3115
+ writeln(`${c4.dim(`+${r.results.length - maxPages} more`)}`);
3054
3116
  }
3055
3117
  return true;
3056
3118
  }
@@ -3060,11 +3122,11 @@ function renderMcpResult(result, opts) {
3060
3122
  let rendered = false;
3061
3123
  for (const block of content.slice(0, maxBlocks)) {
3062
3124
  if (block?.type === "text" && block.text) {
3063
- const maxLines = opts?.verboseOutput ? Number.POSITIVE_INFINITY : 6;
3064
- const lines = block.text.split(`
3065
- `).slice(0, maxLines);
3066
- for (const line of lines)
3067
- writeln(` ${c5.dim("\u2502")} ${line}`);
3125
+ writePreviewLines({
3126
+ label: "",
3127
+ value: block.text,
3128
+ maxLines: opts?.verboseOutput ? Number.POSITIVE_INFINITY : 6
3129
+ });
3068
3130
  rendered = true;
3069
3131
  }
3070
3132
  }
@@ -3152,43 +3214,58 @@ function formatShellCallLine(cmd) {
3152
3214
  const { cwd, rest } = parseShellCdPrefix(cmd);
3153
3215
  const firstCmd = extractFirstCommand(rest);
3154
3216
  const glyph = shellCmdGlyph(firstCmd, rest);
3155
- const cwdSuffix = cwd ? ` ${c6.dim(`in ${cwd}`)}` : "";
3156
- const display = truncateText(rest, 80);
3157
- return `${glyph} ${display}${cwdSuffix}`;
3217
+ const cwdSuffix = cwd ? ` ${c5.dim(`in ${cwd}`)}` : "";
3218
+ return `${glyph} ${rest}${cwdSuffix}`;
3158
3219
  }
3159
3220
  function buildToolCallLine(name, args) {
3160
3221
  const a = args && typeof args === "object" ? args : {};
3161
3222
  if (name === "shell") {
3162
3223
  const cmd = String(a.command ?? "").trim();
3163
3224
  if (!cmd)
3164
- return `${G.run} ${c6.dim("shell")}`;
3225
+ return `${G.run} ${c5.dim("shell")}`;
3165
3226
  return formatShellCallLine(cmd);
3166
3227
  }
3167
3228
  if (name === "listSkills") {
3168
- return `${G.search} ${c6.dim("list skills")}`;
3229
+ return `${G.search} ${c5.dim("list skills")}`;
3169
3230
  }
3170
3231
  if (name === "readSkill") {
3171
3232
  const skillName = typeof a.name === "string" ? a.name : "";
3172
- return `${G.read} ${c6.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
3233
+ return `${G.read} ${c5.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
3173
3234
  }
3174
3235
  if (name === "webSearch") {
3175
3236
  const query = typeof a.query === "string" ? a.query : "";
3176
- const short = query.length > 60 ? `${query.slice(0, 57)}\u2026` : query;
3177
- return `${G.search} ${c6.dim("search")}${short ? ` ${short}` : ""}`;
3237
+ return `${G.search} ${c5.dim("search")}${query ? ` ${query}` : ""}`;
3178
3238
  }
3179
3239
  if (name === "webContent") {
3180
3240
  const urls = Array.isArray(a.urls) ? a.urls : [];
3181
3241
  const label = urls.length === 1 ? String(urls[0]) : `${urls.length} url${urls.length !== 1 ? "s" : ""}`;
3182
- const short = label.length > 60 ? `${label.slice(0, 57)}\u2026` : label;
3183
- return `${G.read} ${c6.dim("fetch")} ${short}`;
3242
+ return `${G.read} ${c5.dim("fetch")} ${label}`;
3184
3243
  }
3185
3244
  if (name.startsWith("mcp_")) {
3186
- return `${G.mcp} ${c6.dim(name)}`;
3245
+ return `${G.mcp} ${c5.dim(name)}`;
3187
3246
  }
3188
- return `${toolGlyph(name)} ${c6.dim(name)}`;
3247
+ return `${toolGlyph(name)} ${c5.dim(name)}`;
3189
3248
  }
3190
- function renderToolCall(toolName, args) {
3191
- writeln(` ${buildToolCallLine(toolName, args)}`);
3249
+ function renderToolCall(toolName, args, opts) {
3250
+ const line = buildToolCallLine(toolName, args);
3251
+ if (opts?.verboseOutput) {
3252
+ writeln(line);
3253
+ return;
3254
+ }
3255
+ const lines = line.split(`
3256
+ `);
3257
+ if (lines.length <= 6) {
3258
+ writeln(line);
3259
+ return;
3260
+ }
3261
+ const head = lines.slice(0, 3);
3262
+ const tail = lines.slice(-2);
3263
+ const hidden = lines.length - head.length - tail.length;
3264
+ for (const l of head)
3265
+ writeln(l);
3266
+ writeln(c5.dim(`\u2026 +${hidden} lines`));
3267
+ for (const l of tail)
3268
+ writeln(l);
3192
3269
  }
3193
3270
  function formatErrorBadge(result) {
3194
3271
  let msg;
@@ -3200,11 +3277,11 @@ function formatErrorBadge(result) {
3200
3277
  msg = JSON.stringify(result);
3201
3278
  const oneLiner = msg.split(`
3202
3279
  `)[0] ?? msg;
3203
- return `${G.err} ${c6.red(oneLiner)}`;
3280
+ return `${G.err} ${c5.red(oneLiner)}`;
3204
3281
  }
3205
3282
  function renderToolResult(toolName, result, isError, opts) {
3206
3283
  if (isError) {
3207
- writeln(` ${formatErrorBadge(result)}`);
3284
+ writeln(formatErrorBadge(result));
3208
3285
  return;
3209
3286
  }
3210
3287
  if (renderToolResultByName(toolName, result, opts)) {
@@ -3212,32 +3289,130 @@ function renderToolResult(toolName, result, isError, opts) {
3212
3289
  }
3213
3290
  const text = JSON.stringify(result);
3214
3291
  if (opts?.verboseOutput || text.length <= 120) {
3215
- writeln(` ${c6.dim(text)}`);
3292
+ writeln(c5.dim(text));
3216
3293
  return;
3217
3294
  }
3218
- writeln(` ${c6.dim(`${text.slice(0, 117)}\u2026`)}`);
3295
+ writeln(c5.dim(`${text.slice(0, 117)}\u2026`));
3219
3296
  }
3220
3297
 
3221
3298
  // src/cli/stream-render.ts
3299
+ function styleReasoning(text) {
3300
+ return c6.italic(c6.dim(text));
3301
+ }
3302
+ function writeReasoningDelta(delta, state) {
3303
+ if (!delta)
3304
+ return;
3305
+ if (!state.blockOpen) {
3306
+ writeln(`${G.info} ${c6.dim("reasoning")}`);
3307
+ state.blockOpen = true;
3308
+ }
3309
+ const lines = delta.split(`
3310
+ `);
3311
+ for (const [i, line] of lines.entries()) {
3312
+ if (line) {
3313
+ if (!state.lineOpen) {
3314
+ write(" ");
3315
+ state.lineOpen = true;
3316
+ }
3317
+ write(styleReasoning(line));
3318
+ }
3319
+ if (i < lines.length - 1) {
3320
+ if (!state.lineOpen)
3321
+ write(" ");
3322
+ writeln();
3323
+ state.lineOpen = false;
3324
+ }
3325
+ }
3326
+ }
3327
+ function finishReasoning(state) {
3328
+ if (!state.blockOpen)
3329
+ return;
3330
+ if (state.lineOpen)
3331
+ writeln();
3332
+ state.blockOpen = false;
3333
+ state.lineOpen = false;
3334
+ }
3335
+ function appendTextDelta(delta, state, spinner, quiet, renderedVisibleOutput) {
3336
+ let chunk = delta ?? "";
3337
+ if (!chunk)
3338
+ return state.inText;
3339
+ if (!state.inText) {
3340
+ chunk = chunk.trimStart();
3341
+ if (!chunk)
3342
+ return false;
3343
+ if (!quiet) {
3344
+ spinner.stop();
3345
+ if (renderedVisibleOutput)
3346
+ writeln();
3347
+ write(`${G.reply} `);
3348
+ }
3349
+ state.inText = true;
3350
+ if (!quiet && terminal.isStdoutTTY) {
3351
+ state.highlighter = createHighlighter();
3352
+ }
3353
+ }
3354
+ const isFirstLine = !state.text.includes(`
3355
+ `);
3356
+ state.text += chunk;
3357
+ if (quiet)
3358
+ return state.inText;
3359
+ spinner.stop();
3360
+ if (state.highlighter) {
3361
+ let colored = state.highlighter.write(chunk);
3362
+ if (colored) {
3363
+ if (isFirstLine && colored.startsWith("\x1B[2K\r")) {
3364
+ colored = `\x1B[2K\r${G.reply} ${colored.slice(5)}`;
3365
+ }
3366
+ write(colored);
3367
+ }
3368
+ } else {
3369
+ write(chunk);
3370
+ }
3371
+ return state.inText;
3372
+ }
3373
+ function flushText(state, quiet) {
3374
+ if (!state.inText)
3375
+ return;
3376
+ if (!quiet) {
3377
+ if (state.highlighter) {
3378
+ let finalColored = state.highlighter.end();
3379
+ if (finalColored) {
3380
+ const isFirstLine = !state.text.includes(`
3381
+ `);
3382
+ if (isFirstLine && finalColored.startsWith("\x1B[2K\r")) {
3383
+ finalColored = `\x1B[2K\r${G.reply} ${finalColored.slice(5)}`;
3384
+ }
3385
+ write(finalColored);
3386
+ }
3387
+ }
3388
+ writeln();
3389
+ }
3390
+ state.inText = false;
3391
+ }
3222
3392
  async function renderTurn(events, spinner, opts) {
3223
3393
  const quiet = opts?.quiet ?? false;
3224
3394
  const showReasoning = !quiet && (opts?.showReasoning ?? true);
3225
3395
  const verboseOutput = opts?.verboseOutput ?? false;
3226
- const content = new StreamRenderContent(spinner, quiet);
3227
- const liveReasoning = new LiveReasoningBlock;
3396
+ const textState = {
3397
+ inText: false,
3398
+ text: "",
3399
+ highlighter: undefined
3400
+ };
3401
+ let reasoningRaw = "";
3402
+ let reasoningComputed = false;
3403
+ let reasoningText = "";
3404
+ const reasoningState = { blockOpen: false, lineOpen: false };
3405
+ const startedToolCalls = new Set;
3406
+ const toolCallInfo = new Map;
3407
+ let parallelCallCount = 0;
3228
3408
  let inputTokens = 0;
3229
3409
  let outputTokens = 0;
3230
3410
  let contextTokens = 0;
3231
3411
  let newMessages = [];
3232
- const startedToolCalls = new Set;
3233
- const toolCallInfo = new Map;
3234
- let parallelCallCount = 0;
3235
3412
  let renderedVisibleOutput = false;
3236
- let reasoningComputed = false;
3237
- let reasoningText = "";
3238
3413
  const getReasoningText = () => {
3239
3414
  if (!reasoningComputed) {
3240
- reasoningText = normalizeReasoningText(content.getReasoning());
3415
+ reasoningText = normalizeReasoningText(reasoningRaw);
3241
3416
  reasoningComputed = true;
3242
3417
  }
3243
3418
  return reasoningText;
@@ -3245,29 +3420,42 @@ async function renderTurn(events, spinner, opts) {
3245
3420
  for await (const event of events) {
3246
3421
  switch (event.type) {
3247
3422
  case "text-delta": {
3248
- liveReasoning.finish();
3249
- content.appendTextDelta(event.delta, renderedVisibleOutput);
3250
- if (content.hasOpenContent())
3423
+ finishReasoning(reasoningState);
3424
+ textState.inText = appendTextDelta(event.delta, textState, spinner, quiet, renderedVisibleOutput);
3425
+ if (textState.inText)
3251
3426
  renderedVisibleOutput = true;
3252
3427
  break;
3253
3428
  }
3254
3429
  case "reasoning-delta": {
3255
- content.flushOpenContent();
3256
- const delta = content.appendReasoningDelta(normalizeReasoningDelta(event.delta));
3430
+ flushText(textState, quiet);
3431
+ let appended = normalizeReasoningDelta(event.delta);
3432
+ if (reasoningRaw.endsWith("**") && appended.startsWith("**") && !reasoningRaw.endsWith(`
3433
+ `)) {
3434
+ appended = `
3435
+ ${appended}`;
3436
+ }
3437
+ reasoningRaw += appended;
3257
3438
  reasoningComputed = false;
3258
- if (showReasoning && delta) {
3439
+ if (showReasoning && appended) {
3259
3440
  spinner.stop();
3260
- if (renderedVisibleOutput && !liveReasoning.isOpen())
3441
+ if (renderedVisibleOutput && !reasoningState.blockOpen)
3261
3442
  writeln();
3262
- liveReasoning.append(delta);
3443
+ writeReasoningDelta(appended, reasoningState);
3263
3444
  renderedVisibleOutput = true;
3264
3445
  }
3265
3446
  break;
3266
3447
  }
3448
+ case "tool-input-delta": {
3449
+ if (quiet)
3450
+ break;
3451
+ finishReasoning(reasoningState);
3452
+ flushText(textState, quiet);
3453
+ spinner.start(`composing ${event.toolName}\u2026`);
3454
+ break;
3455
+ }
3267
3456
  case "tool-call-start": {
3268
- if (startedToolCalls.has(event.toolCallId)) {
3457
+ if (startedToolCalls.has(event.toolCallId))
3269
3458
  break;
3270
- }
3271
3459
  const isConsecutiveToolCall = startedToolCalls.size > 0 && toolCallInfo.size > 0;
3272
3460
  startedToolCalls.add(event.toolCallId);
3273
3461
  toolCallInfo.set(event.toolCallId, {
@@ -3277,13 +3465,14 @@ async function renderTurn(events, spinner, opts) {
3277
3465
  if (toolCallInfo.size > 1) {
3278
3466
  parallelCallCount = toolCallInfo.size;
3279
3467
  }
3280
- liveReasoning.finish();
3281
- content.flushOpenContent();
3468
+ finishReasoning(reasoningState);
3469
+ flushText(textState, quiet);
3282
3470
  if (!quiet) {
3283
3471
  spinner.stop();
3284
- if (renderedVisibleOutput && !isConsecutiveToolCall)
3472
+ if (renderedVisibleOutput && !isConsecutiveToolCall) {
3285
3473
  writeln();
3286
- renderToolCall(event.toolName, event.args);
3474
+ }
3475
+ renderToolCall(event.toolName, event.args, { verboseOutput });
3287
3476
  renderedVisibleOutput = true;
3288
3477
  spinner.start(event.toolName);
3289
3478
  }
@@ -3293,11 +3482,11 @@ async function renderTurn(events, spinner, opts) {
3293
3482
  startedToolCalls.delete(event.toolCallId);
3294
3483
  const callInfo = toolCallInfo.get(event.toolCallId);
3295
3484
  toolCallInfo.delete(event.toolCallId);
3296
- liveReasoning.finish();
3485
+ finishReasoning(reasoningState);
3297
3486
  if (!quiet) {
3298
3487
  spinner.stop();
3299
3488
  if (parallelCallCount > 1 && callInfo) {
3300
- writeln(` ${c7.dim("\u21B3")} ${callInfo.label}`);
3489
+ writeln(`${c6.dim("\u21B3")} ${callInfo.label}`);
3301
3490
  }
3302
3491
  if (toolCallInfo.size === 0)
3303
3492
  parallelCallCount = 0;
@@ -3313,19 +3502,20 @@ async function renderTurn(events, spinner, opts) {
3313
3502
  break;
3314
3503
  }
3315
3504
  case "context-pruned": {
3316
- liveReasoning.finish();
3317
- content.flushOpenContent();
3505
+ finishReasoning(reasoningState);
3506
+ flushText(textState, quiet);
3318
3507
  if (!quiet) {
3319
3508
  spinner.stop();
3320
3509
  const removedKb = (event.removedBytes / 1024).toFixed(1);
3321
- writeln(`${G.info} ${c7.dim("context pruned")} ${c7.dim(`\u2013${event.removedMessageCount} messages`)} ${c7.dim(`\u2013${removedKb} KB`)}`);
3510
+ writeln(`${G.info} ${c6.dim("context pruned")} ${c6.dim(`\u2013${event.removedMessageCount} messages`)} ${c6.dim(`\u2013${removedKb} KB`)}`);
3322
3511
  renderedVisibleOutput = true;
3512
+ spinner.start("thinking");
3323
3513
  }
3324
3514
  break;
3325
3515
  }
3326
3516
  case "turn-complete": {
3327
- liveReasoning.finish();
3328
- content.flushOpenContent();
3517
+ finishReasoning(reasoningState);
3518
+ flushText(textState, quiet);
3329
3519
  spinner.stop();
3330
3520
  if (!quiet && !renderedVisibleOutput)
3331
3521
  writeln();
@@ -3336,14 +3526,14 @@ async function renderTurn(events, spinner, opts) {
3336
3526
  break;
3337
3527
  }
3338
3528
  case "turn-error": {
3339
- liveReasoning.finish();
3340
- content.flushOpenContent();
3529
+ finishReasoning(reasoningState);
3530
+ flushText(textState, quiet);
3341
3531
  spinner.stop();
3342
3532
  inputTokens = event.inputTokens;
3343
3533
  outputTokens = event.outputTokens;
3344
3534
  contextTokens = event.contextTokens;
3345
3535
  if (isAbortError(event.error)) {
3346
- newMessages = buildAbortMessages(event.partialMessages, content.getText());
3536
+ newMessages = buildAbortMessages(event.partialMessages, textState.text);
3347
3537
  } else {
3348
3538
  renderError(event.error, "turn");
3349
3539
  throw new RenderedError(event.error);
@@ -3392,17 +3582,17 @@ function renderUserMessage(text) {
3392
3582
  }
3393
3583
  }
3394
3584
  var G = {
3395
- prompt: c8.green("\u203A"),
3396
- reply: c8.cyan("\u25C6"),
3397
- search: c8.yellow("?"),
3398
- read: c8.dim("\u2190"),
3399
- write: c8.green("\u270E"),
3400
- run: c8.dim("$"),
3401
- mcp: c8.yellow("\u2699"),
3402
- ok: c8.green("\u2714"),
3403
- err: c8.red("\u2716"),
3404
- warn: c8.yellow("!"),
3405
- info: c8.dim("\xB7")
3585
+ prompt: c7.green("\u203A"),
3586
+ reply: c7.cyan("\u25C6"),
3587
+ search: c7.yellow("?"),
3588
+ read: c7.dim("\u2190"),
3589
+ write: c7.green("\u270E"),
3590
+ run: c7.dim("$"),
3591
+ mcp: c7.yellow("\u2699"),
3592
+ ok: c7.green("\u2714"),
3593
+ err: c7.red("\u2716"),
3594
+ warn: c7.yellow("!"),
3595
+ info: c7.dim("\xB7")
3406
3596
  };
3407
3597
  var PREFIX = {
3408
3598
  user: G.prompt,
@@ -3424,17 +3614,17 @@ class RenderedError extends Error {
3424
3614
  function renderError(err, context = "render") {
3425
3615
  logError(err, context);
3426
3616
  const parsed = parseAppError(err);
3427
- writeln(`${G.err} ${c8.red(parsed.headline)}`);
3617
+ writeln(`${G.err} ${c7.red(parsed.headline)}`);
3428
3618
  if (parsed.hint) {
3429
- writeln(` ${c8.dim(parsed.hint)}`);
3619
+ writeln(` ${c7.dim(parsed.hint)}`);
3430
3620
  }
3431
3621
  }
3432
3622
  function renderBanner(model, cwd) {
3433
3623
  writeln();
3434
3624
  const title = PACKAGE_VERSION ? `mini-coder \xB7 v${PACKAGE_VERSION}` : "mini-coder";
3435
- writeln(` ${c8.cyan("mc")} ${c8.dim(title)}`);
3436
- writeln(` ${c8.dim(model)} ${c8.dim("\xB7")} ${c8.dim(tildePath(cwd))}`);
3437
- writeln(` ${c8.dim("/help for commands \xB7 esc cancel \xB7 ctrl+d exit")}`);
3625
+ writeln(` ${c7.cyan("mc")} ${c7.dim(title)}`);
3626
+ writeln(` ${c7.dim(model)} ${c7.dim("\xB7")} ${c7.dim(tildePath(cwd))}`);
3627
+ writeln(` ${c7.dim("/help for commands \xB7 esc cancel \xB7 ctrl+d exit")}`);
3438
3628
  const items = [];
3439
3629
  if (getPreferredShowReasoning())
3440
3630
  items.push("reasoning: on");
@@ -3447,7 +3637,7 @@ function renderBanner(model, cwd) {
3447
3637
  if (skills.size > 0)
3448
3638
  items.push(`${skills.size} skill${skills.size > 1 ? "s" : ""}`);
3449
3639
  if (items.length > 0) {
3450
- writeln(` ${c8.dim(items.join(" \xB7 "))}`);
3640
+ writeln(` ${c7.dim(items.join(" \xB7 "))}`);
3451
3641
  }
3452
3642
  const connParts = [];
3453
3643
  for (const p of discoverConnectedProviders()) {
@@ -3457,7 +3647,7 @@ function renderBanner(model, cwd) {
3457
3647
  if (mcpCount > 0)
3458
3648
  connParts.push(`${mcpCount} mcp`);
3459
3649
  if (connParts.length > 0) {
3460
- writeln(` ${c8.dim(connParts.join(" \xB7 "))}`);
3650
+ writeln(` ${c7.dim(connParts.join(" \xB7 "))}`);
3461
3651
  }
3462
3652
  writeln();
3463
3653
  }
@@ -3472,7 +3662,7 @@ class CliReporter {
3472
3662
  if (this.quiet)
3473
3663
  return;
3474
3664
  this.spinner.stop();
3475
- writeln(`${G.info} ${c8.dim(msg)}`);
3665
+ writeln(`${G.info} ${c7.dim(msg)}`);
3476
3666
  }
3477
3667
  error(msg, hint) {
3478
3668
  this.spinner.stop();
@@ -3676,10 +3866,10 @@ function setPreferredVerboseOutput(verbose) {
3676
3866
  setSetting("preferred_verbose_output", verbose ? "true" : "false");
3677
3867
  }
3678
3868
  // src/agent/session-runner.ts
3679
- import * as c11 from "yoctocolors";
3869
+ import * as c10 from "yoctocolors";
3680
3870
 
3681
3871
  // src/cli/input.ts
3682
- import * as c9 from "yoctocolors";
3872
+ import * as c8 from "yoctocolors";
3683
3873
 
3684
3874
  // src/cli/input-buffer.ts
3685
3875
  var PASTE_TOKEN_START = 57344;
@@ -4088,7 +4278,7 @@ function watchForCancel(abortController) {
4088
4278
  process.stdin.on("data", onData);
4089
4279
  return cleanup;
4090
4280
  }
4091
- var PROMPT = c9.green("\u25B6 ");
4281
+ var PROMPT = c8.green("\u25B6 ");
4092
4282
  var PROMPT_RAW_LEN = 2;
4093
4283
  async function readline(opts) {
4094
4284
  const cwd = opts.cwd ?? process.cwd();
@@ -4137,7 +4327,7 @@ async function readline(opts) {
4137
4327
  process.stdout.write(`${CLEAR_LINE}${prompt}${display}${CSI}${PROMPT_RAW_LEN + displayCursor + 1}G`);
4138
4328
  }
4139
4329
  function renderSearchPrompt() {
4140
- process.stdout.write(`${CLEAR_LINE}${c9.cyan("search:")} ${searchQuery}\u2588`);
4330
+ process.stdout.write(`${CLEAR_LINE}${c8.cyan("search:")} ${searchQuery}\u2588`);
4141
4331
  }
4142
4332
  function applyHistory() {
4143
4333
  if (histIdx < history.length) {
@@ -4400,11 +4590,11 @@ import { streamText } from "ai";
4400
4590
  import { dynamicTool, jsonSchema } from "ai";
4401
4591
 
4402
4592
  // src/llm-api/turn-stream-events.ts
4403
- function shouldLogStreamChunk(c10) {
4404
- return c10.type !== "text-delta" && c10.type !== "reasoning" && c10.type !== "reasoning-delta";
4593
+ function shouldLogStreamChunk(c9) {
4594
+ return c9.type !== "text-delta" && c9.type !== "reasoning" && c9.type !== "reasoning-delta" && c9.type !== "tool-input-delta";
4405
4595
  }
4406
- function extractToolArgs(c10) {
4407
- return c10.input ?? c10.args;
4596
+ function extractToolArgs(c9) {
4597
+ return c9.input ?? c9.args;
4408
4598
  }
4409
4599
  function hasRenderableToolArgs(args) {
4410
4600
  if (args === null || args === undefined)
@@ -4417,10 +4607,10 @@ function hasRenderableToolArgs(args) {
4417
4607
  return Object.keys(args).length > 0;
4418
4608
  return true;
4419
4609
  }
4420
- function mapStreamChunkToTurnEvent(c10) {
4421
- switch (c10.type) {
4610
+ function mapStreamChunkToTurnEvent(c9) {
4611
+ switch (c9.type) {
4422
4612
  case "text-delta": {
4423
- const delta = typeof c10.text === "string" ? c10.text : "";
4613
+ const delta = typeof c9.text === "string" ? c9.text : "";
4424
4614
  return {
4425
4615
  type: "text-delta",
4426
4616
  delta
@@ -4428,7 +4618,7 @@ function mapStreamChunkToTurnEvent(c10) {
4428
4618
  }
4429
4619
  case "reasoning-delta":
4430
4620
  case "reasoning": {
4431
- const delta = getReasoningDeltaFromStreamChunk(c10);
4621
+ const delta = getReasoningDeltaFromStreamChunk(c9);
4432
4622
  if (delta === null)
4433
4623
  return null;
4434
4624
  return {
@@ -4437,49 +4627,65 @@ function mapStreamChunkToTurnEvent(c10) {
4437
4627
  };
4438
4628
  }
4439
4629
  case "tool-input-start": {
4440
- const args = extractToolArgs(c10);
4441
- const hasStableToolCallId = typeof c10.toolCallId === "string" && c10.toolCallId.trim().length > 0;
4630
+ const args = extractToolArgs(c9);
4631
+ const hasStableToolCallId = typeof c9.toolCallId === "string" && c9.toolCallId.trim().length > 0;
4442
4632
  if (hasStableToolCallId && !hasRenderableToolArgs(args))
4443
4633
  return null;
4444
4634
  return {
4445
4635
  type: "tool-call-start",
4446
- toolCallId: String(c10.toolCallId ?? ""),
4447
- toolName: String(c10.toolName ?? ""),
4636
+ toolCallId: String(c9.toolCallId ?? ""),
4637
+ toolName: String(c9.toolName ?? ""),
4448
4638
  args
4449
4639
  };
4450
4640
  }
4641
+ case "tool-input-delta": {
4642
+ let delta = "";
4643
+ if (typeof c9.inputTextDelta === "string") {
4644
+ delta = c9.inputTextDelta;
4645
+ } else if (typeof c9.delta === "string") {
4646
+ delta = c9.delta;
4647
+ }
4648
+ if (!delta)
4649
+ return null;
4650
+ return {
4651
+ type: "tool-input-delta",
4652
+ toolCallId: String(c9.toolCallId ?? c9.id ?? ""),
4653
+ toolName: String(c9.toolName ?? ""),
4654
+ inputTextDelta: delta
4655
+ };
4656
+ }
4451
4657
  case "tool-call": {
4452
4658
  return {
4453
4659
  type: "tool-call-start",
4454
- toolCallId: String(c10.toolCallId ?? ""),
4455
- toolName: String(c10.toolName ?? ""),
4456
- args: extractToolArgs(c10)
4660
+ toolCallId: String(c9.toolCallId ?? ""),
4661
+ toolName: String(c9.toolName ?? ""),
4662
+ args: extractToolArgs(c9)
4457
4663
  };
4458
4664
  }
4459
4665
  case "tool-result": {
4460
4666
  let result;
4461
- if ("output" in c10)
4462
- result = c10.output;
4463
- else if ("result" in c10)
4464
- result = c10.result;
4667
+ if ("output" in c9)
4668
+ result = c9.output;
4669
+ else if ("result" in c9)
4670
+ result = c9.result;
4465
4671
  return {
4466
4672
  type: "tool-result",
4467
- toolCallId: String(c10.toolCallId ?? ""),
4468
- toolName: String(c10.toolName ?? ""),
4673
+ toolCallId: String(c9.toolCallId ?? ""),
4674
+ toolName: String(c9.toolName ?? ""),
4469
4675
  result,
4470
- isError: "isError" in c10 ? Boolean(c10.isError) : false
4676
+ isError: "isError" in c9 ? Boolean(c9.isError) : false
4471
4677
  };
4472
4678
  }
4473
4679
  case "tool-error":
4474
4680
  return {
4475
4681
  type: "tool-result",
4476
- toolCallId: String(c10.toolCallId ?? ""),
4477
- toolName: String(c10.toolName ?? ""),
4478
- result: c10.error ?? "Tool execution failed",
4682
+ toolCallId: String(c9.toolCallId ?? ""),
4683
+ toolName: String(c9.toolName ?? ""),
4684
+ result: c9.error ?? "Tool execution failed",
4479
4685
  isError: true
4480
4686
  };
4481
4687
  case "error": {
4482
- throw normalizeUnknownError(c10.error);
4688
+ throw normalizeUnknownError(c9.error);
4483
4689
  }
4484
4690
  default:
4485
4691
  return null;
@@ -4495,9 +4701,9 @@ function toCoreTool(def) {
4495
4701
  return dynamicTool({
4496
4702
  description: def.description,
4497
4703
  inputSchema: schema,
4498
- execute: async (input) => {
4704
+ execute: async (input, { abortSignal }) => {
4499
4705
  try {
4500
- return await def.execute(input);
4706
+ return await def.execute(input, abortSignal ? { signal: abortSignal } : undefined);
4501
4707
  } catch (err) {
4502
4708
  throw normalizeUnknownError(err);
4503
4709
  }
@@ -4648,6 +4854,7 @@ class StreamToolCallTracker {
4648
4854
  syntheticCount = 0;
4649
4855
  pendingByTool = new Map;
4650
4856
  deferredStartsByTool = new Map;
4857
+ toolNameById = new Map;
4651
4858
  prepare(chunk) {
4652
4859
  const type = chunk.type;
4653
4860
  if (!type) {
@@ -4656,6 +4863,8 @@ class StreamToolCallTracker {
4656
4863
  if (type === "tool-input-start") {
4657
4864
  const toolName = normalizeToolName(chunk.toolName);
4658
4865
  const toolCallId = normalizeStringId(chunk.toolCallId);
4866
+ if (toolCallId && toolName)
4867
+ this.toolNameById.set(toolCallId, toolName);
4659
4868
  const args = extractToolArgs(chunk);
4660
4869
  if (!hasRenderableToolArgs(args)) {
4661
4870
  if (!toolCallId) {
@@ -4690,6 +4899,16 @@ class StreamToolCallTracker {
4690
4899
  suppressTurnEvent: false
4691
4900
  };
4692
4901
  }
4902
+ if (type === "tool-input-delta") {
4903
+ const id = normalizeStringId(chunk.id ?? chunk.toolCallId);
4904
+ const toolName = id ? this.toolNameById.get(id) : undefined;
4905
+ if (toolName) {
4906
+ return {
4907
+ chunk: { ...chunk, toolName, toolCallId: id },
4908
+ suppressTurnEvent: false
4909
+ };
4910
+ }
4911
+ }
4693
4912
  return { chunk, suppressTurnEvent: false };
4694
4913
  }
4695
4914
  trackRenderableStart(chunk, toolName, existingToolCallId) {
@@ -5349,7 +5568,7 @@ async function* runTurn(options) {
5349
5568
  }
5350
5569
 
5351
5570
  // src/session/manager.ts
5352
- import * as c10 from "yoctocolors";
5571
+ import * as c9 from "yoctocolors";
5353
5572
  function newSession(model, cwd) {
5354
5573
  const id = generateSessionId();
5355
5574
  const row = createSession({ id, cwd, model });
@@ -5384,21 +5603,21 @@ function renderSessionTable(footer) {
5384
5603
  if (sessions.length === 0)
5385
5604
  return false;
5386
5605
  writeln(`
5387
- ${c10.bold("Recent sessions:")}`);
5606
+ ${c9.bold("Recent sessions:")}`);
5388
5607
  for (const s of sessions) {
5389
5608
  const date = new Date(s.updated_at).toLocaleString();
5390
5609
  const cwd = tildePath(s.cwd);
5391
- const title = s.title || c10.dim("(untitled)");
5392
- 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)}`);
5610
+ const title = s.title || c9.dim("(untitled)");
5611
+ writeln(` ${c9.dim(s.id.padEnd(14))} ${title.padEnd(30)} ${c9.cyan(s.model.split("/").pop() ?? s.model).padEnd(20)} ${c9.dim(cwd)} ${c9.dim(date)}`);
5393
5612
  }
5394
5613
  writeln(`
5395
5614
  ${footer}`);
5396
5615
  return true;
5397
5616
  }
5398
5617
  function printSessionList() {
5399
- const shown = renderSessionTable(`${c10.dim("Use")} mc --resume <id> ${c10.dim("to continue a session.")}`);
5618
+ const shown = renderSessionTable(`${c9.dim("Use")} mc --resume <id> ${c9.dim("to continue a session.")}`);
5400
5619
  if (!shown)
5401
- writeln(c10.dim("No sessions found."));
5620
+ writeln(c9.dim("No sessions found."));
5402
5621
  }
5403
5622
  function getMostRecentSession() {
5404
5623
  const sessions = listSessions(1);
@@ -5629,7 +5848,7 @@ class SessionRunner {
5629
5848
  }
5630
5849
  this.session = resumed;
5631
5850
  this.currentModel = this.session.model;
5632
- this.reporter.info(`Resumed session ${this.session.id} (${c11.cyan(this.currentModel)})`);
5851
+ this.reporter.info(`Resumed session ${this.session.id} (${c10.cyan(this.currentModel)})`);
5633
5852
  } else {
5634
5853
  this.session = newSession(this.currentModel, this.cwd);
5635
5854
  }
@@ -5875,21 +6094,22 @@ function buildFileEditShellPrelude(command = getFileEditCommand()) {
5875
6094
  // src/tools/shell.ts
5876
6095
  var ShellSchema = z3.object({
5877
6096
  command: z3.string().describe("Shell command to execute"),
5878
- timeout: z3.number().int().min(1000).optional().describe("Timeout in milliseconds. If omitted, the command runs until it exits."),
5879
- env: z3.record(z3.string(), z3.string()).optional().describe("Additional environment variables to set")
6097
+ timeout: z3.number().int().min(1000).nullable().describe("Timeout in milliseconds. If omitted, the command runs until it exits."),
6098
+ env: z3.record(z3.string(), z3.string()).nullable().describe("Additional environment variables to set")
5880
6099
  });
5881
6100
  var MAX_OUTPUT_BYTES = 1e4;
5882
- async function runShellCommand(input) {
6101
+ async function runShellCommand(input, options) {
5883
6102
  const cwd = input.cwd ?? process.cwd();
5884
- const timeout = input.timeout;
5885
- const existingGitCount = Number(input.env?.GIT_CONFIG_COUNT ?? process.env.GIT_CONFIG_COUNT ?? "0") || 0;
6103
+ const timeout = input.timeout ?? undefined;
6104
+ const inputEnv = input.env ?? undefined;
6105
+ const existingGitCount = Number(inputEnv?.GIT_CONFIG_COUNT ?? process.env.GIT_CONFIG_COUNT ?? "0") || 0;
5886
6106
  const gitIdx = String(existingGitCount);
5887
6107
  const env = Object.assign({}, process.env, {
5888
6108
  FORCE_COLOR: "1",
5889
6109
  GIT_CONFIG_COUNT: String(existingGitCount + 1),
5890
6110
  [`GIT_CONFIG_KEY_${gitIdx}`]: "color.ui",
5891
6111
  [`GIT_CONFIG_VALUE_${gitIdx}`]: "always"
5892
- }, input.env ?? {});
6112
+ }, inputEnv ?? {});
5893
6113
  let timedOut = false;
5894
6114
  const readers = [];
5895
6115
  const wasRaw = process.stdin.isTTY ? process.stdin.isRaw : false;
@@ -5900,8 +6120,7 @@ ${input.command}`], {
5900
6120
  stdout: "pipe",
5901
6121
  stderr: "pipe"
5902
6122
  });
5903
- const timer = timeout ? setTimeout(() => {
5904
- timedOut = true;
6123
+ function killProc() {
5905
6124
  try {
5906
6125
  proc.kill("SIGTERM");
5907
6126
  setTimeout(() => {
@@ -5913,7 +6132,20 @@ ${input.command}`], {
5913
6132
  for (const reader of readers) {
5914
6133
  reader.cancel().catch(() => {});
5915
6134
  }
6135
+ }
6136
+ const timer = timeout ? setTimeout(() => {
6137
+ timedOut = true;
6138
+ killProc();
5916
6139
  }, timeout) : undefined;
6140
+ const abortSignal = options?.signal;
6141
+ const onAbort = () => {
6142
+ killProc();
6143
+ };
6144
+ if (abortSignal?.aborted) {
6145
+ onAbort();
6146
+ } else {
6147
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
6148
+ }
5917
6149
  async function collectStream(stream) {
5918
6150
  const reader = stream.getReader();
5919
6151
  readers.push(reader);
@@ -5957,6 +6189,7 @@ ${input.command}`], {
5957
6189
  } finally {
5958
6190
  if (timer)
5959
6191
  clearTimeout(timer);
6192
+ abortSignal?.removeEventListener("abort", onAbort);
5960
6193
  restoreTerminal();
5961
6194
  if (wasRaw) {
5962
6195
  try {
@@ -5981,7 +6214,7 @@ var shellTool = {
5981
6214
  name: "shell",
5982
6215
  description: "Execute a shell command. Returns stdout, stderr, and exit code. " + "Use this for reading/searching code, running tests, builds, git commands, and invoking `mc-edit` for partial file edits. " + "Prefer non-interactive commands. Avoid commands that run indefinitely.",
5983
6216
  schema: ShellSchema,
5984
- execute: runShellCommand
6217
+ execute: (input, options) => runShellCommand(input, options)
5985
6218
  };
5986
6219
 
5987
6220
  // src/agent/tools.ts
@@ -5989,11 +6222,11 @@ function withCwdDefault(tool, cwd) {
5989
6222
  const originalExecute = tool.execute;
5990
6223
  return {
5991
6224
  ...tool,
5992
- execute: async (input) => {
6225
+ execute: async (input, options) => {
5993
6226
  const patched = typeof input === "object" && input !== null ? input : {};
5994
6227
  if (patched.cwd === undefined)
5995
6228
  patched.cwd = cwd;
5996
- return originalExecute(patched);
6229
+ return originalExecute(patched, options);
5997
6230
  }
5998
6231
  };
5999
6232
  }
@@ -6036,7 +6269,7 @@ async function initAgent(opts) {
6036
6269
  for (const row of listMcpServers()) {
6037
6270
  try {
6038
6271
  await connectAndAddMcp(row.name);
6039
- opts.reporter.info(`MCP: connected ${c12.cyan(row.name)}`);
6272
+ opts.reporter.info(`MCP: connected ${c11.cyan(row.name)}`);
6040
6273
  } catch (e) {
6041
6274
  opts.reporter.error(`MCP: failed to connect ${row.name}: ${String(e)}`);
6042
6275
  }
@@ -6094,7 +6327,7 @@ async function initAgent(opts) {
6094
6327
  }
6095
6328
 
6096
6329
  // src/cli/args.ts
6097
- import * as c13 from "yoctocolors";
6330
+ import * as c12 from "yoctocolors";
6098
6331
  function parseArgs(argv) {
6099
6332
  const args = {
6100
6333
  model: null,
@@ -6143,11 +6376,11 @@ function parseArgs(argv) {
6143
6376
  return args;
6144
6377
  }
6145
6378
  function printHelp() {
6146
- writeln(`${c13.bold("mini-coder")} \u2014 a small, fast CLI coding agent
6379
+ writeln(`${c12.bold("mini-coder")} \u2014 a small, fast CLI coding agent
6147
6380
  `);
6148
- writeln(`${c13.bold("Usage:")} mc [options] [prompt]
6381
+ writeln(`${c12.bold("Usage:")} mc [options] [prompt]
6149
6382
  `);
6150
- writeln(`${c13.bold("Options:")}`);
6383
+ writeln(`${c12.bold("Options:")}`);
6151
6384
  const opts = [
6152
6385
  ["-m, --model <id>", "Model to use (e.g. zen/claude-sonnet-4-6)"],
6153
6386
  ["-c, --continue", "Continue the most recent session"],
@@ -6157,10 +6390,10 @@ function printHelp() {
6157
6390
  ["-h, --help", "Show this help"]
6158
6391
  ];
6159
6392
  for (const [flag, desc] of opts) {
6160
- writeln(` ${c13.cyan((flag ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
6393
+ writeln(` ${c12.cyan((flag ?? "").padEnd(22))} ${c12.dim(desc ?? "")}`);
6161
6394
  }
6162
6395
  writeln(`
6163
- ${c13.bold("Provider env vars:")}`);
6396
+ ${c12.bold("Provider env vars:")}`);
6164
6397
  const envs = [
6165
6398
  ["OPENCODE_API_KEY", "OpenCode Zen (recommended)"],
6166
6399
  ["ANTHROPIC_API_KEY", "Anthropic direct"],
@@ -6171,22 +6404,22 @@ ${c13.bold("Provider env vars:")}`);
6171
6404
  ["OLLAMA_BASE_URL", "Ollama base URL (default: http://localhost:11434)"]
6172
6405
  ];
6173
6406
  for (const [env, desc] of envs) {
6174
- writeln(` ${c13.yellow((env ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
6407
+ writeln(` ${c12.yellow((env ?? "").padEnd(22))} ${c12.dim(desc ?? "")}`);
6175
6408
  }
6176
6409
  writeln(`
6177
- ${c13.bold("Examples:")}`);
6178
- writeln(` mc ${c13.dim("# interactive session")}`);
6179
- writeln(` mc "explain this codebase" ${c13.dim("# one-shot prompt then exit")}`);
6180
- writeln(` mc -c ${c13.dim("# continue last session")}`);
6181
- writeln(` mc -m ollama/llama3.2 ${c13.dim("# use local Ollama model")}`);
6182
- writeln(` mc -l ${c13.dim("# list sessions")}`);
6410
+ ${c12.bold("Examples:")}`);
6411
+ writeln(` mc ${c12.dim("# interactive session")}`);
6412
+ writeln(` mc "explain this codebase" ${c12.dim("# one-shot prompt then exit")}`);
6413
+ writeln(` mc -c ${c12.dim("# continue last session")}`);
6414
+ writeln(` mc -m ollama/llama3.2 ${c12.dim("# use local Ollama model")}`);
6415
+ writeln(` mc -l ${c12.dim("# list sessions")}`);
6183
6416
  }
6184
6417
 
6185
6418
  // src/cli/bootstrap.ts
6186
6419
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync } from "fs";
6187
6420
  import { homedir as homedir6 } from "os";
6188
6421
  import { join as join7 } from "path";
6189
- import * as c14 from "yoctocolors";
6422
+ import * as c13 from "yoctocolors";
6190
6423
  var REVIEW_SKILL_CONTENT = `---
6191
6424
  name: review
6192
6425
  description: "Review recent changes for correctness, code quality, and performance. Use when the user asks to review, check, or audit recent code changes, diffs, or pull requests."
@@ -6221,7 +6454,7 @@ function bootstrapGlobalDefaults() {
6221
6454
  if (!existsSync5(skillPath)) {
6222
6455
  mkdirSync2(skillDir, { recursive: true });
6223
6456
  writeFileSync(skillPath, REVIEW_SKILL_CONTENT, "utf-8");
6224
- writeln(`${c14.green("\u2713")} created ${c14.dim("~/.agents/skills/review/SKILL.md")} ${c14.dim("(edit it to customise your reviews)")}`);
6457
+ writeln(`${c13.green("\u2713")} created ${c13.dim("~/.agents/skills/review/SKILL.md")} ${c13.dim("(edit it to customise your reviews)")}`);
6225
6458
  }
6226
6459
  }
6227
6460
 
@@ -6258,25 +6491,25 @@ ${content}
6258
6491
  }
6259
6492
 
6260
6493
  // src/cli/input-loop.ts
6261
- import * as c21 from "yoctocolors";
6494
+ import * as c20 from "yoctocolors";
6262
6495
 
6263
6496
  // src/cli/commands.ts
6264
6497
  import { randomBytes } from "crypto";
6265
6498
  import { unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
6266
6499
  import { tmpdir } from "os";
6267
6500
  import { join as join9 } from "path";
6268
- import * as c20 from "yoctocolors";
6501
+ import * as c19 from "yoctocolors";
6269
6502
 
6270
6503
  // src/cli/commands-help.ts
6271
- import * as c15 from "yoctocolors";
6504
+ import * as c14 from "yoctocolors";
6272
6505
  function renderEntries(entries) {
6273
6506
  for (const [label, description] of entries) {
6274
- writeln(` ${c15.cyan(label.padEnd(28))} ${c15.dim(description)}`);
6507
+ writeln(` ${c14.cyan(label.padEnd(28))} ${c14.dim(description)}`);
6275
6508
  }
6276
6509
  }
6277
6510
  function renderHelpCommand(ctx) {
6278
6511
  writeln();
6279
- writeln(` ${c15.dim("session")}`);
6512
+ writeln(` ${c14.dim("session")}`);
6280
6513
  renderEntries([
6281
6514
  ["/session [id]", "list sessions or switch to one"],
6282
6515
  ["/new", "start a fresh session"],
@@ -6284,7 +6517,7 @@ function renderHelpCommand(ctx) {
6284
6517
  ["/exit", "quit"]
6285
6518
  ]);
6286
6519
  writeln();
6287
- writeln(` ${c15.dim("model + context")}`);
6520
+ writeln(` ${c14.dim("model + context")}`);
6288
6521
  renderEntries([
6289
6522
  ["/model [id]", "list or switch models"],
6290
6523
  ["/reasoning [on|off]", "toggle reasoning display"],
@@ -6297,7 +6530,7 @@ function renderHelpCommand(ctx) {
6297
6530
  ["/help", "show this help"]
6298
6531
  ]);
6299
6532
  writeln();
6300
- writeln(` ${c15.dim("prompt")}`);
6533
+ writeln(` ${c14.dim("prompt")}`);
6301
6534
  renderEntries([
6302
6535
  ["ask normally", "send a prompt to the current agent"],
6303
6536
  ["!cmd", "run a shell command and keep the result in context"],
@@ -6307,44 +6540,44 @@ function renderHelpCommand(ctx) {
6307
6540
  const skills = loadSkillsIndex(ctx.cwd);
6308
6541
  if (skills.size > 0) {
6309
6542
  writeln();
6310
- writeln(` ${c15.dim("skills")}`);
6543
+ writeln(` ${c14.dim("skills")}`);
6311
6544
  for (const skill of skills.values()) {
6312
- const source = skill.source === "local" ? c15.dim("local") : c15.dim("global");
6545
+ const source = skill.source === "local" ? c14.dim("local") : c14.dim("global");
6313
6546
  const desc = truncateText(skill.description, 80);
6314
- writeln(` ${c15.green(`/${skill.name}`.padEnd(28))} ${c15.dim(desc)} ${c15.dim("\xB7")} ${source}`);
6547
+ writeln(` ${c14.green(`/${skill.name}`.padEnd(28))} ${c14.dim(desc)} ${c14.dim("\xB7")} ${source}`);
6315
6548
  }
6316
6549
  }
6317
6550
  writeln();
6318
- writeln(` ${c15.dim("keys")} ${c15.dim("esc")} cancel response ${c15.dim("\xB7")} ${c15.dim("ctrl+c / ctrl+d")} exit ${c15.dim("\xB7")} ${c15.dim("ctrl+r")} history search ${c15.dim("\xB7")} ${c15.dim("\u2191\u2193")} history`);
6551
+ writeln(` ${c14.dim("keys")} ${c14.dim("esc")} cancel response ${c14.dim("\xB7")} ${c14.dim("ctrl+c / ctrl+d")} exit ${c14.dim("\xB7")} ${c14.dim("ctrl+r")} history search ${c14.dim("\xB7")} ${c14.dim("\u2191\u2193")} history`);
6319
6552
  writeln();
6320
6553
  }
6321
6554
 
6322
6555
  // src/cli/commands-login.ts
6323
- import * as c16 from "yoctocolors";
6556
+ import * as c15 from "yoctocolors";
6324
6557
  function renderLoginHelp() {
6325
6558
  writeln();
6326
- writeln(` ${c16.dim("usage:")}`);
6327
- writeln(` /login ${c16.dim("show login status")}`);
6328
- writeln(` /login <provider> ${c16.dim("login via OAuth")}`);
6329
- writeln(` /logout <provider> ${c16.dim("clear saved tokens")}`);
6559
+ writeln(` ${c15.dim("usage:")}`);
6560
+ writeln(` /login ${c15.dim("show login status")}`);
6561
+ writeln(` /login <provider> ${c15.dim("login via OAuth")}`);
6562
+ writeln(` /logout <provider> ${c15.dim("clear saved tokens")}`);
6330
6563
  writeln();
6331
- writeln(` ${c16.dim("providers:")}`);
6564
+ writeln(` ${c15.dim("providers:")}`);
6332
6565
  for (const p of getOAuthProviders()) {
6333
- const status = isLoggedIn(p.id) ? c16.green("logged in") : c16.dim("not logged in");
6334
- writeln(` ${c16.cyan(p.id.padEnd(20))} ${p.name} ${c16.dim("\xB7")} ${status}`);
6566
+ const status = isLoggedIn(p.id) ? c15.green("logged in") : c15.dim("not logged in");
6567
+ writeln(` ${c15.cyan(p.id.padEnd(20))} ${p.name} ${c15.dim("\xB7")} ${status}`);
6335
6568
  }
6336
6569
  writeln();
6337
6570
  }
6338
6571
  function renderStatus() {
6339
6572
  const loggedIn = listLoggedInProviders();
6340
6573
  if (loggedIn.length === 0) {
6341
- writeln(`${PREFIX.info} ${c16.dim("no OAuth logins \u2014 use")} /login <provider>`);
6574
+ writeln(`${PREFIX.info} ${c15.dim("no OAuth logins \u2014 use")} /login <provider>`);
6342
6575
  return;
6343
6576
  }
6344
6577
  for (const id of loggedIn) {
6345
6578
  const provider = getOAuthProvider(id);
6346
6579
  const name = provider?.name ?? id;
6347
- writeln(`${PREFIX.success} ${c16.cyan(id)} ${c16.dim(name)}`);
6580
+ writeln(`${PREFIX.success} ${c15.cyan(id)} ${c15.dim(name)}`);
6348
6581
  }
6349
6582
  }
6350
6583
  async function handleLoginCommand(ctx, args) {
@@ -6365,7 +6598,7 @@ async function handleLoginCommand(ctx, args) {
6365
6598
  if (isLoggedIn(providerId)) {
6366
6599
  const token = await getAccessToken(providerId);
6367
6600
  if (token) {
6368
- writeln(`${PREFIX.success} already logged in to ${c16.cyan(provider.name)}`);
6601
+ writeln(`${PREFIX.success} already logged in to ${c15.cyan(provider.name)}`);
6369
6602
  return;
6370
6603
  }
6371
6604
  }
@@ -6376,7 +6609,7 @@ async function handleLoginCommand(ctx, args) {
6376
6609
  ctx.stopSpinner();
6377
6610
  writeln(`${PREFIX.info} ${instructions}`);
6378
6611
  writeln();
6379
- writeln(` ${c16.cyan(url)}`);
6612
+ writeln(` ${c15.cyan(url)}`);
6380
6613
  writeln();
6381
6614
  let open = "xdg-open";
6382
6615
  if (process.platform === "darwin")
@@ -6388,12 +6621,12 @@ async function handleLoginCommand(ctx, args) {
6388
6621
  },
6389
6622
  onProgress: (msg) => {
6390
6623
  ctx.stopSpinner();
6391
- writeln(`${PREFIX.info} ${c16.dim(msg)}`);
6624
+ writeln(`${PREFIX.info} ${c15.dim(msg)}`);
6392
6625
  ctx.startSpinner("exchanging tokens");
6393
6626
  }
6394
6627
  });
6395
6628
  ctx.stopSpinner();
6396
- writeln(`${PREFIX.success} logged in to ${c16.cyan(provider.name)}`);
6629
+ writeln(`${PREFIX.success} logged in to ${c15.cyan(provider.name)}`);
6397
6630
  } catch (err) {
6398
6631
  ctx.stopSpinner();
6399
6632
  writeln(`${PREFIX.error} login failed: ${err.message}`);
@@ -6406,15 +6639,15 @@ function handleLogoutCommand(_ctx, args) {
6406
6639
  return;
6407
6640
  }
6408
6641
  if (!isLoggedIn(providerId)) {
6409
- writeln(`${PREFIX.info} ${c16.dim("not logged in to")} ${providerId}`);
6642
+ writeln(`${PREFIX.info} ${c15.dim("not logged in to")} ${providerId}`);
6410
6643
  return;
6411
6644
  }
6412
6645
  logout(providerId);
6413
- writeln(`${PREFIX.success} logged out of ${c16.cyan(providerId)}`);
6646
+ writeln(`${PREFIX.success} logged out of ${c15.cyan(providerId)}`);
6414
6647
  }
6415
6648
 
6416
6649
  // src/cli/commands-mcp.ts
6417
- import * as c17 from "yoctocolors";
6650
+ import * as c16 from "yoctocolors";
6418
6651
  async function handleMcpCommand(ctx, args) {
6419
6652
  const parts = args.trim().split(/\s+/);
6420
6653
  const sub = parts[0] ?? "list";
@@ -6422,15 +6655,15 @@ async function handleMcpCommand(ctx, args) {
6422
6655
  case "list": {
6423
6656
  const servers = listMcpServers();
6424
6657
  if (servers.length === 0) {
6425
- writeln(c17.dim(" no MCP servers configured"));
6426
- writeln(c17.dim(" /mcp add <name> http <url> \xB7 /mcp add <name> stdio <cmd> [args...]"));
6658
+ writeln(c16.dim(" no MCP servers configured"));
6659
+ writeln(c16.dim(" /mcp add <name> http <url> \xB7 /mcp add <name> stdio <cmd> [args...]"));
6427
6660
  return;
6428
6661
  }
6429
6662
  writeln();
6430
6663
  for (const s of servers) {
6431
6664
  const detailText = s.url ?? s.command ?? "";
6432
- const detail = detailText ? c17.dim(` ${detailText}`) : "";
6433
- writeln(` ${c17.yellow("\u2699")} ${c17.bold(s.name)} ${c17.dim(s.transport)}${detail}`);
6665
+ const detail = detailText ? c16.dim(` ${detailText}`) : "";
6666
+ writeln(` ${c16.yellow("\u2699")} ${c16.bold(s.name)} ${c16.dim(s.transport)}${detail}`);
6434
6667
  }
6435
6668
  return;
6436
6669
  }
@@ -6475,9 +6708,9 @@ async function handleMcpCommand(ctx, args) {
6475
6708
  }
6476
6709
  try {
6477
6710
  await ctx.connectMcpServer(name);
6478
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} added and connected`);
6711
+ writeln(`${PREFIX.success} mcp server ${c16.cyan(name)} added and connected`);
6479
6712
  } catch (e) {
6480
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} saved ${c17.dim(`(connection failed: ${String(e)})`)}`);
6713
+ writeln(`${PREFIX.success} mcp server ${c16.cyan(name)} saved ${c16.dim(`(connection failed: ${String(e)})`)}`);
6481
6714
  }
6482
6715
  return;
6483
6716
  }
@@ -6489,17 +6722,17 @@ async function handleMcpCommand(ctx, args) {
6489
6722
  return;
6490
6723
  }
6491
6724
  deleteMcpServer(name);
6492
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} removed`);
6725
+ writeln(`${PREFIX.success} mcp server ${c16.cyan(name)} removed`);
6493
6726
  return;
6494
6727
  }
6495
6728
  default:
6496
6729
  writeln(`${PREFIX.error} unknown: /mcp ${sub}`);
6497
- writeln(c17.dim(" subcommands: list \xB7 add \xB7 remove"));
6730
+ writeln(c16.dim(" subcommands: list \xB7 add \xB7 remove"));
6498
6731
  }
6499
6732
  }
6500
6733
 
6501
6734
  // src/cli/commands-model.ts
6502
- import * as c18 from "yoctocolors";
6735
+ import * as c17 from "yoctocolors";
6503
6736
  import { select } from "yoctoselect";
6504
6737
  var THINKING_EFFORTS = ["low", "medium", "high", "xhigh"];
6505
6738
  function parseThinkingEffort(value) {
@@ -6519,21 +6752,21 @@ function renderModelUpdatedMessage(ctx, modelId, effortArg) {
6519
6752
  if (effortArg) {
6520
6753
  if (effortArg === "off") {
6521
6754
  ctx.setThinkingEffort(null);
6522
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)} ${c18.dim("(thinking disabled)")}`);
6755
+ writeln(`${PREFIX.success} model \u2192 ${c17.cyan(modelId)} ${c17.dim("(thinking disabled)")}`);
6523
6756
  return;
6524
6757
  }
6525
6758
  const effort = parseThinkingEffort(effortArg);
6526
6759
  if (effort) {
6527
6760
  ctx.setThinkingEffort(effort);
6528
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)} ${c18.dim(`(\u2726 ${effort})`)}`);
6761
+ writeln(`${PREFIX.success} model \u2192 ${c17.cyan(modelId)} ${c17.dim(`(\u2726 ${effort})`)}`);
6529
6762
  return;
6530
6763
  }
6531
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)}`);
6532
- writeln(`${PREFIX.error} unknown effort level ${c18.cyan(effortArg)} (use low, medium, high, xhigh, off)`);
6764
+ writeln(`${PREFIX.success} model \u2192 ${c17.cyan(modelId)}`);
6765
+ writeln(`${PREFIX.error} unknown effort level ${c17.cyan(effortArg)} (use low, medium, high, xhigh, off)`);
6533
6766
  return;
6534
6767
  }
6535
- const effortTag = ctx.thinkingEffort ? c18.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
6536
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)}${effortTag}`);
6768
+ const effortTag = ctx.thinkingEffort ? c17.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
6769
+ writeln(`${PREFIX.success} model \u2192 ${c17.cyan(modelId)}${effortTag}`);
6537
6770
  }
6538
6771
  async function handleModelSet(ctx, args) {
6539
6772
  const parts = args.trim().split(/\s+/).filter(Boolean);
@@ -6546,7 +6779,7 @@ async function handleModelSet(ctx, args) {
6546
6779
  const snapshot = await fetchAvailableModels();
6547
6780
  const match = findModelIdByAlias(idArg, snapshot.models.map((model) => model.id));
6548
6781
  if (!match) {
6549
- writeln(`${PREFIX.error} unknown model ${c18.cyan(idArg)} ${c18.dim("\u2014 run /models for the full list")}`);
6782
+ writeln(`${PREFIX.error} unknown model ${c17.cyan(idArg)} ${c17.dim("\u2014 run /models for the full list")}`);
6550
6783
  return;
6551
6784
  }
6552
6785
  modelId = match;
@@ -6566,7 +6799,7 @@ function handleModelEffort(ctx, effortArg) {
6566
6799
  return;
6567
6800
  }
6568
6801
  ctx.setThinkingEffort(effort);
6569
- writeln(`${PREFIX.success} thinking effort \u2192 ${c18.cyan(effort)}`);
6802
+ writeln(`${PREFIX.success} thinking effort \u2192 ${c17.cyan(effort)}`);
6570
6803
  }
6571
6804
  async function handleModelSelect(ctx) {
6572
6805
  ctx.startSpinner("fetching models");
@@ -6574,21 +6807,22 @@ async function handleModelSelect(ctx) {
6574
6807
  ctx.stopSpinner();
6575
6808
  if (snapshot.models.length === 0) {
6576
6809
  writeln(`${PREFIX.error} No models found. Check your API keys or Ollama connection.`);
6577
- writeln(c18.dim(" Set OPENCODE_API_KEY for Zen, or start Ollama for local models."));
6810
+ writeln(c17.dim(" Set OPENCODE_API_KEY for Zen, or start Ollama for local models."));
6578
6811
  return;
6579
6812
  }
6580
6813
  if (snapshot.stale) {
6581
6814
  const lastSync = snapshot.lastSyncAt ? new Date(snapshot.lastSyncAt).toLocaleString() : "never";
6582
6815
  const refreshTag = snapshot.refreshing ? " (refreshing in background)" : "";
6583
- writeln(c18.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
6816
+ writeln(c17.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
6584
6817
  }
6585
6818
  const items = snapshot.models.map((model) => {
6586
6819
  const isCurrent = ctx.currentModel === model.id;
6587
- const freeTag = model.free ? c18.green(" free") : "";
6588
- const contextTag = model.context ? c18.dim(` ${Math.round(model.context / 1000)}k`) : "";
6589
- const currentTag = isCurrent ? c18.cyan(" \u25C0") : "";
6820
+ const freeTag = model.free ? c17.green(" free") : "";
6821
+ const contextTag = model.context ? c17.dim(` ${Math.round(model.context / 1000)}k`) : "";
6822
+ const currentTag = isCurrent ? c17.cyan(" \u25C0") : "";
6823
+ const providerTag = c17.dim(` [${model.provider}]`);
6590
6824
  return {
6591
- label: `${model.displayName}${freeTag}${contextTag}${currentTag}`,
6825
+ label: `${model.displayName}${freeTag}${contextTag}${currentTag}${providerTag}`,
6592
6826
  value: model.id,
6593
6827
  filterText: `${model.id} ${model.displayName} ${model.provider}`
6594
6828
  };
@@ -6619,7 +6853,7 @@ async function handleModelCommand(ctx, args) {
6619
6853
  }
6620
6854
 
6621
6855
  // src/cli/commands-session.ts
6622
- import * as c19 from "yoctocolors";
6856
+ import * as c18 from "yoctocolors";
6623
6857
  import { select as select2 } from "yoctoselect";
6624
6858
  async function handleSessionCommand(ctx, args) {
6625
6859
  const id = args.trim();
@@ -6628,15 +6862,15 @@ async function handleSessionCommand(ctx, args) {
6628
6862
  const ok2 = ctx.switchSession(id);
6629
6863
  ctx.stopSpinner();
6630
6864
  if (ok2) {
6631
- writeln(`${PREFIX.success} switched to session ${c19.cyan(id)} (${c19.cyan(ctx.currentModel)})`);
6865
+ writeln(`${PREFIX.success} switched to session ${c18.cyan(id)} (${c18.cyan(ctx.currentModel)})`);
6632
6866
  } else {
6633
- writeln(`${PREFIX.error} session ${c19.cyan(id)} not found`);
6867
+ writeln(`${PREFIX.error} session ${c18.cyan(id)} not found`);
6634
6868
  }
6635
6869
  return;
6636
6870
  }
6637
6871
  const sessions = listSessions(50);
6638
6872
  if (sessions.length === 0) {
6639
- writeln(`${PREFIX.info} ${c19.dim("no sessions found")}`);
6873
+ writeln(`${PREFIX.info} ${c18.dim("no sessions found")}`);
6640
6874
  return;
6641
6875
  }
6642
6876
  const items = sessions.map((s) => {
@@ -6645,7 +6879,7 @@ async function handleSessionCommand(ctx, args) {
6645
6879
  const cwd = tildePath(s.cwd);
6646
6880
  const date = new Date(s.updated_at).toLocaleDateString();
6647
6881
  return {
6648
- label: `${c19.dim(s.id)} ${title} ${c19.cyan(model)} ${c19.dim(cwd)} ${c19.dim(date)}`,
6882
+ label: `${c18.dim(s.id)} ${title} ${c18.cyan(model)} ${c18.dim(cwd)} ${c18.dim(date)}`,
6649
6883
  value: s.id,
6650
6884
  filterText: `${s.id} ${s.title} ${s.model} ${s.cwd}`
6651
6885
  };
@@ -6661,9 +6895,9 @@ async function handleSessionCommand(ctx, args) {
6661
6895
  return;
6662
6896
  const ok = ctx.switchSession(picked);
6663
6897
  if (ok) {
6664
- writeln(`${PREFIX.success} switched to session ${c19.cyan(picked)} (${c19.cyan(ctx.currentModel)})`);
6898
+ writeln(`${PREFIX.success} switched to session ${c18.cyan(picked)} (${c18.cyan(ctx.currentModel)})`);
6665
6899
  } else {
6666
- writeln(`${PREFIX.error} session ${c19.cyan(picked)} not found`);
6900
+ writeln(`${PREFIX.error} session ${c18.cyan(picked)} not found`);
6667
6901
  }
6668
6902
  }
6669
6903
 
@@ -6673,9 +6907,9 @@ async function handleUndo(ctx) {
6673
6907
  try {
6674
6908
  const ok = await ctx.undoLastTurn();
6675
6909
  if (ok) {
6676
- writeln(`${PREFIX.success} ${c20.dim("last conversation turn removed")}`);
6910
+ writeln(`${PREFIX.success} ${c19.dim("last conversation turn removed")}`);
6677
6911
  } else {
6678
- writeln(`${PREFIX.info} ${c20.dim("nothing to undo")}`);
6912
+ writeln(`${PREFIX.info} ${c19.dim("nothing to undo")}`);
6679
6913
  }
6680
6914
  } finally {
6681
6915
  ctx.stopSpinner();
@@ -6733,7 +6967,7 @@ async function handleCommand(command, args, ctx) {
6733
6967
  if (loaded2) {
6734
6968
  const srcPath = skill.source === "local" ? `.agents/skills/${skill.name}/SKILL.md` : `~/.agents/skills/${skill.name}/SKILL.md`;
6735
6969
  if (skill.context === "fork") {
6736
- writeln(`${PREFIX.info} ${c20.cyan(skill.name)} ${c20.dim(`[${srcPath}] (forked subagent)`)}`);
6970
+ writeln(`${PREFIX.info} ${c19.cyan(skill.name)} ${c19.dim(`[${srcPath}] (forked subagent)`)}`);
6737
6971
  writeln();
6738
6972
  const subagentPrompt = args ? `${loaded2.content}
6739
6973
 
@@ -6741,7 +6975,7 @@ ${args}` : loaded2.content;
6741
6975
  const result = await runForkedSkill(skill.name, subagentPrompt, ctx.cwd);
6742
6976
  return { type: "inject-user-message", text: result };
6743
6977
  }
6744
- writeln(`${PREFIX.info} ${c20.cyan(skill.name)} ${c20.dim(`[${srcPath}]`)}`);
6978
+ writeln(`${PREFIX.info} ${c19.cyan(skill.name)} ${c19.dim(`[${srcPath}]`)}`);
6745
6979
  writeln();
6746
6980
  const prompt = args ? `${loaded2.content}
6747
6981
 
@@ -6749,7 +6983,7 @@ ${args}` : loaded2.content;
6749
6983
  return { type: "inject-user-message", text: prompt };
6750
6984
  }
6751
6985
  }
6752
- writeln(`${PREFIX.error} unknown: /${command} ${c20.dim("\u2014 /help for commands")}`);
6986
+ writeln(`${PREFIX.error} unknown: /${command} ${c19.dim("\u2014 /help for commands")}`);
6753
6987
  return { type: "unknown", command };
6754
6988
  }
6755
6989
  }
@@ -6758,7 +6992,7 @@ async function runForkedSkill(skillName, prompt, cwd) {
6758
6992
  const tmpFile = join9(tmpdir(), `mc-fork-${randomBytes(8).toString("hex")}.md`);
6759
6993
  writeFileSync2(tmpFile, prompt, "utf8");
6760
6994
  try {
6761
- writeln(`${PREFIX.info} ${c20.dim("running subagent\u2026")}`);
6995
+ writeln(`${PREFIX.info} ${c19.dim("running subagent\u2026")}`);
6762
6996
  const proc = Bun.spawn([process.execPath, Bun.main], {
6763
6997
  cwd,
6764
6998
  stdin: Bun.file(tmpFile),
@@ -6790,17 +7024,17 @@ ${output}`;
6790
7024
  function handleBooleanToggleCommand(opts) {
6791
7025
  const mode = opts.args.trim().toLowerCase();
6792
7026
  if (!mode) {
6793
- writeln(`${PREFIX.success} ${opts.label} ${opts.current ? c20.green("on") : c20.dim("off")}`);
7027
+ writeln(`${PREFIX.success} ${opts.label} ${opts.current ? c19.green("on") : c19.dim("off")}`);
6794
7028
  return;
6795
7029
  }
6796
7030
  if (mode === "on") {
6797
7031
  opts.set(true);
6798
- writeln(`${PREFIX.success} ${opts.label} ${c20.green("on")}`);
7032
+ writeln(`${PREFIX.success} ${opts.label} ${c19.green("on")}`);
6799
7033
  return;
6800
7034
  }
6801
7035
  if (mode === "off") {
6802
7036
  opts.set(false);
6803
- writeln(`${PREFIX.success} ${opts.label} ${c20.dim("off")}`);
7037
+ writeln(`${PREFIX.success} ${opts.label} ${c19.dim("off")}`);
6804
7038
  return;
6805
7039
  }
6806
7040
  writeln(`${PREFIX.error} usage: ${opts.usage}`);
@@ -6860,13 +7094,12 @@ async function getGitBranch(cwd) {
6860
7094
  }
6861
7095
  async function runInputLoop(opts) {
6862
7096
  const { cwd, reporter, cmdCtx, runner } = opts;
6863
- let lastStatusSignature = null;
6864
7097
  while (true) {
6865
7098
  const branch = await getGitBranch(cwd);
6866
7099
  const status = runner.getStatusInfo();
6867
7100
  const cwdDisplay = tildePath(cwd);
6868
7101
  const contextWindow = getContextWindow(status.model);
6869
- const statusData = {
7102
+ reporter.renderStatusBar({
6870
7103
  model: status.model,
6871
7104
  cwd: cwdDisplay,
6872
7105
  gitBranch: branch,
@@ -6876,12 +7109,7 @@ async function runInputLoop(opts) {
6876
7109
  contextTokens: status.lastContextTokens,
6877
7110
  contextWindow,
6878
7111
  thinkingEffort: status.thinkingEffort
6879
- };
6880
- const statusSignature = buildStatusBarSignature(statusData);
6881
- if (statusSignature !== lastStatusSignature) {
6882
- reporter.renderStatusBar(statusData);
6883
- lastStatusSignature = statusSignature;
6884
- }
7112
+ });
6885
7113
  let input;
6886
7114
  try {
6887
7115
  input = await readline({ cwd });
@@ -6890,14 +7118,14 @@ async function runInputLoop(opts) {
6890
7118
  }
6891
7119
  switch (input.type) {
6892
7120
  case "eof":
6893
- reporter.writeText(c21.dim("Goodbye."));
7121
+ reporter.writeText(c20.dim("Goodbye."));
6894
7122
  return;
6895
7123
  case "interrupt":
6896
7124
  continue;
6897
7125
  case "command": {
6898
7126
  const result = await handleCommand(input.command, input.args, cmdCtx);
6899
7127
  if (result.type === "exit") {
6900
- reporter.writeText(c21.dim("Goodbye."));
7128
+ reporter.writeText(c20.dim("Goodbye."));
6901
7129
  return;
6902
7130
  }
6903
7131
  if (result.type === "inject-user-message") {
@@ -7004,7 +7232,7 @@ async function main() {
7004
7232
  if (last) {
7005
7233
  sessionId = last.id;
7006
7234
  } else {
7007
- writeln(c22.dim("No previous session found, starting fresh."));
7235
+ writeln(c21.dim("No previous session found, starting fresh."));
7008
7236
  }
7009
7237
  } else if (args.sessionId) {
7010
7238
  sessionId = args.sessionId;