free-coding-models 0.5.84 → 0.5.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -192,6 +192,7 @@ A large catalog of coding models from 20+ active providers, ranked by practical
192
192
  | 21 | [SiliconFlow](https://cloud.siliconflow.cn/account/ak) | 3 | A → B+ | 3 models @ $0, 1000 RPM (phone SMS required) | `SILICONFLOW_API_KEY` |
193
193
  | 22 | [Requesty](https://app.requesty.ai/api-keys) | 12 | S+ → C | 200 req/day free, no card (4x OpenRouter) | `REQUESTY_API_KEY` |
194
194
  | 23 | [OrcaRouter](https://www.orcarouter.ai) | 3 | S+ → A+ | Free Hacker tier · 3 $-0 models, zero token markup | `ORCAROUTER_API_KEY` |
195
+ | 24 | [Vercel AI Gateway](https://vercel.com/ai-gateway) | 4 | S+ → B+ | $5 gateway credits every 30 days, no card + explicit $0 models | `VERCEL_AI_GATEWAY_API_KEY` |
195
196
 
196
197
  > **Pollinations Pollen, c'est quoi ?** Pollinations ne facture pas en $ mais en **Pollen** (≈ $1). Pas besoin d'acheter : tu recois du Pollen **gratuit chaque jour** selon ton tier seed/flower/nectar via quests (star le repo `pollinations/pollinations` sur GitHub, aider sur un issue). Si ton solde affiche `0.0000` sur `enter.pollinations.ai`, tout `MISS` (prompt non cache) retourne `402 PAYMENT_REQUIRED` ("Insufficient balance ~0.0001 pollen") et le ping affichera `402`. Un `HIT` Cloudflare cache peut encore passer en `200` meme avec 0 Pollen mais ce n'est pas fiable. Verifie ton solde sur `enter.pollinations.ai` -> API Keys, complete une quest et attends le grant quotidien a minuit UTC. **Note : integration Pollinations encore experimentale et non confirmee comme stable, le systeme Pollen peut changer.**
197
198
  > **SiliconFlow & Requesty** : integrations verifiees le 2026-08-24 via `/v1/models` live et docs officielles, free tiers recurrents confirmes sans Pollen.
@@ -985,6 +986,7 @@ Curated resources kept **outside** the active CLI catalog — IDE extensions, co
985
986
 
986
987
  | Provider | Free limits | Notable models |
987
988
  |----------|-------------|----------------|
989
+ | [Vercel AI Gateway](https://vercel.com/ai-gateway) | $5 credits every 30 days (no card) + explicit $0 models | MiniMax M3 (1M ctx), Laguna S 2.1, MiniMax M2.7, Ling 3.0 Flash Fin |
988
990
  | [OrcaRouter](https://www.orcarouter.ai) | Free Hacker tier, zero token markup, 3 API keys | DeepSeek V4 Flash (Free), Tencent Hy3 (Free), Qwen3.8 27B (Free) |
989
991
  | [OpenRouter](https://openrouter.ai/keys) | 50 req/day, 1K/day with $10 purchase | Qwen3-Coder, Tencent HY3, Laguna, Gemma 4 |
990
992
  | [Google AI Studio](https://aistudio.google.com/apikey) | Varies by Gemini model and region | Gemini 3.8 Flash, Gemini 2.5 Pro |
@@ -0,0 +1,21 @@
1
+ # Changelog v0.5.85 - 2026-09-05
2
+
3
+ ### Added
4
+
5
+ - New provider: **Vercel AI Gateway** (24th provider in the catalog). This is Vercel's official OpenAI-compatible gateway: one endpoint at `https://ai-gateway.vercel.sh/v1/chat/completions`, list prices with zero markup, and it works from your local machine with nothing deployed to Vercel.
6
+ - **Free tier**: every Vercel account gets **$5 of gateway credits every 30 days**, no credit card required. On top of that, the gateway exposes a handful of genuinely $0 models (input AND output priced at $0), and those are the ones we list.
7
+ - **4 models added**, all verified live against `GET /v1/models` (373 models scanned, 2026-09-05):
8
+ - `minimax/minimax-m3-free` - MiniMax M3 (Free), S+ 78.4%, 1M context, vision + tool use
9
+ - `minimax/minimax-m2.7-free` - MiniMax M2.7 (Free), S+ 78.0%, 196k context, software-engineering focused
10
+ - `poolside/laguna-s-2.1-free` - Laguna S 2.1 (Free), S+ tier, 256k context, dedicated agentic coding model
11
+ - `inclusionai/ling-3.0-flash-fin-free` - Ling 3.0 Flash Fin (Free), B+ tier, 256k context, finance-tuned 124B MoE that retains coding and math
12
+ - **Quota marked `limited`** on purpose: the monthly credit only covers a subset of the 373-model catalog, and per Vercel's FAQ purchasing credits once permanently moves the account to the paid tier, which kills the recurring free credit. The Settings panel explains this.
13
+ - **Full cross-surface wiring**: TUI Settings panel entry with its own theme color, key test endpoint (`/v1/models`), web dashboard catalog, OpenCode + Kilo provider config generation, and monthly reset cadence for quota display. Env var: `VERCEL_AI_GATEWAY_API_KEY` (also accepts `AI_GATEWAY_API_KEY`).
14
+ - Get a key: Vercel dashboard, AI Gateway → API Keys.
15
+ - New unit test covering the `vercel-gateway` source entry structure (model IDs must be explicit `-free` $0 models). Suite now at 880 tests.
16
+
17
+ ### Notes
18
+
19
+ - MiniMax M3/M2.7 scores mirror the measured entries already in the catalog (ollama-cloud, benchmarked 2026-07-27); the underlying models are identical.
20
+ - Laguna S 2.1 has no published SWE-bench score; its S+ tier follows the family precedent (Laguna XS 2.1 ships S+ 70.9% via NVIDIA). models.dev flags the model as deprecated as of 2026-09-05 (the Zen free promo ended), but Vercel still serves the $0 variant live today, so it stays listed with a re-verify note for the next audit.
21
+ - Catalog totals: 24 providers, 229 models.
@@ -0,0 +1,10 @@
1
+ # Changelog v0.5.86 - 2026-09-05
2
+
3
+ ### Fixed
4
+ - 🖥️ Provider column in the TUI table widened from 11 to 15 characters, with automatic truncation at 14 characters (13 + ellipsis) for anything longer. Provider names like "Cloudflare AI" (13 chars) now render fully instead of pushing every following cell out of alignment. Any future provider name longer than 14 chars is truncated cleanly with an ellipsis, so a long label can never break the table layout again. The compact-mode truncation (4 chars + ellipsis on narrow terminals) is unchanged.
5
+ - ⚡ Command Palette no longer paints a giant dark rectangle over the table. Each palette row used to be emitted from column 1 with a leading margin of unstyled spaces plus a trailing "erase to end of line": both inherited the still-active panel background, so the panel tint filled the entire screen width for every palette row, masking the frozen table on both sides of the modal. Rows are now positioned directly at the panel's left column and paint only the panel's own cells; the frozen table stays visible beside the palette.
6
+ - ✨ Command Palette no longer flickers on large terminals. While the palette is open the table behind it is frozen, so repainting the full table every frame was pure waste: on a 280-column terminal the per-frame write was ~300 KB, got split into chunks, and the terminal showed the bare table for a moment before the palette painted over it, 30 times per second. The frozen table is now written once when the palette opens; after that only the palette itself is repainted (per-frame output divided by ~50).
7
+ - 🧹 Palette height now stays constant while typing a search. Nothing repaints the cells below the panel while it is open (the table behind is frozen), so a shrinking result list used to leave stale painted rows hanging under the panel's bottom edge. Short result lists are padded to the full body height instead.
8
+
9
+ ### Tests
10
+ - 2 new regression tests: the palette must never emit margin filler or edge-to-edge erase codes, and the panel must keep a constant height when the result list shrinks. 883 tests passing across 11 suites.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-coding-models",
3
- "version": "0.5.84",
3
+ "version": "0.5.86",
4
4
  "description": "Find the fastest coding LLM models in seconds — ping free models from multiple providers, pick the best one for OpenCode, Cursor, or any AI coding assistant.",
5
5
  "keywords": [
6
6
  "nvidia",
package/sources.js CHANGED
@@ -29,7 +29,7 @@
29
29
  * 📖 Secondary: https://swe-rebench.com (independent evals, scores are lower)
30
30
  * 📖 Leaderboard tracker: https://www.marc0.dev/en/leaderboard
31
31
  *
32
- * @exports nvidiaNim, groq, cerebras, sambanova, openrouter, githubModels, mistral, codestral, scaleway, googleai, zai, qwen, cloudflare, ovhcloud, opencodeZen, kilo, llm7, routeway, novita, ollamaCloud, pollinations, siliconflow, requesty, orcarouter — model arrays per active provider
32
+ * @exports nvidiaNim, groq, cerebras, sambanova, openrouter, githubModels, mistral, codestral, scaleway, googleai, zai, qwen, cloudflare, ovhcloud, opencodeZen, kilo, llm7, routeway, novita, ollamaCloud, pollinations, siliconflow, requesty, orcarouter, vercelGateway — model arrays per active provider
33
33
  * @exports sources — map of active free/free-limited providers, each with { name, url, models }
34
34
 
35
35
  * @exports MODELS — flat array of [modelId, label, tier, sweScore, ctx, providerKey]
@@ -564,6 +564,24 @@ export const orcarouter = [
564
564
  ['qwen/qwen3.8-27b-free', 'Qwen3.8 27B (Free)', 'A+', '-', '64k'],
565
565
  ]
566
566
 
567
+ // 📖 Vercel AI Gateway source - https://vercel.com/docs/ai-gateway
568
+ // 📖 OpenAI-compatible gateway: https://ai-gateway.vercel.sh/v1/chat/completions
569
+ // 📖 Official Vercel gateway at list prices (zero markup). Every account gets $5 of
570
+ // 📖 gateway credits every 30 days (no card needed), and the catalog also exposes a
571
+ // 📖 handful of genuinely $0 models (input AND output priced 0). Verified live
572
+ // 📖 2026-09-05 via GET /v1/models (373 models, 5 with $0/$0 pricing).
573
+ // 📖 Caveats: the monthly credit only covers a subset of the catalog, and buying
574
+ // 📖 credits once permanently moves the account to the paid tier (official FAQ),
575
+ // 📖 which is why this provider is quotaCode 'limited'.
576
+ export const vercelGateway = [
577
+ // ── S+ tier — SWE-bench Verified ≥70% ──
578
+ ['minimax/minimax-m3-free', 'MiniMax M3 (Free)', 'S+', '78.4%', '1M'], // score mirrors minimax-m3 (ollama-cloud, measured 2026-07-27)
579
+ ['minimax/minimax-m2.7-free', 'MiniMax M2.7 (Free)', 'S+', '78.0%', '196k'], // score mirrors minimax-m2.7 (ollama-cloud, measured 2026-07-27)
580
+ ['poolside/laguna-s-2.1-free', 'Laguna S 2.1 (Free)', 'S+', '-', '256k'], // tier follows family precedent: laguna-xs-2.1 ships S+ 70.9% via NVIDIA. Caution: models.dev flags laguna-s-2.1 deprecated (2026-09-05, Zen promo ended) but Vercel still serves the $0 variant live - re-verify at next audit
581
+ // ── B+ tier — vertical-tuned lightweight (coding secondary) ──
582
+ ['inclusionai/ling-3.0-flash-fin-free', 'Ling 3.0 Flash Fin (Free)', 'B+', '-', '256k'], // 124B MoE (5.1B active), finance-tuned, retains coding + math
583
+ ]
584
+
567
585
  // 📖 Ollama Cloud source - https://ollama.com/pricing and https://ollama.com/search?c=cloud
568
586
  // 📖 Free plan includes cloud model access with session/weekly limits. This list keeps coding-relevant cloud models only.
569
587
  // 📖 Catalog verified 2026-07-18 against official Ollama cloud model search page.
@@ -773,6 +791,13 @@ export const sources = {
773
791
  quotaCode: 'free',
774
792
  models: orcarouter,
775
793
  },
794
+ 'vercel-gateway': {
795
+ name: 'Vercel AI Gateway',
796
+ url: 'https://ai-gateway.vercel.sh/v1/chat/completions',
797
+ quota: 'Free · $5 credits/30 days + $0 models · no card',
798
+ quotaCode: 'limited',
799
+ models: vercelGateway,
800
+ },
776
801
  'ollama-cloud': {
777
802
  name: 'Ollama Cloud',
778
803
  url: 'https://ollama.com/v1/chat/completions',
@@ -187,6 +187,7 @@ const ENV_VARS = {
187
187
  siliconflow: 'SILICONFLOW_API_KEY',
188
188
  requesty: 'REQUESTY_API_KEY',
189
189
  orcarouter: 'ORCAROUTER_API_KEY',
190
+ 'vercel-gateway': ['VERCEL_AI_GATEWAY_API_KEY', 'AI_GATEWAY_API_KEY'],
190
191
  }
191
192
 
192
193
  // 📖 Smart Router defaults are intentionally conservative: balanced probing,
package/src/core/kilo.js CHANGED
@@ -117,6 +117,13 @@ export async function startKilo(model, fcmConfig) {
117
117
  options: { baseURL: 'https://api.orcarouter.ai/v1', apiKey: '{env:ORCAROUTER_API_KEY}' },
118
118
  models: {}
119
119
  }
120
+ } else if (providerKey === 'vercel-gateway') {
121
+ config.provider['vercel-gateway'] = {
122
+ npm: '@ai-sdk/openai-compatible',
123
+ name: 'Vercel AI Gateway',
124
+ options: { baseURL: 'https://ai-gateway.vercel.sh/v1', apiKey: '{env:VERCEL_AI_GATEWAY_API_KEY}' },
125
+ models: {}
126
+ }
120
127
  } else if (providerKey === 'huggingface') {
121
128
  config.provider.huggingface = {
122
129
  npm: '@ai-sdk/openai-compatible',
@@ -45,6 +45,7 @@ export const PROVIDER_ALIASES = {
45
45
  nvidia: 'nvidia',
46
46
  openrouter: 'openrouter',
47
47
  orcarouter: 'orcarouter',
48
+ 'vercel-gateway': 'vercel',
48
49
  groq: 'groq',
49
50
  cerebras: 'cerebras',
50
51
  github: 'github-models',
@@ -432,6 +432,13 @@ export async function startOpenCode(model, fcmConfig) {
432
432
  options: { baseURL: 'https://api.orcarouter.ai/v1', apiKey: '{env:ORCAROUTER_API_KEY}' },
433
433
  models: {}
434
434
  }
435
+ } else if (providerKey === 'vercel-gateway') {
436
+ config.provider['vercel-gateway'] = {
437
+ npm: '@ai-sdk/openai-compatible',
438
+ name: 'Vercel AI Gateway',
439
+ options: { baseURL: 'https://ai-gateway.vercel.sh/v1', apiKey: '{env:VERCEL_AI_GATEWAY_API_KEY}' },
440
+ models: {}
441
+ }
435
442
  } else if (providerKey === 'huggingface') {
436
443
  config.provider.huggingface = {
437
444
  npm: '@ai-sdk/openai-compatible',
@@ -807,6 +814,13 @@ export async function startOpenCodeDesktop(model, fcmConfig) {
807
814
  options: { baseURL: 'https://api.orcarouter.ai/v1', apiKey: '{env:ORCAROUTER_API_KEY}' },
808
815
  models: {}
809
816
  }
817
+ } else if (providerKey === 'vercel-gateway') {
818
+ config.provider['vercel-gateway'] = {
819
+ npm: '@ai-sdk/openai-compatible',
820
+ name: 'Vercel AI Gateway',
821
+ options: { baseURL: 'https://ai-gateway.vercel.sh/v1', apiKey: '{env:VERCEL_AI_GATEWAY_API_KEY}' },
822
+ models: {}
823
+ }
810
824
  } else if (providerKey === 'huggingface') {
811
825
  config.provider.huggingface = {
812
826
  npm: '@ai-sdk/openai-compatible',
@@ -69,6 +69,7 @@ export const PROVIDER_AUTH_ENDPOINTS = {
69
69
  pollinations: null,
70
70
  requesty: null,
71
71
  orcarouter: { url: 'https://api.orcarouter.ai/v1/models', method: 'GET' },
72
+ 'vercel-gateway': { url: 'https://ai-gateway.vercel.sh/v1/models', method: 'GET' },
72
73
  together: { url: 'https://api.together.xyz/v1/models', method: 'GET' },
73
74
  perplexity: { url: 'https://api.perplexity.ai/v1/models', method: 'GET' },
74
75
  chutes: { url: 'https://chutes.ai/v1/models', method: 'GET' },
@@ -66,6 +66,7 @@ export const ENV_VAR_NAMES = {
66
66
  siliconflow: 'SILICONFLOW_API_KEY',
67
67
  requesty: 'REQUESTY_API_KEY',
68
68
  orcarouter: 'ORCAROUTER_API_KEY',
69
+ 'vercel-gateway': 'VERCEL_AI_GATEWAY_API_KEY',
69
70
  }
70
71
 
71
72
  // 📖 OPENCODE_MODEL_MAP: sparse table of model IDs that differ between sources.js and OpenCode's
@@ -339,6 +340,14 @@ export const PROVIDER_METADATA = {
339
340
  rateLimits: 'Free Hacker tier · zero token markup · 3 API keys',
340
341
  detailedLimits: 'Zero-markup AI gateway: token prices are passed through at provider rates.\nFree Hacker plan: 3 API keys, adaptive routing + automatic failover + guardrails included.\nOnly the explicit $-0 models are listed in this catalog; the orcarouter/fusion family is pay-as-you-go.',
341
342
  },
343
+ 'vercel-gateway': {
344
+ label: 'Vercel AI Gateway',
345
+ color: chalk.rgb(140, 170, 255),
346
+ signupUrl: 'https://vercel.com/ai-gateway',
347
+ signupHint: 'AI Gateway → API Keys ($5 credits/30 days, no card)',
348
+ rateLimits: 'Free tier · $5 credits/30 days + $0 models',
349
+ detailedLimits: 'Official Vercel gateway at list prices, zero markup.\nEvery account gets $5 of credits every 30 days, no card required.\nThe monthly credit covers a subset of the catalog; the explicit $0 models stay free.\nCaution: purchasing credits once permanently moves the account to the paid tier and the monthly free credit stops.',
350
+ },
342
351
  'ollama-cloud': {
343
352
  label: 'Ollama Cloud',
344
353
  color: chalk.rgb(230, 230, 230),
@@ -65,6 +65,8 @@ export const PROVIDER_CAPABILITIES = {
65
65
  siliconflow: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'daily' },
66
66
  requesty: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'daily' },
67
67
  orcarouter: { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'unknown' },
68
+ // 📖 Vercel AI Gateway exposes GET /v1/credits but no fetcher is wired yet; treat as monthly reset.
69
+ 'vercel-gateway': { telemetryType: 'unknown', supportsEndpoint: false, usageDisplay: 'ok', resetCadence: 'monthly' },
68
70
  }
69
71
 
70
72
  /** Fallback for unrecognized providers */
package/src/tui/app.js CHANGED
@@ -1075,8 +1075,15 @@ export async function runApp(cliArgs, config, startupOptions = {}) {
1075
1075
  // 📖 Freeze the full table (including countdown and spinner glyphs) while
1076
1076
  // 📖 the command palette is open so the background remains perfectly static.
1077
1077
  state.commandPaletteFrozenTable = renderTable(tableOpts)
1078
+ tableContent = state.commandPaletteFrozenTable
1079
+ } else {
1080
+ // 📖 The frozen table is already on screen and cannot change while the
1081
+ // 📖 palette is open, so repaint the palette alone. Repainting the full
1082
+ // table every frame made large terminals flicker: the write gets split
1083
+ // into chunks, so the terminal showed the bare table for a moment
1084
+ // before the palette overlay painted over it, 30 times per second.
1085
+ tableContent = null
1078
1086
  }
1079
- tableContent = state.commandPaletteFrozenTable
1080
1087
  } else {
1081
1088
  state.commandPaletteFrozenTable = null
1082
1089
  tableContent = renderTable(tableOpts)
@@ -1101,7 +1108,7 @@ export async function runApp(cliArgs, config, startupOptions = {}) {
1101
1108
  : state.incompatibleFallbackOpen
1102
1109
  ? overlays.renderIncompatibleFallback()
1103
1110
  : state.commandPaletteOpen
1104
- ? tableContent + overlays.renderCommandPalette()
1111
+ ? (tableContent || '') + overlays.renderCommandPalette()
1105
1112
  : state.recommendOpen
1106
1113
  ? overlays.renderRecommend()
1107
1114
  : state.helpVisible
@@ -856,6 +856,11 @@ export function createOverlayRenderers(state, deps) {
856
856
  }
857
857
 
858
858
  const targetLine = cursorLineByRow[state.commandPaletteCursor] ?? 0
859
+ // 📖 Pad short result lists up to bodyRows so the panel height stays constant
860
+ // 📖 while typing: nothing repaints the cells below a shrunken panel (the
861
+ // 📖 table behind is frozen while the palette is open), so a shrinking panel
862
+ // 📖 would leave stale painted rows hanging under its bottom edge.
863
+ while (panelLines.length < bodyRows) panelLines.push('')
859
864
  state.commandPaletteScrollOffset = keepOverlayTargetVisible(
860
865
  state.commandPaletteScrollOffset,
861
866
  targetLine,
@@ -922,11 +927,16 @@ export function createOverlayRenderers(state, deps) {
922
927
  return sty.overlayBgCommandPalette(padded)
923
928
  })
924
929
 
925
- // 📖 Emit each row from column 1 and clear to end of line so stale table cells
926
- // 📖 in the margins beside the panel can never bleed through (the artifacts
927
- // 📖 reported in issue #169). \x1b[K never wraps: panel right edge <= cols.
930
+ // 📖 Emit each row directly at the panel's left column: no margin filler and
931
+ // 📖 no \x1b[K. The old form (col 1 + margin spaces + \x1b[K) painted the
932
+ // 📖 panel tint across the full screen width because the margin spaces and
933
+ // 📖 the erase-to-EOL both inherit the tint background still active from the
934
+ // 📖 previous row. On wide terminals that grew a giant dark rectangle over
935
+ // 📖 the frozen table on both sides of the panel, repainted every frame.
936
+ // 📖 Rows are width-budgeted and the panel is screen-clamped, so a row can
937
+ // 📖 never overflow past the terminal edge (the real issue #169 artifact).
928
938
  return tintedLines
929
- .map((line, idx) => `\x1b[${top + idx};1H${' '.repeat(left - 1)}${line}\x1b[K`)
939
+ .map((line, idx) => `\x1b[${top + idx};${left}H${line}`)
930
940
  .join('')
931
941
  }
932
942
 
@@ -314,7 +314,13 @@ export function renderTable({
314
314
  const W_RANK = 6
315
315
  const W_TIER = 5
316
316
  const W_CTX = 4
317
- const W_SOURCE = 11
317
+ const W_SOURCE = 15
318
+ // 📖 Provider names are display-capped at MAX_PROVIDER_NAME_LEN chars so an
319
+ // 📖 over-long label can never push the following cells and desalign the
320
+ // 📖 whole row (Cloudflare AI at 13 chars overflowed the old 11-wide column).
321
+ // 📖 Anything longer is cut to 13 chars + '…' = 14 visible chars. Keep new
322
+ // 📖 provider names in sources.js at MAX_PROVIDER_NAME_LEN chars or less.
323
+ const MAX_PROVIDER_NAME_LEN = 14
318
324
  const W_MODEL = 26
319
325
  const W_SWE = 5
320
326
  const W_STATUS = 17
@@ -719,11 +725,15 @@ export function renderTable({
719
725
  const tier = tierFn(r.tier.padEnd(W_TIER))
720
726
  // 📖 Keep terminal view provider-specific so each row is monitorable per provider
721
727
  // 📖 In compact mode, truncate provider name to 4 chars + '…'
728
+ // 📖 In normal mode, cap names at MAX_PROVIDER_NAME_LEN chars (13 + '…')
729
+ // 📖 so an over-long label never shifts every cell to its right.
722
730
  const providerNameRaw = sources[r.providerKey]?.name ?? r.providerKey ?? 'NIM'
723
731
  const providerName = normalizeOriginLabel(providerNameRaw, r.providerKey)
724
732
  const providerDisplay = isCompact && providerName.length > 5
725
733
  ? providerName.slice(0, 4) + '…'
726
- : providerName
734
+ : providerName.length > MAX_PROVIDER_NAME_LEN
735
+ ? providerName.slice(0, MAX_PROVIDER_NAME_LEN - 1).trimEnd() + '…'
736
+ : providerName
727
737
  const source = themeColors.provider(r.providerKey, providerDisplay.padEnd(wSource))
728
738
  // 📖 Prefix: ⭐ favorite > 🎯 recommended > 🆕 new — only one emoji, never shifts the line
729
739
  const modelIsNew = isNewModel(r.addedDate)
package/src/tui/theme.js CHANGED
@@ -195,6 +195,7 @@ const PROVIDER_PALETTES = {
195
195
  pollinations: [255, 105, 180],
196
196
  requesty: [100, 149, 255],
197
197
  orcarouter: [255, 138, 64],
198
+ 'vercel-gateway': [170, 190, 230],
198
199
  'ollama-cloud': [230, 230, 230],
199
200
  },
200
201
  light: {
@@ -228,6 +229,7 @@ const PROVIDER_PALETTES = {
228
229
  pollinations: [170, 45, 110],
229
230
  requesty: [0, 72, 170],
230
231
  orcarouter: [170, 74, 0],
232
+ 'vercel-gateway': [60, 80, 130],
231
233
  'ollama-cloud': [88, 88, 88],
232
234
  },
233
235
  }