@trydecember/cli 0.3.26 → 0.3.27

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 (2) hide show
  1. package/dist/december.js +1252 -334
  2. 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.3.26",
68
+ version: "0.3.27",
69
69
  description: "a coding agent for terminal and cloud.",
70
70
  homepage: "https://trydecember.com",
71
71
  repository: {
@@ -244,6 +244,11 @@ var init_env_sanitizer = __esm(() => {
244
244
  "NVIDIA_API_KEY",
245
245
  "PERPLEXITY_API_KEY",
246
246
  "SAMBANOVA_API_KEY",
247
+ "SARVAM_API_KEY",
248
+ "STEPFUN_API_KEY",
249
+ "UPSTAGE_API_KEY",
250
+ "TINKER_API_KEY",
251
+ "THINKINGMACHINES_API_KEY",
247
252
  "SILICONFLOW_API_KEY",
248
253
  "XAI_API_KEY",
249
254
  "ZAI_API_KEY",
@@ -295,6 +300,14 @@ function getModelContextWindow(value) {
295
300
  return 262144;
296
301
  if (lower.includes("muse-spark") || lower.includes("muse"))
297
302
  return 1048576;
303
+ if (lower.includes("laguna-s"))
304
+ return 1048576;
305
+ if (lower.includes("laguna"))
306
+ return 262144;
307
+ if (lower.includes("fugu"))
308
+ return 1e6;
309
+ if (lower.includes("namazu"))
310
+ return 262144;
298
311
  if (lower.includes("gpt-5.6") || lower.includes("gpt-5.5"))
299
312
  return 1050000;
300
313
  if (lower.includes("gpt-5.4"))
@@ -462,7 +475,32 @@ var init_models = __esm(() => {
462
475
  "muse-spark-1.3-contributor": 1048576,
463
476
  "muse-spark-1.2": 1048576,
464
477
  "muse-spark-1.2-contributor": 1048576,
465
- "muse-spark-1.1": 1048576
478
+ "muse-spark-1.1": 1048576,
479
+ "laguna-s-2.1": 1048576,
480
+ "laguna-m.1": 262144,
481
+ "laguna-xs-2.1": 262144,
482
+ "poolside/laguna-s-2.1": 1048576,
483
+ "poolside/laguna-m.1": 262144,
484
+ "poolside/laguna-xs-2.1": 262144,
485
+ fugu: 1e6,
486
+ "fugu-ultra": 1e6,
487
+ "fugu-ultra-v1.1": 1e6,
488
+ "fugu-ultra-v1.0": 1e6,
489
+ "fugu-ultra-20260615": 1e6,
490
+ "fugu-cyber": 1e6,
491
+ "fugu-cyber-v1.0": 1e6,
492
+ "sakana-namazu": 262144,
493
+ "sakana-namazu-v1.0": 262144,
494
+ "sakana/fugu": 1e6,
495
+ "sakana/fugu-ultra": 1e6,
496
+ "sakana/sakana-namazu": 262144,
497
+ "solar-pro4": 524288,
498
+ "solar-pro3": 524288,
499
+ "solar-pro2": 524288,
500
+ "solar-mini": 65536,
501
+ "thinkingmachines/Inkling": 131072,
502
+ "thinkingmachines/Inkling:peft:262144": 262144,
503
+ inkling: 131072
466
504
  };
467
505
  });
468
506
 
@@ -9307,7 +9345,7 @@ function supportsReasoningEffort(model, baseURL) {
9307
9345
  if (name.includes("codestral") || name.includes("mistral") || name.includes("devstral") || name.includes("ministral") || name.includes("magistral") || name.includes("llama") || name.includes("qwen") || name.includes("minimax") || name.includes("kimi-k2") || name.includes("kimi-for-coding")) {
9308
9346
  return false;
9309
9347
  }
9310
- if (baseURL && (baseURL.includes("mistral.ai") || baseURL.includes("groq.com") || baseURL.includes("deepseek.com") || baseURL.includes("siliconflow") || baseURL.includes("together.xyz") || baseURL.includes("hyperbolic.xyz") || baseURL.includes("cerebras.ai") || baseURL.includes("sambanova.ai") || baseURL.includes("arcee.ai") || baseURL.includes("meta.ai") || baseURL.includes("minimax"))) {
9348
+ if (baseURL && (baseURL.includes("mistral.ai") || baseURL.includes("groq.com") || baseURL.includes("deepseek.com") || baseURL.includes("siliconflow") || baseURL.includes("together.xyz") || baseURL.includes("hyperbolic.xyz") || baseURL.includes("cerebras.ai") || baseURL.includes("sambanova.ai") || baseURL.includes("arcee.ai") || baseURL.includes("meta.ai") || baseURL.includes("minimax") || baseURL.includes("poolside.ai") || baseURL.includes("sakana.ai") || baseURL.includes("sarvam.ai") || baseURL.includes("stepfun.ai") || baseURL.includes("upstage.ai"))) {
9311
9349
  return false;
9312
9350
  }
9313
9351
  return true;
@@ -9410,14 +9448,14 @@ function openaiProvider(baseURL, apiKey, defaultHeaders, customClient) {
9410
9448
  });
9411
9449
  }
9412
9450
  }
9413
- const oaiTools = tools?.map((t) => ({
9451
+ const oaiTools = tools && tools.length > 0 ? tools.map((t) => ({
9414
9452
  type: "function",
9415
9453
  function: {
9416
9454
  name: t.name,
9417
9455
  description: t.description,
9418
9456
  parameters: t.inputSchema
9419
9457
  }
9420
- }));
9458
+ })) : undefined;
9421
9459
  const thinkingLevel = modelOptions?.thinkingLevel;
9422
9460
  let reasoningEffort;
9423
9461
  if (thinkingLevel && thinkingLevel !== "off" && thinkingLevel !== "auto") {
@@ -9434,11 +9472,13 @@ function openaiProvider(baseURL, apiKey, defaultHeaders, customClient) {
9434
9472
  const createParams = {
9435
9473
  model: resolvedModel,
9436
9474
  messages: oaiMessages,
9437
- tools: oaiTools,
9438
9475
  stream: true,
9439
9476
  temperature: modelOptions?.temperature,
9440
9477
  max_tokens: modelOptions?.max_tokens
9441
9478
  };
9479
+ if (oaiTools && oaiTools.length > 0) {
9480
+ createParams.tools = oaiTools;
9481
+ }
9442
9482
  if (supportsStreamOptions(baseURL)) {
9443
9483
  createParams.stream_options = { include_usage: true };
9444
9484
  }
@@ -63303,6 +63343,10 @@ function formatInsufficientCreditsNotice(provider, model, rawErrorMsg) {
63303
63343
  normalized = "meta";
63304
63344
  } else if (modelLower.includes("minimax")) {
63305
63345
  normalized = "minimax";
63346
+ } else if (modelLower.includes("laguna")) {
63347
+ normalized = "poolside";
63348
+ } else if (modelLower.includes("fugu") || modelLower.includes("namazu") || modelLower.includes("sakana")) {
63349
+ normalized = "sakana";
63306
63350
  } else if (modelLower.includes("deepseek")) {
63307
63351
  normalized = "deepseek";
63308
63352
  } else if (modelLower.includes("kimi") || modelLower.includes("moonshot")) {
@@ -63377,6 +63421,8 @@ var init_usage_rates = __esm(() => {
63377
63421
  minimax: "https://platform.minimax.io/console/access",
63378
63422
  minimaxai: "https://platform.minimax.io/console/access",
63379
63423
  "minimax-ai": "https://platform.minimax.io/console/access",
63424
+ poolside: "https://platform.poolside.ai/api-keys",
63425
+ sakana: "https://console.sakana.ai/api-keys",
63380
63426
  ollama: "http://localhost:11434"
63381
63427
  };
63382
63428
  PROVIDER_DISPLAY_NAMES = {
@@ -63419,6 +63465,8 @@ var init_usage_rates = __esm(() => {
63419
63465
  minimax: "MiniMax",
63420
63466
  minimaxai: "MiniMax",
63421
63467
  "minimax-ai": "MiniMax",
63468
+ poolside: "Poolside",
63469
+ sakana: "Sakana AI",
63422
63470
  ollama: "Ollama (Local)"
63423
63471
  };
63424
63472
  });
@@ -63810,13 +63858,17 @@ class SkillDiscoveryEngine {
63810
63858
  }
63811
63859
  }
63812
63860
  scanGlobalDeclaredSkills(map) {
63813
- const globalJson = path9.join(this.homeDir, ".config", "december", "skills.json");
63814
- this.scanDeclaredConfigFile(globalJson, "declared", map);
63861
+ const canonicalJson = path9.join(this.homeDir, ".december", "skills.json");
63862
+ const legacyJson = path9.join(this.homeDir, ".config", "december", "skills.json");
63863
+ this.scanDeclaredConfigFile(legacyJson, "declared", map);
63864
+ this.scanDeclaredConfigFile(canonicalJson, "declared", map);
63815
63865
  }
63816
63866
  scanGlobalPluginSkills(map) {
63817
- const decemberPlugins = path9.join(this.homeDir, ".config", "december", "plugins");
63867
+ const legacyPlugins = path9.join(this.homeDir, ".config", "december", "plugins");
63868
+ const canonicalPlugins = path9.join(this.homeDir, ".december", "plugins");
63818
63869
  const geminiPlugins = path9.join(this.homeDir, ".gemini", "config", "plugins");
63819
- this.scanPluginsDir(decemberPlugins, "global-plugin", map);
63870
+ this.scanPluginsDir(legacyPlugins, "global-plugin", map);
63871
+ this.scanPluginsDir(canonicalPlugins, "global-plugin", map);
63820
63872
  this.scanPluginsDir(geminiPlugins, "global-plugin", map);
63821
63873
  }
63822
63874
  scanGlobalUserSkills(map) {
@@ -63828,7 +63880,8 @@ class SkillDiscoveryEngine {
63828
63880
  path9.join(this.homeDir, ".gemini", "config", "skills"),
63829
63881
  path9.join(this.homeDir, ".agents", "skills"),
63830
63882
  path9.join(this.homeDir, ".agent", "skills"),
63831
- path9.join(this.homeDir, ".config", "december", "skills")
63883
+ path9.join(this.homeDir, ".config", "december", "skills"),
63884
+ path9.join(this.homeDir, ".december", "skills")
63832
63885
  ];
63833
63886
  for (const dir of candidateGlobalDirs) {
63834
63887
  this.scanDirectoryForSkills(dir, "global", map);
@@ -64098,17 +64151,17 @@ function anthropicProvider(baseURL, apiKey, customClientOrDefaultHeaders, custom
64098
64151
  }
64099
64152
  }
64100
64153
  }
64101
- const antTools = tools?.map((t, idx) => {
64154
+ const antTools = tools && tools.length > 0 ? tools.map((t, idx) => {
64102
64155
  const toolDef = {
64103
64156
  name: t.name,
64104
64157
  description: t.description,
64105
64158
  input_schema: t.inputSchema
64106
64159
  };
64107
- if (tools && idx === tools.length - 1) {
64160
+ if (idx === tools.length - 1) {
64108
64161
  toolDef.cache_control = { type: "ephemeral" };
64109
64162
  }
64110
64163
  return toolDef;
64111
- });
64164
+ }) : undefined;
64112
64165
  const formattedSystem = systemPrompt ? [
64113
64166
  {
64114
64167
  type: "text",
@@ -64138,7 +64191,7 @@ function anthropicProvider(baseURL, apiKey, customClientOrDefaultHeaders, custom
64138
64191
  model: resolveAnthropicModel(modelOptions?.model),
64139
64192
  messages: antMessages,
64140
64193
  system: formattedSystem,
64141
- tools: antTools,
64194
+ tools: antTools && antTools.length > 0 ? antTools : undefined,
64142
64195
  stream: true,
64143
64196
  max_tokens: maxTokens,
64144
64197
  temperature: thinking ? undefined : modelOptions?.temperature,
@@ -103840,7 +103893,7 @@ function geminiProvider(apiKey, customClient) {
103840
103893
  });
103841
103894
  }
103842
103895
  }
103843
- const geminiTools = tools ? [
103896
+ const geminiTools = tools && tools.length > 0 ? [
103844
103897
  {
103845
103898
  functionDeclarations: tools.map((t) => ({
103846
103899
  name: t.name,
@@ -104151,14 +104204,14 @@ function ollamaProvider(baseURL = "http://localhost:11434/v1", apiKey = "ollama"
104151
104204
  });
104152
104205
  }
104153
104206
  }
104154
- const oaiTools = tools?.map((t) => ({
104207
+ const oaiTools = tools && tools.length > 0 ? tools.map((t) => ({
104155
104208
  type: "function",
104156
104209
  function: {
104157
104210
  name: t.name,
104158
104211
  description: t.description,
104159
104212
  parameters: t.inputSchema
104160
104213
  }
104161
- }));
104214
+ })) : undefined;
104162
104215
  const resolvedModel = resolveOllamaModel(modelOptions?.model);
104163
104216
  const numCtx = modelOptions?.numCtx ?? defaultNumCtx ?? getModelContextWindow(resolvedModel);
104164
104217
  const stream = await client.chat.completions.create({
@@ -104394,7 +104447,7 @@ function antigravityProvider(token, options) {
104394
104447
  });
104395
104448
  }
104396
104449
  }
104397
- const antigravityTools = tools ? [
104450
+ const antigravityTools = tools && tools.length > 0 ? [
104398
104451
  {
104399
104452
  functionDeclarations: tools.map((t) => ({
104400
104453
  name: t.name,
@@ -104859,6 +104912,36 @@ var init_meta = __esm(() => {
104859
104912
  init_openai2();
104860
104913
  });
104861
104914
 
104915
+ // ../../packages/providers/src/providers/poolside.ts
104916
+ var init_poolside = __esm(() => {
104917
+ init_openai2();
104918
+ });
104919
+
104920
+ // ../../packages/providers/src/providers/sakana.ts
104921
+ var init_sakana = __esm(() => {
104922
+ init_openai2();
104923
+ });
104924
+
104925
+ // ../../packages/providers/src/providers/sarvam.ts
104926
+ var init_sarvam = __esm(() => {
104927
+ init_openai2();
104928
+ });
104929
+
104930
+ // ../../packages/providers/src/providers/stepfun.ts
104931
+ var init_stepfun = __esm(() => {
104932
+ init_openai2();
104933
+ });
104934
+
104935
+ // ../../packages/providers/src/providers/upstage.ts
104936
+ var init_upstage = __esm(() => {
104937
+ init_openai2();
104938
+ });
104939
+
104940
+ // ../../packages/providers/src/providers/thinkingmachines.ts
104941
+ var init_thinkingmachines = __esm(() => {
104942
+ init_anthropic();
104943
+ });
104944
+
104862
104945
  // ../../packages/providers/src/index.ts
104863
104946
  var exports_src2 = {};
104864
104947
  __export(exports_src2, {
@@ -104906,6 +104989,12 @@ var init_src3 = __esm(() => {
104906
104989
  init_codex();
104907
104990
  init_arcee();
104908
104991
  init_meta();
104992
+ init_poolside();
104993
+ init_sakana();
104994
+ init_sarvam();
104995
+ init_stepfun();
104996
+ init_upstage();
104997
+ init_thinkingmachines();
104909
104998
  });
104910
104999
 
104911
105000
  // src/utils/openrouter-models.ts
@@ -105020,13 +105109,24 @@ import fs11 from "node:fs/promises";
105020
105109
  import os2 from "node:os";
105021
105110
  import path11 from "node:path";
105022
105111
  function getModelsCacheFile() {
105023
- const dir = process.env.DECEMBER_CONFIG_DIR || path11.join(os2.homedir(), ".config", "december");
105024
- return path11.join(dir, "models-cache.json");
105112
+ if (process.env.DECEMBER_CONFIG_DIR) {
105113
+ return path11.join(process.env.DECEMBER_CONFIG_DIR, "models-cache.json");
105114
+ }
105115
+ const home = process.env.HOME || process.env.USERPROFILE || os2.homedir();
105116
+ const canonicalFile = path11.join(home, ".december", "models-cache.json");
105117
+ const legacyFile = path11.join(home, ".config", "december", "models-cache.json");
105118
+ if (existsSync(canonicalFile) || !existsSync(legacyFile)) {
105119
+ return canonicalFile;
105120
+ }
105121
+ return legacyFile;
105025
105122
  }
105026
105123
  function initDiskCacheSync() {
105027
105124
  if (diskCacheLoaded)
105028
105125
  return;
105029
105126
  diskCacheLoaded = true;
105127
+ const isTestEnv = !!process.env.BUN_TEST || !!process.env.VITEST;
105128
+ if (isTestEnv && !process.env.DECEMBER_TEST_LOAD_CACHE)
105129
+ return;
105030
105130
  try {
105031
105131
  const cacheFile = getModelsCacheFile();
105032
105132
  if (existsSync(cacheFile)) {
@@ -105332,6 +105432,29 @@ async function fetchLiveProviderModels(provider, apiKey, baseUrl, fetchFn = fetc
105332
105432
  case "meta-ai":
105333
105433
  endpoint = "https://api.meta.ai/v1/models";
105334
105434
  break;
105435
+ case "poolside":
105436
+ endpoint = "https://inference.poolside.ai/v1/models";
105437
+ break;
105438
+ case "sakana":
105439
+ case "sakanaai":
105440
+ case "sakana-ai":
105441
+ endpoint = "https://api.sakana.ai/v1/models";
105442
+ break;
105443
+ case "sarvam":
105444
+ case "sarvamai":
105445
+ case "sarvam-ai":
105446
+ endpoint = "https://api.sarvam.ai/v1/models";
105447
+ break;
105448
+ case "stepfun":
105449
+ case "stepfunai":
105450
+ case "stepfun-ai":
105451
+ endpoint = "https://api.stepfun.ai/v1/models";
105452
+ break;
105453
+ case "upstage":
105454
+ case "upstageai":
105455
+ case "solar":
105456
+ endpoint = "https://api.upstage.ai/v1/solar/models";
105457
+ break;
105335
105458
  case "december":
105336
105459
  case "december_proxy": {
105337
105460
  const serverUrl = process.env.SERVER_URL || "https://api.trydecember.com";
@@ -105777,6 +105900,55 @@ var LIVE_MODEL_CACHE_TTL_MS, liveModelCache, diskCacheLoaded = false, getCurated
105777
105900
  { label: "Muse Spark 1.2 Contributor", value: "muse-spark-1.2-contributor" },
105778
105901
  { label: "Muse Spark 1.1", value: "muse-spark-1.1" }
105779
105902
  ];
105903
+ case "poolside":
105904
+ return [
105905
+ { label: "Laguna S 2.1", value: "laguna-s-2.1" },
105906
+ { label: "Laguna M.1", value: "laguna-m.1" },
105907
+ { label: "Laguna XS 2.1", value: "laguna-xs-2.1" }
105908
+ ];
105909
+ case "sakana":
105910
+ case "sakanaai":
105911
+ case "sakana-ai":
105912
+ return [
105913
+ { label: "Fugu", value: "fugu" },
105914
+ { label: "Fugu Ultra", value: "fugu-ultra" },
105915
+ { label: "Sakana Namazu", value: "sakana-namazu" },
105916
+ { label: "Fugu Cyber", value: "fugu-cyber" }
105917
+ ];
105918
+ case "sarvam":
105919
+ case "sarvamai":
105920
+ case "sarvam-ai":
105921
+ return [
105922
+ { label: "Sarvam 105B", value: "sarvam-105b" },
105923
+ { label: "Sarvam 30B", value: "sarvam-30b" }
105924
+ ];
105925
+ case "stepfun":
105926
+ case "stepfunai":
105927
+ case "stepfun-ai":
105928
+ return [
105929
+ { label: "Step 3.7 Flash", value: "step-3.7-flash" },
105930
+ { label: "Step 3.5 Flash", value: "step-3.5-flash" },
105931
+ { label: "Step 1 32K", value: "step-1-32k" }
105932
+ ];
105933
+ case "upstage":
105934
+ case "upstageai":
105935
+ case "solar":
105936
+ return [
105937
+ { label: "Solar Pro 4", value: "solar-pro4" },
105938
+ { label: "Solar Pro 3", value: "solar-pro3" },
105939
+ { label: "Solar Pro 2", value: "solar-pro2" },
105940
+ { label: "Solar Mini", value: "solar-mini" }
105941
+ ];
105942
+ case "thinkingmachines":
105943
+ case "tinker":
105944
+ case "inkling":
105945
+ return [
105946
+ { label: "Thinking Machines Inkling", value: "thinkingmachines/Inkling" },
105947
+ {
105948
+ label: "Thinking Machines Inkling 256k",
105949
+ value: "thinkingmachines/Inkling:peft:262144"
105950
+ }
105951
+ ];
105780
105952
  case "dashscope":
105781
105953
  case "qwen":
105782
105954
  return [
@@ -105870,6 +106042,12 @@ var LIVE_MODEL_CACHE_TTL_MS, liveModelCache, diskCacheLoaded = false, getCurated
105870
106042
  "ollama",
105871
106043
  "arcee",
105872
106044
  "meta",
106045
+ "poolside",
106046
+ "sakana",
106047
+ "sarvam",
106048
+ "stepfun",
106049
+ "upstage",
106050
+ "thinkingmachines",
105873
106051
  "december_proxy"
105874
106052
  ];
105875
106053
  for (const p of allProviders) {
@@ -105891,6 +106069,12 @@ var LIVE_MODEL_CACHE_TTL_MS, liveModelCache, diskCacheLoaded = false, getCurated
105891
106069
  return true;
105892
106070
  if (normalized === "meta" && (model.includes("/") || model.includes(":")))
105893
106071
  return true;
106072
+ if (normalized === "poolside" && (model.includes("/") || model.startsWith("laguna")))
106073
+ return true;
106074
+ if (normalized === "sakana" && (model.includes("/") || model.startsWith("fugu") || model.startsWith("sakana")))
106075
+ return true;
106076
+ if ((normalized === "thinkingmachines" || normalized === "tinker" || normalized === "inkling") && (model.includes("/") || model.startsWith("inkling")))
106077
+ return true;
105894
106078
  if (normalized === "ollama")
105895
106079
  return isToolCompatibleOllamaModel(model);
105896
106080
  const models = getProviderModels(normalized);
@@ -105918,6 +106102,14 @@ var LIVE_MODEL_CACHE_TTL_MS, liveModelCache, diskCacheLoaded = false, getCurated
105918
106102
  }
105919
106103
  return "gemini-3.8-flash";
105920
106104
  }, ensureValidModelForProvider = (provider, model) => {
106105
+ const normalizedProvider = (provider || "").toLowerCase().trim();
106106
+ if ((normalizedProvider === "thinkingmachines" || normalizedProvider === "tinker" || normalizedProvider === "inkling") && model) {
106107
+ const lowerModel = model.toLowerCase().trim();
106108
+ if (lowerModel === "inkling")
106109
+ return "thinkingmachines/Inkling";
106110
+ if (lowerModel === "inkling:peft:262144")
106111
+ return "thinkingmachines/Inkling:peft:262144";
106112
+ }
105921
106113
  if (model && isValidModelForProvider(provider, model)) {
105922
106114
  return model;
105923
106115
  }
@@ -107386,18 +107578,45 @@ __export(exports_config, {
107386
107578
  applyProviderSwitch: () => applyProviderSwitch,
107387
107579
  formatProviderName: () => formatProviderName,
107388
107580
  getAuthStatus: () => getAuthStatus,
107581
+ getConfigDir: () => getConfigDir,
107389
107582
  getConfiguredProviders: () => getConfiguredProviders,
107583
+ getLegacyConfigDir: () => getLegacyConfigDir,
107390
107584
  getProviderConfig: () => getProviderConfig,
107391
107585
  loadConfig: () => loadConfig,
107392
107586
  resolveSwitchTarget: () => resolveSwitchTarget,
107393
107587
  saveConfig: () => saveConfig,
107394
107588
  updateConfig: () => updateConfig
107395
107589
  });
107590
+ import fsSync from "node:fs";
107396
107591
  import fs16 from "node:fs/promises";
107397
107592
  import os8 from "node:os";
107398
107593
  import path16 from "node:path";
107594
+ function getLegacyConfigDir() {
107595
+ const home = process.env.HOME || process.env.USERPROFILE || os8.homedir();
107596
+ const isTestEnv = !!process.env.VITEST;
107597
+ if (isTestEnv && home === os8.homedir()) {
107598
+ return path16.join(os8.tmpdir(), "december-test-config", ".config", "december");
107599
+ }
107600
+ return path16.join(home, ".config", "december");
107601
+ }
107602
+ function getLegacyConfigFile() {
107603
+ return path16.join(getLegacyConfigDir(), "config.json");
107604
+ }
107399
107605
  function getConfigDir() {
107400
- return process.env.DECEMBER_CONFIG_DIR || path16.join(process.env.HOME || os8.homedir(), ".config", "december");
107606
+ if (process.env.DECEMBER_CONFIG_DIR) {
107607
+ return process.env.DECEMBER_CONFIG_DIR;
107608
+ }
107609
+ const home = process.env.HOME || process.env.USERPROFILE || os8.homedir();
107610
+ const isTestEnv = !!process.env.VITEST;
107611
+ if (isTestEnv && home === os8.homedir()) {
107612
+ return path16.join(os8.tmpdir(), "december-test-config", ".december");
107613
+ }
107614
+ const canonicalDir = path16.join(home, ".december");
107615
+ const legacyDir = path16.join(home, ".config", "december");
107616
+ if (fsSync.existsSync(canonicalDir) || !fsSync.existsSync(legacyDir)) {
107617
+ return canonicalDir;
107618
+ }
107619
+ return legacyDir;
107401
107620
  }
107402
107621
  function getConfigFile() {
107403
107622
  return path16.join(getConfigDir(), "config.json");
@@ -107420,7 +107639,22 @@ function deepMergeSettings(base, overrides) {
107420
107639
  async function loadConfig() {
107421
107640
  try {
107422
107641
  const configFile = getConfigFile();
107423
- const data = await fs16.readFile(configFile, "utf-8");
107642
+ let data;
107643
+ try {
107644
+ data = await fs16.readFile(configFile, "utf-8");
107645
+ } catch (readErr) {
107646
+ const legacyConfigFile = getLegacyConfigFile();
107647
+ if (legacyConfigFile !== configFile && fsSync.existsSync(legacyConfigFile)) {
107648
+ data = await fs16.readFile(legacyConfigFile, "utf-8");
107649
+ try {
107650
+ await fs16.mkdir(path16.dirname(configFile), { recursive: true });
107651
+ await fs16.writeFile(configFile, data, "utf-8");
107652
+ await fs16.chmod(configFile, 384).catch(() => {});
107653
+ } catch {}
107654
+ } else {
107655
+ throw readErr;
107656
+ }
107657
+ }
107424
107658
  let config = JSON.parse(data);
107425
107659
  try {
107426
107660
  const workspacePath = path16.join(process.cwd(), ".december", "settings.json");
@@ -107628,6 +107862,28 @@ function formatProviderName(provider) {
107628
107862
  return "Arcee AI";
107629
107863
  case "meta":
107630
107864
  return "Meta AI";
107865
+ case "poolside":
107866
+ return "Poolside";
107867
+ case "sakana":
107868
+ case "sakanaai":
107869
+ case "sakana-ai":
107870
+ return "Sakana AI";
107871
+ case "sarvam":
107872
+ case "sarvamai":
107873
+ case "sarvam-ai":
107874
+ return "Sarvam AI";
107875
+ case "stepfun":
107876
+ case "stepfunai":
107877
+ case "stepfun-ai":
107878
+ return "StepFun (Global)";
107879
+ case "upstage":
107880
+ case "upstageai":
107881
+ case "solar":
107882
+ return "Upstage Solar";
107883
+ case "thinkingmachines":
107884
+ case "tinker":
107885
+ case "inkling":
107886
+ return "Thinking Machines (Tinker)";
107631
107887
  case "claude":
107632
107888
  return "Claude";
107633
107889
  case "copilot":
@@ -107844,6 +108100,34 @@ function resolveSwitchTarget(config, targetInput) {
107844
108100
  model: getTargetModelForProvider(config, "openai")
107845
108101
  };
107846
108102
  }
108103
+ if (["solar", "upstageai"].includes(q) && config.providers["upstage"]) {
108104
+ return {
108105
+ provider: "upstage",
108106
+ authPriority: "byok",
108107
+ model: getTargetModelForProvider(config, "upstage")
108108
+ };
108109
+ }
108110
+ if (["tinker", "inkling"].includes(q) && config.providers["thinkingmachines"]) {
108111
+ return {
108112
+ provider: "thinkingmachines",
108113
+ authPriority: "byok",
108114
+ model: getTargetModelForProvider(config, "thinkingmachines")
108115
+ };
108116
+ }
108117
+ if (["stepfunai", "stepfun-ai"].includes(q) && config.providers["stepfun"]) {
108118
+ return {
108119
+ provider: "stepfun",
108120
+ authPriority: "byok",
108121
+ model: getTargetModelForProvider(config, "stepfun")
108122
+ };
108123
+ }
108124
+ if (["sarvamai", "sarvam-ai"].includes(q) && config.providers["sarvam"]) {
108125
+ return {
108126
+ provider: "sarvam",
108127
+ authPriority: "byok",
108128
+ model: getTargetModelForProvider(config, "sarvam")
108129
+ };
108130
+ }
107847
108131
  }
107848
108132
  if (["december", "wallet", "cloud", "december_proxy"].includes(q)) {
107849
108133
  if (config.decemberToken) {
@@ -108053,7 +108337,7 @@ var init_auth = __esm(() => {
108053
108337
 
108054
108338
  // src/utils/bin-discovery.ts
108055
108339
  import { execFile as execFile2 } from "node:child_process";
108056
- import fsSync from "node:fs";
108340
+ import fsSync2 from "node:fs";
108057
108341
  import fs17 from "node:fs/promises";
108058
108342
  import os9 from "node:os";
108059
108343
  import path17 from "node:path";
@@ -108153,7 +108437,7 @@ async function findAllDecemberBinaries(options) {
108153
108437
  }
108154
108438
  const nvmDir = path17.join(homeDir, ".nvm", "versions", "node");
108155
108439
  try {
108156
- if (fsSync.existsSync(nvmDir)) {
108440
+ if (fsSync2.existsSync(nvmDir)) {
108157
108441
  const versions = await fs17.readdir(nvmDir);
108158
108442
  for (const v of versions) {
108159
108443
  knownLocations.push(path17.join(nvmDir, v, "bin", "december"));
@@ -108419,7 +108703,7 @@ var init_version_check = __esm(() => {
108419
108703
 
108420
108704
  // src/utils/updater.ts
108421
108705
  import { exec as exec3 } from "node:child_process";
108422
- import fsSync2 from "node:fs";
108706
+ import fsSync3 from "node:fs";
108423
108707
  function isPermissionDeniedError2(errMsg) {
108424
108708
  const lower = errMsg.toLowerCase();
108425
108709
  return lower.includes("eacces") || lower.includes("eperm") || lower.includes("permission denied") || lower.includes("missing write access") || lower.includes("operation not permitted");
@@ -108434,8 +108718,8 @@ function detectInstallMethod(options) {
108434
108718
  const rawArgv1 = options?.argv1 ?? (process.argv.length > 1 ? process.argv[1] : "") ?? "";
108435
108719
  let realArgv1 = rawArgv1;
108436
108720
  try {
108437
- if (rawArgv1 && fsSync2.existsSync(rawArgv1)) {
108438
- realArgv1 = fsSync2.realpathSync(rawArgv1);
108721
+ if (rawArgv1 && fsSync3.existsSync(rawArgv1)) {
108722
+ realArgv1 = fsSync3.realpathSync(rawArgv1);
108439
108723
  }
108440
108724
  } catch {}
108441
108725
  const argv1 = rawArgv1.replace(/\\/g, "/");
@@ -108899,7 +109183,9 @@ Examples:`);
108899
109183
  console.log(` december key anthropic sk-ant-...`);
108900
109184
  console.log(` december key openrouter sk-or-...`);
108901
109185
  console.log(` december key deepseek sk-...`);
108902
- console.log(` december key groq gsk_...
109186
+ console.log(` december key groq gsk_...`);
109187
+ console.log(` december key poolside ps_...`);
109188
+ console.log(` december key sakana sk_...
108903
109189
  `);
108904
109190
  return;
108905
109191
  }
@@ -109213,6 +109499,40 @@ ${BLUE}✱${RESET} ${WHITE}December CLI Health & Environment Doctor${RESET}
109213
109499
  console.log(` • Auth Priority: ${GRAY}${config.authPriority || authStatus.authPriority}${RESET}`);
109214
109500
  console.log("");
109215
109501
  }
109502
+ function resolveDocsSectionPath(section) {
109503
+ if (!section)
109504
+ return "";
109505
+ const clean = section.replace(/^\/+/, "").toLowerCase().trim();
109506
+ const map = {
109507
+ intro: "",
109508
+ introduction: "",
109509
+ overview: "",
109510
+ quickstart: "/quickstart",
109511
+ "quick-start": "/quickstart",
109512
+ start: "/quickstart",
109513
+ guide: "/quickstart",
109514
+ arch: "/architecture",
109515
+ architecture: "/architecture",
109516
+ cli: "/cli",
109517
+ commands: "/cli",
109518
+ terminal: "/cli",
109519
+ privacy: "/privacy",
109520
+ terms: "/terms"
109521
+ };
109522
+ return map[clean] !== undefined ? map[clean] : `/${clean}`;
109523
+ }
109524
+ async function handleDocsCommand(options) {
109525
+ const rawSection = options?.section?.toLowerCase().trim();
109526
+ const sectionPath = resolveDocsSectionPath(rawSection);
109527
+ const baseUrl = (process.env.DECEMBER_DOCS_URL || process.env.WEB_URL || "https://trydecember.com").replace(/\/$/, "");
109528
+ const targetUrl = `${baseUrl}/docs${sectionPath}`;
109529
+ console.log("Opening December documentation in your default browser...");
109530
+ console.log(`\x1B[38;2;135;178;244m${targetUrl}\x1B[0m`);
109531
+ try {
109532
+ await Promise.resolve().then(() => init_open());
109533
+ await openUrl(targetUrl);
109534
+ } catch {}
109535
+ }
109216
109536
  var DEFAULT_AGENTS_MD = `# Agent Guidelines & Project Instructions
109217
109537
 
109218
109538
  Add project-specific guidelines, rules, skills, testing commands, architecture patterns, and conventions in this file for December to follow.
@@ -109434,7 +109754,7 @@ ${hasPreviousSummary ? UPDATE_SUMMARY_PROMPT : INITIAL_SUMMARY_PROMPT}`;
109434
109754
  { role: "user", content: userPrompt }
109435
109755
  ];
109436
109756
  let summary = "";
109437
- const stream = llm.stream(compactionMessages, [], undefined, modelOptions, signal);
109757
+ const stream = llm.stream(compactionMessages, undefined, undefined, modelOptions, signal);
109438
109758
  for await (const chunk of stream) {
109439
109759
  if (signal?.aborted)
109440
109760
  throw new Error("Aborted");
@@ -113537,7 +113857,20 @@ function createRequestLogEntry(params) {
113537
113857
  return logEntry;
113538
113858
  }
113539
113859
  function getGlobalConfigDir() {
113540
- return process.env.DECEMBER_CONFIG_DIR || path19.join(process.env.HOME || os10.homedir(), ".config", "december");
113860
+ if (process.env.DECEMBER_CONFIG_DIR) {
113861
+ return process.env.DECEMBER_CONFIG_DIR;
113862
+ }
113863
+ const home = process.env.HOME || os10.homedir();
113864
+ const isTestEnv = !!process.env.VITEST;
113865
+ if (isTestEnv && home === os10.homedir()) {
113866
+ return path19.join(os10.tmpdir(), "december-test-config", ".december");
113867
+ }
113868
+ const canonicalDir = path19.join(home, ".december");
113869
+ const legacyDir = path19.join(home, ".config", "december");
113870
+ if (fs20.existsSync(canonicalDir) || !fs20.existsSync(legacyDir)) {
113871
+ return canonicalDir;
113872
+ }
113873
+ return legacyDir;
113541
113874
  }
113542
113875
  function getLogsDir(customDir) {
113543
113876
  if (customDir)
@@ -119959,8 +120292,8 @@ function mergeMcpConfigs(globalConfig, workspaceConfig) {
119959
120292
  }
119960
120293
  async function loadMcpConfig(options = {}) {
119961
120294
  const workspaceDir = options.workspaceDir || process.cwd();
119962
- const globalConfigDir = options.globalConfigDir || path21.join(os11.homedir(), ".config", "december");
119963
- const altGlobalDir = path21.join(os11.homedir(), ".december");
120295
+ const globalConfigDir = options.globalConfigDir || path21.join(os11.homedir(), ".december");
120296
+ const altGlobalDir = path21.join(os11.homedir(), ".config", "december");
119964
120297
  let globalConfig = { mcpServers: {} };
119965
120298
  let workspaceConfig = { mcpServers: {} };
119966
120299
  try {
@@ -119998,7 +120331,7 @@ async function loadMcpConfig(options = {}) {
119998
120331
  }
119999
120332
  async function saveMcpConfig(options) {
120000
120333
  const { config, scope = "workspace" } = options;
120001
- const targetDir = scope === "workspace" ? path21.join(options.workspaceDir || process.cwd(), ".december") : options.globalConfigDir || path21.join(os11.homedir(), ".config", "december");
120334
+ const targetDir = scope === "workspace" ? path21.join(options.workspaceDir || process.cwd(), ".december") : options.globalConfigDir || path21.join(os11.homedir(), ".december");
120002
120335
  const targetFile = path21.join(targetDir, "mcp.json");
120003
120336
  await fs21.mkdir(targetDir, { recursive: true });
120004
120337
  await fs21.writeFile(targetFile, JSON.stringify(config, null, 2) + `
@@ -177946,14 +178279,22 @@ __export(exports_file_session_repository, {
177946
178279
  FileSessionRepository: () => FileSessionRepository
177947
178280
  });
177948
178281
  import fs23 from "node:fs/promises";
177949
- import os12 from "node:os";
177950
178282
  import path23 from "node:path";
177951
178283
 
177952
178284
  class FileSessionRepository {
177953
178285
  sessionDir;
178286
+ legacySessionDir;
177954
178287
  sessionCache = {};
177955
178288
  constructor(sessionDir) {
177956
- this.sessionDir = sessionDir || path23.join(os12.homedir(), ".config", "december", "sessions");
178289
+ if (sessionDir) {
178290
+ this.sessionDir = sessionDir;
178291
+ } else {
178292
+ this.sessionDir = path23.join(getConfigDir(), "sessions");
178293
+ const legacyDir = path23.join(getLegacyConfigDir(), "sessions");
178294
+ if (legacyDir !== this.sessionDir) {
178295
+ this.legacySessionDir = legacyDir;
178296
+ }
178297
+ }
177957
178298
  }
177958
178299
  async saveContext(sessionId, messages) {
177959
178300
  await fs23.mkdir(this.sessionDir, { recursive: true });
@@ -177991,9 +178332,20 @@ class FileSessionRepository {
177991
178332
  }
177992
178333
  }
177993
178334
  async loadContext(sessionId) {
177994
- const historyPath = path23.join(this.sessionDir, `${sessionId}.jsonl`);
178335
+ let historyPath = path23.join(this.sessionDir, `${sessionId}.jsonl`);
177995
178336
  try {
177996
- const data = await fs23.readFile(historyPath, "utf-8");
178337
+ let data;
178338
+ try {
178339
+ data = await fs23.readFile(historyPath, "utf-8");
178340
+ } catch (err) {
178341
+ if (this.legacySessionDir) {
178342
+ const legacyPath = path23.join(this.legacySessionDir, `${sessionId}.jsonl`);
178343
+ data = await fs23.readFile(legacyPath, "utf-8");
178344
+ historyPath = legacyPath;
178345
+ } else {
178346
+ throw err;
178347
+ }
178348
+ }
177997
178349
  const lines = data.split(`
177998
178350
  `).filter((l) => l.trim().length > 0);
177999
178351
  const msgMap = new Map;
@@ -178015,12 +178367,17 @@ class FileSessionRepository {
178015
178367
  }
178016
178368
  const branch = [];
178017
178369
  let current = latestMsg;
178370
+ let reachedRoot = false;
178018
178371
  while (current) {
178019
178372
  branch.unshift(current);
178020
- if (!current.parentId)
178373
+ if (!current.parentId) {
178374
+ reachedRoot = true;
178021
178375
  break;
178376
+ }
178022
178377
  current = msgMap.get(current.parentId);
178023
178378
  }
178379
+ const hasParentIds = msgs.some((m) => Boolean(m.parentId));
178380
+ const finalBranch = (!reachedRoot || !hasParentIds && msgs.length > 1) && branch.length < msgs.length ? [...msgs].sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0)) : branch;
178024
178381
  if (msgs.length < lines.length) {
178025
178382
  const compacted = msgs.map((m) => JSON.stringify(m)).join(`
178026
178383
  `);
@@ -178031,7 +178388,7 @@ class FileSessionRepository {
178031
178388
  cacheObj[msg.id] = { ...msg };
178032
178389
  }
178033
178390
  this.sessionCache[sessionId] = cacheObj;
178034
- return branch;
178391
+ return finalBranch;
178035
178392
  } catch (e) {
178036
178393
  return [];
178037
178394
  }
@@ -178039,35 +178396,47 @@ class FileSessionRepository {
178039
178396
  async listSessions() {
178040
178397
  try {
178041
178398
  await fs23.mkdir(this.sessionDir, { recursive: true });
178042
- const files = await fs23.readdir(this.sessionDir);
178043
178399
  const sessions = [];
178044
- for (const file of files) {
178045
- if (!file.endsWith(".jsonl"))
178046
- continue;
178047
- const id = file.replace(".jsonl", "");
178048
- const filePath = path23.join(this.sessionDir, file);
178400
+ const seenIds = new Set;
178401
+ const processDirectory = async (dirPath) => {
178049
178402
  try {
178050
- const stat = await fs23.stat(filePath);
178051
- const data = await fs23.readFile(filePath, "utf-8");
178052
- const lines = data.split(`
178053
- `).filter((l) => l.trim().length > 0);
178054
- let preview = "";
178055
- for (const line of lines) {
178403
+ const dirFiles = await fs23.readdir(dirPath);
178404
+ for (const file of dirFiles) {
178405
+ if (!file.endsWith(".jsonl"))
178406
+ continue;
178407
+ const id = file.replace(".jsonl", "");
178408
+ if (seenIds.has(id))
178409
+ continue;
178410
+ seenIds.add(id);
178411
+ const filePath = path23.join(dirPath, file);
178056
178412
  try {
178057
- const msg = JSON.parse(line);
178058
- if (msg.role === "user") {
178059
- preview = msg.content?.substring(0, 80) || "";
178060
- break;
178413
+ const stat = await fs23.stat(filePath);
178414
+ const data = await fs23.readFile(filePath, "utf-8");
178415
+ const lines = data.split(`
178416
+ `).filter((l) => l.trim().length > 0);
178417
+ let preview = "";
178418
+ for (const line of lines) {
178419
+ try {
178420
+ const msg = JSON.parse(line);
178421
+ if (msg.role === "user") {
178422
+ preview = msg.content?.substring(0, 80) || "";
178423
+ break;
178424
+ }
178425
+ } catch {}
178061
178426
  }
178427
+ sessions.push({
178428
+ id,
178429
+ updatedAt: stat.mtime,
178430
+ messageCount: lines.length,
178431
+ preview
178432
+ });
178062
178433
  } catch {}
178063
178434
  }
178064
- sessions.push({
178065
- id,
178066
- updatedAt: stat.mtime,
178067
- messageCount: lines.length,
178068
- preview
178069
- });
178070
178435
  } catch {}
178436
+ };
178437
+ await processDirectory(this.sessionDir);
178438
+ if (this.legacySessionDir) {
178439
+ await processDirectory(this.legacySessionDir);
178071
178440
  }
178072
178441
  sessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
178073
178442
  return sessions;
@@ -178080,6 +178449,11 @@ class FileSessionRepository {
178080
178449
  try {
178081
178450
  await fs23.unlink(historyPath);
178082
178451
  } catch (e) {}
178452
+ if (this.legacySessionDir) {
178453
+ try {
178454
+ await fs23.unlink(path23.join(this.legacySessionDir, `${sessionId}.jsonl`));
178455
+ } catch {}
178456
+ }
178083
178457
  }
178084
178458
  async renameSession(oldSessionId, newSessionId) {
178085
178459
  const oldPath = path23.join(this.sessionDir, `${oldSessionId}.jsonl`);
@@ -178087,7 +178461,9 @@ class FileSessionRepository {
178087
178461
  await fs23.rename(oldPath, newPath);
178088
178462
  }
178089
178463
  }
178090
- var init_file_session_repository = () => {};
178464
+ var init_file_session_repository = __esm(() => {
178465
+ init_config();
178466
+ });
178091
178467
 
178092
178468
  // ../../node_modules/.bun/fast-glob@3.3.3/node_modules/fast-glob/out/utils/array.js
178093
178469
  var require_array = __commonJS(function(exports) {
@@ -184082,6 +184458,28 @@ function instantiateProvider(provider, apiKey, options) {
184082
184458
  case "metaai":
184083
184459
  case "meta-ai":
184084
184460
  return withProviderId(openaiProvider("https://api.meta.ai/v1", apiKey), "meta");
184461
+ case "poolside":
184462
+ return withProviderId(openaiProvider("https://inference.poolside.ai/v1", apiKey), "poolside");
184463
+ case "sakana":
184464
+ case "sakanaai":
184465
+ case "sakana-ai":
184466
+ return withProviderId(openaiProvider("https://api.sakana.ai/v1", apiKey), "sakana");
184467
+ case "sarvam":
184468
+ case "sarvamai":
184469
+ case "sarvam-ai":
184470
+ return withProviderId(openaiProvider("https://api.sarvam.ai/v1", apiKey), "sarvam");
184471
+ case "stepfun":
184472
+ case "stepfunai":
184473
+ case "stepfun-ai":
184474
+ return withProviderId(openaiProvider("https://api.stepfun.ai/v1", apiKey), "stepfun");
184475
+ case "upstage":
184476
+ case "upstageai":
184477
+ case "solar":
184478
+ return withProviderId(openaiProvider("https://api.upstage.ai/v1/solar", apiKey), "upstage");
184479
+ case "thinkingmachines":
184480
+ case "tinker":
184481
+ case "inkling":
184482
+ return withProviderId(anthropicProvider("https://tinker.thinkingmachines.dev/services/tinker-prod/anthropic/api", apiKey, { "anthropic-beta": "oauth-2024-11-18" }), "thinkingmachines");
184085
184483
  case "dashscope":
184086
184484
  case "qwen":
184087
184485
  return withProviderId(openaiProvider("https://dashscope.aliyuncs.com/compatible-mode/v1", apiKey), "dashscope");
@@ -185095,7 +185493,7 @@ var init_environment = __esm(() => {
185095
185493
 
185096
185494
  // ../../node_modules/.bun/ansi-escapes@7.3.0/node_modules/ansi-escapes/base.js
185097
185495
  import process4 from "node:process";
185098
- import os13 from "node:os";
185496
+ import os12 from "node:os";
185099
185497
  var ESC = "\x1B[", SEP = ";", isTerminalApp, isWindows2, isTmux, cwdFunction, cursorTo = (x, y) => {
185100
185498
  if (typeof x !== "number") {
185101
185499
  throw new TypeError("The `x` argument is required");
@@ -185117,7 +185515,7 @@ var ESC = "\x1B[", SEP = ";", isTerminalApp, isWindows2, isTmux, cwdFunction, cu
185117
185515
  if (isBrowser || !isWindows2) {
185118
185516
  return false;
185119
185517
  }
185120
- const parts = os13.release().split(".");
185518
+ const parts = os12.release().split(".");
185121
185519
  const major = Number(parts[0]);
185122
185520
  const build = Number(parts[2] ?? 0);
185123
185521
  if (major < 10) {
@@ -217865,7 +218263,7 @@ var init_ansi_styles2 = __esm(() => {
217865
218263
 
217866
218264
  // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
217867
218265
  import process7 from "node:process";
217868
- import os14 from "node:os";
218266
+ import os13 from "node:os";
217869
218267
  import tty2 from "node:tty";
217870
218268
  function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process7.argv) {
217871
218269
  const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
@@ -217923,7 +218321,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
217923
218321
  return min;
217924
218322
  }
217925
218323
  if (process7.platform === "win32") {
217926
- const osRelease = os14.release().split(".");
218324
+ const osRelease = os13.release().split(".");
217927
218325
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
217928
218326
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
217929
218327
  }
@@ -222273,7 +222671,9 @@ var init_theme = __esm(() => {
222273
222671
  diffDeleteBg: "#3f1316"
222274
222672
  },
222275
222673
  padding: {
222276
- paddingX: 2
222674
+ paddingX: 2,
222675
+ paddingLeft: 2,
222676
+ paddingRight: 4
222277
222677
  },
222278
222678
  glyphs: {
222279
222679
  prompt: "❭",
@@ -222698,7 +223098,7 @@ var init_toast = __esm(async () => {
222698
223098
 
222699
223099
  // ../../packages/tui/src/utils/prompt-history.ts
222700
223100
  import fs27 from "node:fs";
222701
- import os15 from "node:os";
223101
+ import os14 from "node:os";
222702
223102
  import path25 from "node:path";
222703
223103
 
222704
223104
  class PromptHistory {
@@ -222710,9 +223110,10 @@ class PromptHistory {
222710
223110
  if (customPath) {
222711
223111
  this.historyPath = customPath;
222712
223112
  } else {
222713
- const configPath = path25.join(os15.homedir(), ".config", "december", "history");
222714
- const legacyPath = path25.join(os15.homedir(), ".december", "history");
222715
- this.historyPath = fs27.existsSync(configPath) || !fs27.existsSync(legacyPath) ? configPath : legacyPath;
223113
+ const home = process.env.HOME || process.env.USERPROFILE || os14.homedir();
223114
+ const canonicalPath = path25.join(home, ".december", "history");
223115
+ const legacyPath = path25.join(home, ".config", "december", "history");
223116
+ this.historyPath = fs27.existsSync(canonicalPath) || !fs27.existsSync(legacyPath) ? canonicalPath : legacyPath;
222716
223117
  }
222717
223118
  this.load();
222718
223119
  }
@@ -222813,11 +223214,11 @@ var init_menu_footer = __esm(async () => {
222813
223214
 
222814
223215
  // ../../packages/tui/src/utils/clipboard.ts
222815
223216
  import { spawnSync } from "child_process";
222816
- import * as os16 from "os";
223217
+ import * as os15 from "os";
222817
223218
  function writeToClipboard(text) {
222818
- const platform = os16.platform();
223219
+ const platform = os15.platform();
222819
223220
  try {
222820
- const isWsl = platform === "linux" && (!!process.env.WSL_DISTRO_NAME || os16.release().toLowerCase().includes("microsoft"));
223221
+ const isWsl = platform === "linux" && (!!process.env.WSL_DISTRO_NAME || os15.release().toLowerCase().includes("microsoft"));
222821
223222
  if (platform === "darwin") {
222822
223223
  spawnSync("pbcopy", { input: text });
222823
223224
  } else if (platform === "win32") {
@@ -222917,7 +223318,7 @@ var init_handoff = __esm(() => {
222917
223318
 
222918
223319
  // ../../packages/tui/src/components/command-menu/commands.tsx
222919
223320
  import fs29 from "node:fs";
222920
- import os17 from "node:os";
223321
+ import os16 from "node:os";
222921
223322
  import path27 from "node:path";
222922
223323
  var COMMANDS;
222923
223324
  var init_commands2 = __esm(() => {
@@ -222971,6 +223372,12 @@ var init_commands2 = __esm(() => {
222971
223372
  }
222972
223373
  }
222973
223374
  },
223375
+ {
223376
+ name: "docs",
223377
+ description: "Open December documentation in your browser",
223378
+ value: "/docs",
223379
+ action: (ctx) => {}
223380
+ },
222974
223381
  {
222975
223382
  name: "exit",
222976
223383
  description: "Exit the CLI",
@@ -223009,7 +223416,10 @@ var init_commands2 = __esm(() => {
223009
223416
  action: async (ctx) => {
223010
223417
  const archivePath = ".december-handoff.tar.gz";
223011
223418
  try {
223012
- const configPath = path27.join(os17.homedir(), ".config", "december", "config.json");
223419
+ const home = process.env.HOME || process.env.USERPROFILE || os16.homedir();
223420
+ const canonicalConfigPath = path27.join(home, ".december", "config.json");
223421
+ const legacyConfigPath = path27.join(home, ".config", "december", "config.json");
223422
+ const configPath = fs29.existsSync(canonicalConfigPath) || !fs29.existsSync(legacyConfigPath) ? canonicalConfigPath : legacyConfigPath;
223013
223423
  let config = {};
223014
223424
  try {
223015
223425
  if (fs29.existsSync(configPath)) {
@@ -223318,7 +223728,6 @@ function CommandMenu({ query, selectedIndex, windowStart }) {
223318
223728
  const absIdx = windowStart + relIdx;
223319
223729
  const isSelected = absIdx === selectedIndex;
223320
223730
  return /* @__PURE__ */ jsx_runtime5.jsxs(Box_default, {
223321
- paddingLeft: 2,
223322
223731
  children: [
223323
223732
  /* @__PURE__ */ jsx_runtime5.jsx(Text3, {
223324
223733
  color: isSelected ? THEME.colors.brand : THEME.colors.muted,
@@ -224136,7 +224545,8 @@ var init_input_bar = __esm(async () => {
224136
224545
  "/fork",
224137
224546
  "/copy",
224138
224547
  "/handoff",
224139
- "/init"
224548
+ "/init",
224549
+ "/docs"
224140
224550
  ];
224141
224551
  if (forwardCommands.includes(command.value) || !command.action) {
224142
224552
  if (command.value === "/plan") {
@@ -224205,12 +224615,15 @@ var init_input_bar = __esm(async () => {
224205
224615
  onSubmit,
224206
224616
  handleContentChange
224207
224617
  ]);
224208
- const sepWidth = Math.max(10, columns - THEME.padding.paddingX * 2);
224618
+ const paddingLeft = THEME.padding.paddingLeft ?? THEME.padding.paddingX;
224619
+ const paddingRight = THEME.padding.paddingRight ?? 4;
224620
+ const sepWidth = Math.max(10, columns - paddingLeft - paddingRight - 2);
224209
224621
  const sep = "─".repeat(sepWidth);
224210
224622
  const isOverlayActive = Boolean(authUI) && !customInputMode;
224211
224623
  return /* @__PURE__ */ jsx_runtime8.jsxs(Box_default, {
224212
224624
  flexDirection: "column",
224213
- paddingX: THEME.padding.paddingX,
224625
+ paddingLeft,
224626
+ paddingRight,
224214
224627
  marginTop: 1,
224215
224628
  children: [
224216
224629
  dialog.isOpen && dialog.currentDialog && /* @__PURE__ */ jsx_runtime8.jsx(Box_default, {
@@ -224267,7 +224680,6 @@ var init_input_bar = __esm(async () => {
224267
224680
  }),
224268
224681
  /* @__PURE__ */ jsx_runtime8.jsxs(Box_default, {
224269
224682
  width: "100%",
224270
- paddingRight: 4,
224271
224683
  flexDirection: "row",
224272
224684
  children: [
224273
224685
  /* @__PURE__ */ jsx_runtime8.jsx(Box_default, {
@@ -226157,6 +226569,15 @@ function parseTuiError(message, cause, hint) {
226157
226569
  hint: hintMatch ? hintMatch[0] : "Please add credits or top up your balance at https://dev.meta.ai/"
226158
226570
  };
226159
226571
  }
226572
+ if (firstLine.includes("Insufficient credits in your ") || firstLine.includes("Insufficient balance in your ") || firstLine.includes("Insufficient credits or balance ")) {
226573
+ const hintMatch = firstLine.match(/Please (?:add credits|top up|check|upgrade|switch).*$/i);
226574
+ const summary = firstLine.replace(/Please (?:add credits|top up|check|upgrade|switch).*$/i, "").trim();
226575
+ return {
226576
+ message: summary || firstLine,
226577
+ cause: rest,
226578
+ hint: hintMatch ? hintMatch[0] : undefined
226579
+ };
226580
+ }
226160
226581
  if (firstLine.includes("Authentication failed or session expired")) {
226161
226582
  const hintMatch = firstLine.match(/Please run.*$/i);
226162
226583
  const summary = firstLine.replace(/Please run.*$/i, "").trim();
@@ -226226,11 +226647,16 @@ function ErrorMessage({
226226
226647
  cause,
226227
226648
  hint,
226228
226649
  hasTopMargin = false,
226229
- paddingX = THEME.padding.paddingX
226650
+ paddingX,
226651
+ paddingLeft = THEME.padding.paddingLeft ?? THEME.padding.paddingX,
226652
+ paddingRight = THEME.padding.paddingRight ?? 4
226230
226653
  }) {
226231
226654
  const parsed = parseTuiError(message, cause, hint);
226655
+ const effectiveLeft = paddingX ?? paddingLeft;
226656
+ const effectiveRight = paddingX ?? paddingRight;
226232
226657
  return /* @__PURE__ */ jsx_runtime10.jsxs(Box_default, {
226233
- paddingX,
226658
+ paddingLeft: effectiveLeft,
226659
+ paddingRight: effectiveRight,
226234
226660
  paddingY: 0,
226235
226661
  flexDirection: "column",
226236
226662
  children: [
@@ -269285,13 +269711,19 @@ function getHighlightedCode(code, lang) {
269285
269711
  highlightCache.set(key, result);
269286
269712
  return result;
269287
269713
  }
269714
+ function normalizeMarkdown(source) {
269715
+ if (!source)
269716
+ return "";
269717
+ return source.replace(/^([ \t]*)[•●▪‣⁃][ \t]+/gm, "$1* ");
269718
+ }
269288
269719
  function parseMarkdownTokens(source) {
269289
269720
  if (!source)
269290
269721
  return [];
269291
269722
  const cached = astCache.get(source);
269292
269723
  if (cached)
269293
269724
  return cached;
269294
- const tokens = g.lexer(source).filter((t) => t.type !== "space");
269725
+ const normalized = normalizeMarkdown(source);
269726
+ const tokens = g.lexer(normalized).filter((t) => t.type !== "space");
269295
269727
  if (astCache.size >= MAX_AST_CACHE_SIZE) {
269296
269728
  const firstKey = astCache.keys().next().value;
269297
269729
  if (firstKey)
@@ -269356,10 +269788,11 @@ var import_cli_highlight, import_react46, jsx_runtime12, renderToken = (token, i
269356
269788
  children: [
269357
269789
  /* @__PURE__ */ jsx_runtime12.jsx(Text3, {
269358
269790
  color: THEME.colors.dim,
269359
- children: THEME.glyphs.bullet + " "
269791
+ children: token.ordered ? `${(token.start ?? 1) + i}. ` : `${THEME.glyphs.bullet} `
269360
269792
  }),
269361
269793
  /* @__PURE__ */ jsx_runtime12.jsx(Box_default, {
269362
269794
  flexDirection: "column",
269795
+ flexShrink: 1,
269363
269796
  children: item.tokens.map((t, j) => renderToken(t, j))
269364
269797
  })
269365
269798
  ]
@@ -269631,7 +270064,8 @@ var init_bot_message = __esm(async () => {
269631
270064
  BotMessage = import_react47.default.memo(function BotMessage({ blocks, usage, expandCommands }) {
269632
270065
  return /* @__PURE__ */ jsx_runtime14.jsx(Box_default, {
269633
270066
  flexDirection: "column",
269634
- paddingX: THEME.padding.paddingX,
270067
+ paddingLeft: THEME.padding.paddingLeft ?? THEME.padding.paddingX,
270068
+ paddingRight: THEME.padding.paddingRight ?? 4,
269635
270069
  paddingY: 0,
269636
270070
  gap: 0,
269637
270071
  marginTop: 0,
@@ -270014,7 +270448,8 @@ var init_header = __esm(async () => {
270014
270448
  const branch = getGitBranch();
270015
270449
  return /* @__PURE__ */ jsx_runtime15.jsxs(Box_default, {
270016
270450
  flexDirection: "column",
270017
- paddingX: THEME.padding.paddingX,
270451
+ paddingLeft: THEME.padding.paddingLeft ?? THEME.padding.paddingX,
270452
+ paddingRight: THEME.padding.paddingRight ?? 4,
270018
270453
  paddingTop: 1,
270019
270454
  paddingBottom: 0,
270020
270455
  children: [
@@ -270093,7 +270528,8 @@ var init_user_message = __esm(async () => {
270093
270528
  }
270094
270529
  }
270095
270530
  return /* @__PURE__ */ jsx_runtime16.jsxs(Box_default, {
270096
- paddingX: THEME.padding.paddingX,
270531
+ paddingLeft: THEME.padding.paddingLeft ?? THEME.padding.paddingX,
270532
+ paddingRight: THEME.padding.paddingRight ?? 4,
270097
270533
  paddingY: 0,
270098
270534
  marginTop: 1,
270099
270535
  marginBottom: 1,
@@ -270174,9 +270610,11 @@ var init_message_list = __esm(async () => {
270174
270610
  }) {
270175
270611
  return /* @__PURE__ */ jsx_runtime17.jsxs(Box_default, {
270176
270612
  flexDirection: "column",
270613
+ width: "100%",
270177
270614
  children: [
270178
270615
  staticMessages.length > 0 && /* @__PURE__ */ jsx_runtime17.jsx(Static12, {
270179
270616
  items: staticMessages,
270617
+ style: { width: "100%" },
270180
270618
  children: (msg, index) => renderSingleMessage(msg, index, staticMessages, cliVersion, latestVersion, userEmail, expandCommands)
270181
270619
  }, `${staticKey}-${expandCommands}`),
270182
270620
  activeMessages.map((msg, index) => renderSingleMessage(msg, staticMessages.length + index, [...staticMessages, ...activeMessages], cliVersion, latestVersion, userEmail, expandCommands))
@@ -270467,7 +270905,23 @@ var init_byok_key_menu = __esm(async () => {
270467
270905
  openai: "OpenAI",
270468
270906
  openrouter: "OpenRouter",
270469
270907
  perplexity: "Perplexity AI",
270908
+ poolside: "Poolside",
270470
270909
  qwen: "Qwen (DashScope)",
270910
+ sakana: "Sakana AI",
270911
+ "sakana-ai": "Sakana AI",
270912
+ sakanaai: "Sakana AI",
270913
+ sarvam: "Sarvam AI",
270914
+ sarvamai: "Sarvam AI",
270915
+ "sarvam-ai": "Sarvam AI",
270916
+ stepfun: "StepFun (Global)",
270917
+ stepfunai: "StepFun (Global)",
270918
+ "stepfun-ai": "StepFun (Global)",
270919
+ upstage: "Upstage Solar",
270920
+ upstageai: "Upstage Solar",
270921
+ solar: "Upstage Solar",
270922
+ thinkingmachines: "Thinking Machines (Tinker)",
270923
+ tinker: "Thinking Machines (Tinker)",
270924
+ inkling: "Thinking Machines (Tinker)",
270471
270925
  sambanova: "SambaNova Cloud",
270472
270926
  siliconflow: "SiliconFlow",
270473
270927
  together: "Together AI",
@@ -270515,7 +270969,23 @@ var init_byok_key_menu = __esm(async () => {
270515
270969
  openai: "https://platform.openai.com/api-keys",
270516
270970
  openrouter: "https://openrouter.ai/settings/keys",
270517
270971
  perplexity: "https://www.perplexity.ai/settings/api",
270972
+ poolside: "https://platform.poolside.ai/api-keys",
270518
270973
  qwen: "https://dashscope.console.aliyun.com/apiKey",
270974
+ sakana: "https://console.sakana.ai/api-keys",
270975
+ "sakana-ai": "https://console.sakana.ai/api-keys",
270976
+ sakanaai: "https://console.sakana.ai/api-keys",
270977
+ sarvam: "https://indus.sarvam.ai/",
270978
+ sarvamai: "https://indus.sarvam.ai/",
270979
+ "sarvam-ai": "https://indus.sarvam.ai/",
270980
+ stepfun: "https://platform.stepfun.ai/interface-key",
270981
+ stepfunai: "https://platform.stepfun.ai/interface-key",
270982
+ "stepfun-ai": "https://platform.stepfun.ai/interface-key",
270983
+ upstage: "https://console.upstage.ai",
270984
+ upstageai: "https://console.upstage.ai",
270985
+ solar: "https://console.upstage.ai",
270986
+ thinkingmachines: "https://tinker.thinkingmachines.ai/",
270987
+ tinker: "https://tinker.thinkingmachines.ai/",
270988
+ inkling: "https://tinker.thinkingmachines.ai/",
270519
270989
  sambanova: "https://cloud.sambanova.ai/apis",
270520
270990
  siliconflow: "https://cloud.siliconflow.cn/account/ak",
270521
270991
  siliconcloud: "https://cloud.siliconflow.cn/account/ak",
@@ -270757,10 +271227,16 @@ var init_byok_provider_menu = __esm(async () => {
270757
271227
  { label: "OpenAI", value: "openai" },
270758
271228
  { label: "OpenRouter", value: "openrouter" },
270759
271229
  { label: "Perplexity AI", value: "perplexity" },
271230
+ { label: "Poolside", value: "poolside" },
270760
271231
  { label: "Qwen (DashScope)", value: "dashscope" },
271232
+ { label: "Sakana AI", value: "sakana" },
270761
271233
  { label: "SambaNova Cloud", value: "sambanova" },
271234
+ { label: "Sarvam AI", value: "sarvam" },
270762
271235
  { label: "SiliconFlow", value: "siliconflow" },
271236
+ { label: "StepFun (Global)", value: "stepfun" },
271237
+ { label: "Thinking Machines (Tinker)", value: "thinkingmachines" },
270763
271238
  { label: "Together AI", value: "together" },
271239
+ { label: "Upstage Solar", value: "upstage" },
270764
271240
  { label: "xAI", value: "xai" },
270765
271241
  { label: "ZAI", value: "zai" }
270766
271242
  ];
@@ -271969,7 +272445,7 @@ function McpManagerMenu({
271969
272445
  }),
271970
272446
  /* @__PURE__ */ jsx_runtime26.jsx(Text3, {
271971
272447
  color: selectedScope === "global" ? THEME.colors.brand : THEME.colors.dim,
271972
- children: "[Global: ~/.config/december/mcp.json]"
272448
+ children: "[Global: ~/.december/mcp.json]"
271973
272449
  })
271974
272450
  ]
271975
272451
  })
@@ -272132,7 +272608,7 @@ function McpManagerMenu({
272132
272608
  children: [
272133
272609
  /* @__PURE__ */ jsx_runtime26.jsx(Text3, {
272134
272610
  color: THEME.colors.muted,
272135
- children: "No MCP servers configured in .december/mcp.json or ~/.config/december/mcp.json."
272611
+ children: "No MCP servers configured in .december/mcp.json or ~/.december/mcp.json."
272136
272612
  }),
272137
272613
  /* @__PURE__ */ jsx_runtime26.jsx(Box_default, {
272138
272614
  marginTop: 1,
@@ -275670,18 +276146,417 @@ var init_direct_shell = __esm(() => {
275670
276146
  runDirectCommand.start = startDirectCommand;
275671
276147
  });
275672
276148
 
276149
+ // src/utils/usage-rates.ts
276150
+ function inferProviderFromModel(modelName) {
276151
+ const lower = (modelName || "").toLowerCase();
276152
+ if (lower.startsWith("trinity") || lower.startsWith("arcee"))
276153
+ return "arcee";
276154
+ if (lower.startsWith("muse") || lower.startsWith("meta/"))
276155
+ return "meta";
276156
+ if (lower.startsWith("minimax") || lower.startsWith("minimaxai/"))
276157
+ return "minimax";
276158
+ if (lower.startsWith("laguna") || lower.startsWith("poolside/"))
276159
+ return "poolside";
276160
+ if (lower.startsWith("fugu") || lower.startsWith("sakana") || lower.startsWith("namazu"))
276161
+ return "sakana";
276162
+ if (lower.startsWith("sarvam"))
276163
+ return "sarvam";
276164
+ if (lower.startsWith("step-") || lower.startsWith("stepfun"))
276165
+ return "stepfun";
276166
+ if (lower.startsWith("solar"))
276167
+ return "upstage";
276168
+ if (lower.startsWith("thinkingmachines") || lower.startsWith("inkling"))
276169
+ return "thinkingmachines";
276170
+ if (lower.startsWith("claude") || lower.startsWith("anthropic/"))
276171
+ return "anthropic";
276172
+ if (lower.startsWith("gpt") || lower.startsWith("o1") || lower.startsWith("o3") || lower.startsWith("o4") || lower.startsWith("openai/"))
276173
+ return "openai";
276174
+ if (lower.startsWith("gemini") || lower.startsWith("google/"))
276175
+ return "google";
276176
+ if (lower.startsWith("sonar") || lower.startsWith("perplexity"))
276177
+ return "perplexity";
276178
+ if (lower.startsWith("command") || lower.startsWith("cohere"))
276179
+ return "cohere";
276180
+ if (lower.startsWith("deepseek"))
276181
+ return "deepseek";
276182
+ if (lower.startsWith("groq") || lower.includes("llama-3.3-70b-versatile"))
276183
+ return "groq";
276184
+ if (lower.startsWith("mistral") || lower.startsWith("codestral") || lower.startsWith("pixtral") || lower.startsWith("ministral") || lower.startsWith("devstral") || lower.startsWith("magistral"))
276185
+ return "mistral";
276186
+ if (lower.startsWith("moonshot") || lower.startsWith("kimi"))
276187
+ return "moonshot";
276188
+ if (lower.startsWith("grok") || lower.startsWith("xai"))
276189
+ return "xai";
276190
+ if (lower.startsWith("zai") || lower.startsWith("glm"))
276191
+ return "zai";
276192
+ if (lower.startsWith("nvidia") || lower.startsWith("nim") || lower.includes("nemotron"))
276193
+ return "nvidia";
276194
+ if (lower.startsWith("sambanova"))
276195
+ return "sambanova";
276196
+ if (lower.startsWith("cerebras"))
276197
+ return "cerebras";
276198
+ if (lower.startsWith("siliconflow") || lower.startsWith("siliconcloud"))
276199
+ return "siliconflow";
276200
+ if (lower.startsWith("together"))
276201
+ return "together";
276202
+ if (lower.startsWith("hyperbolic"))
276203
+ return "hyperbolic";
276204
+ if (lower.startsWith("fireworks") || lower.startsWith("accounts/fireworks/"))
276205
+ return "fireworks";
276206
+ if (lower.startsWith("agentrouter") || lower.startsWith("agentrouter/"))
276207
+ return "agentrouter";
276208
+ if (lower.includes("meta-llama") || lower.includes("qwen/"))
276209
+ return "huggingface";
276210
+ if (lower.includes("ollama") || lower.includes("llama") || lower.includes("qwen"))
276211
+ return "ollama";
276212
+ return "openrouter";
276213
+ }
276214
+ function formatUsageCard(params) {
276215
+ const { model, authMethod = "byok", isAuthenticated = true } = params;
276216
+ let providerKey = (params.provider || "").toLowerCase();
276217
+ if (!isAuthenticated) {
276218
+ return AUTH_REQUIRED_NOTICE;
276219
+ }
276220
+ if (authMethod === "december") {
276221
+ const billingLink = PROVIDER_BILLING_LINKS2.december;
276222
+ return `Active Model: \`${model}\` (December Wallet)
276223
+ Provider: December Cloud
276224
+
276225
+ *Usage is deducted directly from your December account credits. Request telemetry, token consumption, and monthly invoices are tracked at [${billingLink}](${billingLink})*`;
276226
+ }
276227
+ if (authMethod === "subscription") {
276228
+ const subDisplayName = providerKey === "copilot" || providerKey === "github" ? "GitHub Copilot" : providerKey === "claude" || providerKey === "anthropic" ? "Claude Pro/Max (Claude Code)" : providerKey === "codex" || providerKey === "openai" ? "ChatGPT Plus/Team/Pro (OpenAI Codex)" : providerKey === "gemini" || providerKey === "google" || providerKey === "antigravity" ? "Google One AI Premium (Gemini/Antigravity)" : `${providerKey.toUpperCase()} Subscription`;
276229
+ return `Active Model: \`${model}\` (Subscription)
276230
+ Provider: ${subDisplayName}
276231
+
276232
+ *Usage is covered by your active ${subDisplayName} monthly subscription quota. Prompts route directly from your machine with OAuth authentication; no per-token charges or December proxy fees apply.*`;
276233
+ }
276234
+ if (!providerKey || providerKey === "december_proxy") {
276235
+ providerKey = inferProviderFromModel(model);
276236
+ }
276237
+ if (providerKey === "ollama" || model.toLowerCase().includes("ollama")) {
276238
+ const link = PROVIDER_BILLING_LINKS2.ollama;
276239
+ return `Active Model: \`${model}\` (Local)
276240
+ Provider: Ollama (Local)
276241
+
276242
+ *Running completely locally on your hardware with no API keys, no external network calls, and no usage fees. View status and local models at [${link}](${link})*`;
276243
+ }
276244
+ const displayName = PROVIDER_DISPLAY_NAMES2[providerKey] || providerKey.toUpperCase();
276245
+ const billingLink = PROVIDER_BILLING_LINKS2[providerKey] || `https://openrouter.ai/activity`;
276246
+ return `Active Model: \`${model}\` (BYOK)
276247
+ Provider: ${displayName}
276248
+
276249
+ *Prompts go directly to the provider API; December servers do not track, log, or bill this usage. Token consumption, quotas, and billing are managed in your ${displayName} account at [${billingLink}](${billingLink})*`;
276250
+ }
276251
+ var PROVIDER_BILLING_LINKS2, PROVIDER_DISPLAY_NAMES2;
276252
+ var init_usage_rates2 = __esm(() => {
276253
+ init_messages5();
276254
+ PROVIDER_BILLING_LINKS2 = {
276255
+ december: "https://trydecember.com/settings/usage",
276256
+ google: "https://aistudio.google.com/app/usage",
276257
+ gemini: "https://aistudio.google.com/app/usage",
276258
+ anthropic: "https://console.anthropic.com/settings/billing",
276259
+ openai: "https://platform.openai.com/usage",
276260
+ openrouter: "https://openrouter.ai/activity",
276261
+ deepseek: "https://platform.deepseek.com/usage",
276262
+ groq: "https://console.groq.com/usage",
276263
+ mistral: "https://console.mistral.ai/billing/",
276264
+ mistralai: "https://console.mistral.ai/billing/",
276265
+ "mistral-ai": "https://console.mistral.ai/billing/",
276266
+ moonshot: "https://platform.moonshot.ai/console/api-keys",
276267
+ moonshotai: "https://platform.moonshot.ai/console/api-keys",
276268
+ "moonshot-ai": "https://platform.moonshot.ai/console/api-keys",
276269
+ moonshoot: "https://platform.moonshot.ai/console/api-keys",
276270
+ kimi: "https://platform.moonshot.ai/console/api-keys",
276271
+ xai: "https://console.x.ai/",
276272
+ zai: "https://open.bigmodel.cn/usercenter/apikeys",
276273
+ nvidia: "https://build.nvidia.com/",
276274
+ sambanova: "https://cloud.sambanova.ai/",
276275
+ cerebras: "https://cloud.cerebras.ai/",
276276
+ siliconflow: "https://cloud.siliconflow.cn/account/ak",
276277
+ together: "https://api.together.ai/settings/billing",
276278
+ hyperbolic: "https://app.hyperbolic.ai/settings",
276279
+ fireworks: "https://app.fireworks.ai/settings/billing",
276280
+ perplexity: "https://www.perplexity.ai/settings/api",
276281
+ cohere: "https://dashboard.cohere.com/billing",
276282
+ huggingface: "https://huggingface.co/settings/billing",
276283
+ agentrouter: "https://agentrouter.org/console/token",
276284
+ arcee: "https://platform.arcee.ai/api/api-keys",
276285
+ meta: "https://dev.meta.ai/",
276286
+ minimax: "https://platform.minimax.io/console/access",
276287
+ minimaxai: "https://platform.minimax.io/console/access",
276288
+ "minimax-ai": "https://platform.minimax.io/console/access",
276289
+ poolside: "https://platform.poolside.ai/api-keys",
276290
+ sakana: "https://console.sakana.ai/api-keys",
276291
+ "sakana-ai": "https://console.sakana.ai/api-keys",
276292
+ sakanaai: "https://console.sakana.ai/api-keys",
276293
+ sarvam: "https://indus.sarvam.ai/",
276294
+ sarvamai: "https://indus.sarvam.ai/",
276295
+ "sarvam-ai": "https://indus.sarvam.ai/",
276296
+ stepfun: "https://platform.stepfun.ai/interface-key",
276297
+ stepfunai: "https://platform.stepfun.ai/interface-key",
276298
+ "stepfun-ai": "https://platform.stepfun.ai/interface-key",
276299
+ upstage: "https://console.upstage.ai",
276300
+ upstageai: "https://console.upstage.ai",
276301
+ solar: "https://console.upstage.ai",
276302
+ thinkingmachines: "https://tinker.thinkingmachines.ai/",
276303
+ tinker: "https://tinker.thinkingmachines.ai/",
276304
+ inkling: "https://tinker.thinkingmachines.ai/",
276305
+ ollama: "http://localhost:11434"
276306
+ };
276307
+ PROVIDER_DISPLAY_NAMES2 = {
276308
+ december: "December Cloud",
276309
+ google: "Google AI Studio",
276310
+ gemini: "Google AI Studio",
276311
+ anthropic: "Anthropic Console",
276312
+ openai: "OpenAI Platform",
276313
+ openrouter: "OpenRouter",
276314
+ deepseek: "DeepSeek Platform",
276315
+ groq: "Groq Cloud",
276316
+ mistral: "Mistral AI",
276317
+ mistralai: "Mistral AI",
276318
+ "mistral-ai": "Mistral AI",
276319
+ moonshot: "Moonshot AI (Kimi)",
276320
+ moonshotai: "Moonshot AI (Kimi)",
276321
+ "moonshot-ai": "Moonshot AI (Kimi)",
276322
+ moonshoot: "Moonshot AI (Kimi)",
276323
+ kimi: "Moonshot AI (Kimi)",
276324
+ xai: "xAI Console",
276325
+ zai: "Zhipu AI (GLM)",
276326
+ nvidia: "NVIDIA NIM",
276327
+ sambanova: "SambaNova Cloud",
276328
+ cerebras: "Cerebras Inference",
276329
+ siliconflow: "SiliconFlow (SiliconCloud)",
276330
+ together: "Together AI",
276331
+ hyperbolic: "Hyperbolic",
276332
+ fireworks: "Fireworks AI",
276333
+ perplexity: "Perplexity AI",
276334
+ cohere: "Cohere",
276335
+ huggingface: "Hugging Face",
276336
+ agentrouter: "AgentRouter",
276337
+ arcee: "Arcee AI",
276338
+ meta: "Meta",
276339
+ minimax: "MiniMax",
276340
+ minimaxai: "MiniMax",
276341
+ "minimax-ai": "MiniMax",
276342
+ poolside: "Poolside",
276343
+ sakana: "Sakana AI",
276344
+ "sakana-ai": "Sakana AI",
276345
+ sakanaai: "Sakana AI",
276346
+ sarvam: "Sarvam AI",
276347
+ sarvamai: "Sarvam AI",
276348
+ "sarvam-ai": "Sarvam AI",
276349
+ stepfun: "StepFun (Global)",
276350
+ stepfunai: "StepFun (Global)",
276351
+ "stepfun-ai": "StepFun (Global)",
276352
+ upstage: "Upstage Solar",
276353
+ upstageai: "Upstage Solar",
276354
+ solar: "Upstage Solar",
276355
+ thinkingmachines: "Thinking Machines (Tinker)",
276356
+ tinker: "Thinking Machines (Tinker)",
276357
+ inkling: "Thinking Machines (Tinker)",
276358
+ ollama: "Ollama (Local)"
276359
+ };
276360
+ });
276361
+
275673
276362
  // src/utils/error-parser.ts
275674
276363
  import util5 from "util";
275675
276364
  function isCreditOrBalanceError(combined) {
275676
276365
  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("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"));
275677
276366
  }
275678
- function findMatchingCreditRule(combined) {
276367
+ function normalizeProviderAlias(provider) {
276368
+ if (!provider)
276369
+ return "";
276370
+ const lower = provider.trim().toLowerCase();
276371
+ switch (lower) {
276372
+ case "gemini":
276373
+ case "google":
276374
+ case "google-ai":
276375
+ case "googleai":
276376
+ return "google";
276377
+ case "claude":
276378
+ case "anthropic":
276379
+ return "anthropic";
276380
+ case "chatgpt":
276381
+ case "codex":
276382
+ case "openai":
276383
+ return "openai";
276384
+ case "arceeai":
276385
+ case "arcee-ai":
276386
+ case "arcee":
276387
+ return "arcee";
276388
+ case "metaai":
276389
+ case "meta-ai":
276390
+ case "meta":
276391
+ return "meta";
276392
+ case "minimaxai":
276393
+ case "minimax-ai":
276394
+ case "minimax":
276395
+ return "minimax";
276396
+ case "mistralai":
276397
+ case "mistral-ai":
276398
+ case "mistral":
276399
+ return "mistral";
276400
+ case "moonshotai":
276401
+ case "moonshot-ai":
276402
+ case "moonshoot":
276403
+ case "kimi":
276404
+ case "moonshot":
276405
+ return "moonshot";
276406
+ case "sakanaai":
276407
+ case "sakana-ai":
276408
+ case "sakana":
276409
+ return "sakana";
276410
+ case "sarvamai":
276411
+ case "sarvam-ai":
276412
+ case "sarvam":
276413
+ return "sarvam";
276414
+ case "stepfunai":
276415
+ case "stepfun-ai":
276416
+ case "stepfun":
276417
+ return "stepfun";
276418
+ case "upstageai":
276419
+ case "solar":
276420
+ case "upstage":
276421
+ return "upstage";
276422
+ case "tinker":
276423
+ case "inkling":
276424
+ case "thinkingmachines":
276425
+ return "thinkingmachines";
276426
+ case "siliconcloud":
276427
+ case "siliconflow":
276428
+ return "siliconflow";
276429
+ case "togetherai":
276430
+ case "together":
276431
+ return "together";
276432
+ case "zhipu":
276433
+ case "bigmodel":
276434
+ case "zai":
276435
+ return "zai";
276436
+ case "qwen":
276437
+ case "dashscope":
276438
+ return "dashscope";
276439
+ default:
276440
+ return lower;
276441
+ }
276442
+ }
276443
+ function detectProviderFromText(str) {
276444
+ if (!str)
276445
+ return null;
276446
+ const lower = str.toLowerCase();
276447
+ if (lower.includes("arcee") || lower.includes("trinity") || lower.includes("api.arcee.ai"))
276448
+ return "arcee";
276449
+ if (lower.includes("sarvam") || lower.includes("indus.sarvam.ai"))
276450
+ return "sarvam";
276451
+ if (lower.includes("stepfun") || lower.includes("stepfun.ai"))
276452
+ return "stepfun";
276453
+ if (lower.includes("upstage") || lower.includes("solar") || lower.includes("upstage.ai"))
276454
+ return "upstage";
276455
+ if (lower.includes("thinkingmachines") || lower.includes("tinker") || lower.includes("inkling") || lower.includes("thinkingmachines.ai"))
276456
+ return "thinkingmachines";
276457
+ if (lower.includes("minimax") || lower.includes("api.minimax.io"))
276458
+ return "minimax";
276459
+ if (lower.includes("deepseek") || lower.includes("api.deepseek.com"))
276460
+ return "deepseek";
276461
+ if (lower.includes("openrouter") || lower.includes("openrouter.ai"))
276462
+ return "openrouter";
276463
+ if (lower.includes("meta") || lower.includes("muse-spark") || lower.includes("dev.meta.ai"))
276464
+ return "meta";
276465
+ if (lower.includes("siliconflow") || lower.includes("siliconcloud") || lower.includes("siliconflow.cn"))
276466
+ return "siliconflow";
276467
+ if (lower.includes("moonshot") || lower.includes("kimi") || lower.includes("moonshot.cn") || lower.includes("kimi.com"))
276468
+ return "moonshot";
276469
+ if (lower.includes("together") || lower.includes("together.ai") || lower.includes("together.xyz"))
276470
+ return "together";
276471
+ if (lower.includes("fireworks") || lower.includes("fireworks.ai"))
276472
+ return "fireworks";
276473
+ if (lower.includes("groq") || lower.includes("api.groq.com"))
276474
+ return "groq";
276475
+ if (lower.includes("mistral") || lower.includes("codestral") || lower.includes("pixtral") || lower.includes("mistral.ai"))
276476
+ return "mistral";
276477
+ if (lower.includes("cerebras") || lower.includes("api.cerebras.ai"))
276478
+ return "cerebras";
276479
+ if (lower.includes("sambanova") || lower.includes("api.sambanova.ai"))
276480
+ return "sambanova";
276481
+ if (lower.includes("hyperbolic") || lower.includes("hyperbolic.xyz") || lower.includes("hyperbolic.ai"))
276482
+ return "hyperbolic";
276483
+ if (lower.includes("perplexity") || lower.includes("perplexity.ai"))
276484
+ return "perplexity";
276485
+ if (lower.includes("cohere") || lower.includes("api.cohere.com"))
276486
+ return "cohere";
276487
+ if (lower.includes("xai") || lower.includes("grok") || lower.includes("api.x.ai") || lower.includes("x.ai"))
276488
+ return "xai";
276489
+ if (lower.includes("zai") || lower.includes("zhipu") || lower.includes("bigmodel.cn"))
276490
+ return "zai";
276491
+ if (lower.includes("poolside") || lower.includes("laguna") || lower.includes("poolside.ai"))
276492
+ return "poolside";
276493
+ if (lower.includes("sakana") || lower.includes("fugu") || lower.includes("namazu") || lower.includes("sakana.ai"))
276494
+ return "sakana";
276495
+ if (lower.includes("dashscope") || lower.includes("qwen") || lower.includes("aliyuncs.com"))
276496
+ return "dashscope";
276497
+ if (lower.includes("anthropic") || lower.includes("claude") || lower.includes("api.anthropic.com"))
276498
+ return "anthropic";
276499
+ if (lower.includes("openai") || lower.includes("api.openai.com"))
276500
+ return "openai";
276501
+ if (lower.includes("google") || lower.includes("gemini") || lower.includes("aistudio") || lower.includes("generativelanguage.googleapis.com"))
276502
+ return "google";
276503
+ if (lower.includes("huggingface") || lower.includes("router.huggingface.co"))
276504
+ return "huggingface";
276505
+ if (lower.includes("agentrouter") || lower.includes("agentrouter.org"))
276506
+ return "agentrouter";
276507
+ if (lower.includes("nvidia") || lower.includes("build.nvidia.com"))
276508
+ return "nvidia";
276509
+ return null;
276510
+ }
276511
+ function resolveDynamicCreditRule(combined, context) {
276512
+ let candidate = (context?.provider || "").trim().toLowerCase();
276513
+ if (!candidate && context?.model) {
276514
+ const inferred = inferProviderFromModel(context.model);
276515
+ if (inferred && inferred !== "openrouter") {
276516
+ candidate = inferred;
276517
+ }
276518
+ }
276519
+ if (!candidate) {
276520
+ candidate = detectProviderFromText(combined) || "";
276521
+ }
276522
+ const normalized = normalizeProviderAlias(candidate);
276523
+ if (normalized && PROVIDER_BILLING_URLS[normalized]) {
276524
+ const displayName = PROVIDER_CREDIT_DISPLAY_NAMES[normalized] || normalized.charAt(0).toUpperCase() + normalized.slice(1);
276525
+ const billingUrl = PROVIDER_BILLING_URLS[normalized];
276526
+ return {
276527
+ id: normalized,
276528
+ name: displayName,
276529
+ match: () => true,
276530
+ notice: `Insufficient credits in your ${displayName} account. Please add credits or top up your balance at ${billingUrl}
276531
+ `,
276532
+ message: `Insufficient credits in your ${displayName} account.`,
276533
+ hint: `Please add credits or top up your balance at ${billingUrl}`
276534
+ };
276535
+ }
276536
+ if (context?.baseURL) {
276537
+ return {
276538
+ id: "custom_provider",
276539
+ name: "Custom Provider",
276540
+ match: () => true,
276541
+ notice: `Insufficient credits or balance with your custom provider. Please check your account or top up at ${context.baseURL}
276542
+ `,
276543
+ message: "Insufficient credits or balance with your custom provider.",
276544
+ hint: `Please check your account or top up at ${context.baseURL} or switch models using /model.`
276545
+ };
276546
+ }
276547
+ return null;
276548
+ }
276549
+ function findMatchingCreditRule(combined, context) {
275679
276550
  for (const rule of PROVIDER_CREDIT_RULES) {
275680
276551
  if (rule.match(combined)) {
275681
276552
  return rule;
275682
276553
  }
275683
276554
  }
275684
- if (UNIVERSAL_CREDIT_FALLBACK.match(combined)) {
276555
+ if (isCreditOrBalanceError(combined)) {
276556
+ const dynamicRule = resolveDynamicCreditRule(combined, context);
276557
+ if (dynamicRule) {
276558
+ return dynamicRule;
276559
+ }
275685
276560
  return UNIVERSAL_CREDIT_FALLBACK;
275686
276561
  }
275687
276562
  return null;
@@ -275784,7 +276659,7 @@ function parseErrorMessage(err, context) {
275784
276659
  }
275785
276660
  const isDecemberCredits = lowerStr.includes("december wallet") || lowerStr.includes("trydecember.com") || lowerStr.includes("december cloud");
275786
276661
  if (!isDecemberCredits) {
275787
- const creditRule = findMatchingCreditRule(lowerStr);
276662
+ const creditRule = findMatchingCreditRule(lowerStr, context);
275788
276663
  if (creditRule) {
275789
276664
  const hasNoticeAlready = finalResult.includes(creditRule.message) || creditRule.hint && finalResult.includes(creditRule.hint);
275790
276665
  if (!hasNoticeAlready) {
@@ -275832,7 +276707,7 @@ function parseError(err, context) {
275832
276707
  }
275833
276708
  const isDecemberCredits = combined.includes("december wallet") || combined.includes("trydecember.com") || combined.includes("december cloud");
275834
276709
  if (!isDecemberCredits) {
275835
- const creditRule = findMatchingCreditRule(combined);
276710
+ const creditRule = findMatchingCreditRule(combined, context);
275836
276711
  if (creditRule) {
275837
276712
  const parts = fullMessage.split(`
275838
276713
  `);
@@ -275910,8 +276785,9 @@ function parseError(err, context) {
275910
276785
  hint: err?.hint
275911
276786
  };
275912
276787
  }
275913
- var PROVIDER_CREDIT_RULES, UNIVERSAL_CREDIT_FALLBACK;
276788
+ var PROVIDER_CREDIT_RULES, PROVIDER_BILLING_URLS, PROVIDER_CREDIT_DISPLAY_NAMES, UNIVERSAL_CREDIT_FALLBACK;
275914
276789
  var init_error_parser = __esm(() => {
276790
+ init_usage_rates2();
275915
276791
  PROVIDER_CREDIT_RULES = [
275916
276792
  {
275917
276793
  id: "minimax",
@@ -276075,6 +276951,24 @@ var init_error_parser = __esm(() => {
276075
276951
  message: "Insufficient balance in your Zhipu AI account.",
276076
276952
  hint: "Please top up your balance at https://open.bigmodel.cn/ or switch models using /model."
276077
276953
  },
276954
+ {
276955
+ id: "poolside",
276956
+ name: "Poolside",
276957
+ match: (str) => (str.includes("poolside") || str.includes("inference.poolside.ai")) && isCreditOrBalanceError(str),
276958
+ notice: `Rate limit or quota exhausted in your Poolside account. Please check your account at https://platform.poolside.ai/api-keys
276959
+ `,
276960
+ message: "Rate limit or quota exhausted in your Poolside account.",
276961
+ hint: "Please check your account at https://platform.poolside.ai/api-keys or switch models using /model."
276962
+ },
276963
+ {
276964
+ id: "sakana",
276965
+ name: "Sakana AI",
276966
+ match: (str) => (str.includes("sakana") || str.includes("api.sakana.ai") || str.includes("fugu")) && isCreditOrBalanceError(str),
276967
+ notice: `Rate limit or quota exhausted in your Sakana AI account. Please check your account at https://console.sakana.ai/api-keys
276968
+ `,
276969
+ message: "Rate limit or quota exhausted in your Sakana AI account.",
276970
+ hint: "Please check your account at https://console.sakana.ai/api-keys or switch models using /model."
276971
+ },
276078
276972
  {
276079
276973
  id: "dashscope",
276080
276974
  name: "Alibaba Cloud DashScope",
@@ -276119,8 +277013,128 @@ var init_error_parser = __esm(() => {
276119
277013
  `,
276120
277014
  message: "Insufficient credits in your AgentRouter account.",
276121
277015
  hint: "Please add credits at https://agentrouter.org/ or switch models using /model."
277016
+ },
277017
+ {
277018
+ id: "google",
277019
+ name: "Google AI Studio",
277020
+ match: (str) => (str.includes("google") || str.includes("gemini") || str.includes("aistudio")) && (isCreditOrBalanceError(str) || str.includes("credits") || str.includes("402")),
277021
+ notice: `Insufficient credits in your Google AI Studio account. Please check your account at https://aistudio.google.com/
277022
+ `,
277023
+ message: "Insufficient credits in your Google AI Studio account.",
277024
+ hint: "Please check your account at https://aistudio.google.com/ or switch models using /model."
277025
+ },
277026
+ {
277027
+ id: "sarvam",
277028
+ name: "Sarvam AI",
277029
+ match: (str) => (str.includes("sarvam") || str.includes("indus.sarvam.ai")) && (isCreditOrBalanceError(str) || str.includes("credits") || str.includes("402")),
277030
+ notice: `Insufficient credits in your Sarvam AI account. Please add credits or top up your balance at https://indus.sarvam.ai/
277031
+ `,
277032
+ message: "Insufficient credits in your Sarvam AI account.",
277033
+ hint: "Please add credits or top up your balance at https://indus.sarvam.ai/"
277034
+ },
277035
+ {
277036
+ id: "stepfun",
277037
+ name: "StepFun",
277038
+ match: (str) => (str.includes("stepfun") || str.includes("stepfun.ai")) && (isCreditOrBalanceError(str) || str.includes("credits") || str.includes("402")),
277039
+ notice: `Insufficient credits in your StepFun account. Please add credits or top up your balance at https://platform.stepfun.ai/interface-key
277040
+ `,
277041
+ message: "Insufficient credits in your StepFun account.",
277042
+ hint: "Please add credits or top up your balance at https://platform.stepfun.ai/interface-key"
277043
+ },
277044
+ {
277045
+ id: "upstage",
277046
+ name: "Upstage Solar",
277047
+ match: (str) => (str.includes("upstage") || str.includes("solar") || str.includes("upstage.ai")) && (isCreditOrBalanceError(str) || str.includes("credits") || str.includes("402")),
277048
+ notice: `Insufficient credits in your Upstage Solar account. Please add credits or top up your balance at https://console.upstage.ai/
277049
+ `,
277050
+ message: "Insufficient credits in your Upstage Solar account.",
277051
+ hint: "Please add credits or top up your balance at https://console.upstage.ai/"
277052
+ },
277053
+ {
277054
+ id: "thinkingmachines",
277055
+ name: "Thinking Machines",
277056
+ match: (str) => (str.includes("thinkingmachines") || str.includes("tinker") || str.includes("inkling") || str.includes("thinkingmachines.ai")) && (isCreditOrBalanceError(str) || str.includes("credits") || str.includes("402")),
277057
+ notice: `Insufficient credits in your Thinking Machines account. Please add credits or top up your balance at https://tinker.thinkingmachines.ai/
277058
+ `,
277059
+ message: "Insufficient credits in your Thinking Machines account.",
277060
+ hint: "Please add credits or top up your balance at https://tinker.thinkingmachines.ai/"
277061
+ },
277062
+ {
277063
+ id: "nvidia",
277064
+ name: "NVIDIA NIM",
277065
+ match: (str) => (str.includes("nvidia") || str.includes("nim") || str.includes("nemotron") || str.includes("build.nvidia.com")) && (isCreditOrBalanceError(str) || str.includes("credits") || str.includes("402")),
277066
+ notice: `Insufficient credits in your NVIDIA NIM account. Please check your account at https://build.nvidia.com/
277067
+ `,
277068
+ message: "Insufficient credits in your NVIDIA NIM account.",
277069
+ hint: "Please check your account at https://build.nvidia.com/"
276122
277070
  }
276123
277071
  ];
277072
+ PROVIDER_BILLING_URLS = {
277073
+ agentrouter: "https://agentrouter.org/",
277074
+ anthropic: "https://console.anthropic.com/settings/billing",
277075
+ arcee: "https://platform.arcee.ai/api/api-keys",
277076
+ cerebras: "https://cloud.cerebras.ai/",
277077
+ cohere: "https://dashboard.cohere.com/billing",
277078
+ dashscope: "https://dashscope.console.aliyun.com/",
277079
+ deepseek: "https://platform.deepseek.com/top_up",
277080
+ fireworks: "https://fireworks.ai/account/billing",
277081
+ google: "https://aistudio.google.com/",
277082
+ groq: "https://console.groq.com/settings/limits",
277083
+ huggingface: "https://huggingface.co/settings/billing",
277084
+ hyperbolic: "https://app.hyperbolic.xyz/settings",
277085
+ meta: "https://dev.meta.ai/",
277086
+ minimax: "https://platform.minimax.io/",
277087
+ mistral: "https://console.mistral.ai/billing/",
277088
+ moonshot: "https://platform.moonshot.cn/",
277089
+ nvidia: "https://build.nvidia.com/",
277090
+ openai: "https://platform.openai.com/account/billing",
277091
+ openrouter: "https://openrouter.ai/settings/credits",
277092
+ perplexity: "https://www.perplexity.ai/settings/api",
277093
+ poolside: "https://platform.poolside.ai/api-keys",
277094
+ sakana: "https://console.sakana.ai/api-keys",
277095
+ sambanova: "https://cloud.sambanova.ai/",
277096
+ sarvam: "https://indus.sarvam.ai/",
277097
+ siliconflow: "https://cloud.siliconflow.cn/",
277098
+ stepfun: "https://platform.stepfun.ai/interface-key",
277099
+ thinkingmachines: "https://tinker.thinkingmachines.ai/",
277100
+ together: "https://api.together.ai/settings/billing",
277101
+ upstage: "https://console.upstage.ai/",
277102
+ xai: "https://console.x.ai/",
277103
+ zai: "https://open.bigmodel.cn/"
277104
+ };
277105
+ PROVIDER_CREDIT_DISPLAY_NAMES = {
277106
+ agentrouter: "AgentRouter",
277107
+ anthropic: "Anthropic",
277108
+ arcee: "Arcee AI",
277109
+ cerebras: "Cerebras",
277110
+ cohere: "Cohere",
277111
+ dashscope: "Alibaba Cloud DashScope",
277112
+ deepseek: "DeepSeek",
277113
+ fireworks: "Fireworks AI",
277114
+ google: "Google AI Studio",
277115
+ groq: "Groq",
277116
+ huggingface: "Hugging Face",
277117
+ hyperbolic: "Hyperbolic",
277118
+ meta: "Meta",
277119
+ minimax: "MiniMax",
277120
+ mistral: "Mistral AI",
277121
+ moonshot: "Moonshot AI",
277122
+ nvidia: "NVIDIA NIM",
277123
+ openai: "OpenAI",
277124
+ openrouter: "OpenRouter",
277125
+ perplexity: "Perplexity",
277126
+ poolside: "Poolside",
277127
+ sakana: "Sakana AI",
277128
+ sambanova: "SambaNova",
277129
+ sarvam: "Sarvam AI",
277130
+ siliconflow: "SiliconFlow",
277131
+ stepfun: "StepFun",
277132
+ thinkingmachines: "Thinking Machines",
277133
+ together: "Together AI",
277134
+ upstage: "Upstage Solar",
277135
+ xai: "xAI",
277136
+ zai: "Zhipu AI"
277137
+ };
276124
277138
  UNIVERSAL_CREDIT_FALLBACK = {
276125
277139
  id: "universal_fallback",
276126
277140
  name: "LLM Provider",
@@ -276195,175 +277209,6 @@ ${content.slice(0, 500)}`);
276195
277209
  }
276196
277210
  var init_project_context = () => {};
276197
277211
 
276198
- // src/utils/usage-rates.ts
276199
- function inferProviderFromModel(modelName) {
276200
- const lower = (modelName || "").toLowerCase();
276201
- if (lower.startsWith("trinity") || lower.startsWith("arcee"))
276202
- return "arcee";
276203
- if (lower.startsWith("muse") || lower.startsWith("meta/"))
276204
- return "meta";
276205
- if (lower.startsWith("minimax") || lower.startsWith("minimaxai/"))
276206
- return "minimax";
276207
- if (lower.startsWith("claude") || lower.startsWith("anthropic/"))
276208
- return "anthropic";
276209
- if (lower.startsWith("gpt") || lower.startsWith("o1") || lower.startsWith("o3") || lower.startsWith("o4") || lower.startsWith("openai/"))
276210
- return "openai";
276211
- if (lower.startsWith("gemini") || lower.startsWith("google/"))
276212
- return "google";
276213
- if (lower.startsWith("sonar") || lower.startsWith("perplexity"))
276214
- return "perplexity";
276215
- if (lower.startsWith("command") || lower.startsWith("cohere"))
276216
- return "cohere";
276217
- if (lower.startsWith("deepseek"))
276218
- return "deepseek";
276219
- if (lower.startsWith("groq") || lower.includes("llama-3.3-70b-versatile"))
276220
- return "groq";
276221
- if (lower.startsWith("mistral") || lower.startsWith("codestral") || lower.startsWith("pixtral") || lower.startsWith("ministral") || lower.startsWith("devstral") || lower.startsWith("magistral"))
276222
- return "mistral";
276223
- if (lower.startsWith("moonshot") || lower.startsWith("kimi"))
276224
- return "moonshot";
276225
- if (lower.startsWith("grok") || lower.startsWith("xai"))
276226
- return "xai";
276227
- if (lower.startsWith("zai") || lower.startsWith("glm"))
276228
- return "zai";
276229
- if (lower.startsWith("nvidia") || lower.startsWith("nim") || lower.includes("nemotron"))
276230
- return "nvidia";
276231
- if (lower.startsWith("sambanova"))
276232
- return "sambanova";
276233
- if (lower.startsWith("cerebras"))
276234
- return "cerebras";
276235
- if (lower.startsWith("siliconflow") || lower.startsWith("siliconcloud"))
276236
- return "siliconflow";
276237
- if (lower.startsWith("together"))
276238
- return "together";
276239
- if (lower.startsWith("hyperbolic"))
276240
- return "hyperbolic";
276241
- if (lower.startsWith("fireworks") || lower.startsWith("accounts/fireworks/"))
276242
- return "fireworks";
276243
- if (lower.startsWith("agentrouter") || lower.startsWith("agentrouter/"))
276244
- return "agentrouter";
276245
- if (lower.includes("meta-llama") || lower.includes("qwen/"))
276246
- return "huggingface";
276247
- if (lower.includes("ollama") || lower.includes("llama") || lower.includes("qwen"))
276248
- return "ollama";
276249
- return "openrouter";
276250
- }
276251
- function formatUsageCard(params) {
276252
- const { model, authMethod = "byok", isAuthenticated = true } = params;
276253
- let providerKey = (params.provider || "").toLowerCase();
276254
- if (!isAuthenticated) {
276255
- return AUTH_REQUIRED_NOTICE;
276256
- }
276257
- if (authMethod === "december") {
276258
- const billingLink = PROVIDER_BILLING_LINKS2.december;
276259
- return `Active Model: \`${model}\` (December Wallet)
276260
- Provider: December Cloud
276261
-
276262
- *Usage is deducted directly from your December account credits. Request telemetry, token consumption, and monthly invoices are tracked at [${billingLink}](${billingLink})*`;
276263
- }
276264
- if (authMethod === "subscription") {
276265
- const subDisplayName = providerKey === "copilot" || providerKey === "github" ? "GitHub Copilot" : providerKey === "claude" || providerKey === "anthropic" ? "Claude Pro/Max (Claude Code)" : providerKey === "codex" || providerKey === "openai" ? "ChatGPT Plus/Team/Pro (OpenAI Codex)" : providerKey === "gemini" || providerKey === "google" || providerKey === "antigravity" ? "Google One AI Premium (Gemini/Antigravity)" : `${providerKey.toUpperCase()} Subscription`;
276266
- return `Active Model: \`${model}\` (Subscription)
276267
- Provider: ${subDisplayName}
276268
-
276269
- *Usage is covered by your active ${subDisplayName} monthly subscription quota. Prompts route directly from your machine with OAuth authentication; no per-token charges or December proxy fees apply.*`;
276270
- }
276271
- if (!providerKey || providerKey === "december_proxy") {
276272
- providerKey = inferProviderFromModel(model);
276273
- }
276274
- if (providerKey === "ollama" || model.toLowerCase().includes("ollama")) {
276275
- const link = PROVIDER_BILLING_LINKS2.ollama;
276276
- return `Active Model: \`${model}\` (Local)
276277
- Provider: Ollama (Local)
276278
-
276279
- *Running completely locally on your hardware with no API keys, no external network calls, and no usage fees. View status and local models at [${link}](${link})*`;
276280
- }
276281
- const displayName = PROVIDER_DISPLAY_NAMES2[providerKey] || providerKey.toUpperCase();
276282
- const billingLink = PROVIDER_BILLING_LINKS2[providerKey] || `https://openrouter.ai/activity`;
276283
- return `Active Model: \`${model}\` (BYOK)
276284
- Provider: ${displayName}
276285
-
276286
- *Prompts go directly to the provider API; December servers do not track, log, or bill this usage. Token consumption, quotas, and billing are managed in your ${displayName} account at [${billingLink}](${billingLink})*`;
276287
- }
276288
- var PROVIDER_BILLING_LINKS2, PROVIDER_DISPLAY_NAMES2;
276289
- var init_usage_rates2 = __esm(() => {
276290
- init_messages5();
276291
- PROVIDER_BILLING_LINKS2 = {
276292
- december: "https://trydecember.com/settings/usage",
276293
- google: "https://aistudio.google.com/app/usage",
276294
- gemini: "https://aistudio.google.com/app/usage",
276295
- anthropic: "https://console.anthropic.com/settings/billing",
276296
- openai: "https://platform.openai.com/usage",
276297
- openrouter: "https://openrouter.ai/activity",
276298
- deepseek: "https://platform.deepseek.com/usage",
276299
- groq: "https://console.groq.com/usage",
276300
- mistral: "https://console.mistral.ai/billing/",
276301
- mistralai: "https://console.mistral.ai/billing/",
276302
- "mistral-ai": "https://console.mistral.ai/billing/",
276303
- moonshot: "https://platform.moonshot.ai/console/api-keys",
276304
- moonshotai: "https://platform.moonshot.ai/console/api-keys",
276305
- "moonshot-ai": "https://platform.moonshot.ai/console/api-keys",
276306
- moonshoot: "https://platform.moonshot.ai/console/api-keys",
276307
- kimi: "https://platform.moonshot.ai/console/api-keys",
276308
- xai: "https://console.x.ai/",
276309
- zai: "https://open.bigmodel.cn/usercenter/apikeys",
276310
- nvidia: "https://build.nvidia.com/",
276311
- sambanova: "https://cloud.sambanova.ai/",
276312
- cerebras: "https://cloud.cerebras.ai/",
276313
- siliconflow: "https://cloud.siliconflow.cn/account/ak",
276314
- together: "https://api.together.ai/settings/billing",
276315
- hyperbolic: "https://app.hyperbolic.ai/settings",
276316
- fireworks: "https://app.fireworks.ai/settings/billing",
276317
- perplexity: "https://www.perplexity.ai/settings/api",
276318
- cohere: "https://dashboard.cohere.com/billing",
276319
- huggingface: "https://huggingface.co/settings/billing",
276320
- agentrouter: "https://agentrouter.org/console/token",
276321
- arcee: "https://platform.arcee.ai/api/api-keys",
276322
- meta: "https://dev.meta.ai/",
276323
- minimax: "https://platform.minimax.io/console/access",
276324
- minimaxai: "https://platform.minimax.io/console/access",
276325
- "minimax-ai": "https://platform.minimax.io/console/access",
276326
- ollama: "http://localhost:11434"
276327
- };
276328
- PROVIDER_DISPLAY_NAMES2 = {
276329
- december: "December Cloud",
276330
- google: "Google AI Studio",
276331
- gemini: "Google AI Studio",
276332
- anthropic: "Anthropic Console",
276333
- openai: "OpenAI Platform",
276334
- openrouter: "OpenRouter",
276335
- deepseek: "DeepSeek Platform",
276336
- groq: "Groq Cloud",
276337
- mistral: "Mistral AI",
276338
- mistralai: "Mistral AI",
276339
- "mistral-ai": "Mistral AI",
276340
- moonshot: "Moonshot AI (Kimi)",
276341
- moonshotai: "Moonshot AI (Kimi)",
276342
- "moonshot-ai": "Moonshot AI (Kimi)",
276343
- moonshoot: "Moonshot AI (Kimi)",
276344
- kimi: "Moonshot AI (Kimi)",
276345
- xai: "xAI Console",
276346
- zai: "Zhipu AI (GLM)",
276347
- nvidia: "NVIDIA NIM",
276348
- sambanova: "SambaNova Cloud",
276349
- cerebras: "Cerebras Inference",
276350
- siliconflow: "SiliconFlow (SiliconCloud)",
276351
- together: "Together AI",
276352
- hyperbolic: "Hyperbolic",
276353
- fireworks: "Fireworks AI",
276354
- perplexity: "Perplexity AI",
276355
- cohere: "Cohere",
276356
- huggingface: "Hugging Face",
276357
- agentrouter: "AgentRouter",
276358
- arcee: "Arcee AI",
276359
- meta: "Meta",
276360
- minimax: "MiniMax",
276361
- minimaxai: "MiniMax",
276362
- "minimax-ai": "MiniMax",
276363
- ollama: "Ollama (Local)"
276364
- };
276365
- });
276366
-
276367
277212
  // src/utils/formatters.ts
276368
277213
  function getToolSummary(name, inputStr) {
276369
277214
  try {
@@ -276414,6 +277259,66 @@ function getToolSummary(name, inputStr) {
276414
277259
  function getNextMsgId() {
276415
277260
  return `msg-${Date.now()}-${Math.random().toString(36).slice(2, 7)}-${++msgIdCounter}`;
276416
277261
  }
277262
+ function convertAgentMessagesToTuiMessages(messages) {
277263
+ const resumedMessages = [];
277264
+ for (const msg of messages) {
277265
+ if (msg.role === "user") {
277266
+ let userText = msg.displayText || msg.content;
277267
+ if (!msg.displayText && userText.startsWith("[Skill Invocation: /")) {
277268
+ const match = userText.match(/^\[Skill Invocation: (\/[^\]]+)\]/);
277269
+ if (match) {
277270
+ userText = match[1];
277271
+ }
277272
+ }
277273
+ resumedMessages.push({ id: getNextMsgId(), role: "user", text: userText });
277274
+ } else if (msg.role === "assistant") {
277275
+ const blocks = [];
277276
+ if (msg.thinking) {
277277
+ blocks.push({ type: "thinking", content: msg.thinking });
277278
+ }
277279
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
277280
+ for (const tc of msg.toolCalls) {
277281
+ const toolMsg = messages.find((m) => m.role === "tool" && m.toolCallId === tc.id);
277282
+ const inputStr = typeof tc.input === "string" ? tc.input : JSON.stringify(tc.input);
277283
+ const hasError = toolMsg && (toolMsg.content.startsWith("Error executing tool:") || toolMsg.content.startsWith("Tool execution blocked:") || toolMsg.content.startsWith("Tool ") && toolMsg.content.endsWith(" not found."));
277284
+ blocks.push({
277285
+ type: "command",
277286
+ toolCallId: tc.id,
277287
+ toolName: tc.name,
277288
+ toolInput: inputStr,
277289
+ command: getToolSummary(tc.name, inputStr),
277290
+ status: hasError ? "error" : "success",
277291
+ output: toolMsg?.content || ""
277292
+ });
277293
+ }
277294
+ }
277295
+ if (msg.errorMessage) {
277296
+ const parsed = parseError({ message: msg.errorMessage });
277297
+ blocks.push({
277298
+ type: "error",
277299
+ error: parsed.message,
277300
+ cause: parsed.cause,
277301
+ hint: parsed.hint
277302
+ });
277303
+ } else if (msg.content) {
277304
+ blocks.push({ type: "text", content: msg.content });
277305
+ }
277306
+ if (blocks.length > 0) {
277307
+ const lastResumed = resumedMessages[resumedMessages.length - 1];
277308
+ if (lastResumed && lastResumed.role === "assistant" && lastResumed.blocks) {
277309
+ lastResumed.blocks.push(...blocks);
277310
+ } else {
277311
+ resumedMessages.push({
277312
+ id: getNextMsgId(),
277313
+ role: "assistant",
277314
+ blocks
277315
+ });
277316
+ }
277317
+ }
277318
+ }
277319
+ }
277320
+ return resumedMessages;
277321
+ }
276417
277322
  async function processAgentStream({
276418
277323
  stream,
276419
277324
  setActiveMessages,
@@ -276987,7 +277892,7 @@ ${formatSubscriptionCard(bundle, targetModel)}`
276987
277892
  probeAbortController.abort(new Error("Connection timed out while verifying API key."));
276988
277893
  }, 1e4);
276989
277894
  try {
276990
- const stream = testProvider.stream([{ role: "user", content: "Hi" }], [], undefined, {
277895
+ const stream = testProvider.stream([{ role: "user", content: "Hi" }], undefined, undefined, {
276991
277896
  model: testModel,
276992
277897
  max_tokens: 16
276993
277898
  }, probeAbortController.signal);
@@ -277215,67 +278120,9 @@ ${formatSubscriptionCard(bundle, targetModel)}`
277215
278120
  };
277216
278121
  const handleSessionSelect = async (item) => {
277217
278122
  setAuthMode("none");
277218
- console.clear();
277219
278123
  try {
277220
278124
  await agent.loadContext(item.value);
277221
- const resumedMessages = [];
277222
- for (const msg of agent.messages) {
277223
- if (msg.role === "user") {
277224
- let userText = msg.displayText || msg.content;
277225
- if (!msg.displayText && userText.startsWith("[Skill Invocation: /")) {
277226
- const match = userText.match(/^\[Skill Invocation: (\/[^\]]+)\]/);
277227
- if (match) {
277228
- userText = match[1];
277229
- }
277230
- }
277231
- resumedMessages.push({ id: getNextMsgId(), role: "user", text: userText });
277232
- } else if (msg.role === "assistant") {
277233
- const blocks = [];
277234
- if (msg.thinking) {
277235
- blocks.push({ type: "thinking", content: msg.thinking });
277236
- }
277237
- if (msg.toolCalls && msg.toolCalls.length > 0) {
277238
- for (const tc of msg.toolCalls) {
277239
- const toolMsg = agent.messages.find((m) => m.role === "tool" && m.toolCallId === tc.id);
277240
- const inputStr = typeof tc.input === "string" ? tc.input : JSON.stringify(tc.input);
277241
- const hasError = toolMsg && (toolMsg.content.startsWith("Error executing tool:") || toolMsg.content.startsWith("Tool execution blocked:") || toolMsg.content.startsWith("Tool ") && toolMsg.content.endsWith(" not found."));
277242
- blocks.push({
277243
- type: "command",
277244
- toolCallId: tc.id,
277245
- toolName: tc.name,
277246
- toolInput: inputStr,
277247
- command: getToolSummary(tc.name, inputStr),
277248
- status: hasError ? "error" : "success",
277249
- output: toolMsg?.content || ""
277250
- });
277251
- }
277252
- }
277253
- if (msg.errorMessage) {
277254
- await Promise.resolve().then(() => init_error_parser());
277255
- const parsed = parseError({ message: msg.errorMessage });
277256
- blocks.push({
277257
- type: "error",
277258
- error: parsed.message,
277259
- cause: parsed.cause,
277260
- hint: parsed.hint
277261
- });
277262
- } else if (msg.content) {
277263
- blocks.push({ type: "text", content: msg.content });
277264
- }
277265
- if (blocks.length > 0) {
277266
- const lastResumed = resumedMessages[resumedMessages.length - 1];
277267
- if (lastResumed && lastResumed.role === "assistant" && lastResumed.blocks) {
277268
- lastResumed.blocks.push(...blocks);
277269
- } else {
277270
- resumedMessages.push({
277271
- id: getNextMsgId(),
277272
- role: "assistant",
277273
- blocks
277274
- });
277275
- }
277276
- }
277277
- }
277278
- }
278125
+ const resumedMessages = convertAgentMessagesToTuiMessages(agent.messages);
277279
278126
  setStaticMessages([{ id: "header", role: "header" }, ...resumedMessages]);
277280
278127
  setStaticKey((k) => k + 1);
277281
278128
  setActiveMessages([]);
@@ -277721,6 +278568,24 @@ function useAgentSession({
277721
278568
  });
277722
278569
  }
277723
278570
  }, [agent, setAuthMode, setPendingQuestions, setPendingToolCall]);
278571
+ import_react65.useEffect(() => {
278572
+ if (!agent)
278573
+ return;
278574
+ const hydrateInitialSession = async () => {
278575
+ try {
278576
+ await agent.loadContext();
278577
+ } catch {}
278578
+ const nonSystem = (agent.messages || []).filter((m) => m.role !== "system");
278579
+ if (nonSystem.length > 0) {
278580
+ const resumed = convertAgentMessagesToTuiMessages(agent.messages);
278581
+ if (resumed.length > 0) {
278582
+ setStaticMessages([{ id: "header", role: "header" }, ...resumed]);
278583
+ setStaticKey((k) => k + 1);
278584
+ }
278585
+ }
278586
+ };
278587
+ hydrateInitialSession();
278588
+ }, [agent, setStaticMessages, setStaticKey]);
277724
278589
  const activeShellAbortRef = import_react65.useRef(null);
277725
278590
  import_react65.useEffect(() => {
277726
278591
  const update = () => {
@@ -277880,7 +278745,11 @@ function useAgentSession({
277880
278745
  await generatePlanFromGrill([]);
277881
278746
  }
277882
278747
  } catch (err) {
277883
- const cleanError = parseErrorMessage(err);
278748
+ const errorContext = {
278749
+ provider: agent?.modelOptions?.provider || useCliStore.getState().selectedProvider,
278750
+ model: agent?.modelOptions?.model || useCliStore.getState().activeModel
278751
+ };
278752
+ const cleanError = parseErrorMessage(err, errorContext);
277884
278753
  const isAuthErr = cleanError.includes("401") || cleanError.includes("dummy-key") || cleanError.toLowerCase().includes("incorrect api key") || cleanError.toLowerCase().includes("invalid api key") || cleanError.toLowerCase().includes("unauthorized");
277885
278754
  if (isAuthErr) {
277886
278755
  setActiveMessages([]);
@@ -277897,10 +278766,6 @@ function useAgentSession({
277897
278766
  setStaticMessages((prev) => [...prev, noticeMsg]);
277898
278767
  } else {
277899
278768
  setActiveMessages([]);
277900
- const errorContext = {
277901
- provider: agent?.modelOptions?.provider || useCliStore.getState().selectedProvider,
277902
- model: agent?.modelOptions?.model || useCliStore.getState().activeModel
277903
- };
277904
278769
  const parsed = parseError(err, errorContext);
277905
278770
  const errorMsg = {
277906
278771
  id: getNextMsgId(),
@@ -278581,6 +279446,24 @@ ${decStatus}
278581
279446
  }
278582
279447
  return;
278583
279448
  }
279449
+ const trimmedCmd = text.trim().toLowerCase();
279450
+ if (trimmedCmd === "/docs" || trimmedCmd.startsWith("/docs ")) {
279451
+ const parts = text.trim().split(/\s+/);
279452
+ const section = parts[1];
279453
+ await Promise.resolve().then(() => init_commands());
279454
+ const sectionPath = resolveDocsSectionPath(section);
279455
+ const baseUrl = (process.env.DECEMBER_DOCS_URL || process.env.WEB_URL || "https://trydecember.com").replace(/\/$/, "");
279456
+ const targetUrl = `${baseUrl}/docs${sectionPath}`;
279457
+ addToast("Opening documentation in your browser...", "info");
279458
+ try {
279459
+ await Promise.resolve().then(() => init_open());
279460
+ await openUrl(targetUrl);
279461
+ addToast("Opened documentation in browser.", "success");
279462
+ } catch {
279463
+ addToast(`Docs: ${targetUrl}`, "info");
279464
+ }
279465
+ return;
279466
+ }
278584
279467
  if (text.trim() === "/handoff") {
278585
279468
  const userMsg = { id: getNextMsgId(), role: "user", text: "/handoff" };
278586
279469
  const config = await loadConfig();
@@ -279094,6 +279977,7 @@ If it doesn't open automatically, please click here:
279094
279977
  "clear",
279095
279978
  "context",
279096
279979
  "copy",
279980
+ "docs",
279097
279981
  "exit",
279098
279982
  "feedback",
279099
279983
  "fork",
@@ -279623,6 +280507,7 @@ function parseCliArgs(args) {
279623
280507
  force: { type: "boolean", short: "f" },
279624
280508
  global: { type: "boolean", short: "g" },
279625
280509
  local: { type: "boolean", short: "l" },
280510
+ resume: { type: "boolean", short: "r" },
279626
280511
  model: { type: "string", short: "m" },
279627
280512
  provider: { type: "string", short: "p" },
279628
280513
  "session-id": { type: "string" },
@@ -279640,6 +280525,7 @@ function parseCliArgs(args) {
279640
280525
  const force = Boolean(values.force);
279641
280526
  const isGlobal = Boolean(values.global);
279642
280527
  const isLocal = Boolean(values.local);
280528
+ const isResume = Boolean(values.resume);
279643
280529
  const model = values.model;
279644
280530
  const provider = values.provider;
279645
280531
  const sessionId = values["session-id"];
@@ -279654,7 +280540,9 @@ function parseCliArgs(args) {
279654
280540
  "doctor",
279655
280541
  "auth",
279656
280542
  "link",
279657
- "key"
280543
+ "key",
280544
+ "resume",
280545
+ "docs"
279658
280546
  ];
279659
280547
  let command;
279660
280548
  let prompt;
@@ -279677,6 +280565,7 @@ function parseCliArgs(args) {
279677
280565
  force,
279678
280566
  isGlobal,
279679
280567
  isLocal,
280568
+ resume: isResume || command === "resume",
279680
280569
  model,
279681
280570
  provider,
279682
280571
  sessionId,
@@ -279694,6 +280583,7 @@ function parseCliArgs(args) {
279694
280583
  force: false,
279695
280584
  isGlobal: false,
279696
280585
  isLocal: false,
280586
+ resume: false,
279697
280587
  positionals: []
279698
280588
  };
279699
280589
  }
@@ -279705,6 +280595,7 @@ a coding agent that lives in your terminal.
279705
280595
  Usage:
279706
280596
  december Launch interactive TUI session
279707
280597
  december "<prompt>" Execute headless agent task
280598
+ december resume [session-id] Resume the most recent session or specified session ID
279708
280599
  december auth [status|import] Inspect active subscriptions and authentication status
279709
280600
  december link <provider> Link AI subscription (copilot, claude, chatgpt, gemini)
279710
280601
  december key <provider> [key] Save BYOK API key (openai, anthropic, openrouter, etc.)
@@ -279714,10 +280605,12 @@ Usage:
279714
280605
  december init Initialize local .december configuration
279715
280606
  december update Update December CLI to the latest version
279716
280607
  december doctor [--fix] Inspect installations, health, and resolve PATH collisions
280608
+ december docs [section] Open documentation in your browser
279717
280609
 
279718
280610
  Options:
279719
280611
  -h, --help Show CLI help and exit
279720
280612
  -v, --version Show CLI version and exit
280613
+ -r, --resume Resume the most recent session
279721
280614
  -y, --yes Auto-approve tool permissions (non-interactive mode)
279722
280615
  --json Output structured JSON events
279723
280616
  --fix Automatically fix detected PATH collisions and stale links
@@ -279833,6 +280726,12 @@ ${formattedStdin}`;
279833
280726
  await handleDoctorCommand({ fix: parsedArgs.fix });
279834
280727
  process.exit(0);
279835
280728
  }
280729
+ if (parsedArgs.command === "docs") {
280730
+ const section = parsedArgs.positionals[1];
280731
+ await Promise.resolve().then(() => init_commands());
280732
+ await handleDocsCommand({ section });
280733
+ process.exit(0);
280734
+ }
279836
280735
  if (parsedArgs.prompt) {
279837
280736
  const [
279838
280737
  { AgentHarness },
@@ -279872,7 +280771,14 @@ ${formattedStdin}`;
279872
280771
  llm = openaiProvider(undefined, "dummy-key");
279873
280772
  }
279874
280773
  const sessionRepository = new FileSessionRepository;
279875
- const sessionId = parsedArgs.sessionId || `session-${Date.now()}`;
280774
+ let targetSessionId = parsedArgs.sessionId;
280775
+ if (parsedArgs.resume && !targetSessionId) {
280776
+ const sessions = await sessionRepository.listSessions();
280777
+ if (sessions.length > 0) {
280778
+ targetSessionId = sessions[0].id;
280779
+ }
280780
+ }
280781
+ const sessionId = targetSessionId || `session-${Date.now()}`;
279876
280782
  const config = await loadConfig();
279877
280783
  const activeProvider = providerConfig?.provider || config.activeProvider || "gemini";
279878
280784
  const initialModel = parsedArgs.model || providerConfig?.model || ensureValidModelForProvider(activeProvider, config.activeModel);
@@ -279971,7 +280877,19 @@ Executing Headless Task: "${parsedArgs.prompt}"
279971
280877
  }
279972
280878
  const isAuthenticated = !!providerConfig;
279973
280879
  const sessionRepository = new FileSessionRepository;
279974
- const sessionId = parsedArgs.sessionId || `session-${Date.now()}`;
280880
+ let targetSessionId = parsedArgs.sessionId;
280881
+ if (parsedArgs.command === "resume" || parsedArgs.resume) {
280882
+ if (!targetSessionId && parsedArgs.positionals[1]) {
280883
+ targetSessionId = parsedArgs.positionals[1];
280884
+ }
280885
+ if (!targetSessionId) {
280886
+ const sessions = await sessionRepository.listSessions();
280887
+ if (sessions.length > 0) {
280888
+ targetSessionId = sessions[0].id;
280889
+ }
280890
+ }
280891
+ }
280892
+ const sessionId = targetSessionId || `session-${Date.now()}`;
279975
280893
  const config = await loadConfig();
279976
280894
  const activeProvider = providerConfig?.provider || config.activeProvider || "gemini";
279977
280895
  const initialModel = parsedArgs.model || providerConfig?.model || ensureValidModelForProvider(activeProvider, config.activeModel);
@@ -280042,7 +280960,7 @@ Executing Headless Task: "${parsedArgs.prompt}"
280042
280960
  userEmail,
280043
280961
  sessionRepository,
280044
280962
  onLogin: (onCode) => Promise.resolve().then(() => (init_auth(), {})).then(({}) => loginViaDeviceCode(undefined, onCode))
280045
- })), { exitOnCtrlC: false, incrementalRendering: true });
280963
+ })), { exitOnCtrlC: false });
280046
280964
  }
280047
280965
  main().catch(console.error);
280048
280966
  export {