mini-coder 0.2.3 → 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.3";
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,8 +2613,8 @@ function renderStatusBar(opts) {
2400
2613
  }
2401
2614
 
2402
2615
  // src/cli/stream-render.ts
2403
- import { basename as basename2 } from "path";
2404
- import * as c7 from "yoctocolors";
2616
+ import * as c6 from "yoctocolors";
2617
+ import { createHighlighter } from "yoctomarkdown";
2405
2618
 
2406
2619
  // src/llm-api/history/gemini.ts
2407
2620
  function getGeminiThoughtSignature(part) {
@@ -2659,60 +2872,6 @@ function extractAssistantText(newMessages) {
2659
2872
  `);
2660
2873
  }
2661
2874
 
2662
- // src/cli/live-reasoning.ts
2663
- import * as c4 from "yoctocolors";
2664
- function styleReasoningText(text) {
2665
- return c4.italic(c4.dim(text));
2666
- }
2667
-
2668
- class LiveReasoningBlock {
2669
- blockOpen = false;
2670
- lineOpen = false;
2671
- append(delta) {
2672
- if (!delta)
2673
- return;
2674
- this.openBlock();
2675
- const lines = delta.split(`
2676
- `);
2677
- for (const [index, line] of lines.entries()) {
2678
- if (line)
2679
- this.writeText(line);
2680
- if (index < lines.length - 1)
2681
- this.endLine();
2682
- }
2683
- }
2684
- isOpen() {
2685
- return this.blockOpen;
2686
- }
2687
- finish() {
2688
- if (!this.blockOpen)
2689
- return;
2690
- if (this.lineOpen)
2691
- writeln();
2692
- this.blockOpen = false;
2693
- this.lineOpen = false;
2694
- }
2695
- openBlock() {
2696
- if (this.blockOpen)
2697
- return;
2698
- writeln(`${G.info} ${c4.dim("reasoning")}`);
2699
- this.blockOpen = true;
2700
- }
2701
- writeText(text) {
2702
- if (!this.lineOpen) {
2703
- write(" ");
2704
- this.lineOpen = true;
2705
- }
2706
- write(styleReasoningText(text));
2707
- }
2708
- endLine() {
2709
- if (!this.lineOpen)
2710
- write(" ");
2711
- writeln();
2712
- this.lineOpen = false;
2713
- }
2714
- }
2715
-
2716
2875
  // src/cli/reasoning.ts
2717
2876
  function normalizeReasoningDelta(delta) {
2718
2877
  return delta.replace(/\r\n?/g, `
@@ -2746,130 +2905,34 @@ function normalizeReasoningText(text) {
2746
2905
  `);
2747
2906
  }
2748
2907
 
2749
- // src/cli/stream-render-content.ts
2750
- import { createHighlighter } from "yoctomarkdown";
2751
- class StreamRenderContent {
2752
- spinner;
2753
- quiet;
2754
- inText = false;
2755
- accumulatedText = "";
2756
- accumulatedReasoning = "";
2757
- highlighter;
2758
- constructor(spinner, quiet = false) {
2759
- this.spinner = spinner;
2760
- this.quiet = quiet;
2761
- }
2762
- getText() {
2763
- return this.accumulatedText;
2764
- }
2765
- getReasoning() {
2766
- return this.accumulatedReasoning;
2767
- }
2768
- hasOpenContent() {
2769
- return this.inText;
2770
- }
2771
- appendTextDelta(delta, renderedVisibleOutput) {
2772
- let text = delta ?? "";
2773
- if (!text)
2774
- return;
2775
- if (!this.inText) {
2776
- text = text.trimStart();
2777
- if (!text)
2778
- return;
2779
- if (!this.quiet) {
2780
- this.spinner.stop();
2781
- if (renderedVisibleOutput)
2782
- writeln();
2783
- write(`${G.reply} `);
2784
- }
2785
- this.inText = true;
2786
- if (!this.quiet && terminal.isStdoutTTY)
2787
- this.highlighter = createHighlighter();
2788
- }
2789
- const isFirstLine = !this.accumulatedText.includes(`
2790
- `);
2791
- this.accumulatedText += text;
2792
- if (this.quiet)
2793
- return;
2794
- this.spinner.stop();
2795
- if (this.highlighter) {
2796
- let colored = this.highlighter.write(text);
2797
- if (colored) {
2798
- if (isFirstLine && colored.startsWith("\x1B[2K\r")) {
2799
- colored = `\x1B[2K\r${G.reply} ${colored.slice(5)}`;
2800
- }
2801
- write(colored);
2802
- }
2803
- } else {
2804
- write(text);
2805
- }
2806
- }
2807
- appendReasoningDelta(delta) {
2808
- const text = delta ?? "";
2809
- if (!text)
2810
- return "";
2811
- let appended = text;
2812
- if (this.accumulatedReasoning.endsWith("**") && text.startsWith("**") && !this.accumulatedReasoning.endsWith(`
2813
- `)) {
2814
- appended = `
2815
- ${text}`;
2816
- }
2817
- this.accumulatedReasoning += appended;
2818
- return appended;
2819
- }
2820
- flushOpenContent() {
2821
- if (!this.inText)
2822
- return;
2823
- if (this.quiet) {
2824
- this.inText = false;
2825
- return;
2826
- }
2827
- if (this.highlighter) {
2828
- let finalColored = this.highlighter.end();
2829
- if (finalColored) {
2830
- const isFirstLine = !this.accumulatedText.includes(`
2831
- `);
2832
- if (isFirstLine && finalColored.startsWith("\x1B[2K\r")) {
2833
- finalColored = `\x1B[2K\r${G.reply} ${finalColored.slice(5)}`;
2834
- }
2835
- write(finalColored);
2836
- }
2837
- }
2838
- writeln();
2839
- this.inText = false;
2840
- }
2841
- }
2842
-
2843
2908
  // src/cli/tool-render.ts
2844
- import * as c6 from "yoctocolors";
2909
+ import * as c5 from "yoctocolors";
2845
2910
 
2846
2911
  // src/cli/tool-result-renderers.ts
2847
- import * as c5 from "yoctocolors";
2912
+ import * as c4 from "yoctocolors";
2848
2913
  function writePreviewLines(opts) {
2849
2914
  if (!opts.value.trim())
2850
2915
  return;
2851
2916
  const lines = opts.value.split(`
2852
2917
  `);
2853
- 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)`)}`);
2854
2920
  if (!Number.isFinite(opts.maxLines) || lines.length <= opts.maxLines) {
2855
- for (const line of lines) {
2856
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2857
- }
2921
+ for (const line of lines)
2922
+ writeln(line);
2858
2923
  return;
2859
2924
  }
2860
2925
  const headCount = Math.max(1, Math.ceil(opts.maxLines / 2));
2861
2926
  const tailCount = Math.max(0, Math.floor(opts.maxLines / 2));
2862
- for (const line of lines.slice(0, headCount)) {
2863
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2864
- }
2927
+ for (const line of lines.slice(0, headCount))
2928
+ writeln(line);
2865
2929
  const hiddenLines = Math.max(0, lines.length - (headCount + tailCount));
2866
2930
  if (hiddenLines > 0) {
2867
- writeln(` ${opts.lineColor("\u2502")} ${c5.dim(`\u2026 +${hiddenLines} lines`)}`);
2931
+ writeln(c4.dim(`\u2026 +${hiddenLines} lines`));
2868
2932
  }
2869
2933
  if (tailCount > 0) {
2870
- for (const line of lines.slice(-tailCount)) {
2871
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2872
- }
2934
+ for (const line of lines.slice(-tailCount))
2935
+ writeln(line);
2873
2936
  }
2874
2937
  }
2875
2938
  function truncateOneLine(value, max = 100, verboseOutput = false) {
@@ -2928,11 +2991,11 @@ function renderShellResult(result, opts) {
2928
2991
  const stdoutLines = countShellLines(r.stdout);
2929
2992
  const stderrLines = countShellLines(r.stderr);
2930
2993
  const stdoutSingleLine = getSingleShellLine(r.stdout);
2931
- let badge = c5.red("error");
2994
+ let badge = c4.red("error");
2932
2995
  if (r.timedOut)
2933
- badge = c5.yellow("timeout");
2996
+ badge = c4.yellow("timeout");
2934
2997
  else if (r.success)
2935
- badge = c5.green("done");
2998
+ badge = c4.green("done");
2936
2999
  const parts = buildShellSummaryParts({
2937
3000
  exitCode: r.exitCode,
2938
3001
  stdoutLines,
@@ -2940,11 +3003,10 @@ function renderShellResult(result, opts) {
2940
3003
  stdoutSingleLine,
2941
3004
  verboseOutput
2942
3005
  });
2943
- writeln(` ${badge} ${c5.dim(parts.join(" \xB7 "))}`);
3006
+ writeln(`${badge} ${c4.dim(parts.join(" \xB7 "))}`);
2944
3007
  writePreviewLines({
2945
3008
  label: "stderr",
2946
3009
  value: displayStderr,
2947
- lineColor: c5.red,
2948
3010
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 10
2949
3011
  });
2950
3012
  if (shouldPreviewShellStdout({
@@ -2956,7 +3018,6 @@ function renderShellResult(result, opts) {
2956
3018
  writePreviewLines({
2957
3019
  label: "stdout",
2958
3020
  value: displayStdout,
2959
- lineColor: c5.dim,
2960
3021
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 20
2961
3022
  });
2962
3023
  }
@@ -2967,21 +3028,21 @@ function buildSkillDescriptionPart(description, verboseOutput = false) {
2967
3028
  if (!trimmed)
2968
3029
  return "";
2969
3030
  if (verboseOutput)
2970
- return ` ${c5.dim("\xB7")} ${c5.dim(trimmed)}`;
2971
- 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)}`;
2972
3033
  }
2973
3034
  function renderSkillSummaryLine(skill, opts) {
2974
3035
  const name = skill.name ?? "(unknown)";
2975
3036
  const source = skill.source ?? "unknown";
2976
- const labelPrefix = opts?.label ? `${c5.dim(opts.label)} ` : "";
2977
- 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)}`);
2978
3039
  }
2979
3040
  function renderListSkillsResult(result, opts) {
2980
3041
  const r = result;
2981
3042
  if (!Array.isArray(r?.skills))
2982
3043
  return false;
2983
3044
  if (r.skills.length === 0) {
2984
- writeln(` ${G.info} ${c5.dim("no skills")}`);
3045
+ writeln(`${G.info} ${c4.dim("no skills")}`);
2985
3046
  return true;
2986
3047
  }
2987
3048
  const maxSkills = opts?.verboseOutput ? r.skills.length : 6;
@@ -2991,7 +3052,7 @@ function renderListSkillsResult(result, opts) {
2991
3052
  });
2992
3053
  }
2993
3054
  if (r.skills.length > maxSkills) {
2994
- writeln(` ${c5.dim(`+${r.skills.length - maxSkills} more skills`)}`);
3055
+ writeln(`${c4.dim(`+${r.skills.length - maxSkills} more skills`)}`);
2995
3056
  }
2996
3057
  return true;
2997
3058
  }
@@ -3000,7 +3061,7 @@ function renderReadSkillResult(result, _opts) {
3000
3061
  if (!r || typeof r !== "object")
3001
3062
  return false;
3002
3063
  if (!r.skill) {
3003
- writeln(` ${G.info} ${c5.dim("skill")} ${c5.dim("(not found)")}`);
3064
+ writeln(`${G.info} ${c4.dim("skill")} ${c4.dim("(not found)")}`);
3004
3065
  return true;
3005
3066
  }
3006
3067
  renderSkillSummaryLine(r.skill, {
@@ -3014,19 +3075,19 @@ function renderWebSearchResult(result, opts) {
3014
3075
  if (!Array.isArray(r?.results))
3015
3076
  return false;
3016
3077
  if (r.results.length === 0) {
3017
- writeln(` ${G.info} ${c5.dim("no results")}`);
3078
+ writeln(`${G.info} ${c4.dim("no results")}`);
3018
3079
  return true;
3019
3080
  }
3020
3081
  const maxResults = opts?.verboseOutput ? r.results.length : 5;
3021
3082
  for (const item of r.results.slice(0, maxResults)) {
3022
3083
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
3023
- const score = typeof item.score === "number" ? c5.dim(` (${item.score.toFixed(2)})`) : "";
3024
- 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}`);
3025
3086
  if (item.url)
