mini-coder 0.2.3 → 0.3.1

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 c20 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.1";
17
17
 
18
18
  // src/mcp/client.ts
19
19
  async function connectMcpServer(config) {
@@ -70,7 +70,7 @@ async function connectMcpServer(config) {
70
70
 
71
71
  // src/session/db/connection.ts
72
72
  import { Database } from "bun:sqlite";
73
- import { existsSync, mkdirSync, unlinkSync } from "fs";
73
+ import { existsSync, mkdirSync, renameSync } from "fs";
74
74
  import { homedir } from "os";
75
75
  import { join } from "path";
76
76
  function getConfigDir() {
@@ -201,27 +201,32 @@ function configureDb(db) {
201
201
  db.exec("PRAGMA foreign_keys=ON;");
202
202
  db.exec("PRAGMA busy_timeout=1000;");
203
203
  }
204
+ function rotateDbFiles(dbPath, version) {
205
+ const backupBase = `${dbPath}.bak-v${version}-${Date.now()}`;
206
+ for (const suffix of ["", "-wal", "-shm"]) {
207
+ const path = `${dbPath}${suffix}`;
208
+ if (!existsSync(path))
209
+ continue;
210
+ renameSync(path, `${backupBase}${suffix}`);
211
+ }
212
+ }
204
213
  function getDb() {
205
214
  if (!_db) {
206
215
  const dbPath = getDbPath();
216
+ const dbExists = existsSync(dbPath);
207
217
  let db = new Database(dbPath, { create: true });
208
218
  configureDb(db);
209
219
  const version = db.query("PRAGMA user_version").get()?.user_version ?? 0;
210
- if (version !== DB_VERSION) {
220
+ if (dbExists && version !== DB_VERSION) {
211
221
  try {
212
222
  db.close();
213
223
  } catch {}
214
- for (const path of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
215
- if (existsSync(path))
216
- unlinkSync(path);
217
- }
224
+ rotateDbFiles(dbPath, version);
218
225
  db = new Database(dbPath, { create: true });
219
226
  configureDb(db);
220
- db.exec(SCHEMA);
221
- db.exec(`PRAGMA user_version = ${DB_VERSION};`);
222
- } else {
223
- db.exec(SCHEMA);
224
227
  }
228
+ db.exec(SCHEMA);
229
+ db.exec(`PRAGMA user_version = ${DB_VERSION};`);
225
230
  _db = db;
226
231
  }
227
232
  return _db;
@@ -339,7 +344,7 @@ function deleteMcpServer(name) {
339
344
  }
340
345
  // src/cli/output.ts
341
346
  import { homedir as homedir4 } from "os";
342
- import * as c8 from "yoctocolors";
347
+ import * as c7 from "yoctocolors";
343
348
 
344
349
  // src/agent/context-files.ts
345
350
  import { existsSync as existsSync2, readFileSync } from "fs";
@@ -436,7 +441,7 @@ import { createGoogleGenerativeAI } from "@ai-sdk/google";
436
441
  import { createOpenAI } from "@ai-sdk/openai";
437
442
  import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
438
443
 
439
- // src/session/oauth/anthropic.ts
444
+ // src/session/oauth/openai.ts
440
445
  import { createServer } from "http";
441
446
 
442
447
  // src/session/oauth/pkce.ts
@@ -457,19 +462,27 @@ async function generatePKCE() {
457
462
  return { verifier, challenge };
458
463
  }
459
464
 
460
- // src/session/oauth/anthropic.ts
461
- var CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
462
- var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
463
- var TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
465
+ // src/session/oauth/openai.ts
466
+ var CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
467
+ var AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
468
+ var TOKEN_URL = "https://auth.openai.com/oauth/token";
464
469
  var CALLBACK_HOST = "127.0.0.1";
465
- var CALLBACK_PORT = 53692;
466
- var CALLBACK_PATH = "/callback";
470
+ var CALLBACK_PORT = 1455;
471
+ var CALLBACK_PATH = "/auth/callback";
467
472
  var REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
468
- var SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
473
+ var SCOPES = "openid profile email offline_access";
469
474
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
470
475
  var SUCCESS_HTML = `<!doctype html>
471
476
  <html lang="en"><head><meta charset="utf-8"><title>Authenticated</title></head>
472
- <body><p>Authentication successful. Return to your terminal.</p></body></html>`;
477
+ <body><p>OpenAI authentication successful. Return to your terminal.</p></body></html>`;
478
+ function createState() {
479
+ const bytes = new Uint8Array(16);
480
+ crypto.getRandomValues(bytes);
481
+ let hex = "";
482
+ for (const b of bytes)
483
+ hex += b.toString(16).padStart(2, "0");
484
+ return hex;
485
+ }
473
486
  function startCallbackServer(expectedState) {
474
487
  return new Promise((resolve2, reject) => {
475
488
  let result = null;
@@ -488,7 +501,7 @@ function startCallbackServer(expectedState) {
488
501
  return;
489
502
  }
490
503
  res.writeHead(200, { "Content-Type": "text/html" }).end(SUCCESS_HTML);
491
- result = { code, state };
504
+ result = { code };
492
505
  });
493
506
  server.on("error", reject);
494
507
  server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
@@ -512,10 +525,9 @@ async function postTokenRequest(body, label) {
512
525
  const res = await fetch(TOKEN_URL, {
513
526
  method: "POST",
514
527
  headers: {
515
- "Content-Type": "application/json",
516
- Accept: "application/json"
528
+ "Content-Type": "application/x-www-form-urlencoded"
517
529
  },
518
- body: JSON.stringify(body),
530
+ body,
519
531
  signal: AbortSignal.timeout(30000)
520
532
  });
521
533
  if (!res.ok) {
@@ -529,57 +541,72 @@ async function postTokenRequest(body, label) {
529
541
  expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000
530
542
  };
531
543
  }
532
- function exchangeCode(code, state, verifier) {
533
- return postTokenRequest({
544
+ function exchangeCode(code, verifier) {
545
+ return postTokenRequest(new URLSearchParams({
534
546
  grant_type: "authorization_code",
535
547
  client_id: CLIENT_ID,
536
548
  code,
537
- state,
538
- redirect_uri: REDIRECT_URI,
539
- code_verifier: verifier
540
- }, "Token exchange");
549
+ code_verifier: verifier,
550
+ redirect_uri: REDIRECT_URI
551
+ }), "Token exchange");
541
552
  }
542
- function refreshAnthropicToken(refreshToken) {
543
- return postTokenRequest({
553
+ function refreshOpenAIToken(refreshToken) {
554
+ return postTokenRequest(new URLSearchParams({
544
555
  grant_type: "refresh_token",
545
- client_id: CLIENT_ID,
546
- refresh_token: refreshToken
547
- }, "Token refresh");
556
+ refresh_token: refreshToken,
557
+ client_id: CLIENT_ID
558
+ }), "Token refresh");
548
559
  }
549
- async function loginAnthropic(callbacks) {
560
+ async function loginOpenAI(callbacks) {
550
561
  const { verifier, challenge } = await generatePKCE();
551
- const cb = await startCallbackServer(verifier);
562
+ const state = createState();
563
+ const cb = await startCallbackServer(state);
552
564
  try {
553
565
  const params = new URLSearchParams({
554
- code: "true",
555
- client_id: CLIENT_ID,
556
566
  response_type: "code",
567
+ client_id: CLIENT_ID,
557
568
  redirect_uri: REDIRECT_URI,
558
569
  scope: SCOPES,
559
570
  code_challenge: challenge,
560
571
  code_challenge_method: "S256",
561
- state: verifier
572
+ state,
573
+ id_token_add_organizations: "true",
574
+ codex_cli_simplified_flow: "true",
575
+ originator: "mc"
562
576
  });
563
577
  callbacks.onOpenUrl(`${AUTHORIZE_URL}?${params}`, "Complete login in your browser.");
564
578
  const result = await cb.waitForCode();
565
579
  if (!result)
566
580
  throw new Error("Login cancelled or no code received");
567
581
  callbacks.onProgress("Exchanging authorization code for tokens\u2026");
568
- return exchangeCode(result.code, result.state, verifier);
582
+ return exchangeCode(result.code, verifier);
569
583
  } finally {
570
584
  cb.server.close();
571
585
  }
572
586
  }
573
- var anthropicOAuth = {
574
- id: "anthropic",
575
- name: "Anthropic (Claude Pro/Max)",
576
- login: loginAnthropic,
577
- refreshToken: refreshAnthropicToken
587
+ function extractAccountId(accessToken) {
588
+ try {
589
+ const parts = accessToken.split(".");
590
+ const jwt = parts[1];
591
+ if (parts.length !== 3 || !jwt)
592
+ return null;
593
+ const payload = JSON.parse(atob(jwt));
594
+ const auth = payload["https://api.openai.com/auth"];
595
+ return auth?.chatgpt_account_id ?? null;
596
+ } catch {
597
+ return null;
598
+ }
599
+ }
600
+ var openaiOAuth = {
601
+ id: "openai",
602
+ name: "OpenAI (ChatGPT Plus/Pro)",
603
+ login: loginOpenAI,
604
+ refreshToken: refreshOpenAIToken
578
605
  };
579
606
 
580
607
  // src/session/oauth/auth-storage.ts
581
608
  var PROVIDERS = new Map([
582
- [anthropicOAuth.id, anthropicOAuth]
609
+ [openaiOAuth.id, openaiOAuth]
583
610
  ]);
584
611
  function getOAuthProviders() {
585
612
  return [...PROVIDERS.values()];
@@ -608,10 +635,10 @@ function isAuthError(err) {
608
635
  return /\b(401|403)\b/.test(err.message);
609
636
  }
610
637
  function isLoggedIn(provider) {
611
- return getStoredToken(provider) !== null;
638
+ return PROVIDERS.has(provider) && getStoredToken(provider) !== null;
612
639
  }
613
640
  function listLoggedInProviders() {
614
- return getDb().query("SELECT provider FROM oauth_tokens ORDER BY provider").all().map((r) => r.provider);
641
+ return getDb().query("SELECT provider FROM oauth_tokens ORDER BY provider").all().map((r) => r.provider).filter((provider) => PROVIDERS.has(provider));
615
642
  }
616
643
  async function login(providerId, callbacks) {
617
644
  const provider = PROVIDERS.get(providerId);
@@ -1140,41 +1167,53 @@ async function fetchZenModels() {
1140
1167
  });
1141
1168
  }
1142
1169
  async function fetchOpenAIModels() {
1143
- const key = process.env.OPENAI_API_KEY;
1144
- if (!key)
1145
- 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
- }));
1152
- }
1153
- async function getAnthropicAuth() {
1154
- const envKey = process.env.ANTHROPIC_API_KEY;
1155
- if (envKey)
1156
- return { key: envKey, oauth: false };
1157
- if (isLoggedIn("anthropic")) {
1158
- const token = await getAccessToken("anthropic");
1159
- if (token)
1160
- return { key: token, oauth: true };
1170
+ const envKey = process.env.OPENAI_API_KEY;
1171
+ if (envKey) {
1172
+ return fetchPaginatedModelsList(`${OPENAI_BASE}/v1/models`, { headers: { Authorization: `Bearer ${envKey}` } }, 6000, "data", "id", (_item, modelId) => ({
1173
+ providerModelId: modelId,
1174
+ displayName: modelId,
1175
+ contextWindow: null,
1176
+ free: false
1177
+ }));
1178
+ }
1179
+ if (isLoggedIn("openai")) {
1180
+ const token = await getAccessToken("openai");
1181
+ if (!token)
1182
+ return null;
1183
+ return fetchCodexOAuthModels(token);
1161
1184
  }
1162
1185
  return null;
1163
1186
  }
1164
- async function fetchAnthropicModels() {
1165
- const auth = await getAnthropicAuth();
1166
- if (!auth)
1187
+ var CODEX_MODELS_URL = "https://chatgpt.com/backend-api/codex/models?client_version=1.0.0";
1188
+ async function fetchCodexOAuthModels(token) {
1189
+ try {
1190
+ const res = await fetch(CODEX_MODELS_URL, {
1191
+ headers: { Authorization: `Bearer ${token}` },
1192
+ signal: AbortSignal.timeout(6000)
1193
+ });
1194
+ if (!res.ok)
1195
+ return null;
1196
+ const data = await res.json();
1197
+ return (data.models ?? []).filter((m) => m.visibility === "list").map((m) => ({
1198
+ providerModelId: m.slug,
1199
+ displayName: m.display_name || m.slug,
1200
+ contextWindow: m.context_window,
1201
+ free: false
1202
+ }));
1203
+ } catch {
1167
1204
  return null;
1168
- const headers = {
1169
- "anthropic-version": "2023-06-01"
1170
- };
1171
- if (auth.oauth) {
1172
- headers.Authorization = `Bearer ${auth.key}`;
1173
- headers["anthropic-beta"] = "oauth-2025-04-20";
1174
- } else {
1175
- headers["x-api-key"] = auth.key;
1176
1205
  }
1177
- const payload = await fetchJson(`${ANTHROPIC_BASE}/v1/models`, { headers }, 6000);
1206
+ }
1207
+ async function fetchAnthropicModels() {
1208
+ const key = process.env.ANTHROPIC_API_KEY;
1209
+ if (!key)
1210
+ return null;
1211
+ const payload = await fetchJson(`${ANTHROPIC_BASE}/v1/models`, {
1212
+ headers: {
1213
+ "anthropic-version": "2023-06-01",
1214
+ "x-api-key": key
1215
+ }
1216
+ }, 6000);
1178
1217
  return processModelsList(payload, "data", "id", (item, modelId) => {
1179
1218
  const displayName = typeof item.display_name === "string" && item.display_name.trim().length > 0 ? item.display_name : modelId;
1180
1219
  return {
@@ -1236,7 +1275,7 @@ async function fetchProviderCandidates(provider) {
1236
1275
  var MODELS_DEV_SYNC_KEY = "last_models_dev_sync_at";
1237
1276
  var PROVIDER_SYNC_KEY_PREFIX = "last_provider_sync_at:";
1238
1277
  var CACHE_VERSION_KEY = "model_info_cache_version";
1239
- var CACHE_VERSION = 3;
1278
+ var CACHE_VERSION = 5;
1240
1279
  var MODEL_INFO_TTL_MS = 24 * 60 * 60 * 1000;
1241
1280
  var REMOTE_PROVIDER_ENV_KEYS = [
1242
1281
  { provider: "zen", envKeys: ["OPENCODE_API_KEY"] },
@@ -1281,8 +1320,8 @@ function hasAnyEnvKey(env, keys) {
1281
1320
  }
1282
1321
  function getRemoteProvidersFromEnv(env) {
1283
1322
  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");
1323
+ if (!providers.includes("openai") && isLoggedIn("openai")) {
1324
+ providers.push("openai");
1286
1325
  }
1287
1326
  return providers;
1288
1327
  }
@@ -1487,27 +1526,6 @@ var SUPPORTED_PROVIDERS = [
1487
1526
  "ollama"
1488
1527
  ];
1489
1528
  var ZEN_BASE2 = "https://opencode.ai/zen/v1";
1490
- var OAUTH_STRIP_BETAS = new Set;
1491
- function createOAuthFetch(accessToken) {
1492
- const oauthFetch = async (input, init) => {
1493
- let opts = init;
1494
- if (opts?.headers) {
1495
- const h = new Headers(opts.headers);
1496
- const beta = h.get("anthropic-beta");
1497
- if (beta) {
1498
- const filtered = beta.split(",").filter((b) => !OAUTH_STRIP_BETAS.has(b)).join(",");
1499
- h.set("anthropic-beta", filtered);
1500
- }
1501
- h.delete("x-api-key");
1502
- h.set("authorization", `Bearer ${accessToken}`);
1503
- h.set("user-agent", "claude-cli/2.1.75");
1504
- h.set("x-app", "cli");
1505
- opts = { ...opts, headers: Object.fromEntries(h.entries()) };
1506
- }
1507
- return fetch(input, opts);
1508
- };
1509
- return oauthFetch;
1510
- }
1511
1529
  function requireEnv(name) {
1512
1530
  const value = process.env[name];
1513
1531
  if (!value)
@@ -1586,32 +1604,64 @@ var ZEN_BACKEND_RESOLVERS = {
1586
1604
  function resolveZenModel(modelId) {
1587
1605
  return ZEN_BACKEND_RESOLVERS[getZenBackend(modelId)](modelId);
1588
1606
  }
1589
- function resolveOpenAIModel(modelId) {
1590
- return modelId.startsWith("gpt-") ? directProviders.openai().responses(modelId) : directProviders.openai()(modelId);
1591
- }
1592
- var oauthAnthropicCache = null;
1593
- function createOAuthAnthropicProvider(token) {
1594
- return createAnthropic({
1595
- apiKey: "",
1596
- fetch: createOAuthFetch(token),
1597
- headers: {
1598
- "anthropic-beta": "claude-code-20250219,oauth-2025-04-20"
1607
+ function createOAuthOpenAIProvider(token) {
1608
+ const accountId = extractAccountId(token);
1609
+ return createOpenAI({
1610
+ apiKey: "oauth",
1611
+ baseURL: OPENAI_CODEX_BASE_URL,
1612
+ fetch: (input, init) => {
1613
+ const h = new Headers(init?.headers);
1614
+ h.delete("OpenAI-Organization");
1615
+ h.delete("OpenAI-Project");
1616
+ h.set("Authorization", `Bearer ${token}`);
1617
+ if (accountId)
1618
+ h.set("chatgpt-account-id", accountId);
1619
+ let body = init?.body;
1620
+ if (typeof body === "string") {
1621
+ try {
1622
+ const parsed = JSON.parse(body);
1623
+ if (parsed.input && Array.isArray(parsed.input)) {
1624
+ if (!parsed.instructions) {
1625
+ const sysIdx = parsed.input.findIndex((m) => m.role === "developer" || m.role === "system");
1626
+ if (sysIdx !== -1) {
1627
+ const sysMsg = parsed.input[sysIdx];
1628
+ parsed.instructions = typeof sysMsg.content === "string" ? sysMsg.content : JSON.stringify(sysMsg.content);
1629
+ parsed.input.splice(sysIdx, 1);
1630
+ }
1631
+ }
1632
+ delete parsed.max_output_tokens;
1633
+ parsed.store = false;
1634
+ parsed.stream = true;
1635
+ body = JSON.stringify(parsed);
1636
+ }
1637
+ } catch {}
1638
+ }
1639
+ return fetch(input, {
1640
+ ...init,
1641
+ body,
1642
+ headers: Object.fromEntries(h.entries())
1643
+ });
1599
1644
  }
1600
1645
  });
1601
1646
  }
1602
- async function resolveAnthropicModel(modelId) {
1603
- if (isLoggedIn("anthropic")) {
1604
- const token = await getAccessToken("anthropic");
1647
+ async function resolveOpenAIModel(modelId) {
1648
+ if (isLoggedIn("openai")) {
1649
+ const token = await getAccessToken("openai");
1605
1650
  if (token) {
1606
- if (!oauthAnthropicCache || oauthAnthropicCache.token !== token) {
1607
- oauthAnthropicCache = {
1651
+ if (!oauthOpenAICache || oauthOpenAICache.token !== token) {
1652
+ oauthOpenAICache = {
1608
1653
  token,
1609
- provider: createOAuthAnthropicProvider(token)
1654
+ provider: createOAuthOpenAIProvider(token)
1610
1655
  };
1611
1656
  }
1612
- return oauthAnthropicCache.provider(modelId);
1657
+ return oauthOpenAICache.provider.responses(modelId);
1613
1658
  }
1614
1659
  }
1660
+ return modelId.startsWith("gpt-") ? directProviders.openai().responses(modelId) : directProviders.openai()(modelId);
1661
+ }
1662
+ var OPENAI_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex";
1663
+ var oauthOpenAICache = null;
1664
+ async function resolveAnthropicModel(modelId) {
1615
1665
  return directProviders.anthropic()(modelId);
1616
1666
  }
1617
1667
  var PROVIDER_MODEL_RESOLVERS = {
@@ -1636,18 +1686,15 @@ async function resolveModel(modelString) {
1636
1686
  }
1637
1687
  return PROVIDER_MODEL_RESOLVERS[provider](modelId);
1638
1688
  }
1639
- function isAnthropicOAuth() {
1640
- return isLoggedIn("anthropic");
1641
- }
1642
1689
  function discoverConnectedProviders() {
1643
1690
  const result = [];
1644
1691
  if (process.env.OPENCODE_API_KEY)
1645
1692
  result.push({ name: "zen", via: "env" });
1646
- if (isLoggedIn("anthropic"))
1647
- result.push({ name: "anthropic", via: "oauth" });
1648
- else if (process.env.ANTHROPIC_API_KEY)
1693
+ if (process.env.ANTHROPIC_API_KEY)
1649
1694
  result.push({ name: "anthropic", via: "env" });
1650
- if (process.env.OPENAI_API_KEY)
1695
+ if (isLoggedIn("openai"))
1696
+ result.push({ name: "openai", via: "oauth" });
1697
+ else if (process.env.OPENAI_API_KEY)
1651
1698
  result.push({ name: "openai", via: "env" });
1652
1699
  if (process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY)
1653
1700
  result.push({ name: "google", via: "env" });
@@ -1658,9 +1705,9 @@ function discoverConnectedProviders() {
1658
1705
  function autoDiscoverModel() {
1659
1706
  if (process.env.OPENCODE_API_KEY)
1660
1707
  return "zen/claude-sonnet-4-6";
1661
- if (process.env.ANTHROPIC_API_KEY || isLoggedIn("anthropic"))
1708
+ if (process.env.ANTHROPIC_API_KEY)
1662
1709
  return "anthropic/claude-sonnet-4-6";
1663
- if (process.env.OPENAI_API_KEY)
1710
+ if (process.env.OPENAI_API_KEY || isLoggedIn("openai"))
1664
1711
  return "openai/gpt-5.4";
1665
1712
  if (process.env.GOOGLE_API_KEY || process.env.GEMINI_API_KEY)
1666
1713
  return "google/gemini-3.1-pro";
@@ -2290,9 +2337,6 @@ class Spinner {
2290
2337
  terminal.setBeforeWriteCallback(null);
2291
2338
  terminal.stderrWrite("\r\x1B[2K\x1B[?25h");
2292
2339
  }
2293
- update(label) {
2294
- this.label = label;
2295
- }
2296
2340
  _tick() {
2297
2341
  const f = SPINNER_FRAMES[this.frame++ % SPINNER_FRAMES.length] ?? "\u28FE";
2298
2342
  const label = this.label ? c2.dim(` ${this.label}`) : "";
@@ -2346,19 +2390,6 @@ function buildContextSegment(opts) {
2346
2390
  function renderStatusLine(segments) {
2347
2391
  return segments.join(STATUS_SEP);
2348
2392
  }
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
2393
  function fitStatusSegments(required, optional, cols) {
2363
2394
  const fittedOptional = [...optional];
2364
2395
  let line = renderStatusLine([...required, ...fittedOptional]);
@@ -2400,8 +2431,8 @@ function renderStatusBar(opts) {
2400
2431
  }
2401
2432
 
2402
2433
  // src/cli/stream-render.ts
2403
- import { basename as basename2 } from "path";
2404
- import * as c7 from "yoctocolors";
2434
+ import * as c6 from "yoctocolors";
2435
+ import { createHighlighter } from "yoctomarkdown";
2405
2436
 
2406
2437
  // src/llm-api/history/gemini.ts
2407
2438
  function getGeminiThoughtSignature(part) {
@@ -2659,60 +2690,6 @@ function extractAssistantText(newMessages) {
2659
2690
  `);
2660
2691
  }
2661
2692
 
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
2693
  // src/cli/reasoning.ts
2717
2694
  function normalizeReasoningDelta(delta) {
2718
2695
  return delta.replace(/\r\n?/g, `
@@ -2746,130 +2723,34 @@ function normalizeReasoningText(text) {
2746
2723
  `);
2747
2724
  }
2748
2725
 
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
2726
  // src/cli/tool-render.ts
2844
- import * as c6 from "yoctocolors";
2727
+ import * as c5 from "yoctocolors";
2845
2728
 
2846
2729
  // src/cli/tool-result-renderers.ts
2847
- import * as c5 from "yoctocolors";
2730
+ import * as c4 from "yoctocolors";
2848
2731
  function writePreviewLines(opts) {
2849
2732
  if (!opts.value.trim())
2850
2733
  return;
2851
2734
  const lines = opts.value.split(`
2852
2735
  `);
2853
- writeln(` ${c5.dim(opts.label)} ${c5.dim(`(${lines.length} lines)`)}`);
2736
+ if (opts.label)
2737
+ writeln(`${c4.dim(opts.label)} ${c4.dim(`(${lines.length} lines)`)}`);
2854
2738
  if (!Number.isFinite(opts.maxLines) || lines.length <= opts.maxLines) {
2855
- for (const line of lines) {
2856
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2857
- }
2739
+ for (const line of lines)
2740
+ writeln(line);
2858
2741
  return;
2859
2742
  }
2860
2743
  const headCount = Math.max(1, Math.ceil(opts.maxLines / 2));
2861
2744
  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
- }
2745
+ for (const line of lines.slice(0, headCount))
2746
+ writeln(line);
2865
2747
  const hiddenLines = Math.max(0, lines.length - (headCount + tailCount));
2866
2748
  if (hiddenLines > 0) {
2867
- writeln(` ${opts.lineColor("\u2502")} ${c5.dim(`\u2026 +${hiddenLines} lines`)}`);
2749
+ writeln(c4.dim(`\u2026 +${hiddenLines} lines`));
2868
2750
  }
2869
2751
  if (tailCount > 0) {
2870
- for (const line of lines.slice(-tailCount)) {
2871
- writeln(` ${opts.lineColor("\u2502")} ${line}`);
2872
- }
2752
+ for (const line of lines.slice(-tailCount))
2753
+ writeln(line);
2873
2754
  }
2874
2755
  }
2875
2756
  function truncateOneLine(value, max = 100, verboseOutput = false) {
@@ -2928,11 +2809,11 @@ function renderShellResult(result, opts) {
2928
2809
  const stdoutLines = countShellLines(r.stdout);
2929
2810
  const stderrLines = countShellLines(r.stderr);
2930
2811
  const stdoutSingleLine = getSingleShellLine(r.stdout);
2931
- let badge = c5.red("error");
2812
+ let badge = c4.red("error");
2932
2813
  if (r.timedOut)
2933
- badge = c5.yellow("timeout");
2814
+ badge = c4.yellow("timeout");
2934
2815
  else if (r.success)
2935
- badge = c5.green("done");
2816
+ badge = c4.green("done");
2936
2817
  const parts = buildShellSummaryParts({
2937
2818
  exitCode: r.exitCode,
2938
2819
  stdoutLines,
@@ -2940,11 +2821,10 @@ function renderShellResult(result, opts) {
2940
2821
  stdoutSingleLine,
2941
2822
  verboseOutput
2942
2823
  });
2943
- writeln(` ${badge} ${c5.dim(parts.join(" \xB7 "))}`);
2824
+ writeln(`${badge} ${c4.dim(parts.join(" \xB7 "))}`);
2944
2825
  writePreviewLines({
2945
2826
  label: "stderr",
2946
2827
  value: displayStderr,
2947
- lineColor: c5.red,
2948
2828
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 10
2949
2829
  });
2950
2830
  if (shouldPreviewShellStdout({
@@ -2956,7 +2836,6 @@ function renderShellResult(result, opts) {
2956
2836
  writePreviewLines({
2957
2837
  label: "stdout",
2958
2838
  value: displayStdout,
2959
- lineColor: c5.dim,
2960
2839
  maxLines: verboseOutput ? Number.POSITIVE_INFINITY : 20
2961
2840
  });
2962
2841
  }
@@ -2967,21 +2846,21 @@ function buildSkillDescriptionPart(description, verboseOutput = false) {
2967
2846
  if (!trimmed)
2968
2847
  return "";
2969
2848
  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)}`;
2849
+ return ` ${c4.dim("\xB7")} ${c4.dim(trimmed)}`;
2850
+ return ` ${c4.dim("\xB7")} ${c4.dim(trimmed.length > 60 ? `${trimmed.slice(0, 57)}\u2026` : trimmed)}`;
2972
2851
  }
2973
2852
  function renderSkillSummaryLine(skill, opts) {
2974
2853
  const name = skill.name ?? "(unknown)";
2975
2854
  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)}`);
2855
+ const labelPrefix = opts?.label ? `${c4.dim(opts.label)} ` : "";
2856
+ writeln(`${G.info} ${labelPrefix}${name} ${c4.dim("\xB7")} ${c4.dim(source)}${buildSkillDescriptionPart(skill.description, opts?.verboseOutput === true)}`);
2978
2857
  }
2979
2858
  function renderListSkillsResult(result, opts) {
2980
2859
  const r = result;
2981
2860
  if (!Array.isArray(r?.skills))
2982
2861
  return false;
2983
2862
  if (r.skills.length === 0) {
2984
- writeln(` ${G.info} ${c5.dim("no skills")}`);
2863
+ writeln(`${G.info} ${c4.dim("no skills")}`);
2985
2864
  return true;
2986
2865
  }
2987
2866
  const maxSkills = opts?.verboseOutput ? r.skills.length : 6;
@@ -2991,7 +2870,7 @@ function renderListSkillsResult(result, opts) {
2991
2870
  });
2992
2871
  }
2993
2872
  if (r.skills.length > maxSkills) {
2994
- writeln(` ${c5.dim(`+${r.skills.length - maxSkills} more skills`)}`);
2873
+ writeln(`${c4.dim(`+${r.skills.length - maxSkills} more skills`)}`);
2995
2874
  }
2996
2875
  return true;
2997
2876
  }
@@ -3000,13 +2879,20 @@ function renderReadSkillResult(result, _opts) {
3000
2879
  if (!r || typeof r !== "object")
3001
2880
  return false;
3002
2881
  if (!r.skill) {
3003
- writeln(` ${G.info} ${c5.dim("skill")} ${c5.dim("(not found)")}`);
2882
+ if (typeof r.note === "string" && r.note.trim().length > 0) {
2883
+ writeln(`${G.info} ${c4.dim("skill")} ${c4.dim(r.note.trim())}`);
2884
+ return true;
2885
+ }
2886
+ writeln(`${G.info} ${c4.dim("skill")} ${c4.dim("(not found)")}`);
3004
2887
  return true;
3005
2888
  }
3006
2889
  renderSkillSummaryLine(r.skill, {
3007
2890
  label: "skill",
3008
2891
  verboseOutput: _opts?.verboseOutput === true
3009
2892
  });
2893
+ if (typeof r.note === "string" && r.note.trim().length > 0) {
2894
+ writeln(c4.dim(r.note.trim()));
2895
+ }
3010
2896
  return true;
3011
2897
  }
3012
2898
  function renderWebSearchResult(result, opts) {
@@ -3014,19 +2900,19 @@ function renderWebSearchResult(result, opts) {
3014
2900
  if (!Array.isArray(r?.results))
3015
2901
  return false;
3016
2902
  if (r.results.length === 0) {
3017
- writeln(` ${G.info} ${c5.dim("no results")}`);
2903
+ writeln(`${G.info} ${c4.dim("no results")}`);
3018
2904
  return true;
3019
2905
  }
3020
2906
  const maxResults = opts?.verboseOutput ? r.results.length : 5;
3021
2907
  for (const item of r.results.slice(0, maxResults)) {
3022
2908
  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}`);
2909
+ const score = typeof item.score === "number" ? c4.dim(` (${item.score.toFixed(2)})`) : "";
2910
+ writeln(`${c4.dim("\u2022")} ${title}${score}`);
3025
2911
  if (item.url)
3026
- writeln(` ${c5.dim(item.url)}`);
2912
+ writeln(` ${c4.dim(item.url)}`);
3027
2913
  }
3028
2914
  if (r.results.length > maxResults) {
3029
- writeln(` ${c5.dim(` +${r.results.length - maxResults} more`)}`);
2915
+ writeln(`${c4.dim(`+${r.results.length - maxResults} more`)}`);
3030
2916
  }
3031
2917
  return true;
3032
2918
  }
@@ -3035,23 +2921,23 @@ function renderWebContentResult(result, opts) {
3035
2921
  if (!Array.isArray(r?.results))
3036
2922
  return false;
3037
2923
  if (r.results.length === 0) {
3038
- writeln(` ${G.info} ${c5.dim("no pages")}`);
2924
+ writeln(`${G.info} ${c4.dim("no pages")}`);
3039
2925
  return true;
3040
2926
  }
3041
2927
  const maxPages = opts?.verboseOutput ? r.results.length : 3;
3042
2928
  for (const item of r.results.slice(0, maxPages)) {
3043
2929
  const title = (item.title?.trim() || item.url || "(untitled)").replace(/\s+/g, " ");
3044
- writeln(` ${c5.dim("\u2022")} ${title}`);
2930
+ writeln(`${c4.dim("\u2022")} ${title}`);
3045
2931
  if (item.url)
3046
- writeln(` ${c5.dim(item.url)}`);
2932
+ writeln(` ${c4.dim(item.url)}`);
3047
2933
  const preview = (item.text ?? "").replace(/\s+/g, " ").trim();
3048
2934
  if (preview) {
3049
2935
  const trimmed = opts?.verboseOutput || preview.length <= 220 ? preview : `${preview.slice(0, 217)}\u2026`;
3050
- writeln(` ${c5.dim(trimmed)}`);
2936
+ writeln(` ${c4.dim(trimmed)}`);
3051
2937
  }
3052
2938
  }
3053
2939
  if (r.results.length > maxPages) {
3054
- writeln(` ${c5.dim(` +${r.results.length - maxPages} more`)}`);
2940
+ writeln(`${c4.dim(`+${r.results.length - maxPages} more`)}`);
3055
2941
  }
3056
2942
  return true;
3057
2943
  }
@@ -3061,11 +2947,11 @@ function renderMcpResult(result, opts) {
3061
2947
  let rendered = false;
3062
2948
  for (const block of content.slice(0, maxBlocks)) {
3063
2949
  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}`);
2950
+ writePreviewLines({
2951
+ label: "",
2952
+ value: block.text,
2953
+ maxLines: opts?.verboseOutput ? Number.POSITIVE_INFINITY : 6
2954
+ });
3069
2955
  rendered = true;
3070
2956
  }
3071
2957
  }
@@ -3153,43 +3039,58 @@ function formatShellCallLine(cmd) {
3153
3039
  const { cwd, rest } = parseShellCdPrefix(cmd);
3154
3040
  const firstCmd = extractFirstCommand(rest);
3155
3041
  const glyph = shellCmdGlyph(firstCmd, rest);
3156
- const cwdSuffix = cwd ? ` ${c6.dim(`in ${cwd}`)}` : "";
3157
- const display = truncateText(rest, 80);
3158
- return `${glyph} ${display}${cwdSuffix}`;
3042
+ const cwdSuffix = cwd ? ` ${c5.dim(`in ${cwd}`)}` : "";
3043
+ return `${glyph} ${rest}${cwdSuffix}`;
3159
3044
  }
3160
3045
  function buildToolCallLine(name, args) {
3161
3046
  const a = args && typeof args === "object" ? args : {};
3162
3047
  if (name === "shell") {
3163
3048
  const cmd = String(a.command ?? "").trim();
3164
3049
  if (!cmd)
3165
- return `${G.run} ${c6.dim("shell")}`;
3050
+ return `${G.run} ${c5.dim("shell")}`;
3166
3051
  return formatShellCallLine(cmd);
3167
3052
  }
3168
3053
  if (name === "listSkills") {
3169
- return `${G.search} ${c6.dim("list skills")}`;
3054
+ return `${G.search} ${c5.dim("list skills")}`;
3170
3055
  }
3171
3056
  if (name === "readSkill") {
3172
3057
  const skillName = typeof a.name === "string" ? a.name : "";
3173
- return `${G.read} ${c6.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
3058
+ return `${G.read} ${c5.dim("read skill")}${skillName ? ` ${skillName}` : ""}`;
3174
3059
  }
3175
3060
  if (name === "webSearch") {
3176
3061
  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}` : ""}`;
3062
+ return `${G.search} ${c5.dim("search")}${query ? ` ${query}` : ""}`;
3179
3063
  }
3180
3064
  if (name === "webContent") {
3181
3065
  const urls = Array.isArray(a.urls) ? a.urls : [];
3182
3066
  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}`;
3067
+ return `${G.read} ${c5.dim("fetch")} ${label}`;
3185
3068
  }
3186
3069
  if (name.startsWith("mcp_")) {
3187
- return `${G.mcp} ${c6.dim(name)}`;
3070
+ return `${G.mcp} ${c5.dim(name)}`;
3188
3071
  }
3189
- return `${toolGlyph(name)} ${c6.dim(name)}`;
3072
+ return `${toolGlyph(name)} ${c5.dim(name)}`;
3190
3073
  }
3191
- function renderToolCall(toolName, args) {
3192
- writeln(` ${buildToolCallLine(toolName, args)}`);
3074
+ function renderToolCall(toolName, args, opts) {
3075
+ const line = buildToolCallLine(toolName, args);
3076
+ if (opts?.verboseOutput) {
3077
+ writeln(line);
3078
+ return;
3079
+ }
3080
+ const lines = line.split(`
3081
+ `);
3082
+ if (lines.length <= 6) {
3083
+ writeln(line);
3084
+ return;
3085
+ }
3086
+ const head = lines.slice(0, 3);
3087
+ const tail = lines.slice(-2);
3088
+ const hidden = lines.length - head.length - tail.length;
3089
+ for (const l of head)
3090
+ writeln(l);
3091
+ writeln(c5.dim(`\u2026 +${hidden} lines`));
3092
+ for (const l of tail)
3093
+ writeln(l);
3193
3094
  }
3194
3095
  function formatErrorBadge(result) {
3195
3096
  let msg;
@@ -3201,11 +3102,11 @@ function formatErrorBadge(result) {
3201
3102
  msg = JSON.stringify(result);
3202
3103
  const oneLiner = msg.split(`
3203
3104
  `)[0] ?? msg;
3204
- return `${G.err} ${c6.red(oneLiner)}`;
3105
+ return `${G.err} ${c5.red(oneLiner)}`;
3205
3106
  }
3206
3107
  function renderToolResult(toolName, result, isError, opts) {
3207
3108
  if (isError) {
3208
- writeln(` ${formatErrorBadge(result)}`);
3109
+ writeln(formatErrorBadge(result));
3209
3110
  return;
3210
3111
  }
3211
3112
  if (renderToolResultByName(toolName, result, opts)) {
@@ -3213,32 +3114,130 @@ function renderToolResult(toolName, result, isError, opts) {
3213
3114
  }
3214
3115
  const text = JSON.stringify(result);
3215
3116
  if (opts?.verboseOutput || text.length <= 120) {
3216
- writeln(` ${c6.dim(text)}`);
3117
+ writeln(c5.dim(text));
3217
3118
  return;
3218
3119
  }
3219
- writeln(` ${c6.dim(`${text.slice(0, 117)}\u2026`)}`);
3120
+ writeln(c5.dim(`${text.slice(0, 117)}\u2026`));
3220
3121
  }
3221
3122
 
3222
3123
  // src/cli/stream-render.ts
3124
+ function styleReasoning(text) {
3125
+ return c6.italic(c6.dim(text));
3126
+ }
3127
+ function writeReasoningDelta(delta, state) {
3128
+ if (!delta)
3129
+ return;
3130
+ if (!state.blockOpen) {
3131
+ writeln(`${G.info} ${c6.dim("reasoning")}`);
3132
+ state.blockOpen = true;
3133
+ }
3134
+ const lines = delta.split(`
3135
+ `);
3136
+ for (const [i, line] of lines.entries()) {
3137
+ if (line) {
3138
+ if (!state.lineOpen) {
3139
+ write(" ");
3140
+ state.lineOpen = true;
3141
+ }
3142
+ write(styleReasoning(line));
3143
+ }
3144
+ if (i < lines.length - 1) {
3145
+ if (!state.lineOpen)
3146
+ write(" ");
3147
+ writeln();
3148
+ state.lineOpen = false;
3149
+ }
3150
+ }
3151
+ }
3152
+ function finishReasoning(state) {
3153
+ if (!state.blockOpen)
3154
+ return;
3155
+ if (state.lineOpen)
3156
+ writeln();
3157
+ state.blockOpen = false;
3158
+ state.lineOpen = false;
3159
+ }
3160
+ function appendTextDelta(delta, state, spinner, quiet, renderedVisibleOutput) {
3161
+ let chunk = delta ?? "";
3162
+ if (!chunk)
3163
+ return state.inText;
3164
+ if (!state.inText) {
3165
+ chunk = chunk.trimStart();
3166
+ if (!chunk)
3167
+ return false;
3168
+ if (!quiet) {
3169
+ spinner.stop();
3170
+ if (renderedVisibleOutput)
3171
+ writeln();
3172
+ write(`${G.reply} `);
3173
+ }
3174
+ state.inText = true;
3175
+ if (!quiet && terminal.isStdoutTTY) {
3176
+ state.highlighter = createHighlighter();
3177
+ }
3178
+ }
3179
+ const isFirstLine = !state.text.includes(`
3180
+ `);
3181
+ state.text += chunk;
3182
+ if (quiet)
3183
+ return state.inText;
3184
+ spinner.stop();
3185
+ if (state.highlighter) {
3186
+ let colored = state.highlighter.write(chunk);
3187
+ if (colored) {
3188
+ if (isFirstLine && colored.startsWith("\x1B[2K\r")) {
3189
+ colored = `\x1B[2K\r${G.reply} ${colored.slice(5)}`;
3190
+ }
3191
+ write(colored);
3192
+ }
3193
+ } else {
3194
+ write(chunk);
3195
+ }
3196
+ return state.inText;
3197
+ }
3198
+ function flushText(state, quiet) {
3199
+ if (!state.inText)
3200
+ return;
3201
+ if (!quiet) {
3202
+ if (state.highlighter) {
3203
+ let finalColored = state.highlighter.end();
3204
+ if (finalColored) {
3205
+ const isFirstLine = !state.text.includes(`
3206
+ `);
3207
+ if (isFirstLine && finalColored.startsWith("\x1B[2K\r")) {
3208
+ finalColored = `\x1B[2K\r${G.reply} ${finalColored.slice(5)}`;
3209
+ }
3210
+ write(finalColored);
3211
+ }
3212
+ }
3213
+ writeln();
3214
+ }
3215
+ state.inText = false;
3216
+ }
3223
3217
  async function renderTurn(events, spinner, opts) {
3224
3218
  const quiet = opts?.quiet ?? false;
3225
3219
  const showReasoning = !quiet && (opts?.showReasoning ?? true);
3226
3220
  const verboseOutput = opts?.verboseOutput ?? false;
3227
- const content = new StreamRenderContent(spinner, quiet);
3228
- const liveReasoning = new LiveReasoningBlock;
3221
+ const textState = {
3222
+ inText: false,
3223
+ text: "",
3224
+ highlighter: undefined
3225
+ };
3226
+ let reasoningRaw = "";
3227
+ let reasoningComputed = false;
3228
+ let reasoningText = "";
3229
+ const reasoningState = { blockOpen: false, lineOpen: false };
3230
+ const startedToolCalls = new Set;
3231
+ const toolCallInfo = new Map;
3232
+ let parallelCallCount = 0;
3229
3233
  let inputTokens = 0;
3230
3234
  let outputTokens = 0;
3231
3235
  let contextTokens = 0;
3232
3236
  let newMessages = [];
3233
- const startedToolCalls = new Set;
3234
- const toolCallInfo = new Map;
3235
- let parallelCallCount = 0;
3236
3237
  let renderedVisibleOutput = false;
3237
- let reasoningComputed = false;
3238
- let reasoningText = "";
3239
3238
  const getReasoningText = () => {
3240
3239
  if (!reasoningComputed) {
3241
- reasoningText = normalizeReasoningText(content.getReasoning());
3240
+ reasoningText = normalizeReasoningText(reasoningRaw);
3242
3241
  reasoningComputed = true;
3243
3242
  }
3244
3243
  return reasoningText;
@@ -3246,29 +3245,42 @@ async function renderTurn(events, spinner, opts) {
3246
3245
  for await (const event of events) {
3247
3246
  switch (event.type) {
3248
3247
  case "text-delta": {
3249
- liveReasoning.finish();
3250
- content.appendTextDelta(event.delta, renderedVisibleOutput);
3251
- if (content.hasOpenContent())
3248
+ finishReasoning(reasoningState);
3249
+ textState.inText = appendTextDelta(event.delta, textState, spinner, quiet, renderedVisibleOutput);
3250
+ if (textState.inText)
3252
3251
  renderedVisibleOutput = true;
3253
3252
  break;
3254
3253
  }
3255
3254
  case "reasoning-delta": {
3256
- content.flushOpenContent();
3257
- const delta = content.appendReasoningDelta(normalizeReasoningDelta(event.delta));
3255
+ flushText(textState, quiet);
3256
+ let appended = normalizeReasoningDelta(event.delta);
3257
+ if (reasoningRaw.endsWith("**") && appended.startsWith("**") && !reasoningRaw.endsWith(`
3258
+ `)) {
3259
+ appended = `
3260
+ ${appended}`;
3261
+ }
3262
+ reasoningRaw += appended;
3258
3263
  reasoningComputed = false;
3259
- if (showReasoning && delta) {
3264
+ if (showReasoning && appended) {
3260
3265
  spinner.stop();
3261
- if (renderedVisibleOutput && !liveReasoning.isOpen())
3266
+ if (renderedVisibleOutput && !reasoningState.blockOpen)
3262
3267
  writeln();
3263
- liveReasoning.append(delta);
3268
+ writeReasoningDelta(appended, reasoningState);
3264
3269
  renderedVisibleOutput = true;
3265
3270
  }
3266
3271
  break;
3267
3272
  }
3273
+ case "tool-input-delta": {
3274
+ if (quiet)
3275
+ break;
3276
+ finishReasoning(reasoningState);
3277
+ flushText(textState, quiet);
3278
+ spinner.start(`composing ${event.toolName}\u2026`);
3279
+ break;
3280
+ }
3268
3281
  case "tool-call-start": {
3269
- if (startedToolCalls.has(event.toolCallId)) {
3282
+ if (startedToolCalls.has(event.toolCallId))
3270
3283
  break;
3271
- }
3272
3284
  const isConsecutiveToolCall = startedToolCalls.size > 0 && toolCallInfo.size > 0;
3273
3285
  startedToolCalls.add(event.toolCallId);
3274
3286
  toolCallInfo.set(event.toolCallId, {
@@ -3278,13 +3290,14 @@ async function renderTurn(events, spinner, opts) {
3278
3290
  if (toolCallInfo.size > 1) {
3279
3291
  parallelCallCount = toolCallInfo.size;
3280
3292
  }
3281
- liveReasoning.finish();
3282
- content.flushOpenContent();
3293
+ finishReasoning(reasoningState);
3294
+ flushText(textState, quiet);
3283
3295
  if (!quiet) {
3284
3296
  spinner.stop();
3285
- if (renderedVisibleOutput && !isConsecutiveToolCall)
3297
+ if (renderedVisibleOutput && !isConsecutiveToolCall) {
3286
3298
  writeln();
3287
- renderToolCall(event.toolName, event.args);
3299
+ }
3300
+ renderToolCall(event.toolName, event.args, { verboseOutput });
3288
3301
  renderedVisibleOutput = true;
3289
3302
  spinner.start(event.toolName);
3290
3303
  }
@@ -3294,11 +3307,11 @@ async function renderTurn(events, spinner, opts) {
3294
3307
  startedToolCalls.delete(event.toolCallId);
3295
3308
  const callInfo = toolCallInfo.get(event.toolCallId);
3296
3309
  toolCallInfo.delete(event.toolCallId);
3297
- liveReasoning.finish();
3310
+ finishReasoning(reasoningState);
3298
3311
  if (!quiet) {
3299
3312
  spinner.stop();
3300
3313
  if (parallelCallCount > 1 && callInfo) {
3301
- writeln(` ${c7.dim("\u21B3")} ${callInfo.label}`);
3314
+ writeln(`${c6.dim("\u21B3")} ${callInfo.label}`);
3302
3315
  }
3303
3316
  if (toolCallInfo.size === 0)
3304
3317
  parallelCallCount = 0;
@@ -3314,31 +3327,20 @@ async function renderTurn(events, spinner, opts) {
3314
3327
  break;
3315
3328
  }
3316
3329
  case "context-pruned": {
3317
- liveReasoning.finish();
3318
- content.flushOpenContent();
3330
+ finishReasoning(reasoningState);
3331
+ flushText(textState, quiet);
3319
3332
  if (!quiet) {
3320
3333
  spinner.stop();
3321
3334
  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)}`);
3335
+ writeln(`${G.info} ${c6.dim("context pruned")} ${c6.dim(`\u2013${event.removedMessageCount} messages`)} ${c6.dim(`\u2013${removedKb} KB`)}`);
3335
3336
  renderedVisibleOutput = true;
3337
+ spinner.start("thinking");
3336
3338
  }
3337
3339
  break;
3338
3340
  }
3339
3341
  case "turn-complete": {
3340
- liveReasoning.finish();
3341
- content.flushOpenContent();
3342
+ finishReasoning(reasoningState);
3343
+ flushText(textState, quiet);
3342
3344
  spinner.stop();
3343
3345
  if (!quiet && !renderedVisibleOutput)
3344
3346
  writeln();
@@ -3349,14 +3351,14 @@ async function renderTurn(events, spinner, opts) {
3349
3351
  break;
3350
3352
  }
3351
3353
  case "turn-error": {
3352
- liveReasoning.finish();
3353
- content.flushOpenContent();
3354
+ finishReasoning(reasoningState);
3355
+ flushText(textState, quiet);
3354
3356
  spinner.stop();
3355
3357
  inputTokens = event.inputTokens;
3356
3358
  outputTokens = event.outputTokens;
3357
3359
  contextTokens = event.contextTokens;
3358
3360
  if (isAbortError(event.error)) {
3359
- newMessages = buildAbortMessages(event.partialMessages, content.getText());
3361
+ newMessages = buildAbortMessages(event.partialMessages, textState.text);
3360
3362
  } else {
3361
3363
  renderError(event.error, "turn");
3362
3364
  throw new RenderedError(event.error);
@@ -3405,17 +3407,17 @@ function renderUserMessage(text) {
3405
3407
  }
3406
3408
  }
3407
3409
  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")
3410
+ prompt: c7.green("\u203A"),
3411
+ reply: c7.cyan("\u25C6"),
3412
+ search: c7.yellow("?"),
3413
+ read: c7.dim("\u2190"),
3414
+ write: c7.green("\u270E"),
3415
+ run: c7.dim("$"),
3416
+ mcp: c7.yellow("\u2699"),
3417
+ ok: c7.green("\u2714"),
3418
+ err: c7.red("\u2716"),
3419
+ warn: c7.yellow("!"),
3420
+ info: c7.dim("\xB7")
3419
3421
  };
3420
3422
  var PREFIX = {
3421
3423
  user: G.prompt,
@@ -3437,17 +3439,17 @@ class RenderedError extends Error {
3437
3439
  function renderError(err, context = "render") {
3438
3440
  logError(err, context);
3439
3441
  const parsed = parseAppError(err);
3440
- writeln(`${G.err} ${c8.red(parsed.headline)}`);
3442
+ writeln(`${G.err} ${c7.red(parsed.headline)}`);
3441
3443
  if (parsed.hint) {
3442
- writeln(` ${c8.dim(parsed.hint)}`);
3444
+ writeln(` ${c7.dim(parsed.hint)}`);
3443
3445
  }
3444
3446
  }
3445
3447
  function renderBanner(model, cwd) {
3446
3448
  writeln();
3447
3449
  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")}`);
3450
+ writeln(` ${c7.cyan("mc")} ${c7.dim(title)}`);
3451
+ writeln(` ${c7.dim(model)} ${c7.dim("\xB7")} ${c7.dim(tildePath(cwd))}`);
3452
+ writeln(` ${c7.dim("/help for commands \xB7 esc cancel \xB7 ctrl+d exit")}`);
3451
3453
  const items = [];
3452
3454
  if (getPreferredShowReasoning())
3453
3455
  items.push("reasoning: on");
@@ -3460,7 +3462,7 @@ function renderBanner(model, cwd) {
3460
3462
  if (skills.size > 0)
3461
3463
  items.push(`${skills.size} skill${skills.size > 1 ? "s" : ""}`);
3462
3464
  if (items.length > 0) {
3463
- writeln(` ${c8.dim(items.join(" \xB7 "))}`);
3465
+ writeln(` ${c7.dim(items.join(" \xB7 "))}`);
3464
3466
  }
3465
3467
  const connParts = [];
3466
3468
  for (const p of discoverConnectedProviders()) {
@@ -3470,7 +3472,7 @@ function renderBanner(model, cwd) {
3470
3472
  if (mcpCount > 0)
3471
3473
  connParts.push(`${mcpCount} mcp`);
3472
3474
  if (connParts.length > 0) {
3473
- writeln(` ${c8.dim(connParts.join(" \xB7 "))}`);
3475
+ writeln(` ${c7.dim(connParts.join(" \xB7 "))}`);
3474
3476
  }
3475
3477
  writeln();
3476
3478
  }
@@ -3485,7 +3487,7 @@ class CliReporter {
3485
3487
  if (this.quiet)
3486
3488
  return;
3487
3489
  this.spinner.stop();
3488
- writeln(`${G.info} ${c8.dim(msg)}`);
3490
+ writeln(`${G.info} ${c7.dim(msg)}`);
3489
3491
  }
3490
3492
  error(msg, hint) {
3491
3493
  this.spinner.stop();
@@ -3689,10 +3691,10 @@ function setPreferredVerboseOutput(verbose) {
3689
3691
  setSetting("preferred_verbose_output", verbose ? "true" : "false");
3690
3692
  }
3691
3693
  // src/agent/session-runner.ts
3692
- import * as c11 from "yoctocolors";
3694
+ import * as c10 from "yoctocolors";
3693
3695
 
3694
3696
  // src/cli/input.ts
3695
- import * as c9 from "yoctocolors";
3697
+ import * as c8 from "yoctocolors";
3696
3698
 
3697
3699
  // src/cli/input-buffer.ts
3698
3700
  var PASTE_TOKEN_START = 57344;
@@ -4101,7 +4103,7 @@ function watchForCancel(abortController) {
4101
4103
  process.stdin.on("data", onData);
4102
4104
  return cleanup;
4103
4105
  }
4104
- var PROMPT = c9.green("\u25B6 ");
4106
+ var PROMPT = c8.green("\u25B6 ");
4105
4107
  var PROMPT_RAW_LEN = 2;
4106
4108
  async function readline(opts) {
4107
4109
  const cwd = opts.cwd ?? process.cwd();
@@ -4150,7 +4152,7 @@ async function readline(opts) {
4150
4152
  process.stdout.write(`${CLEAR_LINE}${prompt}${display}${CSI}${PROMPT_RAW_LEN + displayCursor + 1}G`);
4151
4153
  }
4152
4154
  function renderSearchPrompt() {
4153
- process.stdout.write(`${CLEAR_LINE}${c9.cyan("search:")} ${searchQuery}\u2588`);
4155
+ process.stdout.write(`${CLEAR_LINE}${c8.cyan("search:")} ${searchQuery}\u2588`);
4154
4156
  }
4155
4157
  function applyHistory() {
4156
4158
  if (histIdx < history.length) {
@@ -4412,36 +4414,12 @@ import { streamText } from "ai";
4412
4414
  // src/llm-api/turn-execution.ts
4413
4415
  import { dynamicTool, jsonSchema } from "ai";
4414
4416
 
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
4417
  // src/llm-api/turn-stream-events.ts
4440
- function shouldLogStreamChunk(c10) {
4441
- return c10.type !== "text-delta" && c10.type !== "reasoning" && c10.type !== "reasoning-delta";
4418
+ function shouldLogStreamChunk(c9) {
4419
+ return c9.type !== "text-delta" && c9.type !== "reasoning" && c9.type !== "reasoning-delta" && c9.type !== "tool-input-delta";
4442
4420
  }
4443
- function extractToolArgs(c10) {
4444
- return c10.input ?? c10.args;
4421
+ function extractToolArgs(c9) {
4422
+ return c9.input ?? c9.args;
4445
4423
  }
4446
4424
  function hasRenderableToolArgs(args) {
4447
4425
  if (args === null || args === undefined)
@@ -4454,10 +4432,10 @@ function hasRenderableToolArgs(args) {
4454
4432
  return Object.keys(args).length > 0;
4455
4433
  return true;
4456
4434
  }
4457
- function mapStreamChunkToTurnEvent(c10) {
4458
- switch (c10.type) {
4435
+ function mapStreamChunkToTurnEvent(c9) {
4436
+ switch (c9.type) {
4459
4437
  case "text-delta": {
4460
- const delta = typeof c10.text === "string" ? c10.text : "";
4438
+ const delta = typeof c9.text === "string" ? c9.text : "";
4461
4439
  return {
4462
4440
  type: "text-delta",
4463
4441
  delta
@@ -4465,7 +4443,7 @@ function mapStreamChunkToTurnEvent(c10) {
4465
4443
  }
4466
4444
  case "reasoning-delta":
4467
4445
  case "reasoning": {
4468
- const delta = getReasoningDeltaFromStreamChunk(c10);
4446
+ const delta = getReasoningDeltaFromStreamChunk(c9);
4469
4447
  if (delta === null)
4470
4448
  return null;
4471
4449
  return {
@@ -4474,49 +4452,65 @@ function mapStreamChunkToTurnEvent(c10) {
4474
4452
  };
4475
4453
  }
4476
4454
  case "tool-input-start": {
4477
- const args = extractToolArgs(c10);
4478
- const hasStableToolCallId = typeof c10.toolCallId === "string" && c10.toolCallId.trim().length > 0;
4455
+ const args = extractToolArgs(c9);
4456
+ const hasStableToolCallId = typeof c9.toolCallId === "string" && c9.toolCallId.trim().length > 0;
4479
4457
  if (hasStableToolCallId && !hasRenderableToolArgs(args))
4480
4458
  return null;
4481
4459
  return {
4482
4460
  type: "tool-call-start",
4483
- toolCallId: String(c10.toolCallId ?? ""),
4484
- toolName: String(c10.toolName ?? ""),
4461
+ toolCallId: String(c9.toolCallId ?? ""),
4462
+ toolName: String(c9.toolName ?? ""),
4485
4463
  args
4486
4464
  };
4487
4465
  }
4466
+ case "tool-input-delta": {
4467
+ let delta = "";
4468
+ if (typeof c9.inputTextDelta === "string") {
4469
+ delta = c9.inputTextDelta;
4470
+ } else if (typeof c9.delta === "string") {
4471
+ delta = c9.delta;
4472
+ }
4473
+ if (!delta)
4474
+ return null;
4475
+ return {
4476
+ type: "tool-input-delta",
4477
+ toolCallId: String(c9.toolCallId ?? c9.id ?? ""),
4478
+ toolName: String(c9.toolName ?? ""),
4479
+ inputTextDelta: delta
4480
+ };
4481
+ }
4488
4482
  case "tool-call": {
4489
4483
  return {
4490
4484
  type: "tool-call-start",
4491
- toolCallId: String(c10.toolCallId ?? ""),
4492
- toolName: String(c10.toolName ?? ""),
4493
- args: extractToolArgs(c10)
4485
+ toolCallId: String(c9.toolCallId ?? ""),
4486
+ toolName: String(c9.toolName ?? ""),
4487
+ args: extractToolArgs(c9)
4494
4488
  };
4495
4489
  }
4496
4490
  case "tool-result": {
4497
4491
  let result;
4498
- if ("output" in c10)
4499
- result = c10.output;
4500
- else if ("result" in c10)
4501
- result = c10.result;
4492
+ if ("output" in c9)
4493
+ result = c9.output;
4494
+ else if ("result" in c9)
4495
+ result = c9.result;
4502
4496
  return {
4503
4497
  type: "tool-result",
4504
- toolCallId: String(c10.toolCallId ?? ""),
4505
- toolName: String(c10.toolName ?? ""),
4498
+ toolCallId: String(c9.toolCallId ?? ""),
4499
+ toolName: String(c9.toolName ?? ""),
4506
4500
  result,
4507
- isError: "isError" in c10 ? Boolean(c10.isError) : false
4501
+ isError: "isError" in c9 ? Boolean(c9.isError) : false
4508
4502
  };
4509
4503
  }
4510
4504
  case "tool-error":
4511
4505
  return {
4512
4506
  type: "tool-result",
4513
- toolCallId: String(c10.toolCallId ?? ""),
4514
- toolName: String(c10.toolName ?? ""),
4515
- result: c10.error ?? "Tool execution failed",
4507
+ toolCallId: String(c9.toolCallId ?? ""),
4508
+ toolName: String(c9.toolName ?? ""),
4509
+ result: c9.error ?? "Tool execution failed",
4516
4510
  isError: true
4517
4511
  };
4518
4512
  case "error": {
4519
- throw normalizeUnknownError(c10.error);
4513
+ throw normalizeUnknownError(c9.error);
4520
4514
  }
4521
4515
  default:
4522
4516
  return null;
@@ -4532,9 +4526,9 @@ function toCoreTool(def) {
4532
4526
  return dynamicTool({
4533
4527
  description: def.description,
4534
4528
  inputSchema: schema,
4535
- execute: async (input) => {
4529
+ execute: async (input, { abortSignal }) => {
4536
4530
  try {
4537
- return await def.execute(input);
4531
+ return await def.execute(input, abortSignal ? { signal: abortSignal } : undefined);
4538
4532
  } catch (err) {
4539
4533
  throw normalizeUnknownError(err);
4540
4534
  }
@@ -4685,6 +4679,7 @@ class StreamToolCallTracker {
4685
4679
  syntheticCount = 0;
4686
4680
  pendingByTool = new Map;
4687
4681
  deferredStartsByTool = new Map;
4682
+ toolNameById = new Map;
4688
4683
  prepare(chunk) {
4689
4684
  const type = chunk.type;
4690
4685
  if (!type) {
@@ -4693,6 +4688,8 @@ class StreamToolCallTracker {
4693
4688
  if (type === "tool-input-start") {
4694
4689
  const toolName = normalizeToolName(chunk.toolName);
4695
4690
  const toolCallId = normalizeStringId(chunk.toolCallId);
4691
+ if (toolCallId && toolName)
4692
+ this.toolNameById.set(toolCallId, toolName);
4696
4693
  const args = extractToolArgs(chunk);
4697
4694
  if (!hasRenderableToolArgs(args)) {
4698
4695
  if (!toolCallId) {
@@ -4727,6 +4724,16 @@ class StreamToolCallTracker {
4727
4724
  suppressTurnEvent: false
4728
4725
  };
4729
4726
  }
4727
+ if (type === "tool-input-delta") {
4728
+ const id = normalizeStringId(chunk.id ?? chunk.toolCallId);
4729
+ const toolName = id ? this.toolNameById.get(id) : undefined;
4730
+ if (toolName) {
4731
+ return {
4732
+ chunk: { ...chunk, toolName, toolCallId: id },
4733
+ suppressTurnEvent: false
4734
+ };
4735
+ }
4736
+ }
4730
4737
  return { chunk, suppressTurnEvent: false };
4731
4738
  }
4732
4739
  trackRenderableStart(chunk, toolName, existingToolCallId) {
@@ -4788,18 +4795,6 @@ async function* mapFullStreamToTurnEvents(stream, opts) {
4788
4795
  yield { type: "context-pruned", ...rec };
4789
4796
  }
4790
4797
  }
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
4798
  const prepared = toolCallTracker.prepare(originalChunk);
4804
4799
  const chunk = prepared.chunk;
4805
4800
  const route = textPhaseTracker.route(chunk);
@@ -4892,11 +4887,34 @@ function getMessageDiagnostics(messages) {
4892
4887
  }
4893
4888
  };
4894
4889
  }
4890
+ function collectPrunableToolNames(messages) {
4891
+ const names = new Set;
4892
+ for (const message of messages) {
4893
+ if (!Array.isArray(message.content))
4894
+ continue;
4895
+ for (const part of message.content) {
4896
+ if (!isRecord(part))
4897
+ continue;
4898
+ const partRecord = part;
4899
+ const toolName = partRecord.toolName;
4900
+ if (typeof toolName !== "string" || toolName.length === 0)
4901
+ continue;
4902
+ if (toolName === "readSkill")
4903
+ continue;
4904
+ names.add(toolName);
4905
+ }
4906
+ }
4907
+ return [...names].sort((a, b) => a.localeCompare(b));
4908
+ }
4909
+ function buildToolCallPruning(messages, type) {
4910
+ const tools = collectPrunableToolNames(messages);
4911
+ return tools.length === 0 ? "none" : [{ type, tools }];
4912
+ }
4895
4913
  function applyContextPruning(messages) {
4896
4914
  return pruneMessages({
4897
4915
  messages,
4898
4916
  reasoning: "before-last-message",
4899
- toolCalls: "before-last-40-messages",
4917
+ toolCalls: buildToolCallPruning(messages, "before-last-40-messages"),
4900
4918
  emptyMessages: "remove"
4901
4919
  });
4902
4920
  }
@@ -4905,7 +4923,7 @@ function applyStepPruning(messages, initialMessageCount) {
4905
4923
  return pruneMessages({
4906
4924
  messages,
4907
4925
  reasoning: "none",
4908
- toolCalls: `before-last-${40 + newMessageCount}-messages`,
4926
+ toolCalls: buildToolCallPruning(messages, `before-last-${40 + newMessageCount}-messages`),
4909
4927
  emptyMessages: "remove"
4910
4928
  });
4911
4929
  }
@@ -5086,26 +5104,10 @@ function prepareTurnMessages(input) {
5086
5104
  diagnostics: getMessageDiagnostics(compacted)
5087
5105
  });
5088
5106
  }
5089
- let finalMessages = compacted;
5090
- let finalSystemPrompt = systemPrompt;
5091
- if (isAnthropicModelFamily(modelString) && isAnthropicOAuth()) {
5092
- const ccIdentity = "You are Claude Code, Anthropic's official CLI for Claude.";
5093
- const systemMessages = [
5094
- { role: "system", content: ccIdentity }
5095
- ];
5096
- if (finalSystemPrompt) {
5097
- systemMessages.push({
5098
- role: "system",
5099
- content: finalSystemPrompt
5100
- });
5101
- finalSystemPrompt = undefined;
5102
- }
5103
- finalMessages = [...systemMessages, ...finalMessages];
5104
- }
5105
5107
  const wasPruned = postStats.messageCount < preStats.messageCount;
5106
5108
  return {
5107
- messages: finalMessages,
5108
- systemPrompt: finalSystemPrompt,
5109
+ messages: compacted,
5110
+ systemPrompt,
5109
5111
  pruned: wasPruned,
5110
5112
  prePruneMessageCount: preStats.messageCount,
5111
5113
  prePruneTotalBytes: preStats.totalBytes,
@@ -5220,12 +5222,6 @@ function buildTurnProviderOptions(input) {
5220
5222
  const thinkingOpts = thinkingEffort ? getThinkingProviderOptions(modelString, thinkingEffort) : null;
5221
5223
  const reasoningSummaryRequested = isRecord(thinkingOpts) && isRecord(thinkingOpts.openai) && typeof thinkingOpts.openai.reasoningSummary === "string";
5222
5224
  const cacheFamily = getCacheFamily(modelString);
5223
- const googleOpts = isGeminiModelFamily(modelString) ? {
5224
- google: {
5225
- responseModalities: ["TEXT", "IMAGE"],
5226
- ...isRecord(thinkingOpts?.google) ? thinkingOpts.google : {}
5227
- }
5228
- } : {};
5229
5225
  const providerOptions = {
5230
5226
  ...thinkingOpts ?? {},
5231
5227
  ...isOpenAIGPT(modelString) ? {
@@ -5233,8 +5229,7 @@ function buildTurnProviderOptions(input) {
5233
5229
  store: false,
5234
5230
  ...isRecord(thinkingOpts?.openai) ? thinkingOpts.openai : {}
5235
5231
  }
5236
- } : {},
5237
- ...googleOpts
5232
+ } : {}
5238
5233
  };
5239
5234
  return {
5240
5235
  cacheFamily,
@@ -5312,8 +5307,7 @@ async function* runTurn(options) {
5312
5307
  tools,
5313
5308
  systemPrompt,
5314
5309
  signal,
5315
- thinkingEffort,
5316
- cwd
5310
+ thinkingEffort
5317
5311
  } = options;
5318
5312
  const rawToolSet = buildToolSet(tools);
5319
5313
  const toolSet = annotateToolCaching(rawToolSet, modelString);
@@ -5364,7 +5358,6 @@ async function* runTurn(options) {
5364
5358
  result.response.catch(() => {});
5365
5359
  for await (const event of mapFullStreamToTurnEvents(result.fullStream, {
5366
5360
  stepPruneQueue,
5367
- ...cwd ? { cwd } : {},
5368
5361
  onChunk: (streamChunk) => {
5369
5362
  if (streamChunk.type === "tool-call" || streamChunk.type === "tool-result") {
5370
5363
  logApiEvent("stream chunk", {
@@ -5407,7 +5400,7 @@ async function* runTurn(options) {
5407
5400
  }
5408
5401
 
5409
5402
  // src/session/manager.ts
5410
- import * as c10 from "yoctocolors";
5403
+ import * as c9 from "yoctocolors";
5411
5404
  function newSession(model, cwd) {
5412
5405
  const id = generateSessionId();
5413
5406
  const row = createSession({ id, cwd, model });
@@ -5442,21 +5435,21 @@ function renderSessionTable(footer) {
5442
5435
  if (sessions.length === 0)
5443
5436
  return false;
5444
5437
  writeln(`
5445
- ${c10.bold("Recent sessions:")}`);
5438
+ ${c9.bold("Recent sessions:")}`);
5446
5439
  for (const s of sessions) {
5447
5440
  const date = new Date(s.updated_at).toLocaleString();
5448
5441
  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)}`);
5442
+ const title = s.title || c9.dim("(untitled)");
5443
+ 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
5444
  }
5452
5445
  writeln(`
5453
5446
  ${footer}`);
5454
5447
  return true;
5455
5448
  }
5456
5449
  function printSessionList() {
5457
- const shown = renderSessionTable(`${c10.dim("Use")} mc --resume <id> ${c10.dim("to continue a session.")}`);
5450
+ const shown = renderSessionTable(`${c9.dim("Use")} mc --resume <id> ${c9.dim("to continue a session.")}`);
5458
5451
  if (!shown)
5459
- writeln(c10.dim("No sessions found."));
5452
+ writeln(c9.dim("No sessions found."));
5460
5453
  }
5461
5454
  function getMostRecentSession() {
5462
5455
  const sessions = listSessions(1);
@@ -5564,6 +5557,12 @@ Guidelines:
5564
5557
  - Make parallel tool calls when the lookups are independent \u2014 this speeds up multi-file investigation.
5565
5558
  - Before starting work, scan the skills list below. If there is even a small chance a skill applies to your task, load it with \`readSkill\` and follow its instructions before writing code or responding. Skills are mandatory when they match \u2014 not optional references.
5566
5559
  - Keep it simple: DRY, KISS, YAGNI. Avoid unnecessary complexity.
5560
+ - Apply Rob Pike's 5 Rules of Programming:
5561
+ 1. You can't tell where a program is going to spend its time. Bottlenecks occur in surprising places, so don't try to second guess and put in a speed hack until you've proven that's where the bottleneck is.
5562
+ 2. Measure. Don't tune for speed until you've measured, and even then don't unless one part of the code overwhelms the rest.
5563
+ 3. Fancy algorithms are slow when n is small, and n is usually small. Fancy algorithms have big constants. Until you know that n is frequently going to be big, don't get fancy. (Even if n does get big, use Rule 2 first.)
5564
+ 4. Fancy algorithms are buggier than simple ones, and they're much harder to implement. Use simple algorithms as well as simple data structures.
5565
+ 5. Data dominates. If you've chosen the right data structures and organized things well, the algorithms will almost always be self-evident. Data structures, not algorithms, are central to programming.
5567
5566
 
5568
5567
  # File editing with mc-edit
5569
5568
  \`mc-edit\` applies one exact-text replacement per invocation. It fails deterministically if the old text is missing or matches more than once.
@@ -5687,7 +5686,7 @@ class SessionRunner {
5687
5686
  }
5688
5687
  this.session = resumed;
5689
5688
  this.currentModel = this.session.model;
5690
- this.reporter.info(`Resumed session ${this.session.id} (${c11.cyan(this.currentModel)})`);
5689
+ this.reporter.info(`Resumed session ${this.session.id} (${c10.cyan(this.currentModel)})`);
5691
5690
  } else {
5692
5691
  this.session = newSession(this.currentModel, this.cwd);
5693
5692
  }
@@ -5780,8 +5779,7 @@ ${output}
5780
5779
  tools: this.tools,
5781
5780
  ...systemPrompt ? { systemPrompt } : {},
5782
5781
  signal: abortController.signal,
5783
- ...this.currentThinkingEffort ? { thinkingEffort: this.currentThinkingEffort } : {},
5784
- cwd: this.cwd
5782
+ ...this.currentThinkingEffort ? { thinkingEffort: this.currentThinkingEffort } : {}
5785
5783
  });
5786
5784
  const { inputTokens, outputTokens, contextTokens, newMessages } = await this.reporter.renderTurn(events, {
5787
5785
  showReasoning: this.showReasoning,
@@ -5884,7 +5882,7 @@ import { z as z3 } from "zod";
5884
5882
 
5885
5883
  // src/internal/file-edit/command.ts
5886
5884
  import { existsSync as existsSync4 } from "fs";
5887
- import { dirname as dirname3, extname, join as join7 } from "path";
5885
+ import { dirname as dirname3, extname, join as join6 } from "path";
5888
5886
  import { fileURLToPath } from "url";
5889
5887
  function quoteShellArg(value) {
5890
5888
  return `'${value.replaceAll("'", `'\\''`)}'`;
@@ -5896,7 +5894,7 @@ function resolveSiblingFileEditScript(scriptPath) {
5896
5894
  const mainDir = dirname3(scriptPath);
5897
5895
  const mainBase = scriptPath.slice(mainDir.length + 1);
5898
5896
  if (mainBase === `index${ext}` || mainBase === `mc${ext}`) {
5899
- return join7(mainDir, `mc-edit${ext}`);
5897
+ return join6(mainDir, `mc-edit${ext}`);
5900
5898
  }
5901
5899
  return null;
5902
5900
  }
@@ -5905,7 +5903,7 @@ function resolveModuleLocalFileEditScript(moduleUrl) {
5905
5903
  const ext = extname(modulePath);
5906
5904
  if (!ext)
5907
5905
  return null;
5908
- const helperPath = join7(dirname3(modulePath), "..", "..", `mc-edit${ext}`);
5906
+ const helperPath = join6(dirname3(modulePath), "..", "..", `mc-edit${ext}`);
5909
5907
  return existsSync4(helperPath) ? helperPath : null;
5910
5908
  }
5911
5909
  function resolveProcessScriptPath(mainModule, argv1) {
@@ -5937,8 +5935,8 @@ var ShellSchema = z3.object({
5937
5935
  timeout: z3.number().int().min(1000).nullable().describe("Timeout in milliseconds. If omitted, the command runs until it exits."),
5938
5936
  env: z3.record(z3.string(), z3.string()).nullable().describe("Additional environment variables to set")
5939
5937
  });
5940
- var MAX_OUTPUT_BYTES = 1e4;
5941
- async function runShellCommand(input) {
5938
+ var MAX_OUTPUT_BYTES = 24000;
5939
+ async function runShellCommand(input, options) {
5942
5940
  const cwd = input.cwd ?? process.cwd();
5943
5941
  const timeout = input.timeout ?? undefined;
5944
5942
  const inputEnv = input.env ?? undefined;
@@ -5960,8 +5958,7 @@ ${input.command}`], {
5960
5958
  stdout: "pipe",
5961
5959
  stderr: "pipe"
5962
5960
  });
5963
- const timer = timeout ? setTimeout(() => {
5964
- timedOut = true;
5961
+ function killProc() {
5965
5962
  try {
5966
5963
  proc.kill("SIGTERM");
5967
5964
  setTimeout(() => {
@@ -5973,7 +5970,20 @@ ${input.command}`], {
5973
5970
  for (const reader of readers) {
5974
5971
  reader.cancel().catch(() => {});
5975
5972
  }
5973
+ }
5974
+ const timer = timeout ? setTimeout(() => {
5975
+ timedOut = true;
5976
+ killProc();
5976
5977
  }, timeout) : undefined;
5978
+ const abortSignal = options?.signal;
5979
+ const onAbort = () => {
5980
+ killProc();
5981
+ };
5982
+ if (abortSignal?.aborted) {
5983
+ onAbort();
5984
+ } else {
5985
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
5986
+ }
5977
5987
  async function collectStream(stream) {
5978
5988
  const reader = stream.getReader();
5979
5989
  readers.push(reader);
@@ -6017,6 +6027,7 @@ ${input.command}`], {
6017
6027
  } finally {
6018
6028
  if (timer)
6019
6029
  clearTimeout(timer);
6030
+ abortSignal?.removeEventListener("abort", onAbort);
6020
6031
  restoreTerminal();
6021
6032
  if (wasRaw) {
6022
6033
  try {
@@ -6041,7 +6052,7 @@ var shellTool = {
6041
6052
  name: "shell",
6042
6053
  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
6054
  schema: ShellSchema,
6044
- execute: runShellCommand
6055
+ execute: (input, options) => runShellCommand(input, options)
6045
6056
  };
6046
6057
 
6047
6058
  // src/agent/tools.ts
@@ -6049,11 +6060,11 @@ function withCwdDefault(tool, cwd) {
6049
6060
  const originalExecute = tool.execute;
6050
6061
  return {
6051
6062
  ...tool,
6052
- execute: async (input) => {
6063
+ execute: async (input, options) => {
6053
6064
  const patched = typeof input === "object" && input !== null ? input : {};
6054
6065
  if (patched.cwd === undefined)
6055
6066
  patched.cwd = cwd;
6056
- return originalExecute(patched);
6067
+ return originalExecute(patched, options);
6057
6068
  }
6058
6069
  };
6059
6070
  }
@@ -6096,7 +6107,7 @@ async function initAgent(opts) {
6096
6107
  for (const row of listMcpServers()) {
6097
6108
  try {
6098
6109
  await connectAndAddMcp(row.name);
6099
- opts.reporter.info(`MCP: connected ${c12.cyan(row.name)}`);
6110
+ opts.reporter.info(`MCP: connected ${c11.cyan(row.name)}`);
6100
6111
  } catch (e) {
6101
6112
  opts.reporter.error(`MCP: failed to connect ${row.name}: ${String(e)}`);
6102
6113
  }
@@ -6154,7 +6165,7 @@ async function initAgent(opts) {
6154
6165
  }
6155
6166
 
6156
6167
  // src/cli/args.ts
6157
- import * as c13 from "yoctocolors";
6168
+ import * as c12 from "yoctocolors";
6158
6169
  function parseArgs(argv) {
6159
6170
  const args = {
6160
6171
  model: null,
@@ -6203,11 +6214,11 @@ function parseArgs(argv) {
6203
6214
  return args;
6204
6215
  }
6205
6216
  function printHelp() {
6206
- writeln(`${c13.bold("mini-coder")} \u2014 a small, fast CLI coding agent
6217
+ writeln(`${c12.bold("mini-coder")} \u2014 a small, fast CLI coding agent
6207
6218
  `);
6208
- writeln(`${c13.bold("Usage:")} mc [options] [prompt]
6219
+ writeln(`${c12.bold("Usage:")} mc [options] [prompt]
6209
6220
  `);
6210
- writeln(`${c13.bold("Options:")}`);
6221
+ writeln(`${c12.bold("Options:")}`);
6211
6222
  const opts = [
6212
6223
  ["-m, --model <id>", "Model to use (e.g. zen/claude-sonnet-4-6)"],
6213
6224
  ["-c, --continue", "Continue the most recent session"],
@@ -6217,10 +6228,10 @@ function printHelp() {
6217
6228
  ["-h, --help", "Show this help"]
6218
6229
  ];
6219
6230
  for (const [flag, desc] of opts) {
6220
- writeln(` ${c13.cyan((flag ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
6231
+ writeln(` ${c12.cyan((flag ?? "").padEnd(22))} ${c12.dim(desc ?? "")}`);
6221
6232
  }
6222
6233
  writeln(`
6223
- ${c13.bold("Provider env vars:")}`);
6234
+ ${c12.bold("Provider env vars:")}`);
6224
6235
  const envs = [
6225
6236
  ["OPENCODE_API_KEY", "OpenCode Zen (recommended)"],
6226
6237
  ["ANTHROPIC_API_KEY", "Anthropic direct"],
@@ -6231,62 +6242,19 @@ ${c13.bold("Provider env vars:")}`);
6231
6242
  ["OLLAMA_BASE_URL", "Ollama base URL (default: http://localhost:11434)"]
6232
6243
  ];
6233
6244
  for (const [env, desc] of envs) {
6234
- writeln(` ${c13.yellow((env ?? "").padEnd(22))} ${c13.dim(desc ?? "")}`);
6245
+ writeln(` ${c12.yellow((env ?? "").padEnd(22))} ${c12.dim(desc ?? "")}`);
6235
6246
  }
6236
6247
  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")}`);
6243
- }
6244
-
6245
- // src/cli/bootstrap.ts
6246
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync } from "fs";
6247
- import { homedir as homedir6 } from "os";
6248
- import { join as join8 } from "path";
6249
- import * as c14 from "yoctocolors";
6250
- var REVIEW_SKILL_CONTENT = `---
6251
- name: review
6252
- 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."
6253
- context: fork
6254
- ---
6255
-
6256
- Review recent changes and provide actionable feedback.
6257
-
6258
- ## Steps
6259
-
6260
- 1. Identify the changes to review \u2014 check \`git diff\`, \`git log\`, and staged files.
6261
- 2. Read the changed files and understand the intent behind each change.
6262
- 3. Evaluate each change against the criteria below.
6263
- 4. Output a concise summary with only the issues found. If nothing is wrong, say so.
6264
-
6265
- ## Review criteria
6266
-
6267
- - **Correctness** \u2014 Are the changes aligned with their stated goal? Do they introduce bugs or regressions?
6268
- - **Code quality** \u2014 Is there duplicate, dead, or overly complex code? Are abstractions appropriate?
6269
- - **Performance** \u2014 Are there unnecessary allocations, redundant I/O, or algorithmic concerns?
6270
- - **Edge cases** \u2014 Are boundary conditions and error paths handled?
6271
-
6272
- ## Guidelines
6273
-
6274
- - Never flag style choices as bugs \u2014 don't be a zealot.
6275
- - Never flag false positives \u2014 verify before raising an issue.
6276
- - Keep feedback actionable: say what's wrong and suggest a fix.
6277
- `;
6278
- function bootstrapGlobalDefaults() {
6279
- const skillDir = join8(homedir6(), ".agents", "skills", "review");
6280
- const skillPath = join8(skillDir, "SKILL.md");
6281
- if (!existsSync5(skillPath)) {
6282
- mkdirSync2(skillDir, { recursive: true });
6283
- 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)")}`);
6285
- }
6248
+ ${c12.bold("Examples:")}`);
6249
+ writeln(` mc ${c12.dim("# interactive session")}`);
6250
+ writeln(` mc "explain this codebase" ${c12.dim("# one-shot prompt then exit")}`);
6251
+ writeln(` mc -c ${c12.dim("# continue last session")}`);
6252
+ writeln(` mc -m ollama/llama3.2 ${c12.dim("# use local Ollama model")}`);
6253
+ writeln(` mc -l ${c12.dim("# list sessions")}`);
6286
6254
  }
6287
6255
 
6288
6256
  // src/cli/file-refs.ts
6289
- import { join as join9 } from "path";
6257
+ import { join as join7 } from "path";
6290
6258
  async function resolveFileRefs(text, cwd) {
6291
6259
  const atPattern = /@([\w./\-_]+)/g;
6292
6260
  let result = text;
@@ -6296,7 +6264,7 @@ async function resolveFileRefs(text, cwd) {
6296
6264
  const ref = match[1];
6297
6265
  if (!ref)
6298
6266
  continue;
6299
- const filePath = ref.startsWith("/") ? ref : join9(cwd, ref);
6267
+ const filePath = ref.startsWith("/") ? ref : join7(cwd, ref);
6300
6268
  if (isImageFilename(ref)) {
6301
6269
  const attachment = await loadImageFile(filePath);
6302
6270
  if (attachment) {
@@ -6318,25 +6286,25 @@ ${content}
6318
6286
  }
6319
6287
 
6320
6288
  // src/cli/input-loop.ts
6321
- import * as c21 from "yoctocolors";
6289
+ import * as c19 from "yoctocolors";
6322
6290
 
6323
6291
  // src/cli/commands.ts
6324
6292
  import { randomBytes } from "crypto";
6325
- import { unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
6293
+ import { unlinkSync, writeFileSync } from "fs";
6326
6294
  import { tmpdir } from "os";
6327
- import { join as join10 } from "path";
6328
- import * as c20 from "yoctocolors";
6295
+ import { join as join8 } from "path";
6296
+ import * as c18 from "yoctocolors";
6329
6297
 
6330
6298
  // src/cli/commands-help.ts
6331
- import * as c15 from "yoctocolors";
6299
+ import * as c13 from "yoctocolors";
6332
6300
  function renderEntries(entries) {
6333
6301
  for (const [label, description] of entries) {
6334
- writeln(` ${c15.cyan(label.padEnd(28))} ${c15.dim(description)}`);
6302
+ writeln(` ${c13.cyan(label.padEnd(28))} ${c13.dim(description)}`);
6335
6303
  }
6336
6304
  }
6337
6305
  function renderHelpCommand(ctx) {
6338
6306
  writeln();
6339
- writeln(` ${c15.dim("session")}`);
6307
+ writeln(` ${c13.dim("session")}`);
6340
6308
  renderEntries([
6341
6309
  ["/session [id]", "list sessions or switch to one"],
6342
6310
  ["/new", "start a fresh session"],
@@ -6344,7 +6312,7 @@ function renderHelpCommand(ctx) {
6344
6312
  ["/exit", "quit"]
6345
6313
  ]);
6346
6314
  writeln();
6347
- writeln(` ${c15.dim("model + context")}`);
6315
+ writeln(` ${c13.dim("model + context")}`);
6348
6316
  renderEntries([
6349
6317
  ["/model [id]", "list or switch models"],
6350
6318
  ["/reasoning [on|off]", "toggle reasoning display"],
@@ -6352,12 +6320,12 @@ function renderHelpCommand(ctx) {
6352
6320
  ["/mcp list", "list MCP servers"],
6353
6321
  ["/mcp add <n> <t> [u]", "add an MCP server"],
6354
6322
  ["/mcp remove <name>", "remove an MCP server"],
6355
- ["/login [provider]", "login via OAuth (e.g. anthropic)"],
6323
+ ["/login [provider]", "login via OAuth (e.g. openai)"],
6356
6324
  ["/logout <provider>", "clear OAuth tokens"],
6357
6325
  ["/help", "show this help"]
6358
6326
  ]);
6359
6327
  writeln();
6360
- writeln(` ${c15.dim("prompt")}`);
6328
+ writeln(` ${c13.dim("prompt")}`);
6361
6329
  renderEntries([
6362
6330
  ["ask normally", "send a prompt to the current agent"],
6363
6331
  ["!cmd", "run a shell command and keep the result in context"],
@@ -6367,44 +6335,44 @@ function renderHelpCommand(ctx) {
6367
6335
  const skills = loadSkillsIndex(ctx.cwd);
6368
6336
  if (skills.size > 0) {
6369
6337
  writeln();
6370
- writeln(` ${c15.dim("skills")}`);
6338
+ writeln(` ${c13.dim("skills")}`);
6371
6339
  for (const skill of skills.values()) {
6372
- const source = skill.source === "local" ? c15.dim("local") : c15.dim("global");
6340
+ const source = skill.source === "local" ? c13.dim("local") : c13.dim("global");
6373
6341
  const desc = truncateText(skill.description, 80);
6374
- writeln(` ${c15.green(`/${skill.name}`.padEnd(28))} ${c15.dim(desc)} ${c15.dim("\xB7")} ${source}`);
6342
+ writeln(` ${c13.green(`/${skill.name}`.padEnd(28))} ${c13.dim(desc)} ${c13.dim("\xB7")} ${source}`);
6375
6343
  }
6376
6344
  }
6377
6345
  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`);
6346
+ writeln(` ${c13.dim("keys")} ${c13.dim("esc")} cancel response ${c13.dim("\xB7")} ${c13.dim("ctrl+c / ctrl+d")} exit ${c13.dim("\xB7")} ${c13.dim("ctrl+r")} history search ${c13.dim("\xB7")} ${c13.dim("\u2191\u2193")} history`);
6379
6347
  writeln();
6380
6348
  }
6381
6349
 
6382
6350
  // src/cli/commands-login.ts
6383
- import * as c16 from "yoctocolors";
6351
+ import * as c14 from "yoctocolors";
6384
6352
  function renderLoginHelp() {
6385
6353
  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")}`);
6354
+ writeln(` ${c14.dim("usage:")}`);
6355
+ writeln(` /login ${c14.dim("show login status")}`);
6356
+ writeln(` /login <provider> ${c14.dim("login via OAuth")}`);
6357
+ writeln(` /logout <provider> ${c14.dim("clear saved tokens")}`);
6390
6358
  writeln();
6391
- writeln(` ${c16.dim("providers:")}`);
6359
+ writeln(` ${c14.dim("providers:")}`);
6392
6360
  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}`);
6361
+ const status = isLoggedIn(p.id) ? c14.green("logged in") : c14.dim("not logged in");
6362
+ writeln(` ${c14.cyan(p.id.padEnd(20))} ${p.name} ${c14.dim("\xB7")} ${status}`);
6395
6363
  }
6396
6364
  writeln();
6397
6365
  }
6398
6366
  function renderStatus() {
6399
6367
  const loggedIn = listLoggedInProviders();
6400
6368
  if (loggedIn.length === 0) {
6401
- writeln(`${PREFIX.info} ${c16.dim("no OAuth logins \u2014 use")} /login <provider>`);
6369
+ writeln(`${PREFIX.info} ${c14.dim("no OAuth logins \u2014 use")} /login <provider>`);
6402
6370
  return;
6403
6371
  }
6404
6372
  for (const id of loggedIn) {
6405
6373
  const provider = getOAuthProvider(id);
6406
6374
  const name = provider?.name ?? id;
6407
- writeln(`${PREFIX.success} ${c16.cyan(id)} ${c16.dim(name)}`);
6375
+ writeln(`${PREFIX.success} ${c14.cyan(id)} ${c14.dim(name)}`);
6408
6376
  }
6409
6377
  }
6410
6378
  async function handleLoginCommand(ctx, args) {
@@ -6425,7 +6393,7 @@ async function handleLoginCommand(ctx, args) {
6425
6393
  if (isLoggedIn(providerId)) {
6426
6394
  const token = await getAccessToken(providerId);
6427
6395
  if (token) {
6428
- writeln(`${PREFIX.success} already logged in to ${c16.cyan(provider.name)}`);
6396
+ writeln(`${PREFIX.success} already logged in to ${c14.cyan(provider.name)}`);
6429
6397
  return;
6430
6398
  }
6431
6399
  }
@@ -6436,7 +6404,7 @@ async function handleLoginCommand(ctx, args) {
6436
6404
  ctx.stopSpinner();
6437
6405
  writeln(`${PREFIX.info} ${instructions}`);
6438
6406
  writeln();
6439
- writeln(` ${c16.cyan(url)}`);
6407
+ writeln(` ${c14.cyan(url)}`);
6440
6408
  writeln();
6441
6409
  let open = "xdg-open";
6442
6410
  if (process.platform === "darwin")
@@ -6448,12 +6416,12 @@ async function handleLoginCommand(ctx, args) {
6448
6416
  },
6449
6417
  onProgress: (msg) => {
6450
6418
  ctx.stopSpinner();
6451
- writeln(`${PREFIX.info} ${c16.dim(msg)}`);
6419
+ writeln(`${PREFIX.info} ${c14.dim(msg)}`);
6452
6420
  ctx.startSpinner("exchanging tokens");
6453
6421
  }
6454
6422
  });
6455
6423
  ctx.stopSpinner();
6456
- writeln(`${PREFIX.success} logged in to ${c16.cyan(provider.name)}`);
6424
+ writeln(`${PREFIX.success} logged in to ${c14.cyan(provider.name)}`);
6457
6425
  } catch (err) {
6458
6426
  ctx.stopSpinner();
6459
6427
  writeln(`${PREFIX.error} login failed: ${err.message}`);
@@ -6465,16 +6433,21 @@ function handleLogoutCommand(_ctx, args) {
6465
6433
  writeln(`${PREFIX.error} usage: /logout <provider>`);
6466
6434
  return;
6467
6435
  }
6436
+ const provider = getOAuthProvider(providerId);
6437
+ if (!provider) {
6438
+ writeln(`${PREFIX.error} unknown provider "${providerId}" \u2014 available: ${getOAuthProviders().map((p) => p.id).join(", ")}`);
6439
+ return;
6440
+ }
6468
6441
  if (!isLoggedIn(providerId)) {
6469
- writeln(`${PREFIX.info} ${c16.dim("not logged in to")} ${providerId}`);
6442
+ writeln(`${PREFIX.info} ${c14.dim("not logged in to")} ${providerId}`);
6470
6443
  return;
6471
6444
  }
6472
6445
  logout(providerId);
6473
- writeln(`${PREFIX.success} logged out of ${c16.cyan(providerId)}`);
6446
+ writeln(`${PREFIX.success} logged out of ${c14.cyan(provider.id)}`);
6474
6447
  }
6475
6448
 
6476
6449
  // src/cli/commands-mcp.ts
6477
- import * as c17 from "yoctocolors";
6450
+ import * as c15 from "yoctocolors";
6478
6451
  async function handleMcpCommand(ctx, args) {
6479
6452
  const parts = args.trim().split(/\s+/);
6480
6453
  const sub = parts[0] ?? "list";
@@ -6482,15 +6455,15 @@ async function handleMcpCommand(ctx, args) {
6482
6455
  case "list": {
6483
6456
  const servers = listMcpServers();
6484
6457
  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...]"));
6458
+ writeln(c15.dim(" no MCP servers configured"));
6459
+ writeln(c15.dim(" /mcp add <name> http <url> \xB7 /mcp add <name> stdio <cmd> [args...]"));
6487
6460
  return;
6488
6461
  }
6489
6462
  writeln();
6490
6463
  for (const s of servers) {
6491
6464
  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}`);
6465
+ const detail = detailText ? c15.dim(` ${detailText}`) : "";
6466
+ writeln(` ${c15.yellow("\u2699")} ${c15.bold(s.name)} ${c15.dim(s.transport)}${detail}`);
6494
6467
  }
6495
6468
  return;
6496
6469
  }
@@ -6535,9 +6508,9 @@ async function handleMcpCommand(ctx, args) {
6535
6508
  }
6536
6509
  try {
6537
6510
  await ctx.connectMcpServer(name);
6538
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} added and connected`);
6511
+ writeln(`${PREFIX.success} mcp server ${c15.cyan(name)} added and connected`);
6539
6512
  } catch (e) {
6540
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} saved ${c17.dim(`(connection failed: ${String(e)})`)}`);
6513
+ writeln(`${PREFIX.success} mcp server ${c15.cyan(name)} saved ${c15.dim(`(connection failed: ${String(e)})`)}`);
6541
6514
  }
6542
6515
  return;
6543
6516
  }
@@ -6549,17 +6522,17 @@ async function handleMcpCommand(ctx, args) {
6549
6522
  return;
6550
6523
  }
6551
6524
  deleteMcpServer(name);
6552
- writeln(`${PREFIX.success} mcp server ${c17.cyan(name)} removed`);
6525
+ writeln(`${PREFIX.success} mcp server ${c15.cyan(name)} removed`);
6553
6526
  return;
6554
6527
  }
6555
6528
  default:
6556
6529
  writeln(`${PREFIX.error} unknown: /mcp ${sub}`);
6557
- writeln(c17.dim(" subcommands: list \xB7 add \xB7 remove"));
6530
+ writeln(c15.dim(" subcommands: list \xB7 add \xB7 remove"));
6558
6531
  }
6559
6532
  }
6560
6533
 
6561
6534
  // src/cli/commands-model.ts
6562
- import * as c18 from "yoctocolors";
6535
+ import * as c16 from "yoctocolors";
6563
6536
  import { select } from "yoctoselect";
6564
6537
  var THINKING_EFFORTS = ["low", "medium", "high", "xhigh"];
6565
6538
  function parseThinkingEffort(value) {
@@ -6579,21 +6552,21 @@ function renderModelUpdatedMessage(ctx, modelId, effortArg) {
6579
6552
  if (effortArg) {
6580
6553
  if (effortArg === "off") {
6581
6554
  ctx.setThinkingEffort(null);
6582
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)} ${c18.dim("(thinking disabled)")}`);
6555
+ writeln(`${PREFIX.success} model \u2192 ${c16.cyan(modelId)} ${c16.dim("(thinking disabled)")}`);
6583
6556
  return;
6584
6557
  }
6585
6558
  const effort = parseThinkingEffort(effortArg);
6586
6559
  if (effort) {
6587
6560
  ctx.setThinkingEffort(effort);
6588
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)} ${c18.dim(`(\u2726 ${effort})`)}`);
6561
+ writeln(`${PREFIX.success} model \u2192 ${c16.cyan(modelId)} ${c16.dim(`(\u2726 ${effort})`)}`);
6589
6562
  return;
6590
6563
  }
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)`);
6564
+ writeln(`${PREFIX.success} model \u2192 ${c16.cyan(modelId)}`);
6565
+ writeln(`${PREFIX.error} unknown effort level ${c16.cyan(effortArg)} (use low, medium, high, xhigh, off)`);
6593
6566
  return;
6594
6567
  }
6595
- const effortTag = ctx.thinkingEffort ? c18.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
6596
- writeln(`${PREFIX.success} model \u2192 ${c18.cyan(modelId)}${effortTag}`);
6568
+ const effortTag = ctx.thinkingEffort ? c16.dim(` (\u2726 ${ctx.thinkingEffort})`) : "";
6569
+ writeln(`${PREFIX.success} model \u2192 ${c16.cyan(modelId)}${effortTag}`);
6597
6570
  }
6598
6571
  async function handleModelSet(ctx, args) {
6599
6572
  const parts = args.trim().split(/\s+/).filter(Boolean);
@@ -6606,7 +6579,7 @@ async function handleModelSet(ctx, args) {
6606
6579
  const snapshot = await fetchAvailableModels();
6607
6580
  const match = findModelIdByAlias(idArg, snapshot.models.map((model) => model.id));
6608
6581
  if (!match) {
6609
- writeln(`${PREFIX.error} unknown model ${c18.cyan(idArg)} ${c18.dim("\u2014 run /models for the full list")}`);
6582
+ writeln(`${PREFIX.error} unknown model ${c16.cyan(idArg)} ${c16.dim("\u2014 run /models for the full list")}`);
6610
6583
  return;
6611
6584
  }
6612
6585
  modelId = match;
@@ -6626,7 +6599,7 @@ function handleModelEffort(ctx, effortArg) {
6626
6599
  return;
6627
6600
  }
6628
6601
  ctx.setThinkingEffort(effort);
6629
- writeln(`${PREFIX.success} thinking effort \u2192 ${c18.cyan(effort)}`);
6602
+ writeln(`${PREFIX.success} thinking effort \u2192 ${c16.cyan(effort)}`);
6630
6603
  }
6631
6604
  async function handleModelSelect(ctx) {
6632
6605
  ctx.startSpinner("fetching models");
@@ -6634,20 +6607,20 @@ async function handleModelSelect(ctx) {
6634
6607
  ctx.stopSpinner();
6635
6608
  if (snapshot.models.length === 0) {
6636
6609
  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."));
6610
+ writeln(c16.dim(" Set OPENCODE_API_KEY for Zen, or start Ollama for local models."));
6638
6611
  return;
6639
6612
  }
6640
6613
  if (snapshot.stale) {
6641
6614
  const lastSync = snapshot.lastSyncAt ? new Date(snapshot.lastSyncAt).toLocaleString() : "never";
6642
6615
  const refreshTag = snapshot.refreshing ? " (refreshing in background)" : "";
6643
- writeln(c18.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
6616
+ writeln(c16.dim(` model metadata is stale (last sync: ${lastSync})${refreshTag}`));
6644
6617
  }
6645
6618
  const items = snapshot.models.map((model) => {
6646
6619
  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}]`);
6620
+ const freeTag = model.free ? c16.green(" free") : "";
6621
+ const contextTag = model.context ? c16.dim(` ${Math.round(model.context / 1000)}k`) : "";
6622
+ const currentTag = isCurrent ? c16.cyan(" \u25C0") : "";
6623
+ const providerTag = c16.dim(` [${model.provider}]`);
6651
6624
  return {
6652
6625
  label: `${model.displayName}${freeTag}${contextTag}${currentTag}${providerTag}`,
6653
6626
  value: model.id,
@@ -6680,7 +6653,7 @@ async function handleModelCommand(ctx, args) {
6680
6653
  }
6681
6654
 
6682
6655
  // src/cli/commands-session.ts
6683
- import * as c19 from "yoctocolors";
6656
+ import * as c17 from "yoctocolors";
6684
6657
  import { select as select2 } from "yoctoselect";
6685
6658
  async function handleSessionCommand(ctx, args) {
6686
6659
  const id = args.trim();
@@ -6689,15 +6662,15 @@ async function handleSessionCommand(ctx, args) {
6689
6662
  const ok2 = ctx.switchSession(id);
6690
6663
  ctx.stopSpinner();
6691
6664
  if (ok2) {
6692
- writeln(`${PREFIX.success} switched to session ${c19.cyan(id)} (${c19.cyan(ctx.currentModel)})`);
6665
+ writeln(`${PREFIX.success} switched to session ${c17.cyan(id)} (${c17.cyan(ctx.currentModel)})`);
6693
6666
  } else {
6694
- writeln(`${PREFIX.error} session ${c19.cyan(id)} not found`);
6667
+ writeln(`${PREFIX.error} session ${c17.cyan(id)} not found`);
6695
6668
  }
6696
6669
  return;
6697
6670
  }
6698
6671
  const sessions = listSessions(50);
6699
6672
  if (sessions.length === 0) {
6700
- writeln(`${PREFIX.info} ${c19.dim("no sessions found")}`);
6673
+ writeln(`${PREFIX.info} ${c17.dim("no sessions found")}`);
6701
6674
  return;
6702
6675
  }
6703
6676
  const items = sessions.map((s) => {
@@ -6706,7 +6679,7 @@ async function handleSessionCommand(ctx, args) {
6706
6679
  const cwd = tildePath(s.cwd);
6707
6680
  const date = new Date(s.updated_at).toLocaleDateString();
6708
6681
  return {
6709
- label: `${c19.dim(s.id)} ${title} ${c19.cyan(model)} ${c19.dim(cwd)} ${c19.dim(date)}`,
6682
+ label: `${c17.dim(s.id)} ${title} ${c17.cyan(model)} ${c17.dim(cwd)} ${c17.dim(date)}`,
6710
6683
  value: s.id,
6711
6684
  filterText: `${s.id} ${s.title} ${s.model} ${s.cwd}`
6712
6685
  };
@@ -6722,9 +6695,9 @@ async function handleSessionCommand(ctx, args) {
6722
6695
  return;
6723
6696
  const ok = ctx.switchSession(picked);
6724
6697
  if (ok) {
6725
- writeln(`${PREFIX.success} switched to session ${c19.cyan(picked)} (${c19.cyan(ctx.currentModel)})`);
6698
+ writeln(`${PREFIX.success} switched to session ${c17.cyan(picked)} (${c17.cyan(ctx.currentModel)})`);
6726
6699
  } else {
6727
- writeln(`${PREFIX.error} session ${c19.cyan(picked)} not found`);
6700
+ writeln(`${PREFIX.error} session ${c17.cyan(picked)} not found`);
6728
6701
  }
6729
6702
  }
6730
6703
 
@@ -6734,9 +6707,9 @@ async function handleUndo(ctx) {
6734
6707
  try {
6735
6708
  const ok = await ctx.undoLastTurn();
6736
6709
  if (ok) {
6737
- writeln(`${PREFIX.success} ${c20.dim("last conversation turn removed")}`);
6710
+ writeln(`${PREFIX.success} ${c18.dim("last conversation turn removed")}`);
6738
6711
  } else {
6739
- writeln(`${PREFIX.info} ${c20.dim("nothing to undo")}`);
6712
+ writeln(`${PREFIX.info} ${c18.dim("nothing to undo")}`);
6740
6713
  }
6741
6714
  } finally {
6742
6715
  ctx.stopSpinner();
@@ -6794,7 +6767,7 @@ async function handleCommand(command, args, ctx) {
6794
6767
  if (loaded2) {
6795
6768
  const srcPath = skill.source === "local" ? `.agents/skills/${skill.name}/SKILL.md` : `~/.agents/skills/${skill.name}/SKILL.md`;
6796
6769
  if (skill.context === "fork") {
6797
- writeln(`${PREFIX.info} ${c20.cyan(skill.name)} ${c20.dim(`[${srcPath}] (forked subagent)`)}`);
6770
+ writeln(`${PREFIX.info} ${c18.cyan(skill.name)} ${c18.dim(`[${srcPath}] (forked subagent)`)}`);
6798
6771
  writeln();
6799
6772
  const subagentPrompt = args ? `${loaded2.content}
6800
6773
 
@@ -6802,7 +6775,7 @@ ${args}` : loaded2.content;
6802
6775
  const result = await runForkedSkill(skill.name, subagentPrompt, ctx.cwd);
6803
6776
  return { type: "inject-user-message", text: result };
6804
6777
  }
6805
- writeln(`${PREFIX.info} ${c20.cyan(skill.name)} ${c20.dim(`[${srcPath}]`)}`);
6778
+ writeln(`${PREFIX.info} ${c18.cyan(skill.name)} ${c18.dim(`[${srcPath}]`)}`);
6806
6779
  writeln();
6807
6780
  const prompt = args ? `${loaded2.content}
6808
6781
 
@@ -6810,16 +6783,16 @@ ${args}` : loaded2.content;
6810
6783
  return { type: "inject-user-message", text: prompt };
6811
6784
  }
6812
6785
  }
6813
- writeln(`${PREFIX.error} unknown: /${command} ${c20.dim("\u2014 /help for commands")}`);
6786
+ writeln(`${PREFIX.error} unknown: /${command} ${c18.dim("\u2014 /help for commands")}`);
6814
6787
  return { type: "unknown", command };
6815
6788
  }
6816
6789
  }
6817
6790
  }
6818
6791
  async function runForkedSkill(skillName, prompt, cwd) {
6819
- const tmpFile = join10(tmpdir(), `mc-fork-${randomBytes(8).toString("hex")}.md`);
6820
- writeFileSync2(tmpFile, prompt, "utf8");
6792
+ const tmpFile = join8(tmpdir(), `mc-fork-${randomBytes(8).toString("hex")}.md`);
6793
+ writeFileSync(tmpFile, prompt, "utf8");
6821
6794
  try {
6822
- writeln(`${PREFIX.info} ${c20.dim("running subagent\u2026")}`);
6795
+ writeln(`${PREFIX.info} ${c18.dim("running subagent\u2026")}`);
6823
6796
  const proc = Bun.spawn([process.execPath, Bun.main], {
6824
6797
  cwd,
6825
6798
  stdin: Bun.file(tmpFile),
@@ -6844,24 +6817,24 @@ ${stderr.trim()}`;
6844
6817
  ${output}`;
6845
6818
  } finally {
6846
6819
  try {
6847
- unlinkSync2(tmpFile);
6820
+ unlinkSync(tmpFile);
6848
6821
  } catch {}
6849
6822
  }
6850
6823
  }
6851
6824
  function handleBooleanToggleCommand(opts) {
6852
6825
  const mode = opts.args.trim().toLowerCase();
6853
6826
  if (!mode) {
6854
- writeln(`${PREFIX.success} ${opts.label} ${opts.current ? c20.green("on") : c20.dim("off")}`);
6827
+ writeln(`${PREFIX.success} ${opts.label} ${opts.current ? c18.green("on") : c18.dim("off")}`);
6855
6828
  return;
6856
6829
  }
6857
6830
  if (mode === "on") {
6858
6831
  opts.set(true);
6859
- writeln(`${PREFIX.success} ${opts.label} ${c20.green("on")}`);
6832
+ writeln(`${PREFIX.success} ${opts.label} ${c18.green("on")}`);
6860
6833
  return;
6861
6834
  }
6862
6835
  if (mode === "off") {
6863
6836
  opts.set(false);
6864
- writeln(`${PREFIX.success} ${opts.label} ${c20.dim("off")}`);
6837
+ writeln(`${PREFIX.success} ${opts.label} ${c18.dim("off")}`);
6865
6838
  return;
6866
6839
  }
6867
6840
  writeln(`${PREFIX.error} usage: ${opts.usage}`);
@@ -6921,13 +6894,12 @@ async function getGitBranch(cwd) {
6921
6894
  }
6922
6895
  async function runInputLoop(opts) {
6923
6896
  const { cwd, reporter, cmdCtx, runner } = opts;
6924
- let lastStatusSignature = null;
6925
6897
  while (true) {
6926
6898
  const branch = await getGitBranch(cwd);
6927
6899
  const status = runner.getStatusInfo();
6928
6900
  const cwdDisplay = tildePath(cwd);
6929
6901
  const contextWindow = getContextWindow(status.model);
6930
- const statusData = {
6902
+ reporter.renderStatusBar({
6931
6903
  model: status.model,
6932
6904
  cwd: cwdDisplay,
6933
6905
  gitBranch: branch,
@@ -6937,12 +6909,7 @@ async function runInputLoop(opts) {
6937
6909
  contextTokens: status.lastContextTokens,
6938
6910
  contextWindow,
6939
6911
  thinkingEffort: status.thinkingEffort
6940
- };
6941
- const statusSignature = buildStatusBarSignature(statusData);
6942
- if (statusSignature !== lastStatusSignature) {
6943
- reporter.renderStatusBar(statusData);
6944
- lastStatusSignature = statusSignature;
6945
- }
6912
+ });
6946
6913
  let input;
6947
6914
  try {
6948
6915
  input = await readline({ cwd });
@@ -6951,14 +6918,14 @@ async function runInputLoop(opts) {
6951
6918
  }
6952
6919
  switch (input.type) {
6953
6920
  case "eof":
6954
- reporter.writeText(c21.dim("Goodbye."));
6921
+ reporter.writeText(c19.dim("Goodbye."));
6955
6922
  return;
6956
6923
  case "interrupt":
6957
6924
  continue;
6958
6925
  case "command": {
6959
6926
  const result = await handleCommand(input.command, input.args, cmdCtx);
6960
6927
  if (result.type === "exit") {
6961
- reporter.writeText(c21.dim("Goodbye."));
6928
+ reporter.writeText(c19.dim("Goodbye."));
6962
6929
  return;
6963
6930
  }
6964
6931
  if (result.type === "inject-user-message") {
@@ -7065,13 +7032,12 @@ async function main() {
7065
7032
  if (last) {
7066
7033
  sessionId = last.id;
7067
7034
  } else {
7068
- writeln(c22.dim("No previous session found, starting fresh."));
7035
+ writeln(c20.dim("No previous session found, starting fresh."));
7069
7036
  }
7070
7037
  } else if (args.sessionId) {
7071
7038
  sessionId = args.sessionId;
7072
7039
  }
7073
7040
  const model = args.model ?? getPreferredModel() ?? autoDiscoverModel();
7074
- bootstrapGlobalDefaults();
7075
7041
  if (!prompt) {
7076
7042
  renderBanner(model, args.cwd);
7077
7043
  }