@trydecember/cli 0.4.9 → 0.4.11

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.
Files changed (3) hide show
  1. package/README.md +14 -0
  2. package/dist/december.js +1557 -418
  3. package/package.json +1 -1
package/dist/december.js CHANGED
@@ -65,7 +65,7 @@ var package_default;
65
65
  var init_package = __esm(() => {
66
66
  package_default = {
67
67
  name: "@trydecember/cli",
68
- version: "0.4.9",
68
+ version: "0.4.11",
69
69
  description: "a (so much) better coding agent for terminal and cloud.",
70
70
  homepage: "https://trydecember.com",
71
71
  repository: {
@@ -306,7 +306,7 @@ function getModelContextWindow(value) {
306
306
  if (lower.startsWith("ollama/")) {
307
307
  lower = lower.slice("ollama/".length);
308
308
  }
309
- if (lower.includes("december-auto"))
309
+ if (lower.includes("december-auto") || lower.includes("humans-r1"))
310
310
  return 1e6;
311
311
  if (lower.includes("gemini"))
312
312
  return 1e6;
@@ -477,7 +477,7 @@ function supportsModelThinking(model) {
477
477
  if (lower.includes("claude-3-7") || lower.includes("claude-3.7") || lower.includes("claude-4") || lower.includes("claude-opus-4") || lower.includes("claude-sonnet-4") || lower.includes("claude-haiku-4") || lower.includes("claude-5") || lower.includes("claude-fable-5") || lower.includes("sonnet-5") || lower.includes("opus-5")) {
478
478
  return true;
479
479
  }
480
- if (lower.includes("gemini-2.5") || lower.includes("gemini-3") || lower.includes("december-auto")) {
480
+ if (lower.includes("gemini-2.5") || lower.includes("gemini-3") || lower.includes("december-auto") || lower.includes("humans-r1")) {
481
481
  return true;
482
482
  }
483
483
  if (lower.includes("deepseek-reasoner") || lower.includes("deepseek-r1") || lower.includes("r1-1776") || lower.includes("deepseek-v4")) {
@@ -505,6 +505,7 @@ var MODEL_CONTEXT_WINDOWS;
505
505
  var init_models = __esm(() => {
506
506
  MODEL_CONTEXT_WINDOWS = {
507
507
  "december-auto": 1e6,
508
+ "humans-r1": 1e6,
508
509
  "gemini-3.8-flash": 1e6,
509
510
  "gemini-3.7-flash": 1e6,
510
511
  "gemini-3.6-flash": 1e6,
@@ -106769,7 +106770,7 @@ function resolveAntigravityModel(model) {
106769
106770
  function antigravityProvider(token, options) {
106770
106771
  const endpoint = options?.endpoint || ANTIGRAVITY_DEFAULT_ENDPOINT;
106771
106772
  const fetchFn = options?.fetchFn || fetch;
106772
- const bearerToken = token || process.env.ANTIGRAVITY_TOKEN || process.env.GEMINI_OAUTH_TOKEN || process.env.GOOGLE_OAUTH_TOKEN || "dummy-key";
106773
+ let bearerToken = token || process.env.ANTIGRAVITY_TOKEN || process.env.GEMINI_OAUTH_TOKEN || process.env.GOOGLE_OAUTH_TOKEN || "dummy-key";
106773
106774
  return createProvider({
106774
106775
  id: "antigravity",
106775
106776
  name: "Antigravity",
@@ -106903,6 +106904,14 @@ function antigravityProvider(token, options) {
106903
106904
  model: resolveAntigravityModel(modelOptions?.model),
106904
106905
  request: innerRequest
106905
106906
  };
106907
+ if (options?.getToken) {
106908
+ try {
106909
+ const freshToken = await options.getToken();
106910
+ if (freshToken) {
106911
+ bearerToken = freshToken;
106912
+ }
106913
+ } catch {}
106914
+ }
106906
106915
  const headers = {
106907
106916
  "Content-Type": "application/json",
106908
106917
  Accept: "text/event-stream",
@@ -106918,6 +106927,24 @@ function antigravityProvider(token, options) {
106918
106927
  body: JSON.stringify(requestBody),
106919
106928
  signal
106920
106929
  });
106930
+ if (!response.ok && (response.status === 401 || response.status === 403) && options?.getToken) {
106931
+ try {
106932
+ const freshToken = await options.getToken();
106933
+ if (freshToken && freshToken !== bearerToken) {
106934
+ bearerToken = freshToken;
106935
+ headers.Authorization = `Bearer ${bearerToken}`;
106936
+ const retryResponse = await fetchFn(targetUrl, {
106937
+ method: "POST",
106938
+ headers,
106939
+ body: JSON.stringify(requestBody),
106940
+ signal
106941
+ });
106942
+ if (retryResponse.ok) {
106943
+ response = retryResponse;
106944
+ }
106945
+ }
106946
+ } catch {}
106947
+ }
106921
106948
  if (!response.ok && (response.status === 404 || response.status === 403 || response.status === 429 || response.status === 503)) {
106922
106949
  const fallbackEndpoint = endpoint.includes("daily-cloudcode-pa") ? endpoint.replace("daily-cloudcode-pa", "cloudcode-pa") : endpoint.includes("cloudcode-pa") && !endpoint.includes("daily-") ? endpoint.replace("cloudcode-pa", "daily-cloudcode-pa") : null;
106923
106950
  if (fallbackEndpoint) {
@@ -107079,20 +107106,22 @@ function resolveCodexModel(model) {
107079
107106
  if (name.startsWith("openai/")) {
107080
107107
  name = name.slice("openai/".length);
107081
107108
  }
107082
- if (CODEX_SUPPORTED_MODELS.includes(name)) {
107083
- return name;
107084
- }
107085
- if (name.includes("5.5"))
107086
- return "gpt-5.5";
107087
107109
  if (name.includes("5.6-sol") || name.includes("sol"))
107088
107110
  return "gpt-5.6-sol";
107089
107111
  if (name.includes("5.6-terra") || name.includes("terra"))
107090
107112
  return "gpt-5.6-terra";
107091
107113
  if (name.includes("5.6-luna") || name.includes("luna"))
107092
107114
  return "gpt-5.6-luna";
107115
+ if (name.includes("5.5"))
107116
+ return "gpt-5.5";
107093
107117
  if (name.includes("mini"))
107094
107118
  return "gpt-5.4-mini";
107095
- return "gpt-5.4";
107119
+ if (name.includes("5.4"))
107120
+ return "gpt-5.4";
107121
+ if (CODEX_SUPPORTED_MODELS.includes(name)) {
107122
+ return name;
107123
+ }
107124
+ return "gpt-5.6-sol";
107096
107125
  }
107097
107126
  function extractChatGPTAccountId(token) {
107098
107127
  try {
@@ -107300,12 +107329,12 @@ function codexResponsesProvider(token, options) {
107300
107329
  var CODEX_DEFAULT_ENDPOINT = "https://chatgpt.com/backend-api", CODEX_SUPPORTED_MODELS;
107301
107330
  var init_codex = __esm(() => {
107302
107331
  CODEX_SUPPORTED_MODELS = [
107303
- "gpt-5.4",
107304
- "gpt-5.4-mini",
107305
- "gpt-5.5",
107306
107332
  "gpt-5.6-sol",
107307
107333
  "gpt-5.6-terra",
107308
- "gpt-5.6-luna"
107334
+ "gpt-5.6-luna",
107335
+ "gpt-5.5",
107336
+ "gpt-5.4",
107337
+ "gpt-5.4-mini"
107309
107338
  ];
107310
107339
  });
107311
107340
 
@@ -108415,6 +108444,7 @@ __export(exports_models2, {
108415
108444
  fetchOllamaModels: () => fetchOllamaModels,
108416
108445
  getDefaultModelForProvider: () => getDefaultModelForProvider,
108417
108446
  getDefaultUrlForLocalProvider: () => getDefaultUrlForLocalProvider,
108447
+ getModelLabel: () => getModelLabel,
108418
108448
  getProviderModels: () => getProviderModels,
108419
108449
  isValidModelForProvider: () => isValidModelForProvider
108420
108450
  });
@@ -109204,7 +109234,7 @@ var LIVE_MODEL_CACHE_TTL_MS, liveModelCache, diskCacheLoaded = false, getCurated
109204
109234
  ];
109205
109235
  case "december":
109206
109236
  case "december_proxy":
109207
- return [{ label: "december-auto", value: "december-auto" }];
109237
+ return [{ label: "Humans R1", value: "december-auto" }];
109208
109238
  case "copilot":
109209
109239
  case "github_copilot":
109210
109240
  case "github":
@@ -109218,12 +109248,10 @@ var LIVE_MODEL_CACHE_TTL_MS, liveModelCache, diskCacheLoaded = false, getCurated
109218
109248
  case "codex":
109219
109249
  case "chatgpt":
109220
109250
  return [
109221
- { label: "GPT-5.4", value: "gpt-5.4" },
109222
- { label: "GPT-5.4 Mini", value: "gpt-5.4-mini" },
109223
- { label: "GPT-5.5", value: "gpt-5.5" },
109224
109251
  { label: "GPT-5.6 Sol", value: "gpt-5.6-sol" },
109225
109252
  { label: "GPT-5.6 Terra", value: "gpt-5.6-terra" },
109226
- { label: "GPT-5.6 Luna", value: "gpt-5.6-luna" }
109253
+ { label: "GPT-5.6 Luna", value: "gpt-5.6-luna" },
109254
+ { label: "GPT-5.5", value: "gpt-5.5" }
109227
109255
  ];
109228
109256
  case "antigravity":
109229
109257
  return getCuratedProviderModels("gemini");
@@ -112944,6 +112972,7 @@ var init_gemini2 = __esm(() => {
112944
112972
  subscriptionType: "gemini_advanced",
112945
112973
  source: "local_import",
112946
112974
  updatedAt: Date.now(),
112975
+ expiresAt: Date.now() + 55 * 60 * 1000,
112947
112976
  extra: { source: "gcloud_cli" }
112948
112977
  };
112949
112978
  }
@@ -112951,6 +112980,17 @@ var init_gemini2 = __esm(() => {
112951
112980
  },
112952
112981
  async refreshToken(bundle) {
112953
112982
  if (!bundle.refreshToken) {
112983
+ if (bundle.extra?.source === "gcloud_cli") {
112984
+ const fresh = getGcloudToken();
112985
+ if (fresh) {
112986
+ return {
112987
+ ...bundle,
112988
+ accessToken: fresh,
112989
+ updatedAt: Date.now(),
112990
+ expiresAt: Date.now() + 55 * 60 * 1000
112991
+ };
112992
+ }
112993
+ }
112954
112994
  return bundle;
112955
112995
  }
112956
112996
  const clientId = bundle.extra?.client_id || process.env.GOOGLE_OAUTH_CLIENT_ID || process.env.GEMINI_OAUTH_CLIENT_ID || DEFAULT_CLIENT_ID;
@@ -113087,6 +113127,8 @@ You can also run \`gcloud auth application-default login\` or set \`ANTIGRAVITY_
113087
113127
  return false;
113088
113128
  if (!bundle.accessToken && !bundle.refreshToken)
113089
113129
  return false;
113130
+ if (bundle.extra?.source === "gcloud_cli")
113131
+ return true;
113090
113132
  if (bundle.expiresAt && bundle.expiresAt < Date.now() && !bundle.refreshToken) {
113091
113133
  return false;
113092
113134
  }
@@ -113141,7 +113183,7 @@ async function resolveSubscriptionToken(provider, bundle) {
113141
113183
  return bundle;
113142
113184
  }
113143
113185
  const fiveMinutes = 5 * 60 * 1000;
113144
- const isExpiringSoon = !bundle.accessToken || bundle.expiresAt !== undefined && Date.now() >= bundle.expiresAt - fiveMinutes;
113186
+ const isExpiringSoon = !bundle.accessToken || bundle.expiresAt !== undefined && Date.now() >= bundle.expiresAt - fiveMinutes || bundle.expiresAt === undefined && bundle.refreshToken !== undefined && (bundle.updatedAt === undefined || Date.now() - bundle.updatedAt > 50 * 60 * 1000);
113145
113187
  const isCopilotRaw = bundle.provider === "copilot" && (bundle.accessToken.startsWith("gho_") || bundle.accessToken.startsWith("ghu_") || bundle.accessToken.startsWith("ghp_") || bundle.accessToken.startsWith("github_pat_"));
113146
113188
  if (isExpiringSoon || isCopilotRaw) {
113147
113189
  try {
@@ -113255,6 +113297,9 @@ function getLegacyConfigDir() {
113255
113297
  if (isTestEnv && home === os9.homedir()) {
113256
113298
  return path17.join(os9.tmpdir(), "december-test-config", ".config", "december");
113257
113299
  }
113300
+ if (process.env.XDG_CONFIG_HOME) {
113301
+ return path17.join(process.env.XDG_CONFIG_HOME, "december");
113302
+ }
113258
113303
  return path17.join(home, ".config", "december");
113259
113304
  }
113260
113305
  function getLegacyConfigFile() {
@@ -113313,15 +113358,41 @@ async function loadConfig() {
113313
113358
  throw readErr;
113314
113359
  }
113315
113360
  }
113316
- let config = JSON.parse(data);
113361
+ let config;
113362
+ try {
113363
+ config = JSON.parse(data);
113364
+ } catch {
113365
+ try {
113366
+ const repaired = data.replace(/,\s*([\]}])/g, "$1");
113367
+ config = JSON.parse(repaired);
113368
+ } catch {
113369
+ try {
113370
+ const backupFile = `${configFile}.corrupt.${Date.now()}`;
113371
+ await fs17.writeFile(backupFile, data, "utf-8");
113372
+ } catch {}
113373
+ return { providers: {} };
113374
+ }
113375
+ }
113317
113376
  try {
113318
113377
  const workspacePath = path17.join(process.cwd(), ".december", "settings.json");
113319
113378
  const wData = await fs17.readFile(workspacePath, "utf-8");
113320
113379
  const workspaceConfig = JSON.parse(wData);
113321
113380
  config = deepMergeSettings(config, workspaceConfig);
113322
113381
  } catch {}
113323
- if (!config.activeProvider && config.providers && Object.keys(config.providers).length > 0) {
113324
- config.activeProvider = Object.keys(config.providers)[0];
113382
+ if (!config || typeof config !== "object") {
113383
+ config = { providers: {} };
113384
+ } else if (!config.providers || typeof config.providers !== "object" || Array.isArray(config.providers)) {
113385
+ config.providers = {};
113386
+ }
113387
+ if (!config.activeProvider) {
113388
+ if (config.providers && Object.keys(config.providers).length > 0) {
113389
+ config.activeProvider = Object.keys(config.providers)[0];
113390
+ } else if (config.subscriptions && Object.keys(config.subscriptions).length > 0) {
113391
+ config.activeProvider = Object.keys(config.subscriptions)[0];
113392
+ if (!config.authPriority) {
113393
+ config.authPriority = "subscription";
113394
+ }
113395
+ }
113325
113396
  }
113326
113397
  return config;
113327
113398
  } catch {
@@ -113372,21 +113443,24 @@ function resolveSubscriptionBundle(config) {
113372
113443
  if (activeProvider && config.subscriptions[activeProvider]) {
113373
113444
  return { provider: activeProvider, bundle: config.subscriptions[activeProvider] };
113374
113445
  }
113375
- const hasByokForActive = !!(activeProvider && config.providers && config.providers[activeProvider]);
113376
- if (config.authPriority === "subscription" || !hasByokForActive) {
113377
- if (activeProvider === "anthropic" && config.subscriptions["claude"]) {
113446
+ if (activeProvider) {
113447
+ if ((activeProvider === "anthropic" || activeProvider === "claude") && config.subscriptions["claude"]) {
113378
113448
  return { provider: "claude", bundle: config.subscriptions["claude"] };
113379
113449
  }
113380
- if (activeProvider === "openai" && config.subscriptions["codex"]) {
113450
+ if ((activeProvider === "openai" || activeProvider === "codex" || activeProvider === "chatgpt") && config.subscriptions["codex"]) {
113381
113451
  return { provider: "codex", bundle: config.subscriptions["codex"] };
113382
113452
  }
113383
- if (activeProvider === "google" && config.subscriptions["gemini"]) {
113384
- return { provider: "gemini", bundle: config.subscriptions["gemini"] };
113453
+ if ((activeProvider === "google" || activeProvider === "gemini" || activeProvider === "antigravity") && (config.subscriptions["gemini"] || config.subscriptions["google"] || config.subscriptions["antigravity"])) {
113454
+ const bundle = config.subscriptions["gemini"] || config.subscriptions["google"] || config.subscriptions["antigravity"];
113455
+ return { provider: bundle.provider || "gemini", bundle };
113385
113456
  }
113386
113457
  }
113387
- if (config.authPriority === "subscription") {
113458
+ const hasByokForActive = !!(activeProvider && config.providers && config.providers[activeProvider]);
113459
+ if (config.authPriority === "subscription" || !hasByokForActive || !activeProvider) {
113388
113460
  const firstKey = Object.keys(config.subscriptions)[0];
113389
- return { provider: firstKey, bundle: config.subscriptions[firstKey] };
113461
+ if (firstKey && config.subscriptions[firstKey]) {
113462
+ return { provider: firstKey, bundle: config.subscriptions[firstKey] };
113463
+ }
113390
113464
  }
113391
113465
  return;
113392
113466
  }
@@ -113412,7 +113486,7 @@ async function getProviderConfig() {
113412
113486
  authMethod: "byok"
113413
113487
  };
113414
113488
  }
113415
- if (subMatch && config.authPriority !== "byok" && config.authPriority !== "december") {
113489
+ if (subMatch && (config.authPriority === "subscription" || !hasByokConfig && config.authPriority !== "december" || config.authPriority !== "byok" && config.authPriority !== "december")) {
113416
113490
  await Promise.resolve().then(() => init_subscription_manager());
113417
113491
  const resolvedBundle = await resolveSubscriptionToken(subMatch.provider, subMatch.bundle);
113418
113492
  const targetProvider = resolvedBundle.provider || subMatch.provider;
@@ -114311,18 +114385,19 @@ function formatSubscriptionToast(bundle, activeModel) {
114311
114385
  const modelPart = activeModel ? ` • ${activeModel}` : "";
114312
114386
  return `Connected to ${subject}${accountPart}${modelPart}`;
114313
114387
  }
114388
+ function formatSubscriptionSuccessMessage(provider) {
114389
+ const providerName = formatSubscriptionDisplayName(provider);
114390
+ return `${providerName} connected successfully`;
114391
+ }
114314
114392
  function formatSubscriptionCard(bundle, _activeModel) {
114315
- const providerName = formatSubscriptionDisplayName(bundle.provider);
114316
114393
  const plan = formatSubscriptionPlan(bundle);
114317
114394
  const identity = formatSubscriptionIdentity(bundle);
114318
- const lines = [`Linked ${providerName} Subscription`, ` • Plan: ${plan}`];
114319
114395
  if (identity) {
114320
114396
  const isGithub = bundle.provider === "copilot" || bundle.provider === "github";
114321
114397
  const accountDisplay = isGithub && identity.startsWith("@") ? `[${identity}](https://github.com/${identity.slice(1)})` : identity;
114322
- lines.push(` • Account: ${accountDisplay}`);
114398
+ return `Plan: ${plan} (${accountDisplay})`;
114323
114399
  }
114324
- return lines.join(`
114325
- `);
114400
+ return `Plan: ${plan}`;
114326
114401
  }
114327
114402
 
114328
114403
  // src/auth/subscriptions/index.ts
@@ -114335,11 +114410,15 @@ var init_subscriptions = __esm(() => {
114335
114410
  });
114336
114411
 
114337
114412
  // src/auth/device.ts
114338
- async function loginViaDeviceCode(serverUrl = process.env.SERVER_URL || "https://api.trydecember.com", onCodeGenerated) {
114413
+ async function loginViaDeviceCode(serverUrl = process.env.SERVER_URL || "https://api.trydecember.com", onCodeGenerated, signal) {
114414
+ if (signal?.aborted) {
114415
+ throw new Error("Login cancelled");
114416
+ }
114339
114417
  try {
114340
114418
  const genRes = await fetch(`${serverUrl}/api/v1/auth/device/code`, {
114341
114419
  method: "POST",
114342
- headers: { "Content-Type": "application/json" }
114420
+ headers: { "Content-Type": "application/json" },
114421
+ signal
114343
114422
  });
114344
114423
  let genData = {};
114345
114424
  try {
@@ -114350,13 +114429,30 @@ async function loginViaDeviceCode(serverUrl = process.env.SERVER_URL || "https:/
114350
114429
  }
114351
114430
  const { deviceCode, userCode, verificationUri, expiresIn, interval } = genData.data;
114352
114431
  onCodeGenerated(userCode, verificationUri);
114353
- const fullUrl = verificationUri.includes("?") ? `${verificationUri}&code=${encodeURIComponent(userCode)}` : `${verificationUri}?code=${encodeURIComponent(userCode)}`;
114354
- openUrl(fullUrl).catch(() => {});
114355
114432
  const startTime = Date.now();
114356
114433
  const pollInterval = interval * 1000 || 5000;
114357
114434
  return await new Promise((resolve, reject) => {
114435
+ let timeoutId = null;
114436
+ const onAbort = () => {
114437
+ if (timeoutId)
114438
+ clearTimeout(timeoutId);
114439
+ reject(new Error("Login cancelled"));
114440
+ };
114441
+ if (signal) {
114442
+ if (signal.aborted) {
114443
+ onAbort();
114444
+ return;
114445
+ }
114446
+ signal.addEventListener("abort", onAbort, { once: true });
114447
+ }
114358
114448
  const poll = async () => {
114449
+ if (signal?.aborted) {
114450
+ onAbort();
114451
+ return;
114452
+ }
114359
114453
  if (Date.now() - startTime > expiresIn * 1000) {
114454
+ if (signal)
114455
+ signal.removeEventListener("abort", onAbort);
114360
114456
  reject(new Error("Device code expired"));
114361
114457
  return;
114362
114458
  }
@@ -114364,10 +114460,13 @@ async function loginViaDeviceCode(serverUrl = process.env.SERVER_URL || "https:/
114364
114460
  const tokenRes = await fetch(`${serverUrl}/api/v1/auth/device/token`, {
114365
114461
  method: "POST",
114366
114462
  headers: { "Content-Type": "application/json" },
114367
- body: JSON.stringify({ deviceCode })
114463
+ body: JSON.stringify({ deviceCode }),
114464
+ signal
114368
114465
  });
114369
114466
  const tokenData = await tokenRes.json();
114370
114467
  if (tokenRes.ok && tokenData.success) {
114468
+ if (signal)
114469
+ signal.removeEventListener("abort", onAbort);
114371
114470
  resolve({
114372
114471
  token: tokenData.data.token,
114373
114472
  email: tokenData.data.email
@@ -114375,17 +114474,30 @@ async function loginViaDeviceCode(serverUrl = process.env.SERVER_URL || "https:/
114375
114474
  return;
114376
114475
  }
114377
114476
  if (tokenData.message === "authorization_pending") {
114378
- setTimeout(poll, pollInterval);
114477
+ if (!signal?.aborted) {
114478
+ timeoutId = setTimeout(poll, pollInterval);
114479
+ }
114379
114480
  } else {
114481
+ if (signal)
114482
+ signal.removeEventListener("abort", onAbort);
114380
114483
  reject(new Error(tokenData.message || "Polling failed"));
114381
114484
  }
114382
114485
  } catch (err) {
114383
- setTimeout(poll, pollInterval);
114486
+ if (signal?.aborted || err?.name === "AbortError") {
114487
+ onAbort();
114488
+ return;
114489
+ }
114490
+ if (!signal?.aborted) {
114491
+ timeoutId = setTimeout(poll, pollInterval);
114492
+ }
114384
114493
  }
114385
114494
  };
114386
- setTimeout(poll, pollInterval);
114495
+ timeoutId = setTimeout(poll, pollInterval);
114387
114496
  });
114388
114497
  } catch (err) {
114498
+ if (signal?.aborted || err?.name === "AbortError" || err?.message?.includes("cancelled")) {
114499
+ throw new Error("Login cancelled");
114500
+ }
114389
114501
  const msg = err?.message || String(err);
114390
114502
  if (msg.includes("fetch failed") || msg.includes("ECONNREFUSED") || msg.includes("ENOTFOUND") || msg.includes("Failed to fetch") || msg.includes("connect")) {
114391
114503
  throw new Error("Unable to connect. Is the computer able to access the url?", {
@@ -114396,13 +114508,9 @@ async function loginViaDeviceCode(serverUrl = process.env.SERVER_URL || "https:/
114396
114508
  }
114397
114509
  }
114398
114510
  }
114399
- var init_device = __esm(() => {
114400
- init_open();
114401
- });
114402
114511
 
114403
114512
  // src/auth/index.ts
114404
114513
  var init_auth = __esm(() => {
114405
- init_device();
114406
114514
  init_subscriptions();
114407
114515
  });
114408
114516
 
@@ -114781,7 +114889,7 @@ function isPermissionDeniedError2(errMsg) {
114781
114889
  }
114782
114890
  function detectInstallMethod(options) {
114783
114891
  const configMethod = options?.configInstallMethod;
114784
- const validMethods = ["npm", "bun", "pnpm", "npx", "source"];
114892
+ const validMethods = ["npm", "bun", "pnpm", "npx", "curl", "source"];
114785
114893
  if (configMethod && validMethods.includes(configMethod)) {
114786
114894
  return configMethod;
114787
114895
  }
@@ -114803,6 +114911,9 @@ function detectInstallMethod(options) {
114803
114911
  if (combined.includes("/_npx/") || combined.includes("\\_npx\\") || combined.includes("/.bunx/") || env.npm_config_user_agent?.includes("npx")) {
114804
114912
  return "npx";
114805
114913
  }
114914
+ if (execPath.includes(".december/bin") || combined.includes(".december/bin") || execPath.includes(".local/bin/december") || combined.includes(".local/bin/december") || execPath.endsWith("/december") && !execPath.includes("node_modules") && !execPath.includes(".bun") && !execPath.includes("/node") || execPath.endsWith("/december.exe") || combined.includes("december.exe")) {
114915
+ return "curl";
114916
+ }
114806
114917
  if (combined.includes(".bun/bin") || combined.includes("/.bun/") || execPath.includes("/bun") && !execPath.endsWith("/node")) {
114807
114918
  return "bun";
114808
114919
  }
@@ -114813,6 +114924,15 @@ function detectInstallMethod(options) {
114813
114924
  }
114814
114925
  function getUpdateCommand(method, _platform = process.platform) {
114815
114926
  switch (method) {
114927
+ case "curl": {
114928
+ const isWin = _platform === "win32" || process.platform === "win32";
114929
+ const cmd = isWin ? 'powershell -c "irm https://trydecember.com/install.ps1 | iex"' : "curl -fsSL https://trydecember.com/install.sh | bash";
114930
+ return {
114931
+ command: cmd,
114932
+ manualCmd: cmd,
114933
+ description: isWin ? "Standalone binary via PowerShell installer" : "Standalone binary via curl installer"
114934
+ };
114935
+ }
114816
114936
  case "bun": {
114817
114937
  return {
114818
114938
  command: "bun add -g @trydecember/cli@latest",
@@ -114874,8 +114994,8 @@ async function performCliUpdate(options) {
114874
114994
  });
114875
114995
  if (!options?.configInstallMethod && preDiagnosis?.activeBinary?.manager) {
114876
114996
  const activeMgr = preDiagnosis.activeBinary.manager;
114877
- if (activeMgr === "bun" || activeMgr === "npm" || activeMgr === "pnpm" || activeMgr === "source") {
114878
- detectedMethod = activeMgr;
114997
+ if (activeMgr === "bun" || activeMgr === "npm" || activeMgr === "pnpm" || activeMgr === "curl" || activeMgr === "standalone" || activeMgr === "source") {
114998
+ detectedMethod = activeMgr === "standalone" ? "curl" : activeMgr;
114879
114999
  }
114880
115000
  }
114881
115001
  const method = detectedMethod;
@@ -114892,6 +115012,19 @@ async function performCliUpdate(options) {
114892
115012
  output: msg
114893
115013
  };
114894
115014
  }
115015
+ if (method === "curl") {
115016
+ const msg = `Standalone installation detected. To update, re-run the installer:
115017
+ ${manualCmd}`;
115018
+ options?.onProgress?.(msg);
115019
+ return {
115020
+ success: true,
115021
+ method: "curl",
115022
+ command,
115023
+ manualCmd,
115024
+ verified: true,
115025
+ output: msg
115026
+ };
115027
+ }
114895
115028
  if (method === "npx") {
114896
115029
  const msg = "Running December CLI via npx/bunx. Each invocation automatically uses the latest version.";
114897
115030
  options?.onProgress?.(msg);
@@ -115397,7 +115530,10 @@ async function handleLoginCommand(options) {
115397
115530
  const targetProvider = (options?.provider || "december").toLowerCase().trim();
115398
115531
  await Promise.resolve().then(() => init_config());
115399
115532
  if (targetProvider === "copilot" || targetProvider === "github" || targetProvider === "claude" || targetProvider === "codex" || targetProvider === "chatgpt" || targetProvider === "openai" || targetProvider === "gemini" || targetProvider === "google" || targetProvider === "antigravity") {
115400
- await Promise.resolve().then(() => init_subscriptions());
115533
+ const {
115534
+ formatSubscriptionPlan,
115535
+ formatSubscriptionIdentity
115536
+ } = await Promise.resolve().then(() => (init_subscriptions(), {}));
115401
115537
  const providerName = formatSubscriptionDisplayName(targetProvider);
115402
115538
  console.log(`
115403
115539
  Initiating subscription login for ${providerName}...`);
@@ -115418,37 +115554,86 @@ Waiting for authorization...`);
115418
115554
  await Promise.resolve().then(() => init_models5());
115419
115555
  fetchLiveProviderModels(bundle.provider, bundle.accessToken, bundle.endpoint).catch(() => {});
115420
115556
  const GREEN = "\x1B[38;2;110;231;183m";
115421
- const WHITE = "\x1B[38;2;244;244;245m";
115422
- const BRAND = "\x1B[38;2;137;180;248m";
115423
115557
  const RESET = "\x1B[0m";
115424
- const plan = formatSubscriptionPlan(bundle);
115425
- const identity = formatSubscriptionIdentity(bundle);
115426
115558
  console.log(`
115427
- ${GREEN}Linked ${providerName} Subscription${RESET}`);
115428
- console.log(` • Plan: ${WHITE}${plan}${RESET}`);
115429
- if (identity) {
115430
- console.log(` • Account: ${BRAND}${identity}${RESET}`);
115431
- }
115559
+ ${GREEN}${formatSubscriptionSuccessMessage(bundle.provider)}${RESET}`);
115560
+ console.log(formatSubscriptionCard(bundle));
115432
115561
  console.log();
115433
115562
  return;
115434
115563
  }
115564
+ const config = await loadConfig();
115565
+ if (config.decemberToken) {
115566
+ const userEmail = config.email || "December user";
115567
+ if (process.stdin.isTTY) {
115568
+ const readline = await import("node:readline/promises");
115569
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
115570
+ const answer = (await rl.question(`
115571
+ You are already logged in as ${userEmail}.
115572
+ Do you want to switch to a different account? (y/N): `)).trim().toLowerCase();
115573
+ rl.close();
115574
+ if (answer !== "y" && answer !== "yes") {
115575
+ console.log(`
115576
+ Already logged in as ${userEmail}. Keeping current session.
115577
+ `);
115578
+ return;
115579
+ }
115580
+ }
115581
+ }
115435
115582
  await Promise.resolve().then(() => init_auth());
115583
+ await Promise.resolve().then(() => init_open());
115436
115584
  console.log(`
115437
115585
  Generating device code for December login...`);
115438
- const { token, email } = await loginViaDeviceCode(undefined, (code, uri) => {
115439
- console.log(`
115440
- Please open ${uri} on any device and enter code: ${code}
115441
- Waiting for authorization...`);
115442
- });
115443
- const configToSave = await loadConfig();
115444
- configToSave.decemberToken = token;
115445
- if (email)
115446
- configToSave.email = email;
115447
- configToSave.authPriority = "december";
115448
- configToSave.activeModel = "december-auto";
115449
- await saveConfig(configToSave);
115450
- console.log(`\x1B[32mSuccessfully logged in via device code!\x1B[0m
115586
+ let keypressListener = null;
115587
+ const cleanupKeypress = () => {
115588
+ if (keypressListener && process.stdin.isTTY) {
115589
+ process.stdin.removeListener("data", keypressListener);
115590
+ keypressListener = null;
115591
+ try {
115592
+ process.stdin.setRawMode(false);
115593
+ process.stdin.pause();
115594
+ } catch {}
115595
+ }
115596
+ };
115597
+ try {
115598
+ const { token, email } = await loginViaDeviceCode(undefined, (code, uri) => {
115599
+ const fullUrl = uri.includes("?") ? `${uri}&code=${encodeURIComponent(code)}` : `${uri}?code=${encodeURIComponent(code)}`;
115600
+ console.log(`
115601
+ Confirm code: ${code}
115602
+ Open URL: ${fullUrl}
115603
+
115604
+ Press [o] to open in browser · Esc to cancel
115605
+ Waiting for approval...`);
115606
+ if (process.stdin.isTTY) {
115607
+ try {
115608
+ process.stdin.setRawMode(true);
115609
+ process.stdin.resume();
115610
+ keypressListener = (data) => {
115611
+ const char = data.toString();
115612
+ if (char === "o" || char === "O") {
115613
+ openUrl(fullUrl).catch(() => {});
115614
+ } else if (char === "\x03" || char === "\x1B") {
115615
+ cleanupKeypress();
115616
+ process.exit(0);
115617
+ }
115618
+ };
115619
+ process.stdin.on("data", keypressListener);
115620
+ } catch {}
115621
+ }
115622
+ });
115623
+ cleanupKeypress();
115624
+ const configToSave = await loadConfig();
115625
+ configToSave.decemberToken = token;
115626
+ if (email)
115627
+ configToSave.email = email;
115628
+ configToSave.authPriority = "december";
115629
+ configToSave.activeModel = "december-auto";
115630
+ await saveConfig(configToSave);
115631
+ console.log(`\x1B[32mSuccessfully logged in via device code!\x1B[0m
115451
115632
  `);
115633
+ } catch (err) {
115634
+ cleanupKeypress();
115635
+ throw err;
115636
+ }
115452
115637
  }
115453
115638
  async function handleUpdateCommand(options) {
115454
115639
  await Promise.resolve().then(() => init_updater());
@@ -168112,6 +168297,7 @@ async function runInnerLoop(agent, eventQueue, signal, options) {
168112
168297
  toolCalls
168113
168298
  });
168114
168299
  await executeToolCalls(agent, toolCalls, eventQueue, signal, options);
168300
+ eventQueue.push({ type: "AgentStatus", message: "Working..." });
168115
168301
  }
168116
168302
  await agent.saveContext();
168117
168303
  eventQueue.push({ type: "TurnEnd" });
@@ -169880,10 +170066,33 @@ function resolveWorkspaceRoot(targetDir = process.cwd()) {
169880
170066
  }
169881
170067
  return resolved;
169882
170068
  }
170069
+ function formatDisplayPath(targetPath) {
170070
+ const home = path26.resolve(os13.homedir());
170071
+ const resolved = path26.resolve(targetPath);
170072
+ if (resolved === home) {
170073
+ return "~";
170074
+ }
170075
+ if (resolved.startsWith(home + path26.sep)) {
170076
+ return "~" + resolved.slice(home.length);
170077
+ }
170078
+ return resolved;
170079
+ }
169883
170080
  function isWorkspaceTrusted(workspaceRoot, config) {
169884
- const canonicalRoot = path26.resolve(workspaceRoot);
170081
+ let canonicalRoot = path26.resolve(workspaceRoot);
170082
+ try {
170083
+ if (fs25.existsSync(canonicalRoot)) {
170084
+ canonicalRoot = fs25.realpathSync(canonicalRoot);
170085
+ }
170086
+ } catch {}
169885
170087
  const homeDir = path26.resolve(os13.homedir());
169886
- const trustedList = (config.trustedWorkspaces || []).map((p) => path26.resolve(p));
170088
+ const trustedList = (config.trustedWorkspaces || []).map((p) => {
170089
+ const resolved = path26.resolve(p);
170090
+ try {
170091
+ return fs25.existsSync(resolved) ? fs25.realpathSync(resolved) : resolved;
170092
+ } catch {
170093
+ return resolved;
170094
+ }
170095
+ });
169887
170096
  for (const trustedPath of trustedList) {
169888
170097
  if (canonicalRoot === trustedPath) {
169889
170098
  return true;
@@ -169899,8 +170108,20 @@ function isWorkspaceTrusted(workspaceRoot, config) {
169899
170108
  }
169900
170109
  async function addTrustedWorkspace(workspaceRoot) {
169901
170110
  const config = await loadConfig();
169902
- const canonical = path26.resolve(workspaceRoot);
169903
- const existing = (config.trustedWorkspaces || []).map((p) => path26.resolve(p));
170111
+ let canonical = path26.resolve(workspaceRoot);
170112
+ try {
170113
+ if (fs25.existsSync(canonical)) {
170114
+ canonical = fs25.realpathSync(canonical);
170115
+ }
170116
+ } catch {}
170117
+ const existing = (config.trustedWorkspaces || []).map((p) => {
170118
+ const resolved = path26.resolve(p);
170119
+ try {
170120
+ return fs25.existsSync(resolved) ? fs25.realpathSync(resolved) : resolved;
170121
+ } catch {
170122
+ return resolved;
170123
+ }
170124
+ });
169904
170125
  if (!existing.includes(canonical)) {
169905
170126
  config.trustedWorkspaces = [...existing, canonical];
169906
170127
  await saveConfig(config);
@@ -169912,20 +170133,22 @@ async function promptWorkspaceTrust(workspaceRoot) {
169912
170133
  }
169913
170134
  const homeDir = path26.resolve(os13.homedir());
169914
170135
  const isHomeOrRoot = workspaceRoot === homeDir || workspaceRoot === "/";
169915
- const BRAND = "\x1B[38;2;137;180;248m";
169916
- const TEXT = "\x1B[38;2;244;244;245m";
169917
- const MUTED = "\x1B[38;2;170;170;170m";
169918
- const GRAY = "\x1B[38;2;119;119;119m";
169919
- const YELLOW = "\x1B[38;2;253;214;99m";
170136
+ const displayPath = formatDisplayPath(workspaceRoot);
170137
+ const BRAND_BLUE = "\x1B[38;2;137;180;248m";
170138
+ const BLUE = BRAND_BLUE;
170139
+ const WHITE = "\x1B[38;2;244;244;245m";
170140
+ const GRAY = "\x1B[38;2;161;161;170m";
170141
+ const YELLOW = "\x1B[38;2;253;224;71m";
169920
170142
  const BOLD = "\x1B[1m";
169921
170143
  const RESET = "\x1B[0m";
169922
170144
  const options = isHomeOrRoot ? [
169923
- { label: "No, exit", value: false },
169924
- { label: "Yes, trust folder anyway", value: true }
170145
+ { label: "Cancel", value: false },
170146
+ { label: "Trust and continue anyway", value: true }
169925
170147
  ] : [
169926
- { label: "Yes, trust folder", value: true },
169927
- { label: "No, exit", value: false }
170148
+ { label: "Trust and continue", value: true },
170149
+ { label: "Cancel", value: false }
169928
170150
  ];
170151
+ console.clear();
169929
170152
  return new Promise((resolve) => {
169930
170153
  let selectedIndex = 0;
169931
170154
  let renderedLineCount = 0;
@@ -169946,7 +170169,7 @@ async function promptWorkspaceTrust(workspaceRoot) {
169946
170169
  const clearRenderedLines = () => {
169947
170170
  if (renderedLineCount > 0) {
169948
170171
  readline3.cursorTo(process.stdout, 0);
169949
- readline3.moveCursor(process.stdout, 0, -renderedLineCount);
170172
+ readline3.moveCursor(process.stdout, 0, -(renderedLineCount - 1));
169950
170173
  readline3.clearScreenDown(process.stdout);
169951
170174
  }
169952
170175
  };
@@ -169954,25 +170177,21 @@ async function promptWorkspaceTrust(workspaceRoot) {
169954
170177
  clearRenderedLines();
169955
170178
  const lines = [];
169956
170179
  lines.push("");
169957
- lines.push(` ${BOLD}${TEXT}Trust workspace?${RESET}`);
169958
- lines.push("");
169959
- lines.push(` ${GRAY}Directory${RESET} ${BOLD}${BRAND}${workspaceRoot}${RESET}`);
170180
+ lines.push(` ${BOLD}${WHITE}Trust workspace:${RESET} ${BRAND_BLUE}${displayPath}${RESET}`);
169960
170181
  if (isHomeOrRoot) {
169961
- lines.push(` ${YELLOW}Warning${RESET} ${YELLOW}Home or system root directory. Gives access to all personal files.${RESET}`);
169962
- } else {
169963
- lines.push(` ${GRAY}Permission${RESET} ${TEXT}Read, edit, and run commands${RESET}`);
170182
+ lines.push(` ${YELLOW}Warning: Home or root directory gives access to all personal files.${RESET}`);
169964
170183
  }
169965
170184
  lines.push("");
169966
170185
  for (let i = 0;i < options.length; i++) {
169967
170186
  const opt = options[i];
169968
170187
  if (i === selectedIndex) {
169969
- lines.push(` ${BRAND}❭${RESET} ${BOLD}${TEXT}${opt.label}${RESET}`);
170188
+ lines.push(` ${BLUE}❭${RESET} ${BOLD}${WHITE}${opt.label}${RESET}`);
169970
170189
  } else {
169971
- lines.push(` ${MUTED}${opt.label}${RESET}`);
170190
+ lines.push(` ${GRAY}${opt.label}${RESET}`);
169972
170191
  }
169973
170192
  }
169974
170193
  lines.push("");
169975
- lines.push(` ${BRAND}Enter${RESET} ${MUTED}confirm${RESET} ${MUTED}·${RESET} ${BRAND}Esc${RESET} ${MUTED}cancel${RESET} ${MUTED}·${RESET} ${BRAND}↑↓${RESET} ${MUTED}navigate${RESET}`);
170194
+ lines.push(` ${GRAY}Enter confirm · Esc cancel${RESET}`);
169976
170195
  lines.push("");
169977
170196
  renderedLineCount = lines.length;
169978
170197
  process.stdout.write(lines.join(`
@@ -169983,13 +170202,13 @@ async function promptWorkspaceTrust(workspaceRoot) {
169983
170202
  return;
169984
170203
  const lowerStr = (str || "").toLowerCase();
169985
170204
  const keyName = key?.name;
169986
- if (lowerStr === "y" || keyName === "y") {
170205
+ if (lowerStr === "t" || lowerStr === "y") {
169987
170206
  cleanup();
169988
170207
  clearRenderedLines();
169989
170208
  resolve(true);
169990
170209
  return;
169991
170210
  }
169992
- if (lowerStr === "n" || keyName === "n") {
170211
+ if (lowerStr === "c" || lowerStr === "n") {
169993
170212
  cleanup();
169994
170213
  clearRenderedLines();
169995
170214
  resolve(false);
@@ -170001,7 +170220,7 @@ async function promptWorkspaceTrust(workspaceRoot) {
170001
170220
  } else if (keyName === "down" || keyName === "j" || keyName === "tab") {
170002
170221
  selectedIndex = Math.min(options.length - 1, selectedIndex + 1);
170003
170222
  render();
170004
- } else if (keyName === "return" || keyName === "enter") {
170223
+ } else if (keyName === "return" || keyName === "enter" || keyName === "space") {
170005
170224
  cleanup();
170006
170225
  clearRenderedLines();
170007
170226
  resolve(options[selectedIndex].value);
@@ -176865,11 +177084,26 @@ function instantiateProvider(provider, apiKey, options) {
176865
177084
  }
176866
177085
  return openaiProvider(undefined, apiKey);
176867
177086
  }
176868
- case "antigravity":
177087
+ case "antigravity": {
177088
+ const subscription = options?.subscription;
177089
+ const getToken = subscription ? async () => {
177090
+ try {
177091
+ const refreshed = await resolveSubscriptionToken("gemini", subscription);
177092
+ if (refreshed?.accessToken) {
177093
+ subscription.accessToken = refreshed.accessToken;
177094
+ subscription.expiresAt = refreshed.expiresAt;
177095
+ subscription.endpoint = refreshed.endpoint;
177096
+ return refreshed.accessToken;
177097
+ }
177098
+ } catch {}
177099
+ return subscription.accessToken;
177100
+ } : undefined;
176869
177101
  return antigravityProvider(apiKey, {
176870
177102
  endpoint: options?.baseURL,
176871
- headers: options?.headers
177103
+ headers: options?.headers,
177104
+ getToken
176872
177105
  });
177106
+ }
176873
177107
  case "claude":
176874
177108
  case "anthropic": {
176875
177109
  if (options?.authMethod === "subscription" || options?.subscription) {
@@ -176888,9 +177122,23 @@ function instantiateProvider(provider, apiKey, options) {
176888
177122
  case "google": {
176889
177123
  if (options?.authMethod === "subscription" || options?.subscription) {
176890
177124
  const endpoint = options?.baseURL || options?.subscription?.endpoint;
177125
+ const subscription = options?.subscription;
177126
+ const getToken = subscription ? async () => {
177127
+ try {
177128
+ const refreshed = await resolveSubscriptionToken("gemini", subscription);
177129
+ if (refreshed?.accessToken) {
177130
+ subscription.accessToken = refreshed.accessToken;
177131
+ subscription.expiresAt = refreshed.expiresAt;
177132
+ subscription.endpoint = refreshed.endpoint;
177133
+ return refreshed.accessToken;
177134
+ }
177135
+ } catch {}
177136
+ return subscription.accessToken;
177137
+ } : undefined;
176891
177138
  return antigravityProvider(apiKey, {
176892
177139
  endpoint,
176893
- headers: options?.headers
177140
+ headers: options?.headers,
177141
+ getToken
176894
177142
  });
176895
177143
  }
176896
177144
  return geminiProvider(apiKey);
@@ -215991,7 +216239,7 @@ function InlineDialog({ config, close }) {
215991
216239
  return /* @__PURE__ */ jsx_runtime2.jsxs(Box_default, {
215992
216240
  flexDirection: "column",
215993
216241
  width: panelWidth,
215994
- borderStyle: "round",
216242
+ borderStyle: "single",
215995
216243
  borderColor: THEME.colors.border,
215996
216244
  paddingX: 1,
215997
216245
  paddingY: 0,
@@ -216199,6 +216447,14 @@ var init_prompt_history = __esm(() => {
216199
216447
  import { spawnSync } from "child_process";
216200
216448
  import * as os19 from "os";
216201
216449
  function writeToClipboard(text) {
216450
+ if (!text)
216451
+ return;
216452
+ try {
216453
+ if (process.stdout?.isTTY) {
216454
+ const base64 = Buffer.from(text, "utf8").toString("base64");
216455
+ process.stdout.write(`\x1B]52;c;${base64}\x07`);
216456
+ }
216457
+ } catch {}
216202
216458
  const platform = os19.platform();
216203
216459
  try {
216204
216460
  const isWsl = platform === "linux" && (!!process.env.WSL_DISTRO_NAME || os19.release().toLowerCase().includes("microsoft"));
@@ -216214,9 +216470,7 @@ function writeToClipboard(text) {
216214
216470
  spawnSync("xsel", ["--clipboard", "--input"], { input: text });
216215
216471
  }
216216
216472
  }
216217
- } catch (err) {
216218
- console.error("Failed to copy to clipboard", err);
216219
- }
216473
+ } catch {}
216220
216474
  }
216221
216475
  var init_clipboard = () => {};
216222
216476
 
@@ -216557,6 +216811,12 @@ var init_commands2 = __esm(() => {
216557
216811
  value: "/tasks",
216558
216812
  action: (ctx) => {}
216559
216813
  },
216814
+ {
216815
+ name: "tui",
216816
+ description: "Switch TUI renderer mode (fullscreen / classic)",
216817
+ value: "/tui",
216818
+ action: (ctx) => {}
216819
+ },
216560
216820
  {
216561
216821
  name: "update",
216562
216822
  description: "Update to the latest version",
@@ -216885,10 +217145,9 @@ function ShortcutsMenu({ onClose }) {
216885
217145
  const itemsBelow = SHORTCUTS.length - windowEnd;
216886
217146
  return /* @__PURE__ */ jsx_runtime6.jsxs(Box_default, {
216887
217147
  flexDirection: "column",
216888
- paddingX: THEME.padding.paddingX,
216889
217148
  children: [
216890
217149
  itemsAbove > 0 && /* @__PURE__ */ jsx_runtime6.jsx(Box_default, {
216891
- paddingLeft: 1,
217150
+ paddingLeft: 2,
216892
217151
  children: /* @__PURE__ */ jsx_runtime6.jsxs(Text3, {
216893
217152
  color: THEME.colors.muted,
216894
217153
  children: [
@@ -216927,7 +217186,7 @@ function ShortcutsMenu({ onClose }) {
216927
217186
  }, cmd.key);
216928
217187
  }),
216929
217188
  itemsBelow > 0 && /* @__PURE__ */ jsx_runtime6.jsx(Box_default, {
216930
- paddingLeft: 1,
217189
+ paddingLeft: 2,
216931
217190
  children: /* @__PURE__ */ jsx_runtime6.jsxs(Text3, {
216932
217191
  color: THEME.colors.muted,
216933
217192
  children: [
@@ -216938,7 +217197,7 @@ function ShortcutsMenu({ onClose }) {
216938
217197
  })
216939
217198
  }),
216940
217199
  /* @__PURE__ */ jsx_runtime6.jsx(Box_default, {
216941
- paddingLeft: 1,
217200
+ paddingLeft: 2,
216942
217201
  paddingTop: 1,
216943
217202
  children: /* @__PURE__ */ jsx_runtime6.jsxs(Text3, {
216944
217203
  color: THEME.colors.muted,
@@ -217501,6 +217760,7 @@ var init_input_bar = __esm(async () => {
217501
217760
  disabled = false,
217502
217761
  placeholder = "Ask December to build features, fix bugs, or work on your code...",
217503
217762
  activeModel = "unknown",
217763
+ modelLabel,
217504
217764
  authMethod,
217505
217765
  isAuthenticated = true,
217506
217766
  hasBothAuth = false,
@@ -217524,7 +217784,8 @@ var init_input_bar = __esm(async () => {
217524
217784
  tasks,
217525
217785
  onScrollUp,
217526
217786
  onScrollDown,
217527
- onStartVoice
217787
+ onStartVoice,
217788
+ onExit
217528
217789
  }) {
217529
217790
  const [value, setValue] = import_react42.useState("");
217530
217791
  const [isVoiceActive, setIsVoiceActive] = import_react42.useState(false);
@@ -217825,7 +218086,13 @@ var init_input_bar = __esm(async () => {
217825
218086
  }
217826
218087
  if (command.action) {
217827
218088
  command.action({
217828
- exit: () => process.exit(0),
218089
+ exit: () => {
218090
+ if (onExit) {
218091
+ onExit();
218092
+ } else {
218093
+ process.exit(0);
218094
+ }
218095
+ },
217829
218096
  toast,
217830
218097
  dialog,
217831
218098
  agent,
@@ -217834,6 +218101,7 @@ var init_input_bar = __esm(async () => {
217834
218101
  });
217835
218102
  }
217836
218103
  }, [
218104
+ onExit,
217837
218105
  toast,
217838
218106
  dialog,
217839
218107
  agent,
@@ -217896,7 +218164,7 @@ var init_input_bar = __esm(async () => {
217896
218164
  ]);
217897
218165
  const paddingLeft = THEME.padding.paddingLeft ?? THEME.padding.paddingX;
217898
218166
  const paddingRight = THEME.padding.paddingRight ?? 4;
217899
- const sepWidth = Math.max(10, columns - paddingLeft - paddingRight - 2);
218167
+ const sepWidth = Math.max(10, columns - paddingLeft - paddingRight);
217900
218168
  const sep = "─".repeat(sepWidth);
217901
218169
  const isOverlayActive = Boolean(authUI || workflowUI) && !customInputMode;
217902
218170
  const activeModeTag = planWorkflowPhase === "grilling" || grillMode ? "[GRILL]" : planWorkflowPhase === "executing" ? "[EXEC]" : planWorkflowPhase === "reviewing" || planWorkflowPhase === "refining" || planRefineMode || planMode || interactivePlanGoalMode ? "[PLAN]" : null;
@@ -217926,13 +218194,11 @@ var init_input_bar = __esm(async () => {
217926
218194
  }),
217927
218195
  showFileMenu && matchingFiles.length > 0 && /* @__PURE__ */ jsx_runtime8.jsx(Box_default, {
217928
218196
  flexDirection: "column",
217929
- paddingLeft: 1,
217930
218197
  marginBottom: 0,
217931
218198
  children: matchingFiles.map((file, idx) => {
217932
218199
  const isSelected = idx === selectedFileIndex;
217933
218200
  return /* @__PURE__ */ jsx_runtime8.jsxs(Box_default, {
217934
218201
  flexDirection: "row",
217935
- gap: 1,
217936
218202
  children: [
217937
218203
  /* @__PURE__ */ jsx_runtime8.jsx(Text3, {
217938
218204
  color: isSelected ? THEME.colors.brand : THEME.colors.muted,
@@ -218096,7 +218362,7 @@ var init_input_bar = __esm(async () => {
218096
218362
  " "
218097
218363
  ]
218098
218364
  }) : null,
218099
- !isAuthenticated ? "Not connected (run /login)" : `${activeModel}${authMethod === "subscription" ? " (Subscription)" : authMethod === "december" ? " (December Cloud)" : authMethod === "byok" ? " (BYOK)" : ""}`
218365
+ !isAuthenticated ? "Not connected (run /login)" : modelLabel || activeModel
218100
218366
  ]
218101
218367
  }),
218102
218368
  totalTasksCount > 0 && /* @__PURE__ */ jsx_runtime8.jsxs(Text3, {
@@ -218154,10 +218420,12 @@ var init_scroll_viewport = __esm(async () => {
218154
218420
  onScrollStateChange,
218155
218421
  isGenerating = false,
218156
218422
  isActive = true,
218157
- showIndicator = true
218423
+ showIndicator = true,
218424
+ onCopy
218158
218425
  }, ref) {
218159
218426
  const viewportRef = import_react43.useRef(null);
218160
218427
  const contentRef = import_react43.useRef(null);
218428
+ const isDraggingRef = import_react43.useRef(false);
218161
218429
  const defaultHeight = explicitHeight ?? (typeof process !== "undefined" && process.stdout?.rows ? Math.max(1, process.stdout.rows - 6) : 24);
218162
218430
  const [viewportHeight, setViewportHeight] = import_react43.useState(defaultHeight);
218163
218431
  const [contentHeight, setContentHeight] = import_react43.useState(0);
@@ -218184,6 +218452,7 @@ var init_scroll_viewport = __esm(async () => {
218184
218452
  scrollTop
218185
218453
  };
218186
218454
  const lastContentMeasureTimeRef = import_react43.useRef(0);
218455
+ const throttleTimerRef = import_react43.useRef(null);
218187
218456
  const pendingX10MouseRef = import_react43.useRef(false);
218188
218457
  import_react43.useLayoutEffect(() => {
218189
218458
  let vHeight = explicitHeight ?? viewportHeight;
@@ -218200,18 +218469,40 @@ var init_scroll_viewport = __esm(async () => {
218200
218469
  if (contentRef.current) {
218201
218470
  const now = Date.now();
218202
218471
  const shouldThrottle = isGenerating && !isReadingMode;
218203
- if (!shouldThrottle || now - lastContentMeasureTimeRef.current >= 80) {
218472
+ const elapsed = now - lastContentMeasureTimeRef.current;
218473
+ if (!shouldThrottle || elapsed >= 80) {
218474
+ if (throttleTimerRef.current) {
218475
+ clearTimeout(throttleTimerRef.current);
218476
+ throttleTimerRef.current = null;
218477
+ }
218204
218478
  lastContentMeasureTimeRef.current = now;
218205
218479
  const cMeasured = measure_element_default(contentRef.current);
218206
218480
  if (cMeasured.height !== prevContentHeightRef.current) {
218207
218481
  prevContentHeightRef.current = cMeasured.height;
218208
218482
  setContentHeight(cMeasured.height);
218209
218483
  }
218484
+ } else if (!throttleTimerRef.current) {
218485
+ throttleTimerRef.current = setTimeout(() => {
218486
+ throttleTimerRef.current = null;
218487
+ if (contentRef.current) {
218488
+ lastContentMeasureTimeRef.current = Date.now();
218489
+ const cMeasured = measure_element_default(contentRef.current);
218490
+ if (cMeasured.height !== prevContentHeightRef.current) {
218491
+ prevContentHeightRef.current = cMeasured.height;
218492
+ setContentHeight(cMeasured.height);
218493
+ }
218494
+ }
218495
+ }, Math.max(10, 80 - elapsed));
218210
218496
  }
218211
218497
  }
218212
218498
  });
218213
218499
  import_react43.useEffect(() => {
218214
- if (!isGenerating && contentRef.current) {
218500
+ if (contentRef.current) {
218501
+ if (throttleTimerRef.current) {
218502
+ clearTimeout(throttleTimerRef.current);
218503
+ throttleTimerRef.current = null;
218504
+ }
218505
+ lastContentMeasureTimeRef.current = Date.now();
218215
218506
  const cMeasured = measure_element_default(contentRef.current);
218216
218507
  if (cMeasured.height !== prevContentHeightRef.current) {
218217
218508
  prevContentHeightRef.current = cMeasured.height;
@@ -218219,6 +218510,14 @@ var init_scroll_viewport = __esm(async () => {
218219
218510
  }
218220
218511
  }
218221
218512
  }, [isGenerating]);
218513
+ import_react43.useEffect(() => {
218514
+ return () => {
218515
+ if (throttleTimerRef.current) {
218516
+ clearTimeout(throttleTimerRef.current);
218517
+ throttleTimerRef.current = null;
218518
+ }
218519
+ };
218520
+ }, []);
218222
218521
  import_react43.useEffect(() => {
218223
218522
  if (controlledScrollFromBottom !== undefined) {
218224
218523
  if (controlledScrollFromBottom === 0) {
@@ -218318,6 +218617,17 @@ var init_scroll_viewport = __esm(async () => {
218318
218617
  handleScrollDown(3 * downCount);
218319
218618
  return;
218320
218619
  }
218620
+ if (/\[<32;\d+;\d+;M/.test(input)) {
218621
+ isDraggingRef.current = true;
218622
+ return;
218623
+ }
218624
+ if (/\[<(?:0|32);\d+;\d+;m/.test(input)) {
218625
+ if (isDraggingRef.current) {
218626
+ isDraggingRef.current = false;
218627
+ onCopy?.();
218628
+ }
218629
+ return;
218630
+ }
218321
218631
  const pageSize = Math.max(1, stateRef.current.viewportHeight - 2);
218322
218632
  if (key.pageUp) {
218323
218633
  handleScrollUp(pageSize);
@@ -220238,7 +220548,7 @@ function parseTuiError(message, cause, hint) {
220238
220548
  const cleanCause = (c) => c?.replace(/^Cause:\s*/i, "").trim();
220239
220549
  const cleanMessage = (m) => m.replace(/^Error:\s*/i, "").trim();
220240
220550
  const cleanHint = (h) => h?.replace(/^Hint:\s*/i, "").trim();
220241
- if (cause || hint) {
220551
+ if (hint) {
220242
220552
  return {
220243
220553
  message: cleanMessage(message),
220244
220554
  cause: cleanCause(cause),
@@ -220246,6 +220556,27 @@ function parseTuiError(message, cause, hint) {
220246
220556
  };
220247
220557
  }
220248
220558
  const clean = cleanMessage(message);
220559
+ if (clean.includes("Insufficient credits in December Wallet")) {
220560
+ const lines = clean.split(`
220561
+ `).map((l) => l.trim()).filter(Boolean);
220562
+ const firstLine = lines[0] || "";
220563
+ const rest = cleanCause(lines.slice(1).join(`
220564
+ `));
220565
+ const hintMatch = firstLine.match(/Please (?:add credits|top up|check|upgrade|run|switch|configure).*$/i);
220566
+ const summary = hintMatch ? firstLine.replace(/Please (?:add credits|top up|check|upgrade|run|switch|configure).*$/i, "").replace(/^402\s*/, "").trim() : firstLine.replace(/^402\s*/, "").trim() || "Insufficient credits in December Wallet.";
220567
+ return {
220568
+ message: summary || "Insufficient credits in December Wallet.",
220569
+ cause: rest || cleanCause(cause),
220570
+ hint: hintMatch ? hintMatch[0].trim() : "Please add credits at https://app.trydecember.com/settings/billing or configure Bring Your Own Key (BYOK) via `/login` to continue using December."
220571
+ };
220572
+ }
220573
+ if (cause) {
220574
+ return {
220575
+ message: cleanMessage(message),
220576
+ cause: cleanCause(cause),
220577
+ hint: cleanHint(hint)
220578
+ };
220579
+ }
220249
220580
  if (clean.includes(`
220250
220581
  `)) {
220251
220582
  const lines = clean.split(`
@@ -220253,6 +220584,12 @@ function parseTuiError(message, cause, hint) {
220253
220584
  const firstLine = lines[0] || "";
220254
220585
  const rest = cleanCause(lines.slice(1).join(`
220255
220586
  `));
220587
+ if (firstLine.startsWith("Unable to connect") || firstLine.includes("Connection error") || firstLine.includes("Connection refused") || firstLine.includes("timed out") || clean.includes("Endpoint:")) {
220588
+ return {
220589
+ message: clean,
220590
+ cause: cleanCause(cause)
220591
+ };
220592
+ }
220256
220593
  if (firstLine.includes("Rate limit or quota exhausted")) {
220257
220594
  const hintMatch = firstLine.match(/Please.*$/i);
220258
220595
  const summary = firstLine.replace(/Please.*$/i, "").trim();
@@ -220321,6 +220658,20 @@ function parseTuiError(message, cause, hint) {
220321
220658
  cause: rest
220322
220659
  };
220323
220660
  }
220661
+ const cleanLower = clean.toLowerCase();
220662
+ if (clean === "Connection error." || cleanLower === "connection error" || cleanLower.startsWith("connection error")) {
220663
+ return {
220664
+ message: "Unable to connect to LLM provider (Connection error).",
220665
+ cause: cleanCause(cause),
220666
+ hint: cleanHint(hint)
220667
+ };
220668
+ }
220669
+ if (clean.startsWith("Unable to connect to ") && !hint) {
220670
+ return {
220671
+ message: clean,
220672
+ cause: cleanCause(cause)
220673
+ };
220674
+ }
220324
220675
  return {
220325
220676
  message: clean
220326
220677
  };
@@ -263006,7 +263357,7 @@ function Mermaid({ code }) {
263006
263357
  flexDirection: "column",
263007
263358
  paddingX: 2,
263008
263359
  paddingY: 1,
263009
- borderStyle: "round",
263360
+ borderStyle: "single",
263010
263361
  borderColor: THEME.colors.border,
263011
263362
  children: [
263012
263363
  /* @__PURE__ */ jsx_runtime13.jsxs(Box_default, {
@@ -263072,7 +263423,7 @@ function RenderFlowchart({ code }) {
263072
263423
  return /* @__PURE__ */ jsx_runtime13.jsxs(import_react47.default.Fragment, {
263073
263424
  children: [
263074
263425
  /* @__PURE__ */ jsx_runtime13.jsx(Box_default, {
263075
- borderStyle: "round",
263426
+ borderStyle: "single",
263076
263427
  borderColor: THEME.colors.border,
263077
263428
  paddingX: 1,
263078
263429
  children: /* @__PURE__ */ jsx_runtime13.jsx(Text3, {
@@ -263112,7 +263463,7 @@ function RenderFlowchart({ code }) {
263112
263463
  flexDirection: "column",
263113
263464
  children: [
263114
263465
  /* @__PURE__ */ jsx_runtime13.jsx(Box_default, {
263115
- borderStyle: "round",
263466
+ borderStyle: "single",
263116
263467
  borderColor: THEME.colors.border,
263117
263468
  paddingX: 1,
263118
263469
  children: /* @__PURE__ */ jsx_runtime13.jsx(Text3, {
@@ -263195,7 +263546,7 @@ function RenderSequence({ code }) {
263195
263546
  flexDirection: "row",
263196
263547
  gap: 2,
263197
263548
  children: participants.map((p) => /* @__PURE__ */ jsx_runtime13.jsx(Box_default, {
263198
- borderStyle: "round",
263549
+ borderStyle: "single",
263199
263550
  borderColor: THEME.colors.border,
263200
263551
  paddingX: 1,
263201
263552
  children: /* @__PURE__ */ jsx_runtime13.jsx(Text3, {
@@ -263443,7 +263794,7 @@ function Table({ token }) {
263443
263794
  marginY: 1,
263444
263795
  children: [
263445
263796
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263446
- color: THEME.colors.dim,
263797
+ color: THEME.colors.border,
263447
263798
  children: topBorder
263448
263799
  }),
263449
263800
  headers.length > 0 && /* @__PURE__ */ jsx_runtime14.jsxs(jsx_runtime14.Fragment, {
@@ -263452,7 +263803,7 @@ function Table({ token }) {
263452
263803
  flexDirection: "row",
263453
263804
  children: [
263454
263805
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263455
- color: THEME.colors.dim,
263806
+ color: THEME.colors.border,
263456
263807
  children: "│"
263457
263808
  }),
263458
263809
  colWidths.map((w, c) => /* @__PURE__ */ jsx_runtime14.jsxs(import_react48.default.Fragment, {
@@ -263467,7 +263818,7 @@ function Table({ token }) {
263467
263818
  })
263468
263819
  }),
263469
263820
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263470
- color: THEME.colors.dim,
263821
+ color: THEME.colors.border,
263471
263822
  children: "│"
263472
263823
  })
263473
263824
  ]
@@ -263475,7 +263826,7 @@ function Table({ token }) {
263475
263826
  ]
263476
263827
  }, `h-${l}`)),
263477
263828
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263478
- color: THEME.colors.dim,
263829
+ color: THEME.colors.border,
263479
263830
  children: headerSep
263480
263831
  })
263481
263832
  ]
@@ -263488,7 +263839,7 @@ function Table({ token }) {
263488
263839
  flexDirection: "row",
263489
263840
  children: [
263490
263841
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263491
- color: THEME.colors.dim,
263842
+ color: THEME.colors.border,
263492
263843
  children: "│"
263493
263844
  }),
263494
263845
  colWidths.map((w, c) => /* @__PURE__ */ jsx_runtime14.jsxs(import_react48.default.Fragment, {
@@ -263502,7 +263853,7 @@ function Table({ token }) {
263502
263853
  })
263503
263854
  }),
263504
263855
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263505
- color: THEME.colors.dim,
263856
+ color: THEME.colors.border,
263506
263857
  children: "│"
263507
263858
  })
263508
263859
  ]
@@ -263512,7 +263863,7 @@ function Table({ token }) {
263512
263863
  }, r);
263513
263864
  }),
263514
263865
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263515
- color: THEME.colors.dim,
263866
+ color: THEME.colors.border,
263516
263867
  children: bottomBorder
263517
263868
  })
263518
263869
  ]
@@ -263646,16 +263997,16 @@ function parseMarkdownTokens(source) {
263646
263997
  astCache.set(source, tokens);
263647
263998
  return tokens;
263648
263999
  }
263649
- var import_cli_highlight, import_react48, jsx_runtime14, CALLOUT_BORDER, renderToken = (token, index) => {
264000
+ var import_cli_highlight, import_react48, jsx_runtime14, CALLOUT_BORDER, renderToken = (token, index, isStreaming) => {
263650
264001
  switch (token.type) {
263651
264002
  case "paragraph":
263652
264003
  return /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263653
- children: token.tokens?.map((t, i) => renderToken(t, i))
264004
+ children: token.tokens?.map((t, i) => renderToken(t, i, isStreaming))
263654
264005
  }, index);
263655
264006
  case "text":
263656
264007
  if ("tokens" in token && token.tokens) {
263657
264008
  return /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263658
- children: token.tokens.map((t, i) => renderToken(t, i))
264009
+ children: token.tokens.map((t, i) => renderToken(t, i, isStreaming))
263659
264010
  }, index);
263660
264011
  }
263661
264012
  return /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
@@ -263664,12 +264015,12 @@ var import_cli_highlight, import_react48, jsx_runtime14, CALLOUT_BORDER, renderT
263664
264015
  case "strong":
263665
264016
  return /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263666
264017
  bold: true,
263667
- children: token.tokens?.map((t, i) => renderToken(t, i))
264018
+ children: token.tokens?.map((t, i) => renderToken(t, i, isStreaming))
263668
264019
  }, index);
263669
264020
  case "em":
263670
264021
  return /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263671
264022
  italic: true,
263672
- children: token.tokens?.map((t, i) => renderToken(t, i))
264023
+ children: token.tokens?.map((t, i) => renderToken(t, i, isStreaming))
263673
264024
  }, index);
263674
264025
  case "codespan": {
263675
264026
  if (isFilePath(token.text)) {
@@ -263699,7 +264050,8 @@ var import_cli_highlight, import_react48, jsx_runtime14, CALLOUT_BORDER, renderT
263699
264050
  }, index);
263700
264051
  }
263701
264052
  return /* @__PURE__ */ jsx_runtime14.jsx(CodeBlock, {
263702
- token
264053
+ token,
264054
+ isStreaming
263703
264055
  }, index);
263704
264056
  case "list":
263705
264057
  return /* @__PURE__ */ jsx_runtime14.jsx(Box_default, {
@@ -263715,7 +264067,7 @@ var import_cli_highlight, import_react48, jsx_runtime14, CALLOUT_BORDER, renderT
263715
264067
  /* @__PURE__ */ jsx_runtime14.jsx(Box_default, {
263716
264068
  flexDirection: "column",
263717
264069
  flexShrink: 1,
263718
- children: item.tokens.map((t, j) => renderToken(t, j))
264070
+ children: item.tokens.map((t, j) => renderToken(t, j, isStreaming))
263719
264071
  })
263720
264072
  ]
263721
264073
  }, i))
@@ -263731,7 +264083,7 @@ var import_cli_highlight, import_react48, jsx_runtime14, CALLOUT_BORDER, renderT
263731
264083
  }),
263732
264084
  /* @__PURE__ */ jsx_runtime14.jsx(Text3, {
263733
264085
  color: THEME.colors.brand,
263734
- children: token.tokens?.map((t, i) => renderToken(t, i))
264086
+ children: token.tokens?.map((t, i) => renderToken(t, i, isStreaming))
263735
264087
  })
263736
264088
  ]
263737
264089
  }, index);
@@ -263793,13 +264145,19 @@ var init_markdown = __esm(async () => {
263793
264145
  };
263794
264146
  highlightCache = new Map;
263795
264147
  astCache = new Map;
263796
- CodeBlock = import_react48.default.memo(function CodeBlock({ token }) {
264148
+ CodeBlock = import_react48.default.memo(function CodeBlock({
264149
+ token,
264150
+ isStreaming
264151
+ }) {
263797
264152
  const lang = token.lang || "typescript";
263798
264153
  const highlighted = import_react48.default.useMemo(() => {
263799
264154
  if (!token.text)
263800
264155
  return "";
264156
+ if (isStreaming) {
264157
+ return token.text;
264158
+ }
263801
264159
  return getHighlightedCode(token.text, lang);
263802
- }, [token.text, lang]);
264160
+ }, [token.text, lang, isStreaming]);
263803
264161
  return /* @__PURE__ */ jsx_runtime14.jsx(Box_default, {
263804
264162
  flexDirection: "column",
263805
264163
  paddingY: 1,
@@ -263809,7 +264167,7 @@ var init_markdown = __esm(async () => {
263809
264167
  })
263810
264168
  });
263811
264169
  });
263812
- Markdown = import_react48.default.memo(function Markdown({ children }) {
264170
+ Markdown = import_react48.default.memo(function Markdown({ children, isStreaming }) {
263813
264171
  const tokens = import_react48.default.useMemo(() => {
263814
264172
  return parseMarkdownTokens(children);
263815
264173
  }, [children]);
@@ -263818,7 +264176,7 @@ var init_markdown = __esm(async () => {
263818
264176
  return /* @__PURE__ */ jsx_runtime14.jsx(Box_default, {
263819
264177
  flexDirection: "column",
263820
264178
  gap: 1,
263821
- children: tokens.map((token, index) => renderToken(token, index))
264179
+ children: tokens.map((token, index) => renderToken(token, index, isStreaming))
263822
264180
  });
263823
264181
  });
263824
264182
  });
@@ -263874,6 +264232,7 @@ function SmoothMarkdown({ text, isRunning }) {
263874
264232
  content: committed
263875
264233
  }) : null,
263876
264234
  sanitizedTail && sanitizedTail.trim() !== "" ? /* @__PURE__ */ jsx_runtime15.jsx(Markdown, {
264235
+ isStreaming: true,
263877
264236
  children: sanitizedTail
263878
264237
  }) : null
263879
264238
  ]
@@ -264764,6 +265123,102 @@ function getCwd() {
264764
265123
  return "~";
264765
265124
  }
264766
265125
  }
265126
+ function formatModelDisplayName(model) {
265127
+ if (!model)
265128
+ return "";
265129
+ const m = model.trim();
265130
+ const lower = m.toLowerCase();
265131
+ const curated = {
265132
+ "claude-3-7-sonnet": "Claude 3.7 Sonnet",
265133
+ "claude-3.7-sonnet": "Claude 3.7 Sonnet",
265134
+ "claude-3-5-sonnet": "Claude 3.5 Sonnet",
265135
+ "claude-3.5-sonnet": "Claude 3.5 Sonnet",
265136
+ "claude-3-5-haiku": "Claude 3.5 Haiku",
265137
+ "claude-3.5-haiku": "Claude 3.5 Haiku",
265138
+ "claude-4-5-opus": "Claude 4.5 Opus",
265139
+ "claude-4.5-opus": "Claude 4.5 Opus",
265140
+ "claude-opus-5": "Claude Opus 5",
265141
+ "claude-sonnet-4.6": "Claude Sonnet 4.6",
265142
+ "claude-sonnet-5": "Claude Sonnet 5",
265143
+ "gemini-2.5-flash": "Gemini 2.5 Flash",
265144
+ "gemini-2.5-pro": "Gemini 2.5 Pro",
265145
+ "gemini-3.7-flash": "Gemini 3.7 Flash",
265146
+ "gemini-3.6-flash": "Gemini 3.6 Flash",
265147
+ "gemini-3.8-flash": "Gemini 3.8 Flash",
265148
+ "gpt-5.6-sol": "GPT-5.6 Sol",
265149
+ "gpt-5.6-luna": "GPT-5.6 Luna",
265150
+ "gpt-4o": "GPT-4o",
265151
+ "gpt-4o-mini": "GPT-4o Mini",
265152
+ o1: "o1",
265153
+ "o1-mini": "o1-mini",
265154
+ o3: "o3",
265155
+ "o3-mini": "o3-mini",
265156
+ "o4-mini": "o4-mini",
265157
+ "december-auto": "Humans R1",
265158
+ auto: "Humans R1",
265159
+ "humans-r1": "Humans R1"
265160
+ };
265161
+ if (curated[lower])
265162
+ return curated[lower];
265163
+ const parts = m.split(/[/:]/);
265164
+ const last = parts[parts.length - 1];
265165
+ return last.split(/[-_]/).map((part) => {
265166
+ if (/^\d+(\.\d+)*$/.test(part))
265167
+ return part;
265168
+ if (/^(gpt|llm|ai|api|oss)$/i.test(part))
265169
+ return part.toUpperCase();
265170
+ return part.charAt(0).toUpperCase() + part.slice(1);
265171
+ }).join(" ");
265172
+ }
265173
+ function formatBillingLabel(authMethod, provider, model, isAuthenticated = true) {
265174
+ if (!isAuthenticated) {
265175
+ return "Not connected · Run /login";
265176
+ }
265177
+ const p = (provider || "").toLowerCase().trim();
265178
+ const m = (model || "").toLowerCase().trim();
265179
+ let brand = "API";
265180
+ if (p === "copilot" || p === "github") {
265181
+ brand = "Copilot";
265182
+ } else if (p === "claude" || p === "anthropic") {
265183
+ brand = "Claude";
265184
+ } else if (p === "codex" || p === "chatgpt") {
265185
+ brand = "ChatGPT";
265186
+ } else if (p === "openai") {
265187
+ brand = authMethod === "subscription" ? "ChatGPT" : "OpenAI";
265188
+ } else if (p === "gemini" || p === "google") {
265189
+ brand = "Gemini";
265190
+ } else if (p === "deepseek") {
265191
+ brand = "DeepSeek";
265192
+ } else if (p === "groq") {
265193
+ brand = "Groq";
265194
+ } else if (p === "mistral" || p.includes("mistral")) {
265195
+ brand = "Mistral";
265196
+ } else if (p === "openrouter") {
265197
+ brand = "OpenRouter";
265198
+ } else if (p === "ollama") {
265199
+ brand = "Ollama";
265200
+ } else if (p) {
265201
+ brand = p.charAt(0).toUpperCase() + p.slice(1);
265202
+ } else if (m.includes("claude") || m.includes("sonnet") || m.includes("opus") || m.includes("haiku")) {
265203
+ brand = "Claude";
265204
+ } else if (m.includes("gpt") || m.includes("o1") || m.includes("o3") || m.includes("o4")) {
265205
+ brand = authMethod === "subscription" ? "ChatGPT" : "OpenAI";
265206
+ } else if (m.includes("gemini")) {
265207
+ brand = "Gemini";
265208
+ } else if (m.includes("deepseek")) {
265209
+ brand = "DeepSeek";
265210
+ }
265211
+ if (authMethod === "december") {
265212
+ return "December Wallet";
265213
+ }
265214
+ if (authMethod === "subscription") {
265215
+ return `${brand} Subscription`;
265216
+ }
265217
+ if (authMethod === "byok" || authMethod === "env") {
265218
+ return brand === "Ollama" ? "Ollama Local" : `${brand} API`;
265219
+ }
265220
+ return brand ? `${brand} API` : "API";
265221
+ }
264767
265222
  var import_react51, jsx_runtime17, cachedBranch = undefined, Header;
264768
265223
  var init_header = __esm(async () => {
264769
265224
  init_theme();
@@ -264775,10 +265230,29 @@ var init_header = __esm(async () => {
264775
265230
  cliVersion = "0.1.0",
264776
265231
  latestVersion,
264777
265232
  userEmail,
264778
- announcement
265233
+ announcement,
265234
+ activeModel,
265235
+ modelLabel,
265236
+ authMethod,
265237
+ selectedProvider,
265238
+ isAuthenticated
264779
265239
  }) {
264780
265240
  const cwd = getCwd();
264781
265241
  const branch = getGitBranch();
265242
+ let modelStatusLine = null;
265243
+ if (isAuthenticated === false) {
265244
+ modelStatusLine = "Not connected · Run /login";
265245
+ } else {
265246
+ const modelName = modelLabel || formatModelDisplayName(activeModel);
265247
+ const billingLabel = formatBillingLabel(authMethod, selectedProvider, activeModel, isAuthenticated ?? true);
265248
+ if (modelName && billingLabel) {
265249
+ modelStatusLine = `${modelName} · ${billingLabel}`;
265250
+ } else if (modelName) {
265251
+ modelStatusLine = modelName;
265252
+ } else if (billingLabel) {
265253
+ modelStatusLine = billingLabel;
265254
+ }
265255
+ }
264782
265256
  return /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
264783
265257
  flexDirection: "column",
264784
265258
  paddingLeft: THEME.padding.paddingLeft ?? THEME.padding.paddingX,
@@ -264810,6 +265284,10 @@ var init_header = __esm(async () => {
264810
265284
  color: THEME.colors.subtle,
264811
265285
  children: userEmail
264812
265286
  }),
265287
+ modelStatusLine && /* @__PURE__ */ jsx_runtime17.jsx(Text3, {
265288
+ color: THEME.colors.subtle,
265289
+ children: modelStatusLine
265290
+ }),
264813
265291
  /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
264814
265292
  gap: 1,
264815
265293
  children: [
@@ -264868,7 +265346,7 @@ var init_header = __esm(async () => {
264868
265346
  })
264869
265347
  ]
264870
265348
  }),
264871
- announcement.bullets.map((bullet, idx) => /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
265349
+ announcement.bullets.slice(0, 2).map((bullet, idx) => /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
264872
265350
  children: [
264873
265351
  /* @__PURE__ */ jsx_runtime17.jsx(Text3, {
264874
265352
  color: THEME.colors.brand,
@@ -264953,7 +265431,6 @@ var init_user_message = __esm(async () => {
264953
265431
  // ../../packages/tui/src/components/message-list.tsx
264954
265432
  var import_react53, jsx_runtime19, MessageItem, MAX_WINDOW_MESSAGES = 20, MessageList;
264955
265433
  var init_message_list = __esm(async () => {
264956
- init_theme();
264957
265434
  await __promiseAll([
264958
265435
  init_build2(),
264959
265436
  init_header(),
@@ -264970,14 +265447,24 @@ var init_message_list = __esm(async () => {
264970
265447
  latestVersion,
264971
265448
  userEmail,
264972
265449
  expandCommands,
264973
- announcement
265450
+ announcement,
265451
+ activeModel,
265452
+ modelLabel,
265453
+ authMethod,
265454
+ selectedProvider,
265455
+ isAuthenticated
264974
265456
  }) {
264975
265457
  if (msg.role === "header") {
264976
265458
  return /* @__PURE__ */ jsx_runtime19.jsx(Header, {
264977
265459
  cliVersion,
264978
265460
  latestVersion,
264979
265461
  userEmail,
264980
- announcement
265462
+ announcement,
265463
+ activeModel,
265464
+ modelLabel,
265465
+ authMethod,
265466
+ selectedProvider,
265467
+ isAuthenticated
264981
265468
  });
264982
265469
  }
264983
265470
  if (msg.role === "user") {
@@ -265014,6 +265501,16 @@ var init_message_list = __esm(async () => {
265014
265501
  return false;
265015
265502
  if (prev.announcement !== next.announcement)
265016
265503
  return false;
265504
+ if (prev.isAuthenticated !== next.isAuthenticated)
265505
+ return false;
265506
+ if (prev.activeModel !== next.activeModel)
265507
+ return false;
265508
+ if (prev.modelLabel !== next.modelLabel)
265509
+ return false;
265510
+ if (prev.authMethod !== next.authMethod)
265511
+ return false;
265512
+ if (prev.selectedProvider !== next.selectedProvider)
265513
+ return false;
265017
265514
  return true;
265018
265515
  });
265019
265516
  MessageList = import_react53.default.memo(function MessageList({
@@ -265027,7 +265524,11 @@ var init_message_list = __esm(async () => {
265027
265524
  expandCommands,
265028
265525
  fullscreen = true,
265029
265526
  announcement,
265030
- isReadingMode = false
265527
+ isReadingMode = false,
265528
+ activeModel,
265529
+ modelLabel,
265530
+ authMethod,
265531
+ selectedProvider
265031
265532
  }) {
265032
265533
  if (fullscreen) {
265033
265534
  const allMessages = [...staticMessages, ...activeMessages];
@@ -265038,26 +265539,21 @@ var init_message_list = __esm(async () => {
265038
265539
  flexDirection: "column",
265039
265540
  width: "100%",
265040
265541
  children: [
265041
- hiddenCount > 0 && /* @__PURE__ */ jsx_runtime19.jsx(Box_default, {
265042
- paddingLeft: THEME.padding.paddingLeft ?? THEME.padding.paddingX,
265043
- paddingRight: THEME.padding.paddingRight ?? 4,
265044
- marginY: 1,
265045
- children: /* @__PURE__ */ jsx_runtime19.jsx(Box_default, {
265046
- children: /* @__PURE__ */ jsx_runtime19.jsx(Box_default, {
265047
- marginRight: 1,
265048
- children: /* @__PURE__ */ jsx_runtime19.jsx(Header, {
265049
- cliVersion,
265050
- latestVersion,
265051
- userEmail,
265052
- announcement
265053
- })
265054
- })
265055
- })
265542
+ hiddenCount > 0 && /* @__PURE__ */ jsx_runtime19.jsx(Header, {
265543
+ cliVersion,
265544
+ latestVersion,
265545
+ userEmail,
265546
+ announcement,
265547
+ activeModel,
265548
+ modelLabel,
265549
+ authMethod,
265550
+ selectedProvider,
265551
+ isAuthenticated
265056
265552
  }),
265057
265553
  visibleMessages.map((msg, index) => {
265058
265554
  const actualIndex = shouldWindow ? hiddenCount + index : index;
265059
265555
  const prevRole = actualIndex > 0 ? allMessages[actualIndex - 1]?.role : null;
265060
- const key = msg.id != null ? `${msg.id}-${actualIndex}` : `msg-idx-${actualIndex}`;
265556
+ const key = msg.id != null ? `${msg.id}` : `msg-idx-${actualIndex}`;
265061
265557
  return /* @__PURE__ */ jsx_runtime19.jsx(MessageItem, {
265062
265558
  msg,
265063
265559
  index: actualIndex,
@@ -265066,7 +265562,12 @@ var init_message_list = __esm(async () => {
265066
265562
  latestVersion,
265067
265563
  userEmail,
265068
265564
  expandCommands,
265069
- announcement
265565
+ announcement,
265566
+ activeModel,
265567
+ modelLabel,
265568
+ authMethod,
265569
+ selectedProvider,
265570
+ isAuthenticated
265070
265571
  }, key);
265071
265572
  })
265072
265573
  ]
@@ -265081,7 +265582,7 @@ var init_message_list = __esm(async () => {
265081
265582
  style: { width: "100%" },
265082
265583
  children: (msg, index) => {
265083
265584
  const prevRole = index > 0 ? staticMessages[index - 1]?.role : null;
265084
- const key = msg.id != null ? `${msg.id}-${index}` : `msg-idx-${index}`;
265585
+ const key = msg.id != null ? `${msg.id}` : `msg-idx-${index}`;
265085
265586
  return /* @__PURE__ */ jsx_runtime19.jsx(MessageItem, {
265086
265587
  msg,
265087
265588
  index,
@@ -265090,7 +265591,12 @@ var init_message_list = __esm(async () => {
265090
265591
  latestVersion,
265091
265592
  userEmail,
265092
265593
  expandCommands,
265093
- announcement
265594
+ announcement,
265595
+ activeModel,
265596
+ modelLabel,
265597
+ authMethod,
265598
+ selectedProvider,
265599
+ isAuthenticated
265094
265600
  }, key);
265095
265601
  }
265096
265602
  }, staticKey),
@@ -265098,7 +265604,7 @@ var init_message_list = __esm(async () => {
265098
265604
  const actualIndex = staticMessages.length + index;
265099
265605
  const all = [...staticMessages, ...activeMessages];
265100
265606
  const prevRole = actualIndex > 0 ? all[actualIndex - 1]?.role : null;
265101
- const key = msg.id != null ? `${msg.id}-${actualIndex}` : `msg-idx-${actualIndex}`;
265607
+ const key = msg.id != null ? `${msg.id}` : `msg-idx-${actualIndex}`;
265102
265608
  return /* @__PURE__ */ jsx_runtime19.jsx(MessageItem, {
265103
265609
  msg,
265104
265610
  index: actualIndex,
@@ -265107,7 +265613,12 @@ var init_message_list = __esm(async () => {
265107
265613
  latestVersion,
265108
265614
  userEmail,
265109
265615
  expandCommands,
265110
- announcement
265616
+ announcement,
265617
+ activeModel,
265618
+ modelLabel,
265619
+ authMethod,
265620
+ selectedProvider,
265621
+ isAuthenticated
265111
265622
  }, key);
265112
265623
  })
265113
265624
  ]
@@ -265271,8 +265782,9 @@ function ByokProviderMenu(props) {
265271
265782
  const {
265272
265783
  handleProviderSelect,
265273
265784
  handleByokSelect,
265785
+ handleSubscriptionSelect,
265274
265786
  setAuthMode,
265275
- items = PROVIDER_MENU_ITEMS
265787
+ items = UNIFIED_PROVIDER_MENU_ITEMS
265276
265788
  } = props;
265277
265789
  const [selectedIndex, setSelectedIndex] = import_react56.useState(0);
265278
265790
  const [windowStart, setWindowStart] = import_react56.useState(0);
@@ -265328,8 +265840,15 @@ function ByokProviderMenu(props) {
265328
265840
  return;
265329
265841
  }
265330
265842
  if (key.return) {
265331
- if (onSelect && filteredItems[selectedIndex]) {
265332
- onSelect(filteredItems[selectedIndex]);
265843
+ const item = filteredItems[selectedIndex];
265844
+ if (item) {
265845
+ if (item.isSubscription && handleSubscriptionSelect) {
265846
+ handleSubscriptionSelect(item);
265847
+ return;
265848
+ }
265849
+ if (onSelect) {
265850
+ onSelect(item);
265851
+ }
265333
265852
  }
265334
265853
  return;
265335
265854
  }
@@ -265350,6 +265869,22 @@ function ByokProviderMenu(props) {
265350
265869
  const visibleItems = filteredItems.slice(windowStart, windowEnd);
265351
265870
  const itemsAbove = windowStart;
265352
265871
  const itemsBelow = filteredItems.length - windowEnd;
265872
+ const hasInlineHeader = visibleItems.some((item, relIdx) => {
265873
+ const absIdx = windowStart + relIdx;
265874
+ const prevItem = absIdx > 0 ? filteredItems[absIdx - 1] : null;
265875
+ return Boolean(item.section && (!prevItem || prevItem.section !== item.section));
265876
+ });
265877
+ const topSection = visibleItems[0]?.section;
265878
+ let stickyHeader = null;
265879
+ if (!hasInlineHeader && topSection) {
265880
+ if (topSection === "subscription") {
265881
+ stickyHeader = `${THEME.glyphs.bullet} Subscriptions`;
265882
+ } else if (topSection === "popular") {
265883
+ stickyHeader = `${THEME.glyphs.bullet} Popular`;
265884
+ } else if (topSection === "all") {
265885
+ stickyHeader = `${THEME.glyphs.bullet} All Providers`;
265886
+ }
265887
+ }
265353
265888
  const footerItems = isSearching ? [
265354
265889
  { key: "enter / ↓", label: "Focus List" },
265355
265890
  { key: "esc", label: "Exit Search" }
@@ -265359,9 +265894,10 @@ function ByokProviderMenu(props) {
265359
265894
  { key: "/", label: "Search" },
265360
265895
  { key: "esc", label: "Back" }
265361
265896
  ];
265897
+ const hasSubscriptions = items.some((i) => i.isSubscription);
265898
+ const menuTitle = props.title || (hasSubscriptions ? "Select Provider (Key or Subscription):" : "Select API Provider (BYOK):");
265362
265899
  return /* @__PURE__ */ jsx_runtime23.jsxs(Box_default, {
265363
265900
  flexDirection: "column",
265364
- paddingX: THEME.padding.paddingX,
265365
265901
  children: [
265366
265902
  /* @__PURE__ */ jsx_runtime23.jsxs(Box_default, {
265367
265903
  marginBottom: 1,
@@ -265370,7 +265906,7 @@ function ByokProviderMenu(props) {
265370
265906
  children: [
265371
265907
  /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
265372
265908
  color: THEME.colors.text,
265373
- children: "Select API Provider (BYOK):"
265909
+ children: menuTitle
265374
265910
  }),
265375
265911
  /* @__PURE__ */ jsx_runtime23.jsxs(Box_default, {
265376
265912
  flexDirection: "row",
@@ -265407,54 +265943,92 @@ function ByokProviderMenu(props) {
265407
265943
  })
265408
265944
  ]
265409
265945
  }),
265410
- itemsAbove > 0 && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265411
- paddingLeft: 2,
265412
- children: /* @__PURE__ */ jsx_runtime23.jsxs(Text3, {
265413
- color: THEME.colors.muted,
265414
- children: [
265415
- "↑ ",
265416
- itemsAbove,
265417
- " more"
265418
- ]
265419
- })
265420
- }),
265421
- visibleItems.map((item, relIdx) => {
265422
- const absIdx = windowStart + relIdx;
265423
- const isSelected = absIdx === selectedIndex;
265424
- return /* @__PURE__ */ jsx_runtime23.jsxs(Box_default, {
265425
- paddingLeft: 0,
265426
- children: [
265427
- /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265428
- marginRight: 1,
265429
- children: /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
265430
- color: THEME.colors.brand,
265431
- children: isSelected ? THEME.glyphs.selector : " "
265432
- })
265433
- }),
265434
- /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
265435
- color: isSelected ? THEME.colors.brand : THEME.colors.text,
265436
- children: item.label
265946
+ /* @__PURE__ */ jsx_runtime23.jsxs(Box_default, {
265947
+ flexDirection: "column",
265948
+ minHeight: 10,
265949
+ children: [
265950
+ itemsAbove > 0 && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265951
+ paddingLeft: 2,
265952
+ children: /* @__PURE__ */ jsx_runtime23.jsxs(Text3, {
265953
+ color: THEME.colors.muted,
265954
+ children: [
265955
+ "↑ ",
265956
+ itemsAbove,
265957
+ " more"
265958
+ ]
265437
265959
  })
265438
- ]
265439
- }, item.value);
265440
- }),
265441
- itemsBelow > 0 && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265442
- paddingLeft: 2,
265443
- children: /* @__PURE__ */ jsx_runtime23.jsxs(Text3, {
265444
- color: THEME.colors.muted,
265445
- children: [
265446
- "↓ ",
265447
- itemsBelow,
265448
- " more"
265449
- ]
265450
- })
265451
- }),
265452
- filteredItems.length === 0 && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265453
- paddingLeft: 2,
265454
- children: /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
265455
- color: THEME.colors.muted,
265456
- children: "No providers found."
265457
- })
265960
+ }),
265961
+ stickyHeader && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265962
+ paddingLeft: 2,
265963
+ marginY: 0,
265964
+ children: /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
265965
+ color: THEME.colors.subtle,
265966
+ children: stickyHeader
265967
+ })
265968
+ }),
265969
+ visibleItems.map((item, relIdx) => {
265970
+ const absIdx = windowStart + relIdx;
265971
+ const isSelected = absIdx === selectedIndex;
265972
+ const prevItem = absIdx > 0 ? filteredItems[absIdx - 1] : null;
265973
+ const isFirstInSection = item.section && (!prevItem || prevItem.section !== item.section);
265974
+ let sectionHeader = null;
265975
+ if (isFirstInSection) {
265976
+ if (item.section === "subscription") {
265977
+ sectionHeader = `${THEME.glyphs.bullet} Subscriptions`;
265978
+ } else if (item.section === "popular") {
265979
+ sectionHeader = `${THEME.glyphs.bullet} Popular`;
265980
+ } else if (item.section === "all") {
265981
+ sectionHeader = `${THEME.glyphs.bullet} All Providers`;
265982
+ }
265983
+ }
265984
+ return /* @__PURE__ */ jsx_runtime23.jsxs(import_react56.default.Fragment, {
265985
+ children: [
265986
+ sectionHeader && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265987
+ paddingLeft: 2,
265988
+ marginY: 0,
265989
+ children: /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
265990
+ color: THEME.colors.subtle,
265991
+ children: sectionHeader
265992
+ })
265993
+ }),
265994
+ /* @__PURE__ */ jsx_runtime23.jsxs(Box_default, {
265995
+ paddingLeft: 0,
265996
+ children: [
265997
+ /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
265998
+ marginRight: 1,
265999
+ children: /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
266000
+ color: THEME.colors.brand,
266001
+ children: isSelected ? THEME.glyphs.selector : " "
266002
+ })
266003
+ }),
266004
+ /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
266005
+ color: isSelected ? THEME.colors.brand : THEME.colors.text,
266006
+ children: item.label
266007
+ })
266008
+ ]
266009
+ })
266010
+ ]
266011
+ }, `${item.value}-${absIdx}`);
266012
+ }),
266013
+ itemsBelow > 0 && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
266014
+ paddingLeft: 2,
266015
+ children: /* @__PURE__ */ jsx_runtime23.jsxs(Text3, {
266016
+ color: THEME.colors.muted,
266017
+ children: [
266018
+ "↓ ",
266019
+ itemsBelow,
266020
+ " more"
266021
+ ]
266022
+ })
266023
+ }),
266024
+ filteredItems.length === 0 && /* @__PURE__ */ jsx_runtime23.jsx(Box_default, {
266025
+ paddingLeft: 2,
266026
+ children: /* @__PURE__ */ jsx_runtime23.jsx(Text3, {
266027
+ color: THEME.colors.muted,
266028
+ children: "No providers found."
266029
+ })
266030
+ })
266031
+ ]
265458
266032
  }),
265459
266033
  /* @__PURE__ */ jsx_runtime23.jsx(MenuFooter, {
265460
266034
  items: footerItems
@@ -265462,7 +266036,7 @@ function ByokProviderMenu(props) {
265462
266036
  ]
265463
266037
  });
265464
266038
  }
265465
- var import_react56, jsx_runtime23, WINDOW_SIZE4 = 7, PROVIDER_MENU_ITEMS;
266039
+ var import_react56, jsx_runtime23, WINDOW_SIZE4 = 7, PROVIDER_MENU_ITEMS, POPULAR_PROVIDER_VALUES, SUBSCRIPTION_PROVIDER_ITEMS, POPULAR_BYOK_ITEMS, REMAINING_BYOK_ITEMS, UNIFIED_PROVIDER_MENU_ITEMS;
265466
266040
  var init_byok_provider_menu = __esm(async () => {
265467
266041
  init_theme();
265468
266042
  await __promiseAll([
@@ -265660,6 +266234,44 @@ var init_byok_provider_menu = __esm(async () => {
265660
266234
  { label: "Zenifra", value: "zenifra" },
265661
266235
  { label: "ZenMux", value: "zenmux" }
265662
266236
  ];
266237
+ POPULAR_PROVIDER_VALUES = [
266238
+ "anthropic",
266239
+ "openai",
266240
+ "google",
266241
+ "openrouter",
266242
+ "deepseek",
266243
+ "groq",
266244
+ "mistral",
266245
+ "xai",
266246
+ "ollama",
266247
+ "perplexity",
266248
+ "cohere",
266249
+ "together",
266250
+ "fireworks",
266251
+ "cerebras",
266252
+ "sambanova"
266253
+ ];
266254
+ SUBSCRIPTION_PROVIDER_ITEMS = [
266255
+ { label: "Anthropic (Claude)", value: "claude", isSubscription: true, section: "subscription" },
266256
+ { label: "GitHub (Copilot)", value: "copilot", isSubscription: true, section: "subscription" },
266257
+ {
266258
+ label: "Google (Gemini / Antigravity)",
266259
+ value: "gemini",
266260
+ isSubscription: true,
266261
+ section: "subscription"
266262
+ },
266263
+ { label: "OpenAI (ChatGPT)", value: "codex", isSubscription: true, section: "subscription" }
266264
+ ];
266265
+ POPULAR_BYOK_ITEMS = POPULAR_PROVIDER_VALUES.map((val) => {
266266
+ const found = PROVIDER_MENU_ITEMS.find((item) => item.value === val);
266267
+ return found ? { ...found, section: "popular" } : null;
266268
+ }).filter(Boolean);
266269
+ REMAINING_BYOK_ITEMS = PROVIDER_MENU_ITEMS.filter((item) => !POPULAR_PROVIDER_VALUES.includes(item.value)).map((item) => ({ ...item, section: "all" }));
266270
+ UNIFIED_PROVIDER_MENU_ITEMS = [
266271
+ ...SUBSCRIPTION_PROVIDER_ITEMS,
266272
+ ...POPULAR_BYOK_ITEMS,
266273
+ ...REMAINING_BYOK_ITEMS
266274
+ ];
265663
266275
  });
265664
266276
 
265665
266277
  // ../../packages/tui/src/components/menus/byok-key-menu.tsx
@@ -265675,7 +266287,6 @@ function ByokKeyMenu(props) {
265675
266287
  const keyNote = selectedProvider ? PROVIDER_KEY_NOTES[selectedProvider.toLowerCase().trim()] : undefined;
265676
266288
  return /* @__PURE__ */ jsx_runtime24.jsxs(Box_default, {
265677
266289
  flexDirection: "column",
265678
- paddingX: THEME.padding.paddingX,
265679
266290
  children: [
265680
266291
  /* @__PURE__ */ jsx_runtime24.jsxs(Box_default, {
265681
266292
  flexDirection: "column",
@@ -266170,11 +266781,11 @@ function ContextSelectMenu(props) {
266170
266781
  filled++;
266171
266782
  }
266172
266783
  };
266173
- addSquares(Math.round(basePromptTokens / maxTokens * totalSquares), THEME.glyphs.status, THEME.colors.muted);
266174
- addSquares(Math.round(rulesTokens / maxTokens * totalSquares), THEME.glyphs.status, THEME.colors.warning);
266175
- addSquares(Math.round(skillsTokens / maxTokens * totalSquares), THEME.glyphs.status, THEME.colors.error);
266176
- addSquares(Math.round(toolsTokens / maxTokens * totalSquares), THEME.glyphs.status, THEME.colors.brand);
266177
- addSquares(Math.round(conversationHistoryTokens / maxTokens * totalSquares), THEME.glyphs.status, THEME.colors.success);
266784
+ addSquares(Math.round(basePromptTokens / maxTokens * totalSquares), "■", THEME.colors.muted);
266785
+ addSquares(Math.round(rulesTokens / maxTokens * totalSquares), "■", THEME.colors.warning);
266786
+ addSquares(Math.round(skillsTokens / maxTokens * totalSquares), "■", THEME.colors.error);
266787
+ addSquares(Math.round(toolsTokens / maxTokens * totalSquares), "■", THEME.colors.brand);
266788
+ addSquares(Math.round(conversationHistoryTokens / maxTokens * totalSquares), "■", THEME.colors.success);
266178
266789
  while (filled < totalSquares) {
266179
266790
  squares.push(/* @__PURE__ */ jsx_runtime25.jsx(Text3, {
266180
266791
  color: THEME.colors.border,
@@ -266191,7 +266802,6 @@ function ContextSelectMenu(props) {
266191
266802
  }
266192
266803
  return /* @__PURE__ */ jsx_runtime25.jsxs(Box_default, {
266193
266804
  flexDirection: "column",
266194
- paddingX: THEME.padding.paddingX,
266195
266805
  children: [
266196
266806
  /* @__PURE__ */ jsx_runtime25.jsx(Box_default, {
266197
266807
  marginBottom: 1,
@@ -266242,7 +266852,7 @@ function ContextSelectMenu(props) {
266242
266852
  children: [
266243
266853
  /* @__PURE__ */ jsx_runtime25.jsx(Text3, {
266244
266854
  color: THEME.colors.muted,
266245
- children: THEME.glyphs.status
266855
+ children: "■"
266246
266856
  }),
266247
266857
  /* @__PURE__ */ jsx_runtime25.jsxs(Text3, {
266248
266858
  color: THEME.colors.muted,
@@ -266261,7 +266871,7 @@ function ContextSelectMenu(props) {
266261
266871
  children: [
266262
266872
  /* @__PURE__ */ jsx_runtime25.jsx(Text3, {
266263
266873
  color: THEME.colors.warning,
266264
- children: THEME.glyphs.status
266874
+ children: "■"
266265
266875
  }),
266266
266876
  /* @__PURE__ */ jsx_runtime25.jsxs(Text3, {
266267
266877
  color: THEME.colors.muted,
@@ -266280,7 +266890,7 @@ function ContextSelectMenu(props) {
266280
266890
  children: [
266281
266891
  /* @__PURE__ */ jsx_runtime25.jsx(Text3, {
266282
266892
  color: THEME.colors.error,
266283
- children: THEME.glyphs.status
266893
+ children: "■"
266284
266894
  }),
266285
266895
  /* @__PURE__ */ jsx_runtime25.jsxs(Text3, {
266286
266896
  color: THEME.colors.muted,
@@ -266299,7 +266909,7 @@ function ContextSelectMenu(props) {
266299
266909
  children: [
266300
266910
  /* @__PURE__ */ jsx_runtime25.jsx(Text3, {
266301
266911
  color: THEME.colors.brand,
266302
- children: THEME.glyphs.status
266912
+ children: "■"
266303
266913
  }),
266304
266914
  /* @__PURE__ */ jsx_runtime25.jsxs(Text3, {
266305
266915
  color: THEME.colors.muted,
@@ -266318,7 +266928,7 @@ function ContextSelectMenu(props) {
266318
266928
  children: [
266319
266929
  /* @__PURE__ */ jsx_runtime25.jsx(Text3, {
266320
266930
  color: THEME.colors.success,
266321
- children: THEME.glyphs.status
266931
+ children: "■"
266322
266932
  }),
266323
266933
  /* @__PURE__ */ jsx_runtime25.jsxs(Text3, {
266324
266934
  color: THEME.colors.muted,
@@ -266885,7 +267495,6 @@ function GrillQuestionMenu(props) {
266885
267495
  if (confirmExit) {
266886
267496
  return /* @__PURE__ */ jsx_runtime26.jsxs(Box_default, {
266887
267497
  flexDirection: "column",
266888
- paddingX: THEME.padding.paddingX,
266889
267498
  children: [
266890
267499
  /* @__PURE__ */ jsx_runtime26.jsxs(Box_default, {
266891
267500
  marginBottom: 1,
@@ -266950,7 +267559,6 @@ function GrillQuestionMenu(props) {
266950
267559
  ];
266951
267560
  return /* @__PURE__ */ jsx_runtime26.jsxs(Box_default, {
266952
267561
  flexDirection: "column",
266953
- paddingX: THEME.padding.paddingX,
266954
267562
  children: [
266955
267563
  /* @__PURE__ */ jsx_runtime26.jsxs(Box_default, {
266956
267564
  marginBottom: 1,
@@ -267072,7 +267680,6 @@ function LogoutSelectMenu(props) {
267072
267680
  const { handleLogoutSelect, logoutItems } = props;
267073
267681
  return /* @__PURE__ */ jsx_runtime27.jsxs(Box_default, {
267074
267682
  flexDirection: "column",
267075
- paddingX: THEME.padding.paddingX,
267076
267683
  children: [
267077
267684
  /* @__PURE__ */ jsx_runtime27.jsx(Box_default, {
267078
267685
  marginBottom: 1,
@@ -267111,23 +267718,58 @@ var init_logout_select_menu = __esm(async () => {
267111
267718
 
267112
267719
  // ../../packages/tui/src/components/menus/menu-menu.tsx
267113
267720
  function MenuMenu(props) {
267114
- const { handleAuthMenuSelect, setAuthMode } = props;
267721
+ const {
267722
+ handleAuthMenuSelect,
267723
+ setAuthMode,
267724
+ userEmail,
267725
+ currentEmail,
267726
+ isAuthenticated,
267727
+ authMethod,
267728
+ hasBothAuth,
267729
+ hasDecember,
267730
+ decemberEmail,
267731
+ addToast
267732
+ } = props;
267115
267733
  const [selectedIndex, setSelectedIndex] = import_react60.useState(0);
267734
+ const [confirmSwitch, setConfirmSwitch] = import_react60.useState(false);
267735
+ const email = decemberEmail || currentEmail || userEmail;
267736
+ const isDecemberLoggedIn = Boolean(hasDecember !== undefined ? hasDecember || authMethod === "december" : isAuthenticated && email && (authMethod === "december" || hasBothAuth || !authMethod));
267116
267737
  const items = [
267117
267738
  {
267118
- label: "Bring Your Own Key",
267739
+ label: "Bring Your Own Key or Subscription",
267119
267740
  value: "byok"
267120
267741
  },
267121
- {
267122
- label: "Use AI Subscription",
267123
- value: "subscriptions"
267124
- },
267125
267742
  {
267126
267743
  label: "Login via December",
267744
+ status: isDecemberLoggedIn ? email ? `(Logged in as ${email})` : "(Logged in)" : undefined,
267127
267745
  value: "december"
267128
267746
  }
267129
267747
  ];
267130
267748
  use_input_default((input, key) => {
267749
+ if (confirmSwitch) {
267750
+ if (input === "y" || input === "Y") {
267751
+ setConfirmSwitch(false);
267752
+ if (handleAuthMenuSelect) {
267753
+ handleAuthMenuSelect({
267754
+ label: "Login via December",
267755
+ value: "december",
267756
+ force: true
267757
+ });
267758
+ }
267759
+ return;
267760
+ }
267761
+ if (input === "n" || input === "N" || key.escape || input === "\x1B" || key.return) {
267762
+ setConfirmSwitch(false);
267763
+ if (setAuthMode) {
267764
+ setAuthMode("none");
267765
+ }
267766
+ if (addToast) {
267767
+ addToast(`Already logged in as ${email || "December user"}.`, "info");
267768
+ }
267769
+ return;
267770
+ }
267771
+ return;
267772
+ }
267131
267773
  if (key.upArrow || input === "k") {
267132
267774
  if (selectedIndex > 0) {
267133
267775
  setSelectedIndex(selectedIndex - 1);
@@ -267141,8 +267783,15 @@ function MenuMenu(props) {
267141
267783
  return;
267142
267784
  }
267143
267785
  if (key.return) {
267144
- if (handleAuthMenuSelect && items[selectedIndex]) {
267145
- handleAuthMenuSelect(items[selectedIndex]);
267786
+ const currentItem = items[selectedIndex];
267787
+ if (!currentItem)
267788
+ return;
267789
+ if (currentItem.value === "december" && isDecemberLoggedIn) {
267790
+ setConfirmSwitch(true);
267791
+ return;
267792
+ }
267793
+ if (handleAuthMenuSelect) {
267794
+ handleAuthMenuSelect(currentItem);
267146
267795
  }
267147
267796
  return;
267148
267797
  }
@@ -267153,9 +267802,44 @@ function MenuMenu(props) {
267153
267802
  return;
267154
267803
  }
267155
267804
  });
267805
+ if (confirmSwitch) {
267806
+ return /* @__PURE__ */ jsx_runtime28.jsxs(Box_default, {
267807
+ flexDirection: "column",
267808
+ children: [
267809
+ /* @__PURE__ */ jsx_runtime28.jsx(Box_default, {
267810
+ marginBottom: 1,
267811
+ children: /* @__PURE__ */ jsx_runtime28.jsxs(Text3, {
267812
+ color: THEME.colors.text,
267813
+ children: [
267814
+ "You are already logged in as",
267815
+ " ",
267816
+ /* @__PURE__ */ jsx_runtime28.jsx(Text3, {
267817
+ color: THEME.colors.brand,
267818
+ bold: true,
267819
+ children: email || "December user"
267820
+ }),
267821
+ "."
267822
+ ]
267823
+ })
267824
+ }),
267825
+ /* @__PURE__ */ jsx_runtime28.jsx(Box_default, {
267826
+ marginBottom: 1,
267827
+ children: /* @__PURE__ */ jsx_runtime28.jsx(Text3, {
267828
+ color: THEME.colors.warning,
267829
+ children: "Do you want to switch to a different account? (y/N)"
267830
+ })
267831
+ }),
267832
+ /* @__PURE__ */ jsx_runtime28.jsx(MenuFooter, {
267833
+ items: [
267834
+ { key: "y", label: "Switch Account" },
267835
+ { key: "n / esc", label: "Cancel" }
267836
+ ]
267837
+ })
267838
+ ]
267839
+ });
267840
+ }
267156
267841
  return /* @__PURE__ */ jsx_runtime28.jsxs(Box_default, {
267157
267842
  flexDirection: "column",
267158
- paddingX: THEME.padding.paddingX,
267159
267843
  children: [
267160
267844
  /* @__PURE__ */ jsx_runtime28.jsx(Box_default, {
267161
267845
  marginBottom: 1,
@@ -267179,7 +267863,14 @@ function MenuMenu(props) {
267179
267863
  /* @__PURE__ */ jsx_runtime28.jsx(Text3, {
267180
267864
  color: isSelected ? THEME.colors.brand : THEME.colors.text,
267181
267865
  children: item.label
267182
- })
267866
+ }),
267867
+ item.status ? /* @__PURE__ */ jsx_runtime28.jsxs(Text3, {
267868
+ color: THEME.colors.success,
267869
+ children: [
267870
+ " ",
267871
+ item.status
267872
+ ]
267873
+ }) : null
267183
267874
  ]
267184
267875
  }, item.value);
267185
267876
  }),
@@ -267258,7 +267949,6 @@ function ModelSelectMenu(props) {
267258
267949
  const itemsBelow = items.length - windowEnd;
267259
267950
  return /* @__PURE__ */ jsx_runtime29.jsxs(Box_default, {
267260
267951
  flexDirection: "column",
267261
- paddingX: THEME.padding.paddingX,
267262
267952
  children: [
267263
267953
  /* @__PURE__ */ jsx_runtime29.jsx(Box_default, {
267264
267954
  marginBottom: 1,
@@ -267358,7 +268048,6 @@ function OllamaSetupMenu({
267358
268048
  };
267359
268049
  return /* @__PURE__ */ jsx_runtime30.jsxs(Box_default, {
267360
268050
  flexDirection: "column",
267361
- paddingX: THEME.padding.paddingX,
267362
268051
  children: [
267363
268052
  /* @__PURE__ */ jsx_runtime30.jsx(Box_default, {
267364
268053
  marginBottom: 1,
@@ -267537,7 +268226,8 @@ function PlanItemComponent({
267537
268226
  color = THEME.colors.error;
267538
268227
  }
267539
268228
  return /* @__PURE__ */ jsx_runtime31.jsx(Text3, {
267540
- color,
268229
+ color: isSelected ? color : THEME.colors.muted,
268230
+ bold: isSelected,
267541
268231
  children: label
267542
268232
  });
267543
268233
  }
@@ -267562,7 +268252,6 @@ function PlanApproveMenu({ handlePlanApprovalSelect, planSummary }) {
267562
268252
  });
267563
268253
  return /* @__PURE__ */ jsx_runtime31.jsxs(Box_default, {
267564
268254
  flexDirection: "column",
267565
- paddingX: THEME.padding.paddingX,
267566
268255
  children: [
267567
268256
  /* @__PURE__ */ jsx_runtime31.jsxs(Box_default, {
267568
268257
  marginBottom: 1,
@@ -267570,7 +268259,7 @@ function PlanApproveMenu({ handlePlanApprovalSelect, planSummary }) {
267570
268259
  gap: 1,
267571
268260
  children: [
267572
268261
  planSummary && /* @__PURE__ */ jsx_runtime31.jsx(Box_default, {
267573
- borderStyle: "round",
268262
+ borderStyle: "single",
267574
268263
  borderColor: THEME.colors.border,
267575
268264
  paddingX: 1,
267576
268265
  children: /* @__PURE__ */ jsx_runtime31.jsx(Text3, {
@@ -267840,7 +268529,6 @@ function SessionSelectMenu(props) {
267840
268529
  ];
267841
268530
  return /* @__PURE__ */ jsx_runtime32.jsxs(Box_default, {
267842
268531
  flexDirection: "column",
267843
- paddingX: THEME.padding.paddingX,
267844
268532
  children: [
267845
268533
  /* @__PURE__ */ jsx_runtime32.jsxs(Box_default, {
267846
268534
  marginBottom: 1,
@@ -268017,47 +268705,47 @@ function SettingsMainMenu(props) {
268017
268705
  const providerName = providerKey === "december" || providerKey === "december_proxy" ? "December Cloud" : formatProviderName2(providerKey);
268018
268706
  const providerLabel = providerKey ? authMethod === "subscription" ? `${providerName} (Subscription)` : authMethod === "december" ? "December Cloud" : `${providerName} (BYOK)` : "Not configured";
268019
268707
  const modelLabel = activeModel || "default";
268708
+ const formatSettingRow = (title, value) => `${title.padEnd(25, " ")}[${value}]`;
268020
268709
  const mainItems = [
268021
268710
  {
268022
- label: `Active Provider [${providerLabel}]`,
268711
+ label: formatSettingRow("Active Provider", providerLabel),
268023
268712
  value: "switchProvider"
268024
268713
  },
268025
268714
  {
268026
- label: `Active Model [${modelLabel}]`,
268715
+ label: formatSettingRow("Active Model", modelLabel),
268027
268716
  value: "activeModel"
268028
268717
  },
268029
268718
  {
268030
- label: `Tool Permission [${settingsToolPermission}]`,
268719
+ label: formatSettingRow("Tool Permission", settingsToolPermission),
268031
268720
  value: "toolPermission"
268032
268721
  },
268033
268722
  {
268034
- label: `PathGuard Protection [${settingsPathGuard !== false ? "on" : "off"}]`,
268723
+ label: formatSettingRow("PathGuard Protection", settingsPathGuard !== false ? "on" : "off"),
268035
268724
  value: "pathGuard"
268036
268725
  },
268037
268726
  {
268038
- label: `Non-Workspace Access [${settingsNonWorkspace ? "on" : "off"}]`,
268727
+ label: formatSettingRow("Non-Workspace Access", settingsNonWorkspace ? "on" : "off"),
268039
268728
  value: "nonWorkspaceAccess"
268040
268729
  },
268041
268730
  {
268042
- label: `Thinking Level [${settingsThinkingLevel}]`,
268731
+ label: formatSettingRow("Thinking Level", settingsThinkingLevel),
268043
268732
  value: "thinkingLevel"
268044
268733
  },
268045
268734
  {
268046
- label: `Steering Mode [${settingsSteeringMode}]`,
268735
+ label: formatSettingRow("Steering Mode", settingsSteeringMode),
268047
268736
  value: "steeringMode"
268048
268737
  },
268049
268738
  {
268050
- label: `Follow-Up Mode [${settingsFollowUpMode}]`,
268739
+ label: formatSettingRow("Follow-Up Mode", settingsFollowUpMode),
268051
268740
  value: "followUpMode"
268052
268741
  },
268053
268742
  {
268054
- label: `Browser Window [${settingsBrowserVisible !== false ? "on" : "off"}]`,
268743
+ label: formatSettingRow("Browser Window", settingsBrowserVisible !== false ? "on" : "off"),
268055
268744
  value: "browserVisible"
268056
268745
  }
268057
268746
  ];
268058
268747
  return /* @__PURE__ */ jsx_runtime33.jsxs(Box_default, {
268059
268748
  flexDirection: "column",
268060
- paddingX: THEME.padding.paddingX,
268061
268749
  children: [
268062
268750
  /* @__PURE__ */ jsx_runtime33.jsx(Box_default, {
268063
268751
  marginBottom: 1,
@@ -268177,7 +268865,6 @@ function SubscriptionSelectMenu(props) {
268177
268865
  ];
268178
268866
  return /* @__PURE__ */ jsx_runtime34.jsxs(Box_default, {
268179
268867
  flexDirection: "column",
268180
- paddingX: THEME.padding.paddingX,
268181
268868
  children: [
268182
268869
  /* @__PURE__ */ jsx_runtime34.jsxs(Box_default, {
268183
268870
  marginBottom: 1,
@@ -268369,7 +269056,6 @@ function SwitchSelectMenu(props) {
268369
269056
  ];
268370
269057
  return /* @__PURE__ */ jsx_runtime35.jsxs(Box_default, {
268371
269058
  flexDirection: "column",
268372
- paddingX: THEME.padding.paddingX,
268373
269059
  children: [
268374
269060
  /* @__PURE__ */ jsx_runtime35.jsx(Box_default, {
268375
269061
  marginBottom: 1,
@@ -268771,7 +269457,6 @@ function TasksModeMenu(props) {
268771
269457
  if (!task) {
268772
269458
  return /* @__PURE__ */ jsx_runtime36.jsxs(Box_default, {
268773
269459
  flexDirection: "column",
268774
- paddingX: THEME.padding.paddingX,
268775
269460
  children: [
268776
269461
  /* @__PURE__ */ jsx_runtime36.jsx(Box_default, {
268777
269462
  marginBottom: 1,
@@ -268796,7 +269481,6 @@ function TasksModeMenu(props) {
268796
269481
  const gutterWidth = Math.max(2, outputLines.length.toString().length);
268797
269482
  return /* @__PURE__ */ jsx_runtime36.jsxs(Box_default, {
268798
269483
  flexDirection: "column",
268799
- paddingX: THEME.padding.paddingX,
268800
269484
  children: [
268801
269485
  /* @__PURE__ */ jsx_runtime36.jsxs(Box_default, {
268802
269486
  marginBottom: 1,
@@ -268867,7 +269551,7 @@ function TasksModeMenu(props) {
268867
269551
  }),
268868
269552
  /* @__PURE__ */ jsx_runtime36.jsx(Box_default, {
268869
269553
  borderColor: THEME.colors.border,
268870
- borderStyle: "round",
269554
+ borderStyle: "single",
268871
269555
  flexDirection: "column",
268872
269556
  paddingX: 1,
268873
269557
  children: visibleLines.length === 0 || visibleLines.length === 1 && visibleLines[0] === "" ? /* @__PURE__ */ jsx_runtime36.jsx(Text3, {
@@ -268940,7 +269624,6 @@ function TasksModeMenu(props) {
268940
269624
  }
268941
269625
  return /* @__PURE__ */ jsx_runtime36.jsxs(Box_default, {
268942
269626
  flexDirection: "column",
268943
- paddingX: THEME.padding.paddingX,
268944
269627
  children: [
268945
269628
  /* @__PURE__ */ jsx_runtime36.jsx(Box_default, {
268946
269629
  marginBottom: 1,
@@ -269391,7 +270074,6 @@ function ToolPermissionMenu({ toolCall, questions, onComplete }) {
269391
270074
  });
269392
270075
  return /* @__PURE__ */ jsx_runtime38.jsxs(Box_default, {
269393
270076
  flexDirection: "column",
269394
- paddingX: THEME.padding.paddingX,
269395
270077
  children: [
269396
270078
  /* @__PURE__ */ jsx_runtime38.jsxs(Box_default, {
269397
270079
  marginBottom: 1,
@@ -269404,7 +270086,7 @@ function ToolPermissionMenu({ toolCall, questions, onComplete }) {
269404
270086
  }),
269405
270087
  toolSummary && /* @__PURE__ */ jsx_runtime38.jsxs(Box_default, {
269406
270088
  flexDirection: "column",
269407
- borderStyle: "round",
270089
+ borderStyle: "single",
269408
270090
  borderColor: THEME.colors.border,
269409
270091
  paddingX: 1,
269410
270092
  marginTop: 1,
@@ -269587,7 +270269,6 @@ function UsageSelectMenu(props) {
269587
270269
  const topModelSummary = weekly.topModels && weekly.topModels.length > 0 ? `${weekly.topModels[0].model} (${weekly.topModels[0].percentage}%)` : "None";
269588
270270
  return /* @__PURE__ */ jsx_runtime39.jsxs(Box_default, {
269589
270271
  flexDirection: "column",
269590
- paddingX: THEME.padding.paddingX,
269591
270272
  children: [
269592
270273
  /* @__PURE__ */ jsx_runtime39.jsx(Box_default, {
269593
270274
  marginBottom: 1,
@@ -269625,7 +270306,7 @@ function UsageSelectMenu(props) {
269625
270306
  }),
269626
270307
  /* @__PURE__ */ jsx_runtime39.jsx(Text3, {
269627
270308
  color: THEME.colors.border,
269628
- children: "──────────────────────────"
270309
+ children: "─".repeat(34)
269629
270310
  }),
269630
270311
  dailyItems.map((item) => {
269631
270312
  const spark = getSpark(item.tokens);
@@ -269692,7 +270373,7 @@ function UsageSelectMenu(props) {
269692
270373
  }),
269693
270374
  /* @__PURE__ */ jsx_runtime39.jsx(Text3, {
269694
270375
  color: THEME.colors.border,
269695
- children: "──────────────────────────"
270376
+ children: "─".repeat(34)
269696
270377
  }),
269697
270378
  /* @__PURE__ */ jsx_runtime39.jsxs(Box_default, {
269698
270379
  gap: 1,
@@ -269738,7 +270419,7 @@ function UsageSelectMenu(props) {
269738
270419
  }),
269739
270420
  /* @__PURE__ */ jsx_runtime39.jsx(Text3, {
269740
270421
  color: THEME.colors.border,
269741
- children: "─────────────"
270422
+ children: "─".repeat(38)
269742
270423
  }),
269743
270424
  /* @__PURE__ */ jsx_runtime39.jsxs(Box_default, {
269744
270425
  gap: 1,
@@ -269826,7 +270507,7 @@ function UsageSelectMenu(props) {
269826
270507
  }),
269827
270508
  /* @__PURE__ */ jsx_runtime39.jsx(Text3, {
269828
270509
  color: THEME.colors.border,
269829
- children: "───────────────"
270510
+ children: "─".repeat(38)
269830
270511
  }),
269831
270512
  /* @__PURE__ */ jsx_runtime39.jsxs(Box_default, {
269832
270513
  gap: 1,
@@ -270074,7 +270755,6 @@ function AskQuestionMenu({ questions, onComplete }) {
270074
270755
  return null;
270075
270756
  return /* @__PURE__ */ jsx_runtime41.jsxs(Box_default, {
270076
270757
  flexDirection: "column",
270077
- paddingX: THEME.padding.paddingX,
270078
270758
  gap: 1,
270079
270759
  children: [
270080
270760
  /* @__PURE__ */ jsx_runtime41.jsxs(Box_default, {
@@ -270355,6 +271035,16 @@ function GlobalShortcuts(session) {
270355
271035
  }
270356
271036
  return;
270357
271037
  }
271038
+ if (session.pendingDeviceAuthUrl) {
271039
+ if (input === "o" || input === "O") {
271040
+ if (session.handleOpenDeviceAuthUrl) {
271041
+ session.handleOpenDeviceAuthUrl();
271042
+ }
271043
+ } else if (key.escape || input === "\x1B") {
271044
+ session.handleAbort();
271045
+ }
271046
+ return;
271047
+ }
270358
271048
  if (session.isStreaming && (key.escape || input === "\x1B")) {
270359
271049
  session.handleAbort();
270360
271050
  return;
@@ -270450,12 +271140,24 @@ function ChatApp({
270450
271140
  onLogin,
270451
271141
  onUpdateSuccess,
270452
271142
  session,
270453
- isInline = false,
270454
- announcement
271143
+ announcement,
271144
+ activeModel,
271145
+ authMethod,
271146
+ selectedProvider,
271147
+ modelLabel,
271148
+ onExit
270455
271149
  }) {
270456
271150
  const [exitConfirm, setExitConfirm] = import_react69.useState(false);
270457
271151
  const exitTimerRef = import_react69.useRef(null);
270458
271152
  const handleInterrupt = import_react69.useCallback(() => {
271153
+ if (session.pendingDeviceAuthUrl) {
271154
+ if (onExit) {
271155
+ onExit();
271156
+ } else {
271157
+ process.exit(0);
271158
+ }
271159
+ return;
271160
+ }
270459
271161
  if (session.isStreaming) {
270460
271162
  if (session.handleAbort) {
270461
271163
  session.handleAbort();
@@ -270468,7 +271170,11 @@ function ChatApp({
270468
271170
  clearTimeout(exitTimerRef.current);
270469
271171
  exitTimerRef.current = null;
270470
271172
  }
270471
- process.exit(0);
271173
+ if (onExit) {
271174
+ onExit();
271175
+ } else {
271176
+ process.exit(0);
271177
+ }
270472
271178
  } else {
270473
271179
  setExitConfirm(true);
270474
271180
  if (exitTimerRef.current) {
@@ -270479,7 +271185,7 @@ function ChatApp({
270479
271185
  exitTimerRef.current = null;
270480
271186
  }, 3000);
270481
271187
  }
270482
- }, [exitConfirm, session, agent]);
271188
+ }, [exitConfirm, session, agent, onExit]);
270483
271189
  import_react69.useEffect(() => {
270484
271190
  return () => {
270485
271191
  if (exitTimerRef.current) {
@@ -270489,18 +271195,33 @@ function ChatApp({
270489
271195
  };
270490
271196
  }, []);
270491
271197
  import_react69.useEffect(() => {
270492
- if (!process.stdout?.isTTY || isInline)
271198
+ if (!process.stdout?.isTTY)
270493
271199
  return;
271200
+ const originalWrite = process.stdout.write.bind(process.stdout);
271201
+ try {
271202
+ originalWrite("\x1B[?1049h\x1B[?1000h\x1B[?1002h\x1B[?1006h\x1B[?1007h");
271203
+ } catch {}
271204
+ const synchronizedWrite = (chunk, ...rest) => {
271205
+ if (typeof chunk === "string" && chunk.length > 0 && !chunk.startsWith("\x1B]52;") && !chunk.includes("\x1B[?2026h")) {
271206
+ return originalWrite(`\x1B[?2026h${chunk}\x1B[?2026l`, ...rest);
271207
+ }
271208
+ return originalWrite(chunk, ...rest);
271209
+ };
271210
+ process.stdout.write = synchronizedWrite;
270494
271211
  const handleResize = () => {
270495
271212
  try {
270496
- process.stdout.write("\x1B[?2026h\x1B[2J\x1B[H\x1B[?2026l");
271213
+ originalWrite("\x1B[?2026h\x1B[2J\x1B[H\x1B[?2026l");
270497
271214
  } catch {}
270498
271215
  };
270499
271216
  process.stdout.on("resize", handleResize);
270500
271217
  return () => {
270501
271218
  process.stdout.off("resize", handleResize);
271219
+ process.stdout.write = originalWrite;
271220
+ try {
271221
+ originalWrite("\x1B[?2026l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?1007l\x1B[?1049l");
271222
+ } catch {}
270502
271223
  };
270503
- }, [isInline]);
271224
+ }, []);
270504
271225
  use_input_default((input, key) => {
270505
271226
  if (key.ctrl && input === "c") {
270506
271227
  handleInterrupt();
@@ -270579,9 +271300,10 @@ function ChatApp({
270579
271300
  const text = lastAssistant.blocks?.map((b) => b.content || "").join(`
270580
271301
  `) || "";
270581
271302
  writeToClipboard(text);
271303
+ session.addToast?.("Copied to clipboard.", "success");
270582
271304
  }
270583
271305
  }).catch(() => {});
270584
- }, [staticMessages, activeMessages]);
271306
+ }, [staticMessages, activeMessages, session]);
270585
271307
  const handleResetChat = import_react69.useCallback(() => {
270586
271308
  console.clear();
270587
271309
  setStaticMessages([{ id: "header-" + Date.now(), role: "header" }]);
@@ -270589,22 +271311,22 @@ function ChatApp({
270589
271311
  setActiveMessages([]);
270590
271312
  session.setQueuedPrompts?.([]);
270591
271313
  session.addToast?.("Started a new conversation.", "success");
270592
- }, [
270593
- setStaticMessages,
270594
- setStaticKey,
270595
- setActiveMessages,
270596
- session.setQueuedPrompts,
270597
- session.addToast
270598
- ]);
271314
+ }, [setStaticMessages, setStaticKey, setActiveMessages, session]);
271315
+ const effectiveModel = session.activeModel || activeModel || agent?.modelOptions?.model || "gemini-3.7-flash";
271316
+ const effectiveModelLabel = session.activeModel ? formatModelDisplayName(session.activeModel) : modelLabel || formatModelDisplayName(effectiveModel);
271317
+ const effectiveAuthMethod = session.authMethod || authMethod;
271318
+ const effectiveProvider = session.selectedProvider || selectedProvider;
271319
+ const isDeviceAuthPending = Boolean(session.pendingDeviceAuthUrl);
270599
271320
  const inputBarElement = /* @__PURE__ */ jsx_runtime43.jsx(InputBar, {
270600
271321
  onSubmit: handleFormSubmit,
270601
271322
  onScrollUp: handleScrollUp,
270602
271323
  onScrollDown: handleScrollDown,
270603
271324
  onStartVoice: session.onStartVoice,
270604
- disabled: authMode !== "none" || Boolean(workflowUI) && !session.customInputMode,
271325
+ disabled: authMode !== "none" || Boolean(workflowUI) && !session.customInputMode || isDeviceAuthPending,
270605
271326
  onCopy: handleCopy,
270606
- placeholder: "Ask December to build features, fix bugs, or work on your code...",
270607
- activeModel: session.activeModel || agent?.modelOptions?.model || "gemini-3.7-flash",
271327
+ placeholder: isDeviceAuthPending ? "Waiting for approval... Press [o] to open in browser" : "Ask December to build features, fix bugs, or work on your code...",
271328
+ activeModel: effectiveModel,
271329
+ modelLabel: effectiveModelLabel,
270608
271330
  contextTokens: totalTokens,
270609
271331
  authMethod: session.authMethod,
270610
271332
  isAuthenticated,
@@ -270622,33 +271344,9 @@ function ChatApp({
270622
271344
  planRefineMode: session.planRefineMode,
270623
271345
  customInputMode: session.customInputMode || false,
270624
271346
  showExitConfirm: exitConfirm,
270625
- tasks: session.tasks
271347
+ tasks: session.tasks,
271348
+ onExit
270626
271349
  });
270627
- if (isInline) {
270628
- return /* @__PURE__ */ jsx_runtime43.jsxs(Box_default, {
270629
- flexDirection: "column",
270630
- width: "100%",
270631
- children: [
270632
- /* @__PURE__ */ jsx_runtime43.jsx(GlobalShortcuts, {
270633
- ...session,
270634
- agent
270635
- }),
270636
- /* @__PURE__ */ jsx_runtime43.jsx(MessageList, {
270637
- staticKey,
270638
- staticMessages,
270639
- activeMessages,
270640
- isAuthenticated,
270641
- cliVersion,
270642
- latestVersion,
270643
- userEmail: currentEmail || userEmail,
270644
- expandCommands: session.expandCommands,
270645
- fullscreen: false,
270646
- announcement
270647
- }),
270648
- inputBarElement
270649
- ]
270650
- });
270651
- }
270652
271350
  return /* @__PURE__ */ jsx_runtime43.jsxs(Box_default, {
270653
271351
  flexDirection: "column",
270654
271352
  height: rows,
@@ -270663,6 +271361,7 @@ function ChatApp({
270663
271361
  ref: scrollViewportRef,
270664
271362
  isGenerating: session.isStreaming,
270665
271363
  isActive: authMode === "none",
271364
+ onCopy: handleCopy,
270666
271365
  onScrollChange: (linesBelow) => setIsReadingMode(linesBelow > 0),
270667
271366
  children: /* @__PURE__ */ jsx_runtime43.jsx(MessageList, {
270668
271367
  staticKey,
@@ -270675,7 +271374,11 @@ function ChatApp({
270675
271374
  expandCommands: session.expandCommands,
270676
271375
  fullscreen: true,
270677
271376
  announcement,
270678
- isReadingMode
271377
+ isReadingMode,
271378
+ activeModel: effectiveModel,
271379
+ modelLabel: effectiveModelLabel,
271380
+ authMethod: effectiveAuthMethod,
271381
+ selectedProvider: effectiveProvider
270679
271382
  })
270680
271383
  }),
270681
271384
  /* @__PURE__ */ jsx_runtime43.jsx(Box_default, {
@@ -270693,6 +271396,7 @@ var init_app = __esm(async () => {
270693
271396
  await __promiseAll([
270694
271397
  init_build2(),
270695
271398
  init_global_shortcuts(),
271399
+ init_header(),
270696
271400
  init_input_bar(),
270697
271401
  init_ask_question_menu(),
270698
271402
  init_auth_menus(),
@@ -270726,6 +271430,8 @@ var init_src7 = __esm(async () => {
270726
271430
  init_menu_items();
270727
271431
  init_auth_menus();
270728
271432
  init_ask_question_menu();
271433
+ init_command_menu();
271434
+ init_use_command_menu();
270729
271435
  init_header();
270730
271436
  init_use_delayed_tip();
270731
271437
  init_tips();
@@ -270854,6 +271560,10 @@ var init_store = __esm(() => {
270854
271560
  setAuthMethod: (authMethod) => set({ authMethod }),
270855
271561
  hasBothAuth: false,
270856
271562
  setHasBothAuth: (hasBothAuth) => set({ hasBothAuth }),
271563
+ hasDecember: false,
271564
+ setHasDecember: (hasDecember) => set({ hasDecember }),
271565
+ decemberEmail: undefined,
271566
+ setDecemberEmail: (decemberEmail) => set({ decemberEmail }),
270857
271567
  settingsAuthPriority: "byok",
270858
271568
  setSettingsAuthPriority: (settingsAuthPriority) => set({ settingsAuthPriority }),
270859
271569
  currentEmail: undefined,
@@ -270872,6 +271582,8 @@ var init_store = __esm(() => {
270872
271582
  setApiKey: (apiKey) => set({ apiKey }),
270873
271583
  authError: null,
270874
271584
  setAuthError: (authError) => set({ authError }),
271585
+ pendingDeviceAuthUrl: null,
271586
+ setPendingDeviceAuthUrl: (pendingDeviceAuthUrl) => set({ pendingDeviceAuthUrl }),
270875
271587
  openRouterModels: [],
270876
271588
  setOpenRouterModels: (openRouterModels) => set({ openRouterModels }),
270877
271589
  ollamaStatus: null,
@@ -270928,6 +271640,8 @@ var init_store = __esm(() => {
270928
271640
  setQueuedPrompts: (updater) => set((state) => ({
270929
271641
  queuedPrompts: typeof updater === "function" ? updater(state.queuedPrompts) : updater
270930
271642
  })),
271643
+ isInline: false,
271644
+ setIsInline: (isInline) => set({ isInline }),
270931
271645
  sessionItems: [],
270932
271646
  setSessionItems: (sessionItems) => set({ sessionItems }),
270933
271647
  sessionsData: [],
@@ -271566,6 +272280,35 @@ var init_usage_rates2 = __esm(() => {
271566
272280
 
271567
272281
  // src/utils/error-parser.ts
271568
272282
  import util5 from "util";
272283
+ function inferProviderEndpoint(provider, baseURL) {
272284
+ if (baseURL)
272285
+ return baseURL;
272286
+ const norm = (provider || "").toLowerCase().trim();
272287
+ switch (norm) {
272288
+ case "december":
272289
+ case "december_proxy":
272290
+ return "https://api.trydecember.com/api/v1/cli";
272291
+ case "anthropic":
272292
+ case "claude":
272293
+ return "https://api.anthropic.com/v1/messages";
272294
+ case "openai":
272295
+ case "chatgpt":
272296
+ return "https://api.openai.com/v1/chat/completions";
272297
+ case "gemini":
272298
+ case "google":
272299
+ return "https://generativelanguage.googleapis.com/v1beta";
272300
+ case "ollama":
272301
+ return "http://localhost:11434/v1";
272302
+ case "openrouter":
272303
+ return "https://openrouter.ai/api/v1/chat/completions";
272304
+ case "deepseek":
272305
+ return "https://api.deepseek.com/chat/completions";
272306
+ case "groq":
272307
+ return "https://api.groq.com/openai/v1/chat/completions";
272308
+ default:
272309
+ return;
272310
+ }
272311
+ }
271569
272312
  function isCreditOrBalanceError(combined) {
271570
272313
  return combined.includes("insufficient balance") || combined.includes("insufficient credits") || combined.includes("insufficient_balance") || combined.includes("insufficient_credits") || combined.includes("insufficient_quota") || combined.includes("balance is insufficient") || combined.includes("balance insufficient") || combined.includes("balance exhausted") || combined.includes("out of credits") || combined.includes("credit balance is too low") || combined.includes("credits exhausted") || combined.includes("requires more credits") || combined.includes("can only afford") || combined.includes("payment required") || combined.includes("quota exceeded") || combined.includes("quota_exhausted") || combined.includes("budget_exhausted") || combined.includes("budget exhausted") || combined.includes("budget exceeded") || combined.includes("budget_exceeded") || combined.includes("402") || combined.includes("1008") || combined.includes("20009") || (combined.includes("credits") || combined.includes("balance")) && (combined.includes("insufficient") || combined.includes("exhausted") || combined.includes("empty") || combined.includes("zero") || combined.includes("low") || combined.includes("top up") || combined.includes("recharge") || combined.includes("afford") || combined.includes("add credits"));
271571
272314
  }
@@ -271984,7 +272727,21 @@ function parseError(err, context) {
271984
272727
  }
271985
272728
  let explicitCause;
271986
272729
  if (err?.cause) {
271987
- explicitCause = typeof err.cause === "string" ? err.cause : err.cause?.message || (typeof err.cause === "object" ? util5.inspect(err.cause) : String(err.cause));
272730
+ if (typeof err.cause === "string") {
272731
+ explicitCause = err.cause;
272732
+ } else if (err.cause?.message) {
272733
+ const nested = err.cause?.cause;
272734
+ const nestedDetail = typeof nested === "string" ? nested : nested?.message || nested?.code || (typeof nested === "object" ? util5.inspect(nested) : undefined);
272735
+ if (nestedDetail && nestedDetail !== err.cause.message) {
272736
+ explicitCause = `${err.cause.message} (${nestedDetail})`;
272737
+ } else {
272738
+ explicitCause = err.cause.message;
272739
+ }
272740
+ } else if (typeof err.cause === "object") {
272741
+ explicitCause = util5.inspect(err.cause);
272742
+ } else {
272743
+ explicitCause = String(err.cause);
272744
+ }
271988
272745
  } else if (err?.originalError) {
271989
272746
  explicitCause = typeof err.originalError === "string" ? err.originalError : err.originalError?.message || (typeof err.originalError === "object" ? util5.inspect(err.originalError) : String(err.originalError));
271990
272747
  } else if (err?.response?.data) {
@@ -272007,20 +272764,33 @@ function parseError(err, context) {
272007
272764
  hint: rateDetails.hint
272008
272765
  };
272009
272766
  }
272010
- const isDecemberCredits = combined.includes("december wallet") || combined.includes("trydecember.com") || combined.includes("december cloud");
272011
- if (!isDecemberCredits) {
272012
- const creditRule = findMatchingCreditRule(combined, context);
272013
- if (creditRule) {
272014
- const parts = fullMessage.split(`
272767
+ const isDecemberCredits = combined.includes("december wallet") || isCreditOrBalanceError(combined) && (combined.includes("trydecember.com") || combined.includes("december cloud"));
272768
+ if (isDecemberCredits) {
272769
+ const parts = fullMessage.split(`
272770
+ `).map((l) => l.trim()).filter(Boolean);
272771
+ const firstLine = parts[0] || fullMessage;
272772
+ const cause = explicitCause || (parts.length > 1 ? parts.slice(1).join(`
272773
+ `).trim() : undefined);
272774
+ const hintMatch = firstLine.match(/Please (?:add credits|top up|check|upgrade|run|switch|configure).*$/i);
272775
+ const summary = hintMatch ? firstLine.replace(/Please (?:add credits|top up|check|upgrade|run|switch|configure).*$/i, "").replace(/^402\s*/, "").trim() : firstLine.replace(/^402\s*/, "").trim() || "Insufficient credits in December Wallet.";
272776
+ const hint = hintMatch ? hintMatch[0].trim() : "Please add credits at https://app.trydecember.com/settings/billing or configure Bring Your Own Key (BYOK) via `/login` to continue using December.";
272777
+ return {
272778
+ message: summary || "Insufficient credits in December Wallet.",
272779
+ cause: cause && !cause.startsWith(summary) ? cause : explicitCause,
272780
+ hint
272781
+ };
272782
+ }
272783
+ const creditRule = findMatchingCreditRule(combined, context);
272784
+ if (creditRule) {
272785
+ const parts = fullMessage.split(`
272015
272786
  `);
272016
- const cause = explicitCause || (parts.length > 1 ? parts.slice(1).join(`
272787
+ const cause = explicitCause || (parts.length > 1 ? parts.slice(1).join(`
272017
272788
  `).trim() : fullMessage);
272018
- return {
272019
- message: creditRule.message,
272020
- cause: cause && !cause.startsWith(creditRule.message) ? cause : explicitCause || parts[0],
272021
- hint: creditRule.hint
272022
- };
272023
- }
272789
+ return {
272790
+ message: creditRule.message,
272791
+ cause: cause && !cause.startsWith(creditRule.message) ? cause : explicitCause || parts[0],
272792
+ hint: creditRule.hint
272793
+ };
272024
272794
  }
272025
272795
  const isChannelError = combined.includes("无可用渠道") || combined.includes("no available channel") || combined.includes("channel not found");
272026
272796
  if (isChannelError) {
@@ -272092,12 +272862,54 @@ function parseError(err, context) {
272092
272862
  hint: "Check file permissions or run the command with appropriate access privileges."
272093
272863
  };
272094
272864
  }
272095
- if (combined.includes("econnrefused")) {
272096
- const primaryMessage = err?.message && !err.message.includes("ECONNREFUSED") ? err.message : "Connection refused by destination host.";
272865
+ const isNetworkOrConnectionError = combined.includes("connection error") || combined.includes("econnrefused") || combined.includes("enotfound") || combined.includes("etimedout") || combined.includes("econnreset") || combined.includes("ehostunreach") || combined.includes("enetunreach") || combined.includes("fetch failed") || combined.includes("socket hang up") || err?.name === "APIConnectionError";
272866
+ if (isNetworkOrConnectionError) {
272867
+ const inferred = context?.model ? inferProviderFromModel(context.model) : undefined;
272868
+ const rawProvider = context?.provider || inferred;
272869
+ const isDecember = rawProvider === "december_proxy" || rawProvider === "december";
272870
+ const providerDisplayName = isDecember ? "December Cloud" : rawProvider ? formatProviderName(rawProvider) : undefined;
272871
+ const endpoint = inferProviderEndpoint(rawProvider, context?.baseURL);
272872
+ const isLocalOllama = rawProvider === "ollama" || context?.baseURL?.includes("11434") || combined.includes("11434") || combined.includes("ollama");
272873
+ const modelLabel = context?.model ? isDecember && context.model === "december-auto" ? "Humans R1" : getModelLabel(context.model) : undefined;
272874
+ let headline;
272875
+ if (isDecember) {
272876
+ headline = `Unable to connect to December Cloud (${modelLabel || "Humans R1"}).`;
272877
+ } else if (isLocalOllama) {
272878
+ headline = "Unable to connect to Ollama (Connection refused).";
272879
+ } else if (combined.includes("enotfound")) {
272880
+ const target = providerDisplayName || "destination host";
272881
+ headline = modelLabel ? `Unable to connect to ${target} (${modelLabel}).` : `Unable to connect to ${target} (DNS lookup failed).`;
272882
+ } else if (combined.includes("etimedout") || combined.includes("timed out")) {
272883
+ const target = providerDisplayName || "destination host";
272884
+ headline = modelLabel ? `Connection to ${target} (${modelLabel}) timed out.` : `Connection to ${target} timed out.`;
272885
+ } else if (combined.includes("econnrefused") && !rawProvider && !isDecember) {
272886
+ const primaryMessage = err?.message && !err.message.includes("ECONNREFUSED") ? err.message : "Connection refused by destination host.";
272887
+ return {
272888
+ message: primaryMessage,
272889
+ cause: explicitCause || fullMessage,
272890
+ hint: "Verify that the server or target service is running and network is reachable."
272891
+ };
272892
+ } else if (combined.includes("econnrefused")) {
272893
+ headline = providerDisplayName ? `Connection to ${providerDisplayName} was refused.` : err?.message && !err.message.includes("ECONNREFUSED") ? err.message : "Connection refused by destination host.";
272894
+ } else {
272895
+ const target = providerDisplayName || "LLM provider";
272896
+ headline = modelLabel ? `Unable to connect to ${target} (${modelLabel}).` : err?.message && err.message !== "Connection error." && !err.message.includes("fetch failed") ? err.message : `Unable to connect to ${target} (Connection error).`;
272897
+ }
272898
+ const rawCause = explicitCause && explicitCause !== "Connection error." ? explicitCause : fullMessage && fullMessage !== "Connection error." && fullMessage !== headline && !headline.includes(fullMessage) ? fullMessage : undefined;
272899
+ let detailLine;
272900
+ if (endpoint && rawCause) {
272901
+ detailLine = `Endpoint: ${endpoint} (${rawCause})`;
272902
+ } else if (endpoint) {
272903
+ detailLine = `Endpoint: ${endpoint}`;
272904
+ } else if (rawCause) {
272905
+ detailLine = rawCause;
272906
+ }
272907
+ const fullMsg = detailLine ? `${headline}
272908
+ ${detailLine}` : headline;
272097
272909
  return {
272098
- message: primaryMessage,
272099
- cause: explicitCause || fullMessage,
272100
- hint: "Verify that the server or target service is running and network is reachable."
272910
+ message: fullMsg,
272911
+ cause: rawCause,
272912
+ hint: undefined
272101
272913
  };
272102
272914
  }
272103
272915
  const cleanMsg = err?.message || fullMessage;
@@ -272109,6 +272921,8 @@ function parseError(err, context) {
272109
272921
  }
272110
272922
  var PROVIDER_CREDIT_RULES, PROVIDER_BILLING_URLS, PROVIDER_CREDIT_DISPLAY_NAMES, UNIVERSAL_CREDIT_FALLBACK;
272111
272923
  var init_error_parser = __esm(() => {
272924
+ init_config();
272925
+ init_models5();
272112
272926
  init_usage_rates2();
272113
272927
  PROVIDER_CREDIT_RULES = [
272114
272928
  {
@@ -273144,12 +273958,19 @@ async function processAgentStream({
273144
273958
  let finalMsg = { ...msg };
273145
273959
  for (const event of eventsToProcess) {
273146
273960
  switch (event.type) {
273147
- case "TurnStart":
273148
- blocks.push({
273149
- type: "text",
273150
- content: event.initialStatus || "Thinking..."
273151
- });
273961
+ case "TurnStart": {
273962
+ const initialStatus = event.initialStatus || "Thinking...";
273963
+ const lastBlock = blocks[blocks.length - 1];
273964
+ if (lastBlock && lastBlock.type === "text" && isStatusMessage(lastBlock.content)) {
273965
+ lastBlock.content = initialStatus;
273966
+ } else {
273967
+ blocks.push({
273968
+ type: "text",
273969
+ content: initialStatus
273970
+ });
273971
+ }
273152
273972
  break;
273973
+ }
273153
273974
  case "AgentError": {
273154
273975
  finalizeThinking(blocks);
273155
273976
  const lastBlock = blocks[blocks.length - 1];
@@ -273293,7 +274114,7 @@ async function processAgentStream({
273293
274114
  flush();
273294
274115
  }
273295
274116
  pendingEvents.push(event);
273296
- const isImmediateEvent = event.type === "TurnStart" || event.type === "AgentError" || event.type === "AgentInterrupt" || event.type === "ToolCallStart" || event.type === "ToolCallResult" || event.type === "ThinkingChunk" && !thinkingStartTime;
274117
+ const isImmediateEvent = event.type === "TurnStart" || event.type === "AgentError" || event.type === "AgentInterrupt" || event.type === "ToolCallStart" || event.type === "ToolCallResult" || event.type === "AgentStatus" || event.type === "ThinkingChunk" && !thinkingStartTime;
273297
274118
  if (isImmediateEvent) {
273298
274119
  if (flushTimeout) {
273299
274120
  clearTimeout(flushTimeout);
@@ -273357,6 +274178,7 @@ function useAuthHandlers(agent, onLogin, onLoginHeadless) {
273357
274178
  setOllamaStatus,
273358
274179
  setSwitchItems
273359
274180
  } = useCliStore.getState();
274181
+ const deviceAuthAbortRef = { current: null };
273360
274182
  const handleAuthMenuSelect = async (item) => {
273361
274183
  if (item.value === "subscriptions" || item.value === "subscription_select") {
273362
274184
  setAuthMode("subscription_select");
@@ -273367,14 +274189,25 @@ function useAuthHandlers(agent, onLogin, onLoginHeadless) {
273367
274189
  return;
273368
274190
  }
273369
274191
  if (item.value === "december" || item.value === "december_headless") {
274192
+ if (useCliStore.getState().isStreaming) {
274193
+ return;
274194
+ }
274195
+ const hasDecember = useCliStore.getState().hasDecember || useCliStore.getState().authMethod === "december";
274196
+ if (!item.force && hasDecember) {
274197
+ setAuthMode("menu");
274198
+ return;
274199
+ }
273370
274200
  setAuthMode("none");
273371
274201
  setIsStreaming(true);
274202
+ const authAbortController = new AbortController;
274203
+ deviceAuthAbortRef.current = authAbortController;
274204
+ let codeMsgId = null;
273372
274205
  try {
273373
274206
  const loginFn = onLogin || onLoginHeadless;
273374
274207
  if (!loginFn) {
273375
274208
  throw new Error("Login functionality is not provided by the host environment.");
273376
274209
  }
273377
- const codeMsgId = getNextMsgId();
274210
+ codeMsgId = getNextMsgId();
273378
274211
  setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
273379
274212
  setActiveMessages([
273380
274213
  {
@@ -273384,6 +274217,8 @@ function useAuthHandlers(agent, onLogin, onLoginHeadless) {
273384
274217
  }
273385
274218
  ]);
273386
274219
  const onCode = (code, uri) => {
274220
+ const fullUrl = uri.includes("?") ? `${uri}&code=${encodeURIComponent(code)}` : `${uri}?code=${encodeURIComponent(code)}`;
274221
+ useCliStore.getState().setPendingDeviceAuthUrl(fullUrl);
273387
274222
  setActiveMessages([
273388
274223
  {
273389
274224
  id: codeMsgId,
@@ -273392,17 +274227,18 @@ function useAuthHandlers(agent, onLogin, onLoginHeadless) {
273392
274227
  {
273393
274228
  type: "text",
273394
274229
  content: `
273395
- Please open [${uri}](${uri}) on any device and enter code: \`${code}\``
273396
- },
273397
- {
273398
- type: "text",
273399
- content: "Waiting for authorization..."
274230
+ Confirm code: \`${code}\`
274231
+ Open URL: [${fullUrl}](${fullUrl})
274232
+
274233
+ Press [o] to open in browser · Esc to cancel
274234
+ Waiting for approval...`
273400
274235
  }
273401
274236
  ]
273402
274237
  }
273403
274238
  ]);
273404
274239
  };
273405
- const { token, email } = await loginFn(onCode);
274240
+ const { token, email } = await loginFn(onCode, authAbortController.signal);
274241
+ useCliStore.getState().setPendingDeviceAuthUrl(null);
273406
274242
  const config = await loadConfig();
273407
274243
  config.decemberToken = token;
273408
274244
  config.authPriority = "december";
@@ -273433,30 +274269,118 @@ Please open [${uri}](${uri}) on any device and enter code: \`${code}\``
273433
274269
  setAuthMethod(providerConfig.authMethod);
273434
274270
  setHasBothAuth(authStatus.hasByok && authStatus.hasDecember);
273435
274271
  setSettingsAuthPriority(authStatus.authPriority);
274272
+ useCliStore.getState().setHasDecember(authStatus.hasDecember);
274273
+ if (email || config.email) {
274274
+ useCliStore.getState().setDecemberEmail(email || config.email);
274275
+ }
274276
+ }
274277
+ const cleanActiveMessages = useCliStore.getState().activeMessages.map((m) => {
274278
+ if (m.id === codeMsgId) {
274279
+ return {
274280
+ ...m,
274281
+ blocks: m.blocks?.map((b) => {
274282
+ if (b.type === "text") {
274283
+ return {
274284
+ ...b,
274285
+ content: b.content.replace(/\n\s*Waiting for approval\.\.\./g, "").replace(/\n\s*Press \[o\].*$/gm, "").trim()
274286
+ };
274287
+ }
274288
+ return b;
274289
+ })
274290
+ };
274291
+ }
274292
+ return m;
274293
+ });
274294
+ setStaticMessages((prev) => [...prev, ...cleanActiveMessages]);
274295
+ const successBlocks = [
274296
+ {
274297
+ type: "text",
274298
+ content: `
274299
+ ${MESSAGES.AUTH.LOGIN_SUCCESS_DEVICE}`,
274300
+ color: "#6EE7B7"
274301
+ }
274302
+ ];
274303
+ if (providerConfig?.authMethod === "december" && token) {
274304
+ try {
274305
+ const serverUrl = process.env.SERVER_URL || "https://api.trydecember.com";
274306
+ const overviewRes = await fetch(`${serverUrl}/api/v1/billing/overview`, {
274307
+ headers: { Authorization: `Bearer ${token}` },
274308
+ signal: AbortSignal.timeout(2000)
274309
+ });
274310
+ if (overviewRes.ok) {
274311
+ const overviewJson = await overviewRes.json();
274312
+ const balanceCents = overviewJson.data?.creditBalance ?? 0;
274313
+ if (balanceCents <= 0) {
274314
+ successBlocks.push({
274315
+ type: "text",
274316
+ content: `
274317
+ Your December Wallet balance is $0.00.
274318
+ To add credits, visit [https://app.trydecember.com/settings/billing](https://app.trydecember.com/settings/billing).
274319
+ You can also connect an AI Subscription or API key anytime with \`/login\`.`
274320
+ });
274321
+ } else {
274322
+ successBlocks.push({
274323
+ type: "text",
274324
+ content: `
274325
+ December Wallet: $${(balanceCents / 100).toFixed(2)}. Ready to code!`
274326
+ });
274327
+ }
274328
+ }
274329
+ } catch {}
273436
274330
  }
273437
- setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
273438
274331
  setActiveMessages([
273439
274332
  {
273440
274333
  id: getNextMsgId(),
273441
274334
  role: "assistant",
273442
- blocks: [
273443
- {
273444
- type: "text",
273445
- content: MESSAGES.AUTH.LOGIN_SUCCESS_DEVICE,
273446
- color: "#6EE7B7"
273447
- }
273448
- ]
274335
+ blocks: successBlocks
273449
274336
  }
273450
274337
  ]);
273451
274338
  } catch (err) {
274339
+ useCliStore.getState().setPendingDeviceAuthUrl(null);
274340
+ const cleanActiveMessages = useCliStore.getState().activeMessages.map((m) => {
274341
+ if (m.id === codeMsgId) {
274342
+ return {
274343
+ ...m,
274344
+ blocks: m.blocks?.map((b) => {
274345
+ if (b.type === "text") {
274346
+ return {
274347
+ ...b,
274348
+ content: b.content.replace(/\n\s*Waiting for approval\.\.\./g, "").replace(/\n\s*Press \[o\].*$/gm, "").trim()
274349
+ };
274350
+ }
274351
+ return b;
274352
+ })
274353
+ };
274354
+ }
274355
+ return m;
274356
+ });
274357
+ setStaticMessages((prev) => [...prev, ...cleanActiveMessages]);
274358
+ if (err?.name === "AbortError" || err?.message?.includes("cancelled")) {
274359
+ setActiveMessages([
274360
+ {
274361
+ id: getNextMsgId(),
274362
+ role: "assistant",
274363
+ blocks: [
274364
+ {
274365
+ type: "text",
274366
+ content: "Login cancelled. Run /login anytime to connect an account.",
274367
+ color: "#888888"
274368
+ }
274369
+ ]
274370
+ }
274371
+ ]);
274372
+ setAuthMode("none");
274373
+ return;
274374
+ }
273452
274375
  const parsed = parseError(err);
273453
274376
  let cleanMsg = parsed.message;
273454
274377
  if (cleanMsg.includes("fetch failed") || cleanMsg.includes("ECONNREFUSED") || cleanMsg.includes("ENOTFOUND") || cleanMsg.includes("Failed to fetch") || cleanMsg.includes("Unable to connect")) {
273455
- cleanMsg = "Unable to connect. Is the computer able to access the url?";
274378
+ cleanMsg = "Unable to connect to December. Check your connection and run /login again.";
274379
+ } else if (cleanMsg.toLowerCase().includes("expired")) {
274380
+ cleanMsg = "Device code expired. Run /login to generate a new code.";
273456
274381
  }
273457
274382
  const errorText = `Login failed: ${cleanMsg}`;
273458
274383
  setAuthError(errorText);
273459
- setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
273460
274384
  setActiveMessages([
273461
274385
  {
273462
274386
  id: getNextMsgId(),
@@ -273466,7 +274390,10 @@ Please open [${uri}](${uri}) on any device and enter code: \`${code}\``
273466
274390
  hint: parsed.hint || "Check your network connection or verify the authentication endpoint."
273467
274391
  }
273468
274392
  ]);
274393
+ setAuthMode("none");
273469
274394
  } finally {
274395
+ useCliStore.getState().setPendingDeviceAuthUrl(null);
274396
+ deviceAuthAbortRef.current = null;
273470
274397
  setIsStreaming(false);
273471
274398
  }
273472
274399
  } else if (item.value === "byok") {
@@ -273561,8 +274488,9 @@ Please open [${uri}](${uri}) on any device and enter code: \`${code}\``
273561
274488
  if (isOauthProvider) {
273562
274489
  setAuthMode("none");
273563
274490
  setIsStreaming(true);
274491
+ let codeMsgId = null;
273564
274492
  try {
273565
- const codeMsgId = getNextMsgId();
274493
+ codeMsgId = getNextMsgId();
273566
274494
  setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
273567
274495
  setActiveMessages([
273568
274496
  {
@@ -273628,7 +274556,24 @@ Please open [${uri}](${uri}) on your device and enter code: \`${code}\``;
273628
274556
  const authStatus = await getAuthStatus();
273629
274557
  setHasBothAuth(authStatus.hasByok && authStatus.hasDecember);
273630
274558
  setSettingsAuthPriority(authStatus.authPriority);
273631
- setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
274559
+ const cleanActiveMessages = useCliStore.getState().activeMessages.map((m) => {
274560
+ if (m.id === codeMsgId) {
274561
+ return {
274562
+ ...m,
274563
+ blocks: m.blocks?.filter((b) => b.type !== "text" || !b.content.includes("Waiting for authorization")).map((b) => {
274564
+ if (b.type === "text") {
274565
+ return {
274566
+ ...b,
274567
+ content: b.content.replace(/\n\s*Waiting for authorization.*$/gm, "").trim()
274568
+ };
274569
+ }
274570
+ return b;
274571
+ })
274572
+ };
274573
+ }
274574
+ return m;
274575
+ });
274576
+ setStaticMessages((prev) => [...prev, ...cleanActiveMessages]);
273632
274577
  setActiveMessages([
273633
274578
  {
273634
274579
  id: getNextMsgId(),
@@ -273637,7 +274582,12 @@ Please open [${uri}](${uri}) on your device and enter code: \`${code}\``;
273637
274582
  {
273638
274583
  type: "text",
273639
274584
  content: `
273640
- ${formatSubscriptionCard(bundle, targetModel)}`
274585
+ ${formatSubscriptionSuccessMessage(bundle.provider)}`,
274586
+ color: "#6EE7B7"
274587
+ },
274588
+ {
274589
+ type: "text",
274590
+ content: formatSubscriptionCard(bundle, targetModel)
273641
274591
  }
273642
274592
  ]
273643
274593
  }
@@ -273649,7 +274599,24 @@ ${formatSubscriptionCard(bundle, targetModel)}`
273649
274599
  const parsed = parseError(err);
273650
274600
  const errorText = parsed.message.startsWith("Subscription verification failed") || parsed.message.startsWith("No active GitHub Copilot subscription") ? parsed.message : `Subscription verification failed: ${parsed.message}`;
273651
274601
  setAuthError(errorText);
273652
- setStaticMessages((prev) => [...prev, ...useCliStore.getState().activeMessages]);
274602
+ const cleanActiveMessages = useCliStore.getState().activeMessages.map((m) => {
274603
+ if (m.id === codeMsgId) {
274604
+ return {
274605
+ ...m,
274606
+ blocks: m.blocks?.filter((b) => b.type !== "text" || !b.content.includes("Waiting for authorization")).map((b) => {
274607
+ if (b.type === "text") {
274608
+ return {
274609
+ ...b,
274610
+ content: b.content.replace(/\n\s*Waiting for authorization.*$/gm, "").trim()
274611
+ };
274612
+ }
274613
+ return b;
274614
+ })
274615
+ };
274616
+ }
274617
+ return m;
274618
+ });
274619
+ setStaticMessages((prev) => [...prev, ...cleanActiveMessages]);
273653
274620
  setActiveMessages([
273654
274621
  {
273655
274622
  id: getNextMsgId(),
@@ -273811,6 +274778,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
273811
274778
  await Promise.resolve().then(() => init_models5());
273812
274779
  const finalModel = testModel || getDefaultModelForProvider(selectedProvider);
273813
274780
  const config = await loadConfig();
274781
+ config.providers = config.providers || {};
273814
274782
  config.providers[selectedProvider] = trimmedKey;
273815
274783
  config.activeProvider = selectedProvider;
273816
274784
  config.activeModel = finalModel;
@@ -273845,6 +274813,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
273845
274813
  await Promise.resolve().then(() => init_models5());
273846
274814
  const finalModel = testModel || getDefaultModelForProvider(selectedProvider);
273847
274815
  const config = await loadConfig();
274816
+ config.providers = config.providers || {};
273848
274817
  config.providers[selectedProvider] = trimmedKey;
273849
274818
  config.activeProvider = selectedProvider;
273850
274819
  config.activeModel = finalModel;
@@ -273920,6 +274889,8 @@ ${formatSubscriptionCard(bundle, targetModel)}`
273920
274889
  config.decemberToken = undefined;
273921
274890
  config.email = undefined;
273922
274891
  setCurrentEmail(undefined);
274892
+ useCliStore.getState().setHasDecember(false);
274893
+ useCliStore.getState().setDecemberEmail(undefined);
273923
274894
  removedName = "December Cloud Wallet";
273924
274895
  if (config.activeProvider === "december" || config.activeProvider === "december_proxy") {
273925
274896
  config.activeProvider = Object.keys(config.subscriptions || {})[0] || Object.keys(config.providers || {})[0] || undefined;
@@ -273939,7 +274910,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
273939
274910
  delete config.providers[provider];
273940
274911
  removedName = `${provider.charAt(0).toUpperCase() + provider.slice(1)} API Key`;
273941
274912
  if (config.activeProvider === provider) {
273942
- config.activeProvider = Object.keys(config.subscriptions || {})[0] || Object.keys(config.providers)[0] || (config.decemberToken ? "december_proxy" : undefined);
274913
+ config.activeProvider = Object.keys(config.subscriptions || {})[0] || Object.keys(config.providers || {})[0] || (config.decemberToken ? "december_proxy" : undefined);
273943
274914
  }
273944
274915
  }
273945
274916
  }
@@ -273949,6 +274920,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
273949
274920
  const authStatus = await getAuthStatus();
273950
274921
  setIsAuthenticated(!!providerConfig);
273951
274922
  setHasBothAuth(authStatus.hasByok && authStatus.hasDecember);
274923
+ useCliStore.getState().setHasDecember(authStatus.hasDecember);
273952
274924
  setSettingsAuthPriority(authStatus.authPriority);
273953
274925
  if (providerConfig && agent) {
273954
274926
  const llm = instantiateProvider(providerConfig.provider, providerConfig.apiKey, {
@@ -274066,6 +275038,23 @@ ${formatSubscriptionCard(bundle, targetModel)}`
274066
275038
  const targetModel = modelName || getDefaultModelForProvider(currentProvider) || "default";
274067
275039
  await applyOllamaConfig(urlToUse, targetModel, currentProvider);
274068
275040
  };
275041
+ const handleOpenDeviceAuthUrl = async () => {
275042
+ const url = useCliStore.getState().pendingDeviceAuthUrl;
275043
+ if (url) {
275044
+ await Promise.resolve().then(() => init_open());
275045
+ await openUrl(url).catch(() => {});
275046
+ addToast("Opening authorization link in browser...", "info");
275047
+ }
275048
+ };
275049
+ const handleAbortAuth = () => {
275050
+ if (deviceAuthAbortRef.current) {
275051
+ deviceAuthAbortRef.current.abort();
275052
+ deviceAuthAbortRef.current = null;
275053
+ }
275054
+ useCliStore.getState().setPendingDeviceAuthUrl(null);
275055
+ useCliStore.getState().setIsStreaming(false);
275056
+ useCliStore.getState().setAuthMode("none");
275057
+ };
274069
275058
  return {
274070
275059
  handleAuthMenuSelect,
274071
275060
  handleModelSelect,
@@ -274079,7 +275068,9 @@ ${formatSubscriptionCard(bundle, targetModel)}`
274079
275068
  handleSessionSelect,
274080
275069
  handleOllamaRetry,
274081
275070
  handleOllamaCancel,
274082
- handleOllamaProceed
275071
+ handleOllamaProceed,
275072
+ handleOpenDeviceAuthUrl,
275073
+ handleAbortAuth
274083
275074
  };
274084
275075
  }
274085
275076
  var init_use_auth_handlers = __esm(async () => {
@@ -274800,6 +275791,8 @@ function useAgentSession({
274800
275791
  isAuthenticated: initialAuth,
274801
275792
  authMethod: initialAuthMethod,
274802
275793
  hasBothAuth: initialHasBothAuth,
275794
+ hasDecember: initialHasDecember,
275795
+ decemberEmail: initialDecemberEmail,
274803
275796
  settingsAuthPriority: initialSettingsAuthPriority,
274804
275797
  cliVersion,
274805
275798
  userEmail,
@@ -274815,6 +275808,10 @@ function useAgentSession({
274815
275808
  setAuthMethod,
274816
275809
  hasBothAuth,
274817
275810
  setHasBothAuth,
275811
+ hasDecember,
275812
+ setHasDecember,
275813
+ decemberEmail,
275814
+ setDecemberEmail,
274818
275815
  settingsAuthPriority,
274819
275816
  setSettingsAuthPriority,
274820
275817
  currentEmail,
@@ -274947,10 +275944,20 @@ function useAgentSession({
274947
275944
  isAuthenticated: initialAuth,
274948
275945
  authMethod: initialAuthMethod,
274949
275946
  hasBothAuth: initialHasBothAuth !== undefined ? initialHasBothAuth : prev.hasBothAuth,
275947
+ hasDecember: initialHasDecember !== undefined ? initialHasDecember : prev.hasDecember,
275948
+ decemberEmail: initialDecemberEmail !== undefined ? initialDecemberEmail : prev.decemberEmail,
274950
275949
  settingsAuthPriority: initialSettingsAuthPriority !== undefined ? initialSettingsAuthPriority : prev.settingsAuthPriority,
274951
275950
  currentEmail: userEmail !== undefined ? userEmail : prev.currentEmail
274952
275951
  }));
274953
- }, [initialAuth, initialAuthMethod, initialHasBothAuth, initialSettingsAuthPriority, userEmail]);
275952
+ }, [
275953
+ initialAuth,
275954
+ initialAuthMethod,
275955
+ initialHasBothAuth,
275956
+ initialHasDecember,
275957
+ initialDecemberEmail,
275958
+ initialSettingsAuthPriority,
275959
+ userEmail
275960
+ ]);
274954
275961
  import_react71.useEffect(() => {
274955
275962
  if (agent) {
274956
275963
  setupAgentInterceptors(agent, {
@@ -275263,7 +276270,11 @@ function useAgentSession({
275263
276270
  role: "user",
275264
276271
  text: `Generate plan from grill interview for: "${originalPrompt}"`
275265
276272
  },
275266
- { id: assistantMsgId, role: "assistant", blocks: [] }
276273
+ {
276274
+ id: assistantMsgId,
276275
+ role: "assistant",
276276
+ blocks: [{ type: "text", content: "Thinking..." }]
276277
+ }
275267
276278
  ]);
275268
276279
  let planSuccess = false;
275269
276280
  const errorContext = {
@@ -275346,7 +276357,11 @@ function useAgentSession({
275346
276357
  role: "user",
275347
276358
  text: `Refine plan: "${feedback}"`
275348
276359
  },
275349
- { id: assistantMsgId, role: "assistant", blocks: [] }
276360
+ {
276361
+ id: assistantMsgId,
276362
+ role: "assistant",
276363
+ blocks: [{ type: "text", content: "Thinking..." }]
276364
+ }
275350
276365
  ]);
275351
276366
  let planSuccess = false;
275352
276367
  const errorContext = {
@@ -275449,7 +276464,11 @@ function useAgentSession({
275449
276464
  role: "user",
275450
276465
  text: `/plan ${trimmedGoal}`
275451
276466
  },
275452
- { id: assistantMsgId, role: "assistant", blocks: [] }
276467
+ {
276468
+ id: assistantMsgId,
276469
+ role: "assistant",
276470
+ blocks: [{ type: "text", content: "Thinking..." }]
276471
+ }
275453
276472
  ]);
275454
276473
  let planSuccess = false;
275455
276474
  const errorContext = {
@@ -276406,6 +277425,25 @@ ${decStatus}
276406
277425
  setAuthMode("tasks_mode");
276407
277426
  return;
276408
277427
  }
277428
+ if (text.trim() === "/tui" || text.trim().startsWith("/tui ")) {
277429
+ const subArg = text.trim().slice("/tui".length).trim().toLowerCase();
277430
+ const currentIsInline = useCliStore.getState().isInline;
277431
+ let targetInline;
277432
+ if (subArg === "fullscreen" || subArg === "full") {
277433
+ targetInline = false;
277434
+ } else if (subArg === "classic" || subArg === "inline") {
277435
+ targetInline = true;
277436
+ } else {
277437
+ targetInline = !currentIsInline;
277438
+ }
277439
+ useCliStore.getState().setIsInline(targetInline);
277440
+ if (!targetInline) {
277441
+ addToast("Switched to fullscreen renderer (DEC 2026 synchronized updates, alternate buffer, mouse auto-copy).", "info");
277442
+ } else {
277443
+ addToast("Switched to classic inline renderer.", "info");
277444
+ }
277445
+ return;
277446
+ }
276409
277447
  if (text.trim() === "/usage") {
276410
277448
  await fetchUsageData();
276411
277449
  setAuthMode("usage");
@@ -276524,6 +277562,7 @@ If it doesn't open automatically, please click here:
276524
277562
  "skill",
276525
277563
  "skills",
276526
277564
  "tasks",
277565
+ "tui",
276527
277566
  "update",
276528
277567
  "usage"
276529
277568
  ]);
@@ -276559,7 +277598,13 @@ If it doesn't open automatically, please click here:
276559
277598
  });
276560
277599
  return [...prev, ...currentActive, newUserMsg];
276561
277600
  });
276562
- setActiveMessages([{ id: assistantMsgId, role: "assistant", blocks: [] }]);
277601
+ setActiveMessages([
277602
+ {
277603
+ id: assistantMsgId,
277604
+ role: "assistant",
277605
+ blocks: [{ type: "text", content: "Thinking..." }]
277606
+ }
277607
+ ]);
276563
277608
  const errorContext = {
276564
277609
  provider: agent?.modelOptions?.provider || useCliStore.getState().selectedProvider,
276565
277610
  model: agent?.modelOptions?.model || useCliStore.getState().activeModel
@@ -276654,19 +277699,6 @@ If it doesn't open automatically, please click here:
276654
277699
  setSettingsAuthPriority,
276655
277700
  setSwitchItems
276656
277701
  ]);
276657
- const handleAbort = import_react71.useCallback(() => {
276658
- if (activeShellAbortRef.current) {
276659
- activeShellAbortRef.current();
276660
- activeShellAbortRef.current = null;
276661
- }
276662
- if (isStreaming && agent) {
276663
- agent.abort();
276664
- setQueuedPrompts([]);
276665
- }
276666
- if (useCliStore.getState().planWorkflow.phase === "executing") {
276667
- setPlanWorkflow({ phase: "idle" });
276668
- }
276669
- }, [isStreaming, agent, setQueuedPrompts, setPlanWorkflow]);
276670
277702
  const { handleSettingsMainSelect } = useSettingsHandlers();
276671
277703
  const {
276672
277704
  handleAuthMenuSelect,
@@ -276681,8 +277713,46 @@ If it doesn't open automatically, please click here:
276681
277713
  handleSessionSelect,
276682
277714
  handleOllamaRetry,
276683
277715
  handleOllamaCancel,
276684
- handleOllamaProceed
277716
+ handleOllamaProceed,
277717
+ handleOpenDeviceAuthUrl,
277718
+ handleAbortAuth
276685
277719
  } = useAuthHandlers(agent, onLogin, onLoginHeadless);
277720
+ const handleAbort = import_react71.useCallback(() => {
277721
+ if (activeShellAbortRef.current) {
277722
+ activeShellAbortRef.current();
277723
+ activeShellAbortRef.current = null;
277724
+ }
277725
+ if (handleAbortAuth) {
277726
+ handleAbortAuth();
277727
+ }
277728
+ if (isStreaming && agent) {
277729
+ agent.abort();
277730
+ setQueuedPrompts([]);
277731
+ }
277732
+ if (useCliStore.getState().planWorkflow.phase === "executing") {
277733
+ setPlanWorkflow({ phase: "idle" });
277734
+ }
277735
+ }, [isStreaming, agent, setQueuedPrompts, setPlanWorkflow, handleAbortAuth]);
277736
+ const hasTriggeredFirstLaunchRef = import_react71.useRef(false);
277737
+ const handleAuthMenuSelectRef = import_react71.useRef(handleAuthMenuSelect);
277738
+ handleAuthMenuSelectRef.current = handleAuthMenuSelect;
277739
+ import_react71.useEffect(() => {
277740
+ if (hasTriggeredFirstLaunchRef.current)
277741
+ return;
277742
+ hasTriggeredFirstLaunchRef.current = true;
277743
+ let isMounted = true;
277744
+ const checkFirstLaunchAuth = async () => {
277745
+ await Promise.resolve().then(() => init_config());
277746
+ const config = await loadConfig();
277747
+ if (!config.email && !config.decemberToken && !initialAuth && isMounted) {
277748
+ await handleAuthMenuSelectRef.current({ value: "december" });
277749
+ }
277750
+ };
277751
+ checkFirstLaunchAuth().catch(() => {});
277752
+ return () => {
277753
+ isMounted = false;
277754
+ };
277755
+ }, [initialAuth]);
276686
277756
  const handlePlanApprovalSelect = import_react71.useCallback(async (item) => {
276687
277757
  const originalPrompt = currentPlannedPrompt || useCliStore.getState().currentPlannedPrompt || "";
276688
277758
  const planText = currentPlanText || useCliStore.getState().currentPlanText || "";
@@ -276734,7 +277804,13 @@ If it doesn't open automatically, please click here:
276734
277804
  });
276735
277805
  return [...prev, ...currentActive, newUserMsg];
276736
277806
  });
276737
- setActiveMessages([{ id: assistantMsgId, role: "assistant", blocks: [] }]);
277807
+ setActiveMessages([
277808
+ {
277809
+ id: assistantMsgId,
277810
+ role: "assistant",
277811
+ blocks: [{ type: "text", content: "Thinking..." }]
277812
+ }
277813
+ ]);
276738
277814
  const errorContext = {
276739
277815
  provider: agent?.modelOptions?.provider || useCliStore.getState().selectedProvider,
276740
277816
  model: agent?.modelOptions?.model || useCliStore.getState().activeModel
@@ -276895,6 +277971,10 @@ If it doesn't open automatically, please click here:
276895
277971
  setIsAuthenticated,
276896
277972
  authMethod,
276897
277973
  hasBothAuth,
277974
+ hasDecember,
277975
+ setHasDecember,
277976
+ decemberEmail,
277977
+ setDecemberEmail,
276898
277978
  settingsAuthPriority,
276899
277979
  currentEmail,
276900
277980
  setCurrentEmail,
@@ -276984,7 +278064,13 @@ If it doesn't open automatically, please click here:
276984
278064
  handleRefreshUsage: fetchUsageData,
276985
278065
  handleOpenBilling,
276986
278066
  onRefresh: fetchUsageData,
276987
- onOpenBilling: handleOpenBilling
278067
+ onOpenBilling: handleOpenBilling,
278068
+ isInline: useCliStore((state) => state.isInline),
278069
+ setIsInline: useCliStore((state) => state.setIsInline),
278070
+ handleOpenDeviceAuthUrl,
278071
+ handleAbortAuth,
278072
+ pendingDeviceAuthUrl: useCliStore((state) => state.pendingDeviceAuthUrl),
278073
+ setPendingDeviceAuthUrl: useCliStore((state) => state.setPendingDeviceAuthUrl)
276988
278074
  };
276989
278075
  }
276990
278076
  var import_react71;
@@ -277012,6 +278098,24 @@ var init_use_agent_session = __esm(async () => {
277012
278098
  import_react71 = __toESM(require_react(), 1);
277013
278099
  });
277014
278100
 
278101
+ // src/utils/banner.ts
278102
+ function resolveAnnouncement(options) {
278103
+ const { config, isInline = false, isNewVersion = false, releaseHighlights } = options;
278104
+ if (config.showChangelogBanner === false) {
278105
+ return null;
278106
+ }
278107
+ if (!releaseHighlights || !Array.isArray(releaseHighlights.bullets) || releaseHighlights.bullets.length === 0) {
278108
+ return null;
278109
+ }
278110
+ if (isInline && !isNewVersion) {
278111
+ return null;
278112
+ }
278113
+ return {
278114
+ ...releaseHighlights,
278115
+ bullets: releaseHighlights.bullets.slice(0, 2)
278116
+ };
278117
+ }
278118
+
277015
278119
  // src/index.ts
277016
278120
  init_package();
277017
278121
  import path41 from "node:path";
@@ -277032,7 +278136,6 @@ function parseCliArgs(args) {
277032
278136
  global: { type: "boolean", short: "g" },
277033
278137
  local: { type: "boolean", short: "l" },
277034
278138
  resume: { type: "boolean", short: "r" },
277035
- inline: { type: "boolean" },
277036
278139
  model: { type: "string", short: "m" },
277037
278140
  provider: { type: "string", short: "p" },
277038
278141
  "session-id": { type: "string" },
@@ -277051,7 +278154,7 @@ function parseCliArgs(args) {
277051
278154
  const isGlobal = Boolean(values.global);
277052
278155
  const isLocal = Boolean(values.local);
277053
278156
  const isResume = Boolean(values.resume);
277054
- const isInline = Boolean(values.inline);
278157
+ const isInline = false;
277055
278158
  const model = values.model;
277056
278159
  const provider = values.provider;
277057
278160
  const sessionId = values["session-id"];
@@ -277152,12 +278255,11 @@ Options:
277152
278255
  }
277153
278256
  // src/constants/release-highlights.json
277154
278257
  var release_highlights_default = {
277155
- version: "0.4.9",
277156
- title: "What's New in v0.4.9",
278258
+ version: "0.4.11",
278259
+ title: "What's New in v0.4.11",
277157
278260
  bullets: [
277158
- "*(tui)* Remove expand mode and make thoughts transient with live topic tracking",
277159
- "*(tui)* Implement ephemeral discovery and silent reads for clean terminal history",
277160
- "*(cli)* Stream transient thinking topics and initialize turn with thinking status"
278261
+ "Add fullscreen renderer mode with synchronized updates and mouse auto-copy",
278262
+ "Update december billing label to december wallet and clean up inline mode"
277161
278263
  ],
277162
278264
  url: "https://trydecember.com/docs/changelog"
277163
278265
  };
@@ -277400,7 +278502,7 @@ Executing Headless Task: "${parsedArgs.prompt}"
277400
278502
  { useAgentSession },
277401
278503
  { localOperations, setActiveScopeDir },
277402
278504
  { instantiateProvider },
277403
- { ensureValidModelForProvider },
278505
+ { ensureValidModelForProvider, getModelLabel },
277404
278506
  { useCliStore }
277405
278507
  ] = await Promise.all([
277406
278508
  Promise.resolve().then(() => (init_src5(), exports_src3)),
@@ -277456,6 +278558,21 @@ Executing Headless Task: "${parsedArgs.prompt}"
277456
278558
  const initialModel = providerConfig?.authMethod === "december" ? "december-auto" : parsedArgs.model || providerConfig?.model || ensureValidModelForProvider(activeProvider, config.activeModel);
277457
278559
  useCliStore.getState().setActiveModel(initialModel);
277458
278560
  useCliStore.getState().setSelectedProvider(activeProvider);
278561
+ useCliStore.getState().setIsAuthenticated(isAuthenticated);
278562
+ useCliStore.getState().setHasDecember(authStatus.hasDecember);
278563
+ if (config.decemberToken && config.email) {
278564
+ useCliStore.getState().setDecemberEmail(config.email);
278565
+ }
278566
+ if (providerConfig?.authMethod) {
278567
+ useCliStore.getState().setAuthMethod(providerConfig.authMethod);
278568
+ }
278569
+ if (!isAuthenticated) {
278570
+ if (!config.email && !config.decemberToken) {
278571
+ useCliStore.getState().setAuthMode("none");
278572
+ } else {
278573
+ useCliStore.getState().setAuthMode("menu");
278574
+ }
278575
+ }
277459
278576
  const harness = new AgentHarness({
277460
278577
  llm,
277461
278578
  tools: CORE_TOOLS,
@@ -277488,15 +278605,17 @@ Executing Headless Task: "${parsedArgs.prompt}"
277488
278605
  agent.loadContext().catch(() => {});
277489
278606
  }
277490
278607
  await Promise.resolve().then(() => init_bin_discovery());
277491
- const isFirstRun = !config.lastSeenVersion || compareVersions(package_default.version, config.lastSeenVersion) > 0;
277492
- let announcement = null;
277493
- if (isFirstRun) {
277494
- if (release_highlights_default && Array.isArray(release_highlights_default.bullets) && release_highlights_default.bullets.length > 0) {
277495
- announcement = release_highlights_default;
277496
- }
278608
+ const isNewVersion = !config.lastSeenVersion || compareVersions(package_default.version, config.lastSeenVersion) > 0;
278609
+ if (isNewVersion) {
277497
278610
  config.lastSeenVersion = package_default.version;
277498
278611
  saveConfig(config).catch(() => {});
277499
278612
  }
278613
+ await Promise.resolve();
278614
+ const announcement = resolveAnnouncement({
278615
+ config,
278616
+ isNewVersion,
278617
+ releaseHighlights: release_highlights_default
278618
+ });
277500
278619
  function AppWrapper(props) {
277501
278620
  const [latestVersion, setLatestVersion] = React.useState(undefined);
277502
278621
  React.useEffect(() => {
@@ -277520,37 +278639,57 @@ Executing Headless Task: "${parsedArgs.prompt}"
277520
278639
  session
277521
278640
  });
277522
278641
  }
277523
- const userEmail = config.decemberToken ? config.email : undefined;
277524
- const isFullscreen = !parsedArgs.isInline;
278642
+ const userEmail = config.decemberToken ? config.email : providerConfig?.subscription?.email || config.email || undefined;
278643
+ let inkInstance = null;
278644
+ const handleExit = () => {
278645
+ if (inkInstance) {
278646
+ try {
278647
+ inkInstance.clear();
278648
+ inkInstance.unmount();
278649
+ } catch {}
278650
+ }
278651
+ process.exit(0);
278652
+ };
277525
278653
  if (process.stdout.isTTY) {
277526
- const enterSequences = isFullscreen ? "\x1B[?2004h\x1B[?1000h\x1B[?1002h\x1B[?1006h\x1B[?1007h" : "\x1B[?2004h";
277527
- const exitSequences = isFullscreen ? "\x1B[?2026l\x1B[?2004l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?1007l" : "\x1B[?2026l\x1B[?2004l";
277528
- process.stdout.write(enterSequences);
278654
+ const exitSequences = "\x1B[?2026l\x1B[?2004l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?1007l\x1B[?1049l\x1B[?25h";
277529
278655
  const cleanupTerminal = () => {
277530
278656
  try {
278657
+ if (inkInstance) {
278658
+ try {
278659
+ inkInstance.clear();
278660
+ inkInstance.unmount();
278661
+ } catch {}
278662
+ }
277531
278663
  process.stdout.write(exitSequences);
277532
278664
  } catch {}
277533
278665
  };
277534
278666
  process.on("exit", cleanupTerminal);
277535
- process.on("SIGINT", cleanupTerminal);
277536
- process.on("SIGTERM", cleanupTerminal);
278667
+ process.on("SIGINT", handleExit);
278668
+ process.on("SIGTERM", handleExit);
277537
278669
  }
277538
- render_default(React.createElement(RootLayout, { fullscreen: isFullscreen }, React.createElement(AppWrapper, {
278670
+ inkInstance = render_default(React.createElement(RootLayout, { fullscreen: true }, React.createElement(AppWrapper, {
277539
278671
  agent,
277540
278672
  isAuthenticated,
277541
278673
  authMethod: providerConfig?.authMethod,
277542
278674
  hasBothAuth: authStatus.hasByok && authStatus.hasDecember,
278675
+ hasDecember: authStatus.hasDecember,
278676
+ decemberEmail: config.decemberToken ? config.email : undefined,
277543
278677
  settingsAuthPriority: authStatus.authPriority,
277544
278678
  cliVersion: package_default.version,
277545
278679
  userEmail,
278680
+ activeModel: initialModel,
278681
+ modelLabel: getModelLabel(initialModel),
278682
+ selectedProvider: activeProvider,
277546
278683
  sessionRepository,
277547
- isInline: parsedArgs.isInline,
277548
- onLogin: (onCode) => Promise.resolve().then(() => (init_auth(), {})).then(({}) => loginViaDeviceCode(undefined, onCode))
278684
+ onExit: handleExit,
278685
+ onLogin: (onCode, signal) => Promise.resolve().then(() => (init_auth(), {})).then(({}) => loginViaDeviceCode(undefined, onCode, signal))
277549
278686
  })), {
277550
- alternateScreen: isFullscreen,
278687
+ alternateScreen: true,
277551
278688
  exitOnCtrlC: false,
277552
278689
  maxFps: 60
277553
278690
  });
278691
+ await inkInstance.waitUntilExit();
278692
+ handleExit();
277554
278693
  }
277555
278694
  main().catch(console.error);
277556
278695
  export {