3026
- writeln(` ${c5.dim(item.url)}`);
3087
+ writeln(` ${c4.dim(item.url)}`);
3027
3088
  }
3028
3089
  if (r.results.length > maxResults) {
3029
- writeln(` ${c5.dim(` +${r.results.length - maxResults} more`)}`);
3090
+ writeln(`${c4.dim(`+${r.results.length - maxResults} more`)}`);
3030
3091
  }
3031
3092
  return true;
3032
3093
  }
@@ -3035,23 +3096,23 @@ function renderWebContentResult(result, opts) {
3035
3096
  if (!Array.isArray(r?.results))
3036
3097
  return false;
3037
3098
  if (r.results.length === 0) {
3038
- writeln(` ${G.info} ${c5.dim("no pages")}`);
3099
+ writeln(`${G.info} ${c4.dim("no pages")}`);
3039
3100
  return true;
3040
3101
  }
3041
3102
  const maxPages = opts?.verboseOutput ? r.results.length : 3;
3042
3103
  for (const item of r.results.slice(0, maxPages)) {
3043
3104
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
3044
- writeln(` ${c5.dim("\u2022")} ${title}`);
3105
+ writeln(`${c4.dim("\u2022")} ${title}`);
3045
3106
  if (item.url)
3046
- writeln(` ${c5.dim(item.url)}`);
3107
+ writeln(` ${c4.dim(item.url)}`);
3047
3108
  const preview = (item.text ?? "").replace(/\s+/g, " ").trim();
3048
3109
  if (preview) {
3049
3110
  const trimmed = opts?.verboseOutput || preview.length <= 220 ? preview : `${preview.slice(0, 217)}\u2026`;
3050
- writeln(` ${c5.dim(trimmed)}`);
3111
+ writeln(` ${c4.dim(trimmed)}`);
3051
3112
  }
3052
3113
  }
3053
3114
  if (r.results.length > maxPages) {
3054
- writeln(` ${c5.dim(` +${r.results.length - maxPages} more`)}`);
3115
+ writeln(`${c4.dim(`+${r.results.length - maxPages} more`)}`);
3055
3116
  }
3056
3117
  return true;
3057
3118
  }
@@ -3061,11 +3122,11 @@ function renderMcpResult(result, opts) {
3061
3122
  let rendered = false;
3062
3123
  for (const block of content.slice(0, maxBlocks)) {
3063
3124
  if (block?.type === "text" && block.text) {
3064
- const maxLines = opts?.verboseOutput ? Number.POSITIVE_INFINITY : 6;
3065
- const lines = block.text.split(`
3066
- `).slice(0, maxLines);
3067
- for (const line of lines)
3068
- writeln(` ${c5.dim("\u2502")} ${line}`);
3125
+ writePreviewLines({
3126
+ label: "",
3127
+ value: block.text,
3128
+ maxLines: opts?.verboseOutput ? Number.POSITIVE_INFINITY : 6
3129
+ });
3069
3130
  rendered = true;
3070
3131
  }
3071
3132
  }
@@ -3153,43 +3214,58 @@ function formatShellCallLine(cmd) {
3153
3214
  const { cwd, rest } = parseShellCdPrefix(cmd);
3154
3215
  const firstCmd = extractFirstCommand(rest);
3155
3216
  const glyph = shellCmdGlyph(firstCmd, rest);
3156
- const cwdSuffix = cwd ? ` ${c6.dim(`in ${cwd}`)}` : "";
3157
- const display = truncateText(rest, 80);
3158
- return `${glyph} ${display}${cwdSuffix}`;
3217
+ const cwdSuffix = cwd ? ` ${c5.dim(`in ${cwd}`)}` : "";
3218
+ return `${glyph} ${rest}${cwdSuffix}`;
3159
3219
  }
3160
3220
  function buildToolCallLine(name, args) {
3161
3221
  const a = args && typeof args === "object" ? args : {};
3162
3222
  if (name === "shell") {
3163
3223
  const cmd = String(a.command ?? "").trim();
3164
3224
  if (!cmd)
3165
- return `${G.run} ${c6.dim("shell")}`;
3225
+ return `${G.run} ${c5.dim("shell")}`;
3166
3226
  return formatShellCallLine(cmd);
3167
3227
  }
3168
3228
  if (name === "listSkills") {
3169
- return `${G.search} ${c6.dim("list skills")}`;
3229
+ return `${G.search} ${c5.dim("list skills")}`;
3170
3230
  }
3171
3231
  if (name === "readSkill") {
3172
3232
  const skillName = typeof a.name === "string" ? a.name : "";
3173
- return `${G.read} ${c6.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
3233
+ return `${G.read} ${c5.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
3174
3234
  }
3175
3235
  if (name === "webSearch") {
3176
3236
  const query = typeof a.query === "string" ? a.query : "";
3177
- const short = query.length > 60 ? `${query.slice(0, 57)}\u2026` : query;
3178
- return `${G.search} ${c6.dim("search")}${short ? ` ${short}` : ""}`;
3237
+ return `${G.search} ${c5.dim("search")}${query ? ` ${query}` : ""}`;
3179
3238
  }
3180
3239
  if (name === "webContent") {
3181
3240
  const urls = Array.isArray(a.urls) ? a.urls : [];
3182
3241
  const label = urls.length === 1 ? String(urls[0]) : `${urls.length} url${urls.length !== 1 ? "s" : ""}`;
3183
- const short = label.length > 60 ? `${label.slice(0, 57)}\u2026` : label;
3184
- return `${G.read} ${c6.dim("fetch")} ${short}`;
3242
+ return `${G.read} ${c5.dim("fetch")} ${label}`;
3185
3243
  }
3186
3244
  if (name.startsWith("mcp_")) {
3187
- return `${G.mcp} ${c6.dim(name)}`;
3245
+ return `${G.mcp} ${c5.dim(name)}`;
3188
3246
  }
3189
- return `${toolGlyph(name)} ${c6.dim(name)}`;
3247
+ return `${toolGlyph(name)} ${c5.dim(name)}`;
3190
3248
  }
3191
- function renderToolCall(toolName, args) {
3192
- 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);
3193
3269
  }
3194
3270
  function formatErrorBadge(result) {
3195
3271
  let msg;
@@ -3201,11 +3277,11 @@ function formatErrorBadge(result) {
3201
3277
  msg = JSON.stringify(result);
3202
3278
  const oneLiner = msg.split(`
3203
3279
  `)[0] ?? msg;
3204
- return `${G.err} ${c6.red(oneLiner)}`;
3280
+ return `${G.err} ${c5.red(oneLiner)}`;
3205
3281
  }
3206
3282
  function renderToolResult(toolName, result, isError, opts) {
3207
3283
  if (isError) {
3208
- writeln(` ${formatErrorBadge(result)}`);
3284
+ writeln(formatErrorBadge(result));
3209
3285
  return;
3210
3286
  }
3211
3287
  if (renderToolResultByName(toolName, result, opts)) {
@@ -3213,32 +3289,130 @@ function renderToolResult(toolName, result, isError, opts) {
3213
3289
  }
3214
3290
  const text = JSON.stringify(result);
3215
3291
  if (opts?.verboseOutput || text.length <= 120) {
3216
- writeln(` ${c6.dim(text)}`);
3292
+ writeln(c5.dim(text));
3217
3293
  return;
3218
3294
  }
3219
- writeln(` ${c6.dim(`${text.slice(0, 117)}\u2026`)}`);
3295
+ writeln(c5.dim(`${text.slice(0, 117)}\u2026`));
3220
3296
  }
3221
3297
 
3222
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
+ }
3223
3392
  async function renderTurn(events, spinner, opts) {
3224
3393
  const quiet = opts?.quiet ?? false;
3225
3394
  const showReasoning = !quiet && (opts?.showReasoning ?? true);
3226
3395
  const verboseOutput = opts?.verboseOutput ?? false;
3227
- const content = new StreamRenderContent(spinner, quiet);
3228
- 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;
3229
3408
  let inputTokens = 0;
3230
3409
  let outputTokens = 0;
3231
3410
  let contextTokens = 0;
3232
3411
  let newMessages = [];
3233
- const startedToolCalls = new Set;
3234
- const toolCallInfo = new Map;
3235
- let parallelCallCount = 0;
3236
3412
  let renderedVisibleOutput = false;
3237
- let reasoningComputed = false;
3238
- let reasoningText = "";
3239
3413
  const getReasoningText = () => {
3240
3414
  if (!reasoningComputed) {
3241
- reasoningText = normalizeReasoningText(content.getReasoning());
3415
+ reasoningText = normalizeReasoningText(reasoningRaw);
3242
3416
  reasoningComputed = true;
3243
3417
  }
3244
3418
  return reasoningText;
@@ -3246,29 +3420,42 @@ async function renderTurn(events, spinner, opts) {
3246
3420
  for await (const event of events) {
3247
3421
  switch (event.type) {
3248
3422
  case "text-delta": {
3249
- liveReasoning.finish();
3250
- content.appendTextDelta(event.delta, renderedVisibleOutput);
3251
- if (content.hasOpenContent())
3423
+ finishReasoning(reasoningState);
3424
+ textState.inText = appendTextDelta(event.delta, textState, spinner, quiet, renderedVisibleOutput);
3425
+ if (textState.inText)
3252
3426
  renderedVisibleOutput = true;
3253
3427
  break;
3254
3428
  }
3255
3429
  case "reasoning-delta": {
3256
- content.flushOpenContent();
3257
- 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;
3258
3438
  reasoningComputed = false;
3259
- if (showReasoning && delta) {
3439
+ if (showReasoning && appended) {
3260
3440
  spinner.stop();
3261
- if (renderedVisibleOutput && !liveReasoning.isOpen())
3441
+ if (renderedVisibleOutput && !reasoningState.blockOpen)
3262
3442
  writeln();
3263
- liveReasoning.append(delta);
3443
+ writeReasoningDelta(appended, reasoningState);
3264
3444
  renderedVisibleOutput = true;
3265
3445
  }
3266
3446
  break;
3267
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
+ }
3268
3456
  case "tool-call-start": {
3269
- if (startedToolCalls.has(event.toolCallId)) {
3457
+ if (startedToolCalls.has(event.toolCallId))
3270
3458
  break;
3271
- }
3272
3459
  const isConsecutiveToolCall = startedToolCalls.size > 0 && toolCallInfo.size > 0;
3273
3460
  startedToolCalls.add(event.toolCallId);
3274
3461
  toolCallInfo.set(event.toolCallId, {
@@ -3278,13 +3465,14 @@ async function renderTurn(events, spinner, opts) {
3278
3465
  if (toolCallInfo.size > 1) {
3279
3466
  parallelCallCount = toolCallInfo.size;
3280
3467
  }
3281
- liveReasoning.finish();
3282
- content.flushOpenContent();
3468
+ finishReasoning(reasoningState);
3469
+ flushText(textState, quiet);
3283
3470
  if (!quiet) {
3284
3471
  spinner.stop();
3285
- if (renderedVisibleOutput && !isConsecutiveToolCall)
3472
+ if (renderedVisibleOutput && !isConsecutiveToolCall) {
3286
3473
  writeln();
3287
- renderToolCall(event.toolName, event.args);
3474
+ }
3475
+ renderToolCall(event.toolName, event.args, { verboseOutput });
3288
3476
  renderedVisibleOutput = true;
3289
3477
  spinner.start(event.toolName);
3290
3478
  }
@@ -3294,11 +3482,11 @@ async function renderTurn(events, spinner, opts) {
3294
3482
  startedToolCalls.delete(event.toolCallId);
3295
3483
  const callInfo = toolCallInfo.get(event.toolCallId);
3296
3484
  toolCallInfo.delete(event.toolCallId);
3297
- liveReasoning.finish();
3485
+ finishReasoning(reasoningState);
3298
3486
  if (!quiet) {
3299
3487
  spinner.stop();
3300
3488
  if (parallelCallCount > 1 && callInfo) {
3301
- writeln(` ${c7.dim("\u21B3")} ${callInfo.label}`);
3489
+ writeln(`${c6.dim("\u21B3")} ${callInfo.label}`);
3302
3490
  }
3303
3491
  if (toolCallInfo.size === 0)
3304
3492
  parallelCallCount = 0;
@@ -3314,31 +3502,20 @@ async function renderTurn(events, spinner, opts) {
3314
3502
  break;
3315
3503
  }
3316
3504
  case "context-pruned": {
3317
- liveReasoning.finish();
3318
- content.flushOpenContent();
3505
+ finishReasoning(reasoningState);
3506
+ flushText(textState, quiet);
3319
3507
  if (!quiet) {
3320
3508
  spinner.stop();
3321
3509
  const removedKb = (event.removedBytes / 1024).toFixed(1);
3322
- writeln(`${G.info} ${c7.dim("context pruned")} ${c7.dim(`\u2013${event.removedMessageCount} messages`)} ${c7.dim(`\u2013${removedKb} KB`)}`);
3323
- renderedVisibleOutput = true;
3324
- }
3325
- break;
3326
- }
3327
- case "file-generated": {
3328
- liveReasoning.finish();
3329
- content.flushOpenContent();
3330
- if (!quiet) {
3331
- spinner.stop();
3332
- if (renderedVisibleOutput)
3333
- writeln();
3334
- writeln(`${G.info} ${c7.dim("file")} ${c7.dim(event.mediaType)} ${c7.dim("\u2192")} ${basename2(event.filePath)}`);
3510
+ writeln(`${G.info} ${c6.dim("context pruned")} ${c6.dim(`\u2013${event.removedMessageCount} messages`)} ${c6.dim(`\u2013${removedKb} KB`)}`);
3335
3511
  renderedVisibleOutput = true;
3512
+ spinner.start("thinking");
3336
3513
  }
3337
3514
  break;
3338
3515
  }
3339
3516
  case "turn-complete": {
3340
- liveReasoning.finish();
3341
- content.flushOpenContent();
3517
+ finishReasoning(reasoningState);
3518
+ flushText(textState, quiet);
3342
3519
  spinner.stop();
3343
3520
  if (!quiet && !renderedVisibleOutput)
3344
3521
  writeln();
@@ -3349,14 +3526,14 @@ async function renderTurn(events, spinner, opts) {
3349
3526
  break;
3350
3527
  }
3351
3528
  case "turn-error": {
3352
- liveReasoning.finish();
3353
- content.flushOpenContent();
3529
+ finishReasoning(reasoningState);
3530
+ flushText(textState, quiet);
3354
3531
  spinner.stop();
3355
3532
  inputTokens = event.inputTokens;
3356
3533
  outputTokens = event.outputTokens;
3357
3534
  contextTokens = event.contextTokens;
3358
3535
  if (isAbortError(event.error)) {
3359
- newMessages = buildAbortMessages(event.partialMessages, content.getText());
3536
+ newMessages = buildAbortMessages(event.partialMessages, textState.text);
3360
3537
  } else {
3361
3538
  renderError(event.error, "turn");
3362
3539
  throw new RenderedError(event.error);
@@ -3405,17 +3582,17 @@ function renderUserMessage(text) {
3405
3582
  }
3406
3583
  }
3407
3584
  var G = {
3408
- prompt: c8.green("\u203A"),
3409
- reply: c8.cyan("\u25C6"),
3410
- search: c8.yellow("?"),
3411
- read: c8.dim("\u2190"),
3412
- write: c8.green("\u270E"),
3413
- run: c8.dim("$"),
3414
- mcp: c8.yellow("\u2699"),
3415
- ok: c8.green("\u2714"),
3416
- err: c8.red("\u2716"),
3417
- warn: c8.yellow("!"),
3418
- 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")
3419
3596
  };
3420
3597
  var PREFIX = {
3421
3598
  user: G.prompt,
@@ -3437,17 +3614,17 @@ class RenderedError extends Error {
3437
3614
  function renderError(err, context = "render") {
3438
3615
  logError(err, context);
3439
3616
  const parsed = parseAppError(err);
3440
- writeln(`${G.err} ${c8.red(parsed.headline)}`);
3617
+ writeln(`${G.err} ${c7.red(parsed.headline)}`);
3441
3618
  if (parsed.hint) {
3442
- writeln(` ${c8.dim(parsed.hint)}`);
3619
+ writeln(` ${c7.dim(parsed.hint)}`);
3443
3620
  }
3444
3621
  }
3445
3622
  function renderBanner(model, cwd) {
3446
3623
  writeln();
3447
3624
  const title = PACKAGE_VERSION ? `mini-coder \xB7 v${PACKAGE_VERSION}` : "mini-coder";
3448
- writeln(` ${c8.cyan("mc")} ${c8.dim(title)}`);
3449
- writeln(` ${c8.dim(model)} ${c8.dim("\xB7")} ${c8.dim(tildePath(cwd))}`);
3450
- 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")}`);
3451
3628
  const items = [];
3452
3629
  if (getPreferredShowReasoning())
3453
3630
  items.push("reasoning: on");
@@ -3460,7 +3637,7 @@ function renderBanner(model, cwd) {
3460
3637
  if (skills.size > 0)
3461
3638
  items.push(`${skills.size} skill${skills.size > 1 ? "s" : ""}`);
3462
3639
  if (items.length > 0) {
3463
- writeln(` ${c8.dim(items.join(" \xB7 "))}`);
3640
+ writeln(` ${c7.dim(items.join(" \xB7 "))}`);
3464
3641
  }
3465
3642
  const connParts = [];
3466
3643
  for (const p of discoverConnectedProviders()) {
@@ -3470,7 +3647,7 @@ function renderBanner(model, cwd) {
3470
3647
  if (mcpCount > 0)
3471
3648
  connParts.push(`${mcpCount} mcp`);
3472
3649
  if (connParts.length > 0) {
3473
- writeln(` ${c8.dim(connParts.join(" \xB7 "))}`);
3650
+ writeln(` ${c7.dim(connParts.join(" \xB7 "))}`);
3474
3651
  }
3475
3652
  writeln();
3476
3653
  }
@@ -3485,7 +3662,7 @@ class CliReporter {
3485
3662
  if (this.quiet)
3486
3663
  return;
3487
3664
  this.spinner.stop();
3488
- writeln(`${G.info} ${c8.dim(msg)}`);
3665
+ writeln(`${G.info} ${c7.dim(msg)}`);
3489
3666
  }
3490
3667
  error(msg, hint) {
3491
3668
  this.spinner.stop();
@@ -3689,10 +3866,10 @@ function setPreferredVerboseOutput(verbose) {
3689
3866
  setSetting("preferred_verbose_output", verbose ? "true" : "false");
3690
3867
  }
3691
3868
  // src/agent/session-runner.ts
3692
- import * as c11 from "yoctocolors";
3869
+ import * as c10 from "yoctocolors";
3693
3870
 
3694
3871
  // src/cli/input.ts
3695
- import * as c9 from "yoctocolors";
3872
+ import * as c8 from "yoctocolors";
3696
3873
 
3697
3874
  // src/cli/input-buffer.ts
3698
3875
  var PASTE_TOKEN_START = 57344;
@@ -4101,7 +4278,7 @@ function watchForCancel(abortController) {
4101
4278
  process.stdin.on("data", onData);
4102
4279
  return cleanup;
4103
4280
  }
4104
- var PROMPT = c9.green("\u25B6 ");
4281
+ var PROMPT = c8.green("\u25B6 ");
4105
4282
  var PROMPT_RAW_LEN = 2;
4106
4283
  async function readline(opts) {
4107
4284
  const cwd = opts.cwd ?? process.cwd();
@@ -4150,7 +4327,7 @@ async function readline(opts) {
4150
4327
  process.stdout.write(`${CLEAR_LINE}${prompt}${display}${CSI}${PROMPT_RAW_LEN + displayCursor + 1}G`);
4151
4328
  }
4152
4329
  function renderSearchPrompt() {
4153
- process.stdout.write(`${CLEAR_LINE}${c9.cyan("search:")} ${searchQuery}\u2588`);
4330
+ process.stdout.write(`${CLEAR_LINE}${c8.cyan("search:")} ${searchQuery}\u2588`);
4154
4331
  }
4155
4332
  function applyHistory() {
4156
4333
  if (histIdx < history.length) {
@@ -4412,36 +4589,12 @@ import { streamText } from "ai";
4412
4589
  // src/llm-api/turn-execution.ts
4413
4590
  import { dynamicTool, jsonSchema } from "ai";
4414
4591
 
4415
- // src/llm-api/generated-files.ts
4416
- import { join as join6 } from "path";
4417
- var MEDIA_TYPE_TO_EXT = {
4418
- "image/jpeg": "jpg",
4419
- "image/svg+xml": "svg"
4420
- };
4421
- function extensionFromMediaType(mediaType) {
4422
- if (MEDIA_TYPE_TO_EXT[mediaType])
4423
- return MEDIA_TYPE_TO_EXT[mediaType];
4424
- const slash = mediaType.indexOf("/");
4425
- if (slash === -1 || slash === mediaType.length - 1)
4426
- return "bin";
4427
- return mediaType.slice(slash + 1);
4428
- }
4429
- var counter = 0;
4430
- async function saveGeneratedFile(file, cwd) {
4431
- counter += 1;
4432
- const ext = extensionFromMediaType(file.mediaType);
4433
- const name = `generated-${counter}.${ext}`;
4434
- const filePath = join6(cwd, name);
4435
- await Bun.write(filePath, file.uint8Array);
4436
- return filePath;
4437
- }
4438
-
4439
4592
  // src/llm-api/turn-stream-events.ts
4440
- function shouldLogStreamChunk(c10) {
4441
- 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";
4442
4595
  }
4443
- function extractToolArgs(c10) {
4444
- return c10.input ?? c10.args;
4596
+ function extractToolArgs(c9) {
4597
+ return c9.input ?? c9.args;
4445
4598
  }
4446
4599
  function hasRenderableToolArgs(args) {
4447
4600
  if (args === null || args === undefined)
@@ -4454,10 +4607,10 @@ function hasRenderableToolArgs(args) {
4454
4607
  return Object.keys(args).length > 0;
4455
4608
  return true;
4456
4609
  }
4457
- function mapStreamChunkToTurnEvent(c10) {
4458
- switch (c10.type) {
4610
+ function mapStreamChunkToTurnEvent(c9) {
4611
+ switch (c9.type) {
4459
4612
  case "text-delta": {
4460
- const delta = typeof c10.text === "string" ? c10.text : "";
4613
+ const delta = typeof c9.text === "string" ? c9.text : "";
4461
4614
  return {
4462
4615
  type: "text-delta",
4463
4616
  delta
@@ -4465,7 +4618,7 @@ function mapStreamChunkToTurnEvent(c10) {
4465
4618
  }
4466
4619
  case "reasoning-delta":
4467
4620
  case "reasoning": {
4468
- const delta = getReasoningDeltaFromStreamChunk(c10);
4621
+ const delta = getReasoningDeltaFromStreamChunk(c9);
4469
4622
  if (delta === null)
4470
4623
  return null;
4471
4624
  return {
@@ -4474,49 +4627,65 @@ function mapStreamChunkToTurnEvent(c10) {
4474
4627
  };
4475
4628
  }
4476
4629
  case "tool-input-start": {
4477
- const args = extractToolArgs(c10);
4478
- 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;
4479
4632
  if (hasStableToolCallId && !hasRenderableToolArgs(args))
4480
4633
  return null;
4481
4634
  return {
4482
4635
  type: "tool-call-start",
4483
- toolCallId: String(c10.toolCallId ?? ""),
4484
- toolName: String(c10.toolName ?? ""),
4636
+ toolCallId: String(c9.toolCallId ?? ""),
4637
+ toolName: String(c9.toolName ?? ""),
4485
4638
  args
4486
4639
  };
4487
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
+ }
4488
4657
  case "tool-call": {
4489
4658
  return {
4490
4659
  type: "tool-call-start",
4491
- toolCallId: String(c10.toolCallId ?? ""),
4492
- toolName: String(c10.toolName ?? ""),
4493
- args: extractToolArgs(c10)
4660
+ toolCallId: String(c9.toolCallId ?? ""),
4661
+ toolName: String(c9.toolName ?? ""),
4662
+ args: extractToolArgs(c9)
4494
4663
  };
4495
4664
  }
4496
4665
  case "tool-result": {
4497
4666
  let result;
4498
- if ("output" in c10)
4499
- result = c10.output;
4500
- else if ("result" in c10)
4501
- result = c10.result;
4667
+ if ("output" in c9)
4668
+ result = c9.output;
4669
+ else if ("result" in c9)
4670
+ result = c9.result;
4502
4671
  return {
4503
4672
  type: "tool-result",
4504
- toolCallId: String(c10.toolCallId ?? ""),
4505
- toolName: String(c10.toolName ?? ""),
4673
+ toolCallId: String(c9.toolCallId ?? ""),
4674
+ toolName: String(c9.toolName ?? ""),
4506
4675
  result,
4507
- isError: "isError" in c10 ? Boolean(c10.isError) : false
4676
+ isError: "isError" in c9 ? Boolean(c9.isError) : false
4508
4677
  };
4509
4678
  }
4510
4679
  case "tool-error":
4511
4680
  return {
4512
4681
  type: "tool-result",
4513
- toolCallId: String(c10.toolCallId ?? ""),
4514
- toolName: String(c10.toolName ?? ""),
4515
- result: c10.error ?? "Tool execution failed",
4682
+ toolCallId: String(c9.toolCallId ?? ""),
4683
+ toolName: String(c9.toolName ?? ""),
4684
+ result: c9.error ?? "Tool execution failed",
4516
4685
  isError: true
4517
4686
  };
4518
4687
  case "error": {
4519
- throw normalizeUnknownError(c10.error);
4688
+ throw normalizeUnknownError(c9.error);
4520
4689
  }
4521
4690
  default:
4522
4691
  return null;
@@ -4532,9 +4701,9 @@ function toCoreTool(def) {
4532
4701
  return dynamicTool({
4533
4702
  description: def.description,
4534
4703
  inputSchema: schema,
4535
- execute: async (input) => {
4704
+ execute: async (input, { abortSignal }) => {
4536
4705
  try {
4537
- return await def.execute(input);
4706
+ return await def.execute(input, abortSignal ? { signal: abortSignal } : undefined);
4538
4707
  } catch (err) {
4539
4708
  throw normalizeUnknownError(err);
4540
4709
  }
@@ -4685,6 +4854,7 @@ class StreamToolCallTracker {
4685
4854
  syntheticCount = 0;
4686
4855
  pendingByTool = new Map;
4687
4856
  deferredStartsByTool = new Map;
4857
+ toolNameById = new Map;
4688
4858
  prepare(chunk) {
4689
4859
  const type = chunk.type;
4690
4860
  if (!type) {
@@ -4693,6 +4863,8 @@ class StreamToolCallTracker {
4693
4863
  if (type === "tool-input-start") {
4694
4864
  const toolName = normalizeToolName(chunk.toolName);
4695
4865
  const toolCallId = normalizeStringId(chunk.toolCallId);
4866
+ if (toolCallId && toolName)
4867
+ this.toolNameById.set(toolCallId, toolName);
4696
4868
  const args = extractToolArgs(chunk);
4697
4869
  if (!hasRenderableToolArgs(args)) {
4698
4870
  if (!toolCallId) {
@@ -4727,6 +4899,16 @@ class StreamToolCallTracker {
4727
4899
  suppressTurnEvent: false
4728
4900
  };
4729
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
+ }
4730
4912
  return { chunk, suppressTurnEvent: false };
4731
4913
  }
4732
4914
  trackRenderableStart(chunk, toolName, existingToolCallId) {
@@ -4788,18 +4970,6 @@ async function* mapFullStreamToTurnEvents(stream, opts) {
4788
4970
  yield { type: "context-pruned", ...rec };
4789
4971
  }
4790
4972
  }
4791
- if (originalChunk.type === "file" && opts.cwd) {
4792
- const fileData = originalChunk.file;
4793
- if (fileData?.uint8Array) {
4794
- const filePath = await saveGeneratedFile(fileData, opts.cwd);
4795
- yield {
4796
- type: "file-generated",
4797
- filePath,
4798
- mediaType: fileData.mediaType
4799
- };
4800
- continue;
4801
- }
4802
- }
4803
4973
  const prepared = toolCallTracker.prepare(originalChunk);
4804
4974
  const chunk = prepared.chunk;
4805
4975
  const route = textPhaseTracker.route(chunk);
@@ -5220,12 +5390,6 @@ function buildTurnProviderOptions(input) {
5220
5390
  const thinkingOpts = thinkingEffort ? getThinkingProviderOptions(modelString, thinkingEffort) : null;
5221
5391
  const reasoningSummaryRequested = isRecord(thinkingOpts) && isRecord(thinkingOpts.openai) && typeof thinkingOpts.openai.reasoningSummary === "string";
5222
5392
  const cacheFamily = getCacheFamily(modelString);
5223
- const googleOpts = isGeminiModelFamily(modelString) ? {
5224
- google: {
5225
- responseModalities: ["TEXT", "IMAGE"],
5226
- ...isRecord(thinkingOpts?.google) ? thinkingOpts.google : {}
5227
- }
5228
- } : {};
5229
5393
  const providerOptions = {
5230
5394
  ...thinkingOpts ?? {},
5231
5395
  ...isOpenAIGPT(modelString) ? {
@@ -5233,8 +5397,7 @@ function buildTurnProviderOptions(input) {
5233
5397
  store: false,
5234
5398
  ...isRecord(thinkingOpts?.openai) ? thinkingOpts.openai : {}
5235
5399
  }
5236
- } : {},
5237
- ...googleOpts
5400
+ } : {}
5238
5401
  };
5239
5402
  return {
5240
5403
  cacheFamily,
@@ -5312,8 +5475,7 @@ async function* runTurn(options) {
5312
5475
  tools,
5313
5476
  systemPrompt,
5314
5477
  signal,
5315
- thinkingEffort,
5316
- cwd
5478
+ thinkingEffort
5317
5479
  } = options;
5318
5480
  const rawToolSet = buildToolSet(tools);
5319
5481
  const toolSet = annotateToolCaching(rawToolSet, modelString);
@@ -5364,7 +5526,6 @@ async function* runTurn(options) {
5364
5526
  result.response.catch(() => {});
5365
5527
  for await (const event of mapFullStreamToTurnEvents(result.fullStream, {
5366
5528
  stepPruneQueue,
5367
- ...cwd ? { cwd } : {},
5368
5529
  onChunk: (streamChunk) => {
5369
5530
  if (streamChunk.type === "tool-call" || streamChunk.type === "tool-result") {
5370
5531
  logApiEvent("stream chunk", {
@@ -5407,7 +5568,7 @@ async function* runTurn(options) {
5407
5568
  }
5408
5569
 
5409
5570
  // src/session/manager.ts
5410
- import * as c10 from "yoctocolors";
5571
+ import * as c9 from "yoctocolors";
5411
5572
  function newSession(model, cwd) {
5412
5573
  const id = generateSessionId();
5413
5574
  const row = createSession({ id, cwd, model });
@@ -5442,21 +5603,21 @@ function renderSessionTable(footer) {
5442
5603
  if (sessions.length === 0)
5443
5604
  return false;
5444
5605
  writeln(`
5445
- ${c10.bold("Recent sessions:")}`);
5606
+ ${c9.bold("Recent sessions:")}`);
5446
5607
  for (const s of sessions) {
5447
5608
  const date = new Date(s.updated_at).toLocaleString();
5448
5609
  const cwd = tildePath(s.cwd);
5449
- const title = s.title || c10.dim("(untitled)");
5450
- 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)}`);
5451
5612
  }
5452
5613
  writeln(`
5453
5614
  ${footer}`);
5454
5615
  return true;
5455
5616
  }
5456
5617
  function printSessionList() {
5457
- 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.")}`);
5458
5619
  if (!shown)
5459
- writeln(c10.dim("No sessions found."));
5620
+ writeln(c9.dim("No sessions found."));
5460
5621
  }
5461
5622
  function getMostRecentSession() {
5462
5623
  const sessions = listSessions(1);
@@ -5687,7 +5848,7 @@ class SessionRunner {
5687
5848
  }
5688
5849
  this.session = resumed;
5689
5850
  this.currentModel = this.session.model;
5690
- 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)})`);
5691
5852
  } else {
5692
5853
  this.session = newSession(this.currentModel, this.cwd);
5693
5854
  }
@@ -5780,8 +5941,7 @@ ${output}
5780
5941
  tools: this.tools,
5781
5942
  ...systemPrompt ? { systemPrompt } : {},
5782
5943
  signal: abortController.signal,
5783
- ...this.currentThinkingEffort ? { thinkingEffort: this.currentThinkingEffort } : {},
5784
- cwd: this.cwd
5944
+ ...this.currentThinkingEffort ? { thinkingEffort: this.currentThinkingEffort } : {}
5785
5945
  });
5786
5946
  const { inputTokens, outputTokens, contextTokens, newMessages } = await this.reporter.renderTurn(events, {
5787
5947
  showReasoning: this.showReasoning,
@@ -5884,7 +6044,7 @@ import { z as z3 } from "zod";
5884
6044
 
5885
6045
  // src/internal/file-edit/command.ts
5886
6046
  import { existsSync as existsSync4 } from "fs";
5887
- import { dirname as dirname3, extname, join as join7 } from "path";
6047
+ import { dirname as dirname3, extname, join as join6 } from "path";
5888
6048
  import { fileURLToPath } from "url";
5889
6049
  function quoteShellArg(value) {
5890
6050
  return `'${value.replaceAll("'", `'\\''`)}'`;
@@ -5896,7 +6056,7 @@ function resolveSiblingFileEditScript(scriptPath) {
5896
6056
  const mainDir = dirname3(scriptPath);
5897
6057
  const mainBase = scriptPath.slice(mainDir.length + 1);
5898
6058
  if (mainBase === `index${ext}` || mainBase === `mc${ext}`) {
5899
- return join7(mainDir, `mc-edit${ext}`);
6059
+ return join6(mainDir, `mc-edit${ext}`);
5900
6060
  }
5901
6061
  return null;
5902
6062
  }
@@ -5905,7 +6065,7 @@ function resolveModuleLocalFileEditScript(moduleUrl) {
5905
6065
  const ext = extname(modulePath);
5906
6066
  if (!ext)
5907
6067
  return null;
5908
- const helperPath = join7(dirname3(modulePath), "..", "..", `mc-edit${ext}`);
6068
+ const helperPath = join6(dirname3(modulePath), "..", "..", `mc-edit${ext}`);
5909
6069
  return existsSync4(helperPath) ? helperPath : null;
5910
6070
  }
5911
6071
  function resolveProcessScriptPath(mainModule, argv1) {
@@ -5938,7 +6098,7 @@ var ShellSchema = z3.object({
5938
6098
  env: z3.record(z3.string(), z3.string()).nullable().describe("Additional environment variables to set")
5939
6099
  });
5940
6100
  var MAX_OUTPUT_BYTES = 1e4;
5941
- async function runShellCommand(input) {
6101
+ async function runShellCommand(input, options) {
5942
6102
  const cwd = input.cwd ?? process.cwd();
5943
6103
  const timeout = input.timeout ?? undefined;
5944
6104
  const inputEnv = input.env ?? undefined;
@@ -5960,8 +6120,7 @@ ${input.command}`], {
5960
6120
  stdout: "pipe",
5961
6121
  stderr: "pipe"
5962
6122
  });
5963
- const timer = timeout ? setTimeout(() => {
5964
- timedOut = true;
6123
+ function killProc() {
5965
6124
  try {
5966
6125
  proc.kill("SIGTERM");
5967
6126
  setTimeout(() => {
@@ -5973,7 +6132,20 @@ ${input.command}`], {
5973
6132
  for (const reader of readers) {
5974
6133
  reader.cancel().catch(() => {});
5975
6134
  }
6135
+ }
6136
+ const timer = timeout ? setTimeout(() => {
6137
+ timedOut = true;
6138
+ killProc();
5976
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
+ }
5977
6149
  async function collectStream(stream) {
5978
6150
  const reader = stream.getReader();
5979
6151
  readers.push(reader);
@@ -6017,6 +6189,7 @@ ${input.command}`], {
6017
6189
  } finally {
6018
6190
  if (timer)
6019
6191
  clearTimeout(timer);
6192
+ abortSignal?.removeEventListener("abort", onAbort);
6020
6193
  restoreTerminal();
6021
6194
  if (wasRaw) {
6022
6195
  try {
@@ -6041,7 +6214,7 @@ var shellTool = {
6041
6214
  name: "shell",
6042
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.",
6043
6216
  schema: ShellSchema,
6044
- execute: runShellCommand
6217
+ execute: (input, options) => runShellCommand(input, options)
6045
6218
  };
6046
6219
 
6047
6220
  // src/agent/tools.ts
@@ -6049,11 +6222,11 @@ function withCwdDefault(tool, cwd) {
6049
6222
  const originalExecute = tool.execute;
6050
6223
  return {
6051
6224
  ...tool,
6052
- execute: async (input) => {
6225
+ execute: async (input, options) => {
6053
6226
  const patched = typeof input === "object" && input !== null ? input : {};
6054
6227
  if (patched.cwd === undefined)
6055
6228
  patched.cwd = cwd;
6056
- return originalExecute(patched);
6229
+ return originalExecute(patched, options);
6057
6230
  }
6058
6231
  };
6059
6232
  }
@@ -6096,7 +6269,7 @@ async function initAgent(opts) {
6096
6269
  for (const row of listMcpServers()) {
6097
6270
  try {
6098
6271
  await connectAndAddMcp(row.name);
6099
- opts.reporter.info(`MCP: connected ${c12.cyan(row.name)}`);
6272
+ opts.reporter.info(`MCP: connected ${c11.cyan(row.name)}`);
6100
6273
  } catch (e) {
6101
6274
  opts.reporter.error(`MCP: failed to connect ${row.name}: ${String(e)}`);
6102
6275
  }
@@ -6154,7 +6327,7 @@ async function initAgent(opts) {
6154
6327
  }
6155
6328
 
6156
6329
  // src/cli/args.ts
6157
- import * as c13 from "yoctocolors";
6330
+ import * as c12 from "yoctocolors";
6158
6331
  function parseArgs(argv) {
6159
6332
  const args = {
6160
6333
  model: null,
@@ -6203,11 +6376,11 @@ function parseArgs(argv) {
6203
6376
  return args;
6204
6377
  }
6205
6378
  function printHelp() {
6206
- 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
6207
6380
  `);
6208
- writeln(`${c13.bold("Usage:")} mc [options] [prompt]
6381
+ writeln(`${c12.bold("Usage:")} mc [options] [prompt]
6209
6382
  `);
6210
- writeln(`${c13.bold("Options:")}`);
6383
+ writeln(`${c12.bold("Options:")}`);
6211
6384
  const opts = [
6212
6385
  ["-m, --model <id>", "Model to use (e.g. zen/claude-sonnet-4-6)"],
6213
6386
  ["-c, --continue", "Continue the most recent session"],
@@ -6217,10 +6390,10 @@ function printHelp() {
6217
6390
  ["-h, --help", "Show this help"]
6218
6391
  ];
6219
6392
  for (const [flag, desc] of opts) {
6220
- writeln(` ${c13.cyan((flag ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
6393
+ writeln(` ${c12.cyan((flag ?? "").padEnd(22))} ${c12.dim(desc ?? "")}`);
6221
6394
  }
6222
6395
  writeln(`
6223
- ${c13.bold("Provider env vars:")}`);
6396
+ ${c12.bold("Provider env vars:")}`);
6224
6397
  const envs = [
6225
6398
  ["OPENCODE_API_KEY", "OpenCode Zen (recommended)"],
6226
6399
  ["ANTHROPIC_API_KEY", "Anthropic direct"],
@@ -6231,22 +6404,22 @@ ${c13.bold("Provider env vars:")}`);
6231
6404
  ["OLLAMA_BASE_URL", "Ollama base URL (default: http://localhost:11434)"]
6232
6405
  ];
6233
6406
  for (const [env, desc] of envs) {
6234
- writeln(` ${c13.yellow((env ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
6407
+ writeln(` ${c12.yellow((env ?? "").padEnd(22))} ${c12.dim(desc ?? "")}`);
6235
6408
  }
6236
6409
  writeln(`
6237
- ${c13.bold("Examples:")}`);
6238
- writeln(` mc ${c13.dim("# interactive session")}`);
6239
- writeln(` mc "explain this codebase" ${c13.dim("# one-shot prompt then exit")}`);
6240
- writeln(` mc -c ${c13.dim("# continue last session")}`);
6241
- writeln(` mc -m ollama/llama3.2 ${c13.dim("# use local Ollama model")}`);
6242
- 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")}`);
6243
6416
  }
6244
6417
 
6245
6418
  // src/cli/bootstrap.ts
6246
6419
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync } from "fs";
6247
6420
  import { homedir as homedir6 } from "os";
6248
- import { join as join8 } from "path";
6249
- import * as c14 from "yoctocolors";
6421
+ import { join as join7 } from "path";
6422
+ import * as c13 from "yoctocolors";
6250
6423
  var REVIEW_SKILL_CONTENT = `---
6251
6424
  name: review
6252
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."
@@ -6276,17 +6449,17 @@ Review recent changes and provide actionable feedback.
6276
6449
  - Keep feedback actionable: say what's wrong and suggest a fix.
6277
6450
  `;
6278
6451
  function bootstrapGlobalDefaults() {
6279
- const skillDir = join8(homedir6(), ".agents", "skills", "review");
6280
- const skillPath = join8(skillDir, "SKILL.md");
6452
+ const skillDir = join7(homedir6(), ".agents", "skills", "review");
6453
+ const skillPath = join7(skillDir, "SKILL.md");
6281
6454
  if (!existsSync5(skillPath)) {
6282
6455
  mkdirSync2(skillDir, { recursive: true });
6283
6456
  writeFileSync(skillPath, REVIEW_SKILL_CONTENT, "utf-8");
6284
- 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)")}`);
6285
6458
  }
6286
6459
  }
6287
6460
 
6288
6461
  // src/cli/file-refs.ts
6289
- import { join as join9 } from "path";
6462
+ import { join as join8 } from "path";
6290
6463
  async function resolveFileRefs(text, cwd) {
6291
6464
  const atPattern = /@([\w./\-_]+)/g;
6292
6465
  let result = text;
@@ -6296,7 +6469,7 @@ async function resolveFileRefs(text, cwd) {
6296
6469
  const ref = match[1];
6297
6470
  if (!ref)
6298
6471
  continue;
6299
- const filePath = ref.startsWith("/") ? ref : join9(cwd, ref);
6472
+ const filePath = ref.startsWith("/") ? ref : join8(cwd, ref);
6300
6473
  if (isImageFilename(ref)) {
6301
6474
  const attachment = await loadImageFile(filePath);
6302
6475
  if (attachment) {
@@ -6318,25 +6491,25 @@ ${content}
6318
6491
  }
6319
6492
 
6320
6493
  // src/cli/input-loop.ts
6321
- import * as c21 from "yoctocolors";
6494
+ import * as c20 from "yoctocolors";
6322
6495
 
6323
6496
  // src/cli/commands.ts
6324
6497
  import { randomBytes } from "crypto";
6325
6498
  import { unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
6326
6499
  import { tmpdir } from "os";
6327
- import { join as join10 } from "path";
6328
- import * as c20 from "yoctocolors";
6500
+ import { join as join9 } from "path";
6501
+ import * as c19 from "yoctocolors";
6329
6502
 
6330
6503
  // src/cli/commands-help.ts
6331
- import * as c15 from "yoctocolors";
6504
+ import * as c14 from "yoctocolors";
6332
6505
  function renderEntries(entries) {
6333
6506
  for (const [label, description] of entries) {
6334
- writeln(` ${c15.cyan(label.padEnd(28))} ${c15.dim(description)}`);
6507
+ writeln(` ${c14.cyan(label.padEnd(28))} ${c14.dim(description)}`);
6335
6508
  }
6336
6509
  }
6337
6510
  function renderHelpCommand(ctx) {
6338
6511
  writeln();
6339
- writeln(` ${c15.dim("session")}`);
6512
+ writeln(` ${c14.dim("session")}`);
6340
6513
  renderEntries([
6341
6514
  ["/session [id]", "list sessions or switch to one"],
6342
6515
  ["/new", "start a fresh session"],
@@ -6344,7 +6517,7 @@ function renderHelpCommand(ctx) {
6344
6517
  ["/exit", "quit"]
6345
6518
  ]);
6346
6519
  writeln();
6347
- writeln(` ${c15.dim("model + context")}`);
6520
+ writeln(` ${c14.dim("model + context")}`);
6348
6521
  renderEntries([
6349
6522
  ["/model [id]", "list or switch models"],
6350
6523
  ["/reasoning [on|off]", "toggle reasoning display"],
@@ -6357,7 +6530,7 @@ function renderHelpCommand(ctx) {
6357
6530
  ["/help", "show this help"]
6358
6531
  ]);
6359
6532
  writeln();
6360
- writeln(` ${c15.dim("prompt")}`);
6533
+ writeln(` ${c14.dim("prompt")}`);
6361
6534
  renderEntries([
6362
6535
  ["ask normally", "send a prompt to the current agent"],
6363
6536
  ["!cmd", "run a shell command and keep the result in context"],
@@ -6367,44 +6540,44 @@ function renderHelpCommand(ctx) {
6367
6540
  const skills = loadSkillsIndex(ctx.cwd);
6368
6541
  if (skills.size > 0) {
6369
6542
  writeln();
6370
- writeln(` ${c15.dim("skills")}`);
6543
+ writeln(` ${c14.dim("skills")}`);
6371
6544
  for (const skill of skills.values()) {
6372
- const source = skill.source === "local" ? c15.dim("local") : c15.dim("global");
6545
+ const source = skill.source === "local" ? c14.dim("local") : c14.dim("global");
6373
6546
  const desc = truncateText(skill.description, 80);
6374
- 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}`);
6375
6548
  }
6376
6549
  }
6377
6550
  writeln();
6378
- 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`);
6379
6552
  writeln();
6380
6553
  }
6381
6554
 
6382
6555
  // src/cli/commands-login.ts
6383
- import * as c16 from "yoctocolors";
6556
+ import * as c15 from "yoctocolors";
6384
6557
  function renderLoginHelp() {
6385
6558
  writeln();
6386
- writeln(` ${c16.dim("usage:")}`);
6387
- writeln(` /login ${c16.dim("show login status")}`);
6388
- writeln(` /login <provider> ${c16.dim("login via OAuth")}`);
6389
- 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")}`);
6390
6563
  writeln();
6391
- writeln(` ${c16.dim("providers:")}`);
6564
+ writeln(` ${c15.dim("providers:")}`);
6392
6565
  for (const p of getOAuthProviders()) {
6393
- const status = isLoggedIn(p.id) ? c16.green("logged in") : c16.dim("not logged in");
6394
- 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}`);
6395
6568
  }
6396
6569
  writeln();
6397
6570
  }
6398
6571
  function renderStatus() {
6399
6572
  const loggedIn = listLoggedInProviders();
6400
6573
  if (loggedIn.length === 0) {
6401
- 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>`);
6402
6575
  return;
6403
6576
  }
6404
6577
  for (const id of loggedIn) {
6405
6578
  const provider = getOAuthProvider(id);
6406
6579
  const name = provider?.name ?? id;
6407
- writeln(`${PREFIX.success} ${c16.cyan(id)} ${c16.dim(name)}`);
6580
+ writeln(`${PREFIX.success} ${c15.cyan(id)} ${c15.dim(name)}`);
6408
6581
  }
6409
6582
  }
6410
6583
  async function handleLoginCommand(ctx, args) {
@@ -6425,7 +6598,7 @@ async function handleLoginCommand(ctx, args) {
6425
6598
  if (isLoggedIn(providerId)) {
6426
6599
  const token = await getAccessToken(providerId);
6427
6600
  if (token) {
6428
- writeln(`${PREFIX.success} already logged in to ${c16.cyan(provider.name)}`);
6601
+ writeln(`${PREFIX.success} already logged in to ${c15.cyan(provider.name)}`);
6429
6602
  return;
6430
6603
  }
6431
6604
  }
@@ -6436,7 +6609,7 @@ async function handleLoginCommand(ctx, args) {
6436
6609
  ctx.stopSpinner();
6437
6610
  writeln(`${PREFIX.info} ${instructions}`);
6438
6611
  writeln();
6439
- writeln(` ${c16.cyan(url)}`);
6612
+ writeln(` ${c15.cyan(url)}`);
6440
6613
  writeln();
6441
6614
  let open = "xdg-open";
6442
6615
  if (process.platform === "darwin")
@@ -6448,12 +6621,12 @@ async function handleLoginCommand(ctx, args) {
6448
6621
  },
6449
6622
  onProgress: (msg) => {
6450
6623
  ctx.stopSpinner();
6451
- writeln(`${PREFIX.info} ${c16.dim(msg)}`);
6624
+ writeln(`${PREFIX.info} ${c15.dim(msg)}`);
6452
6625
  ctx.startSpinner("exchanging tokens");
6453
6626
  }
6454
6627
  });
6455
6628
  ctx.stopSpinner();
6456
- writeln(`${PREFIX.success} logged in to ${c16.cyan(provider.name)}`);
6629
+ writeln(`${PREFIX.success} logged in to ${c15.cyan(provider.name)}`);
6457
6630
  } catch (err) {
6458
6631
  ctx.stopSpinner();
6459
6632
  writeln(`${PREFIX.error} login failed: ${err.message}`);
@@ -6466,15 +6639,15 @@ function handleLogoutCommand(_ctx, args) {
6466
6639
  return;
6467
6640
  }
6468
6641
  if (!isLoggedIn(providerId)) {
6469
- writeln(`${PREFIX.info} ${c16.dim("not logged in to")} ${providerId}`);
6642
+ writeln(`${PREFIX.info} ${c15.dim("not logged in to")} ${providerId}`);
6470
6643
  return;
6471
6644
  }
6472
6645
  logout(providerId);
6473
- writeln(`${PREFIX.success} logged out of ${c16.cyan(providerId)}`);
6646
+ writeln(`${PREFIX.success} logged out of ${c15.cyan(providerId)}`);
6474
6647
  }
6475
6648
 
6476
6649
  // src/cli/commands-mcp.ts
6477
- import * as c17 from "yoctocolors";
6650
+ import * as c16 from "yoctocolors";
6478
6651
  async function handleMcpCommand(ctx, args) {
6479
6652
  const parts = args.trim().split(/\s+/);
6480
6653
  const sub = parts[0] ?? "list";
@@ -6482,15 +6655,15 @@ async function handleMcpCommand(ctx, args) {
6482
6655
  case "list": {
6483
6656
  const servers = listMcpServers();
6484
6657
  if (servers.length === 0) {
6485
- writeln(c17.dim(" no MCP servers configured"));
6486
- 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...]"));
6487
6660
  return;
6488
6661
  }
6489
6662
  writeln();
6490
6663
  for (const s of servers) {
6491
6664
  const detailText = s.url ?? s.command ?? "";
6492
- const detail = detailText ? c17.dim(` ${detailText}`) : "";
6493
- 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}`);
6494
6667
  }
6495
6668
  return;
6496
6669
  }
@@ -6535,9 +6708,9 @@ async function handleMcpCommand(ctx, args) {
6535
6708
  }
6536
6709
  try {
6537
6710
  await ctx.connectMcpServer(name);
6538
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} added and connected`);
6711
+ writeln(`${PREFIX.success} mcp server ${c16.cyan(name)} added and connected`);
6539
6712
  } catch (e) {
6540
- 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)})`)}`);
6541
6714
  }
6542
6715
  return;
6543
6716
  }
@@ -6549,17 +6722,17 @@ async function handleMcpCommand(ctx, args) {
6549
6722
  return;
6550
6723
  }
6551
6724
  deleteMcpServer(name);
6552
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} removed`);
6725
+ writeln(`${PREFIX.success} mcp server ${c16.cyan(name)} removed`);
6553
6726
  return;
6554
6727
  }
6555
6728
  default:
6556
6729
  writeln(`${PREFIX.error} unknown: /mcp ${sub}`);
6557
- writeln(c17.dim(" subcommands: list \xB7 add \xB7 remove"));
6730
+ writeln(c16.dim(" subcommands: list \xB7 add \xB7 remove"));
6558
6731
  }
6559
6732
  }
6560
6733
 
6561
6734
  // src/cli/commands-model.ts
6562
- import * as c18 from "yoctocolors";
6735
+ import * as c17 from "yoctocolors";
6563
6736
  import { select } from "yoctoselect";
6564
6737
  var THINKING_EFFORTS = ["low", "medium", "high", "xhigh"];
6565
6738
  function parseThinkingEffort(value) {
@@ -6579,21 +6752,21 @@ function renderModelUpdatedMessage(ctx, modelId, effortArg) {
6579
6752
  if (effortArg) {
6580
6753
  if (effortArg === "off") {
6581
6754
  ctx.setThinkingEffort(null);
6582
- 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)")}`);
6583
6756
  return;
6584
6757
  }
6585
6758
  const effort = parseThinkingEffort(effortArg);
6586
6759
  if (effort) {
6587
6760
  ctx.setThinkingEffort(effort);
6588
- 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})`)}`);
6589
6762
  return;
6590
6763
  }
6591
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)}`);
6592
- 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)`);
6593
6766
  return;
6594
6767
  }
6595
- const effortTag = ctx.thinkingEffort ? c18.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
6596
- 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}`);
6597
6770
  }
6598
6771
  async function handleModelSet(ctx, args) {
6599
6772
  const parts = args.trim().split(/\s+/).filter(Boolean);
@@ -6606,7 +6779,7 @@ async function handleModelSet(ctx, args) {
6606
6779
  const snapshot = await fetchAvailableModels();
6607
6780
  const match = findModelIdByAlias(idArg, snapshot.models.map((model) => model.id));
6608
6781
  if (!match) {
6609
- 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")}`);
6610
6783
  return;
6611
6784
  }
6612
6785
  modelId = match;
@@ -6626,7 +6799,7 @@ function handleModelEffort(ctx, effortArg) {
6626
6799
  return;
6627
6800
  }
6628
6801
  ctx.setThinkingEffort(effort);
6629
- writeln(`${PREFIX.success} thinking effort \u2192 ${c18.cyan(effort)}`);
6802
+ writeln(`${PREFIX.success} thinking effort \u2192 ${c17.cyan(effort)}`);
6630
6803
  }
6631
6804
  async function handleModelSelect(ctx) {
6632
6805
  ctx.startSpinner("fetching models");
@@ -6634,20 +6807,20 @@ async function handleModelSelect(ctx) {
6634
6807
  ctx.stopSpinner();
6635
6808
  if (snapshot.models.length === 0) {
6636
6809
  writeln(`${PREFIX.error} No models found. Check your API keys or Ollama connection.`);
6637
- 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."));
6638
6811
  return;
6639
6812
  }
6640
6813
  if (snapshot.stale) {
6641
6814
  const lastSync = snapshot.lastSyncAt ? new Date(snapshot.lastSyncAt).toLocaleString() : "never";
6642
6815
  const refreshTag = snapshot.refreshing ? " (refreshing in background)" : "";
6643
- writeln(c18.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
6816
+ writeln(c17.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
6644
6817
  }
6645
6818
  const items = snapshot.models.map((model) => {
6646
6819
  const isCurrent = ctx.currentModel === model.id;
6647
- const freeTag = model.free ? c18.green(" free") : "";
6648
- const contextTag = model.context ? c18.dim(` ${Math.round(model.context / 1000)}k`) : "";
6649
- const currentTag = isCurrent ? c18.cyan(" \u25C0") : "";
6650
- const providerTag = c18.dim(` [${model.provider}]`);
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}]`);
6651
6824
  return {
6652
6825
  label: `${model.displayName}${freeTag}${contextTag}${currentTag}${providerTag}`,
6653
6826
  value: model.id,
@@ -6680,7 +6853,7 @@ async function handleModelCommand(ctx, args) {
6680
6853
  }
6681
6854
 
6682
6855
  // src/cli/commands-session.ts
6683
- import * as c19 from "yoctocolors";
6856
+ import * as c18 from "yoctocolors";
6684
6857
  import { select as select2 } from "yoctoselect";
6685
6858
  async function handleSessionCommand(ctx, args) {
6686
6859
  const id = args.trim();
@@ -6689,15 +6862,15 @@ async function handleSessionCommand(ctx, args) {
6689
6862
  const ok2 = ctx.switchSession(id);
6690
6863
  ctx.stopSpinner();
6691
6864
  if (ok2) {
6692
- 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)})`);
6693
6866
  } else {
6694
- writeln(`${PREFIX.error} session ${c19.cyan(id)} not found`);
6867
+ writeln(`${PREFIX.error} session ${c18.cyan(id)} not found`);
6695
6868
  }
6696
6869
  return;
6697
6870
  }
6698
6871
  const sessions = listSessions(50);
6699
6872
  if (sessions.length === 0) {
6700
- writeln(`${PREFIX.info} ${c19.dim("no sessions found")}`);
6873
+ writeln(`${PREFIX.info} ${c18.dim("no sessions found")}`);
6701
6874
  return;
6702
6875
  }
6703
6876
  const items = sessions.map((s) => {
@@ -6706,7 +6879,7 @@ async function handleSessionCommand(ctx, args) {
6706
6879
  const cwd = tildePath(s.cwd);
6707
6880
  const date = new Date(s.updated_at).toLocaleDateString();
6708
6881
  return {
6709
- 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)}`,
6710
6883
  value: s.id,
6711
6884
  filterText: `${s.id} ${s.title} ${s.model} ${s.cwd}`
6712
6885
  };
@@ -6722,9 +6895,9 @@ async function handleSessionCommand(ctx, args) {
6722
6895
  return;
6723
6896
  const ok = ctx.switchSession(picked);
6724
6897
  if (ok) {
6725
- 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)})`);
6726
6899
  } else {
6727
- writeln(`${PREFIX.error} session ${c19.cyan(picked)} not found`);
6900
+ writeln(`${PREFIX.error} session ${c18.cyan(picked)} not found`);
6728
6901
  }
6729
6902
  }
6730
6903
 
@@ -6734,9 +6907,9 @@ async function handleUndo(ctx) {
6734
6907
  try {
6735
6908
  const ok = await ctx.undoLastTurn();
6736
6909
  if (ok) {
6737
- writeln(`${PREFIX.success} ${c20.dim("last conversation turn removed")}`);
6910
+ writeln(`${PREFIX.success} ${c19.dim("last conversation turn removed")}`);
6738
6911
  } else {
6739
- writeln(`${PREFIX.info} ${c20.dim("nothing to undo")}`);
6912
+ writeln(`${PREFIX.info} ${c19.dim("nothing to undo")}`);
6740
6913
  }
6741
6914
  } finally {
6742
6915
  ctx.stopSpinner();
@@ -6794,7 +6967,7 @@ async function handleCommand(command, args, ctx) {
6794
6967
  if (loaded2) {
6795
6968
  const srcPath = skill.source === "local" ? `.agents/skills/${skill.name}/SKILL.md` : `~/.agents/skills/${skill.name}/SKILL.md`;
6796
6969
  if (skill.context === "fork") {
6797
- 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)`)}`);
6798
6971
  writeln();
6799
6972
  const subagentPrompt = args ? `${loaded2.content}
6800
6973
 
@@ -6802,7 +6975,7 @@ ${args}` : loaded2.content;
6802
6975
  const result = await runForkedSkill(skill.name, subagentPrompt, ctx.cwd);
6803
6976
  return { type: "inject-user-message", text: result };
6804
6977
  }
6805
- writeln(`${PREFIX.info} ${c20.cyan(skill.name)} ${c20.dim(`[${srcPath}]`)}`);
6978
+ writeln(`${PREFIX.info} ${c19.cyan(skill.name)} ${c19.dim(`[${srcPath}]`)}`);
6806
6979
  writeln();
6807
6980
  const prompt = args ? `${loaded2.content}
6808
6981
 
@@ -6810,16 +6983,16 @@ ${args}` : loaded2.content;
6810
6983
  return { type: "inject-user-message", text: prompt };
6811
6984
  }
6812
6985
  }
6813
- writeln(`${PREFIX.error} unknown: /${command} ${c20.dim("\u2014 /help for commands")}`);
6986
+ writeln(`${PREFIX.error} unknown: /${command} ${c19.dim("\u2014 /help for commands")}`);
6814
6987
  return { type: "unknown", command };
6815
6988
  }
6816
6989
  }
6817
6990
  }
6818
6991
  async function runForkedSkill(skillName, prompt, cwd) {
6819
- const tmpFile = join10(tmpdir(), `mc-fork-${randomBytes(8).toString("hex")}.md`);
6992
+ const tmpFile = join9(tmpdir(), `mc-fork-${randomBytes(8).toString("hex")}.md`);
6820
6993
  writeFileSync2(tmpFile, prompt, "utf8");
6821
6994
  try {
6822
- writeln(`${PREFIX.info} ${c20.dim("running subagent\u2026")}`);
6995
+ writeln(`${PREFIX.info} ${c19.dim("running subagent\u2026")}`);
6823
6996
  const proc = Bun.spawn([process.execPath, Bun.main], {
6824
6997
  cwd,
6825
6998
  stdin: Bun.file(tmpFile),
@@ -6851,17 +7024,17 @@ ${output}`;
6851
7024
  function handleBooleanToggleCommand(opts) {
6852
7025
  const mode = opts.args.trim().toLowerCase();
6853
7026
  if (!mode) {
6854
- 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")}`);
6855
7028
  return;
6856
7029
  }
6857
7030
  if (mode === "on") {
6858
7031
  opts.set(true);
6859
- writeln(`${PREFIX.success} ${opts.label} ${c20.green("on")}`);
7032
+ writeln(`${PREFIX.success} ${opts.label} ${c19.green("on")}`);
6860
7033
  return;
6861
7034
  }
6862
7035
  if (mode === "off") {
6863
7036
  opts.set(false);
6864
- writeln(`${PREFIX.success} ${opts.label} ${c20.dim("off")}`);
7037
+ writeln(`${PREFIX.success} ${opts.label} ${c19.dim("off")}`);
6865
7038
  return;
6866
7039
  }
6867
7040
  writeln(`${PREFIX.error} usage: ${opts.usage}`);
@@ -6921,13 +7094,12 @@ async function getGitBranch(cwd) {
6921
7094
  }
6922
7095
  async function runInputLoop(opts) {
6923
7096
  const { cwd, reporter, cmdCtx, runner } = opts;
6924
- let lastStatusSignature = null;
6925
7097
  while (true) {
6926
7098
  const branch = await getGitBranch(cwd);
6927
7099
  const status = runner.getStatusInfo();
6928
7100
  const cwdDisplay = tildePath(cwd);
6929
7101
  const contextWindow = getContextWindow(status.model);
6930
- const statusData = {
7102
+ reporter.renderStatusBar({
6931
7103
  model: status.model,
6932
7104
  cwd: cwdDisplay,
6933
7105
  gitBranch: branch,
@@ -6937,12 +7109,7 @@ async function runInputLoop(opts) {
6937
7109
  contextTokens: status.lastContextTokens,
6938
7110
  contextWindow,
6939
7111
  thinkingEffort: status.thinkingEffort
6940
- };
6941
- const statusSignature = buildStatusBarSignature(statusData);
6942
- if (statusSignature !== lastStatusSignature) {
6943
- reporter.renderStatusBar(statusData);
6944
- lastStatusSignature = statusSignature;
6945
- }
7112
+ });
6946
7113
  let input;
6947
7114
  try {
6948
7115
  input = await readline({ cwd });
@@ -6951,14 +7118,14 @@ async function runInputLoop(opts) {
6951
7118
  }
6952
7119
  switch (input.type) {
6953
7120
  case "eof":
6954
- reporter.writeText(c21.dim("Goodbye."));
7121
+ reporter.writeText(c20.dim("Goodbye."));
6955
7122
  return;
6956
7123
  case "interrupt":
6957
7124
  continue;
6958
7125
  case "command": {
6959
7126
  const result = await handleCommand(input.command, input.args, cmdCtx);
6960
7127
  if (result.type === "exit") {
6961
- reporter.writeText(c21.dim("Goodbye."));
7128
+ reporter.writeText(c20.dim("Goodbye."));
6962
7129
  return;
6963
7130
  }
6964
7131
  if (result.type === "inject-user-message") {
@@ -7065,7 +7232,7 @@ async function main() {
7065
7232
  if (last) {
7066
7233
  sessionId = last.id;
7067
7234
  } else {
7068
- writeln(c22.dim("No previous session found, starting fresh."));
7235
+ writeln(c21.dim("No previous session found, starting fresh."));
7069
7236
  }
7070
7237
  } else if (args.sessionId) {
7071
7238
  sessionId = args.sessionId;