free-coding-models 0.3.21 → 0.3.23

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/CHANGELOG.md CHANGED
@@ -1,7 +1,49 @@
1
1
  # Changelog
2
-
3
2
  ---
4
3
 
4
+ ## 0.3.23
5
+
6
+ ### Added
7
+ - **Favorites display mode (`Y`)**: Added a global toggle to switch favorites between `pinned + always visible` and `normal rows` (starred only, fully obeying active filters/sort).
8
+ - **Favorites mode row in Settings**: Added a dedicated Settings row to inspect/toggle favorites display behavior without leaving the maintenance screen.
9
+ - **Expanded command palette action menus**: Added nested menus for Ping Mode (speed/normal/slow/forced with explanations), Target Tool (all supported tools with explanations), and Favorites Mode (including the new `Y` flow).
10
+ - **Active text-filter footer alert**: When a custom search filter is active (for example `deep`), the last TUI footer line now shows a high-visibility inline badge (between `N Changelog` and `Ctrl+C Exit`) with the exact query and an `X` shortcut to clear it instantly.
11
+
12
+ ### Changed
13
+ - **Favorites sorting/filtering behavior**: Sort/filter logic now respects the selected favorites mode across the table refresh loop, hotkeys, and renderer so non-pinned mode behaves consistently everywhere.
14
+ - **Favorites default mode**: New/legacy configs now default to `Normal filter/sort` favorites mode (not pinned) until users press `Y` to opt into pinned+sticky behavior.
15
+ - **Footer/help/docs shortcut hints**: Surfaced `Y` in the TUI footer, Help overlay, and README so the new favorites mode is discoverable.
16
+
17
+ ## 0.3.22
18
+
19
+ ### Added
20
+ - **Hierarchical command palette navigation**: Ctrl+P now opens an improved command palette with expandable/collapsible categories and subcategories for better organization.
21
+ - **Arrow key navigation in command palette**: Use left/right arrows to expand and collapse categories, up/down to navigate, Enter to execute or toggle.
22
+ - **Rich color scheme for command palette**: Categories use bold blue headers, subcategories use bold text, commands show keyboard shortcuts.
23
+ - **Visual expand/collapse indicators**: ▼ shows expanded categories, ▶ shows collapsed, • marks individual commands.
24
+ - **Concise default view**: Categories are collapsed by default (except Filters) showing less detail on first open.
25
+ - **Colored tier filters**: Tier filters (S+, S, A+, A, A-, B+, B, C) now display with their corresponding TUI colors for quick identification.
26
+ - **Specific provider filters**: Added 13 individual provider filters (NVIDIA NIM, Groq, Cerebras, SambaNova, OpenRouter, Together AI, DeepInfra, Fireworks, Hyperbolic, Google AI, Hugging Face) with their signature provider colors.
27
+ - **Filter by model category**: New "Filter by model" category with autocomplete that dynamically shows top 20 visible models, complete with provider icons and colored model names.
28
+ - **Improved search cursor**: Cursor placement fixed to appear right after the `>` prompt instead of after placeholder text for natural typing flow.
29
+ - **Lightning bolt in title**: Command Palette title now shows ⚡ emoji for better visibility and visual appeal.
30
+
31
+ ### Changed
32
+ - **Footer layout cleanup**: Added consistent spacing before `F Toggle Favorite`, moved `N Changelog • Ctrl+C Exit` to a dedicated final footer line for better readability.
33
+ - **Removed Y key binding**: Install Endpoints is no longer a direct hotkey — accessible only via Settings (`P`) or Command Palette (`Ctrl+P`). The `Y` key is now free/unbound.
34
+ - **Removed proxy notice from footer**: The "Proxy is temporarily disabled" banner has been fully retired from the TUI footer and its backing constant removed.
35
+ - **Command palette fuzzy search fix**: `buildCommandPaletteEntries()` now expands all categories so child commands are visible to fuzzy search.
36
+ - **Flat Pages + Actions in ⚡️ Command Palette**: page entries and action entries are now listed directly at root level (no extra submenu depth) for faster access.
37
+ - **Command explanations after shortcuts**: command palette rows now show concise English hints after hotkeys (example: `(Z) — Change target AI Coding CLI Tool.`).
38
+ - **⚡️ emoji consistency**: user-facing Command Palette mentions now consistently render as `⚡️ Command Palette` in TUI and docs.
39
+ - **README Quick Start flow**: install section now explicitly adds “create a free account on one of the providers” with a direct anchor link.
40
+ - **Provider section renamed for clarity**: Quick Start provider table now lives under `List of Free AI Providers`.
41
+ - **Quick Start CTA highlight**: added a large green `USE ⚡️ COMMAND PALETTE / CTRL+P` badge right after the command palette instruction.
42
+
43
+ ### Fixed
44
+ - **Double emoji display bug**: Fixed duplicate emoji icons in command palette entries (was showing `▶ 🔍 🔍 Filters` instead of `▶ 🔍 Filters`).
45
+ - **Provider cycle command behavior**: `Cycle provider` in ⚡️ Command Palette now correctly cycles providers again instead of resetting to `All`.
46
+
5
47
  ## 0.3.21
6
48
 
7
49
  ### Changed
package/README.md CHANGED
@@ -22,12 +22,14 @@ npm install -g free-coding-models
22
22
  free-coding-models
23
23
  ```
24
24
 
25
+ create a free account on one of the [providers](#-list-of-free-ai-providers)
26
+
25
27
  </p>
26
28
 
27
29
  <p align="center">
28
30
  <a href="#-why-this-tool">Why</a> •
29
31
  <a href="#-quick-start">Quick Start</a> •
30
- <a href="#-providers">Providers</a> •
32
+ <a href="#-list-of-free-ai-providers">Providers</a> •
31
33
  <a href="#-usage">Usage</a> •
32
34
  <a href="#-tui-keys">TUI Keys</a> •
33
35
  <a href="#-contributing">Contributing</a>
@@ -55,7 +57,9 @@ It then writes the model you pick directly into your coding tool's config — so
55
57
 
56
58
  ## ⚡ Quick Start
57
59
 
58
- **① Get a free API key** — you only need one to get started:
60
+ ### 🟢 List of Free AI Providers
61
+
62
+ Create a free account on one provider below to get started:
59
63
 
60
64
  **160 coding models** across 20 providers, ranked by [SWE-bench Verified](https://www.swebench.com).
61
65
 
@@ -94,7 +98,7 @@ It then writes the model you pick directly into your coding tool's config — so
94
98
  | **A-/B+** | 30–40% | Smaller tasks, constrained infra |
95
99
  | **B/C** | < 30% | Code completion, edge/minimal setups |
96
100
 
97
- **② Install and run:**
101
+ **① Install and run:**
98
102
 
99
103
  ```bash
100
104
  npm install -g free-coding-models
@@ -103,9 +107,15 @@ free-coding-models
103
107
 
104
108
  On first run, you'll be prompted to enter your API key(s). You can skip providers and add more later with **`P`**.
105
109
 
110
+ Use ⚡️ Command Palette! with **Ctrl+P**.
111
+
112
+ <p align="center">
113
+ <img src="https://img.shields.io/badge/USE_%E2%9A%A1%EF%B8%8F%20COMMAND%20PALETTE-CTRL%2BP-22c55e?style=for-the-badge" alt="Use ⚡️ Command Palette with Ctrl+P">
114
+ </p>
115
+
106
116
  Need to fix contrast because your terminal theme is fighting the TUI? Press **`G`** at any time to cycle **Auto → Dark → Light**. The switch recolors the full interface live: table, Settings, Help, Smart Recommend, Feedback, and Changelog.
107
117
 
108
- **③ Pick a model and launch your tool:**
118
+ **② Pick a model and launch your tool:**
109
119
 
110
120
  ```
111
121
  ↑↓ navigate → Enter to launch
@@ -175,11 +185,12 @@ Press **`Z`** in the TUI to cycle between tools without restarting.
175
185
  | `D` | Cycle provider filter |
176
186
  | `E` | Toggle configured-only mode |
177
187
  | `F` | Favorite / unfavorite model |
188
+ | `Y` | Toggle favorites mode (`Normal filter/sort` default ↔ `Pinned + always visible`) |
189
+ | `X` | Clear active custom text filter |
178
190
  | `G` | Cycle global theme (`Auto → Dark → Light`) |
179
- | `Ctrl+P` | Open command palette (search + run actions) |
191
+ | `Ctrl+P` | Open ⚡️ command palette (search + run actions) |
180
192
  | `R/S/C/M/O/L/A/H/V/B/U` | Sort columns |
181
193
  | `P` | Settings (API keys, providers, updates, theme) |
182
- | `Y` | Install Endpoints (push provider into tool config) |
183
194
  | `Q` | Smart Recommend overlay |
184
195
  | `N` | Changelog |
185
196
  | `W` | Cycle ping cadence |
@@ -197,12 +208,12 @@ Press **`Z`** in the TUI to cycle between tools without restarting.
197
208
  - **Adaptive monitoring** — 2s burst for 60s → 10s normal → 30s idle
198
209
  - **Stability score** — composite 0–100 (p95 latency, jitter, spike rate, uptime)
199
210
  - **Smart ranking** — top 3 highlighted 🥇🥈🥉
200
- - **Favorites** — pin models with `F`, persisted across sessions
211
+ - **Favorites** — star models with `F`, persisted across sessions, default to normal rows, and switch display mode with `Y` (pinned+sticky vs normal rows)
201
212
  - **Configured-only default** — only shows providers you have keys for
202
213
  - **Keyless latency** — models ping even without an API key (show 🔑 NO KEY)
203
214
  - **Smart Recommend** — questionnaire picks the best model for your task type
204
- - **Command Palette** — `Ctrl+P` opens a searchable action launcher for filters, sorting, overlays, and quick toggles
205
- - **Install Endpoints** — push a full provider catalog into any tool's config (`Y`)
215
+ - **⚡️ Command Palette** — `Ctrl+P` opens a searchable action launcher for filters, sorting, overlays, and quick toggles
216
+ - **Install Endpoints** — push a full provider catalog into any tool's config (from Settings `P` or ⚡️ Command Palette)
206
217
  - **Missing tool bootstrap** — detect absent CLIs, offer one-click install, then continue the selected launch automatically
207
218
  - **Width guardrail** — shows a warning instead of a broken table in narrow terminals
208
219
  - **Readable everywhere** — semantic theme palette keeps table rows, overlays, badges, and help screens legible in dark and light terminals
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-coding-models",
3
- "version": "0.3.21",
3
+ "version": "0.3.23",
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/src/app.js CHANGED
@@ -21,8 +21,8 @@
21
21
  * - JSON config stored in ~/.free-coding-models.json (auto-migrates from old plain-text)
22
22
  * - Multi-provider support via sources.js (NIM/Groq/Cerebras/OpenRouter/Hugging Face/Replicate/DeepInfra/... — extensible)
23
23
  * - Settings screen (P key) to manage API keys, provider toggles, manual updates, and provider-key diagnostics
24
- * - Install Endpoints flow (Y key) to push provider catalogs into OpenCode, OpenClaw, Crush, and Goose
25
- * - Favorites system: toggle with F, pin rows to top, persist between sessions
24
+ * - Install Endpoints flow (Settings / Command Palette) to push provider catalogs into OpenCode, OpenClaw, Crush, and Goose
25
+ * - Favorites system: toggle with F, switch pinning mode with Y, persist between sessions
26
26
  * - Uptime percentage tracking (successful pings / total pings)
27
27
  * - Sortable columns (R/O/M/L/A/S/C/H/V/B/U/G keys)
28
28
  * - Tier filtering via T key (cycles S+→S→A+→A→A-→B+→B→C→All)
@@ -307,7 +307,7 @@ export async function runApp(cliArgs, config) {
307
307
  }
308
308
 
309
309
  // 📖 Re-sync tracked external-tool catalogs after the live provider catalog has settled.
310
- // 📖 This keeps prior `Y` installs aligned with the current FCM model list.
310
+ // 📖 This keeps prior endpoint installs aligned with the current FCM model list.
311
311
  refreshInstalledEndpoints(config)
312
312
 
313
313
  // 📖 Build results from MODELS — only include enabled providers
@@ -383,6 +383,7 @@ export async function runApp(cliArgs, config) {
383
383
  tierFilterMode: 0, // 📖 Index into TIER_CYCLE (0=All, 1=S+, 2=S, ...)
384
384
  originFilterMode: 0, // 📖 Index into ORIGIN_CYCLE (0=All, then providers)
385
385
  hideUnconfiguredModels: config.settings?.hideUnconfiguredModels === true, // 📖 Hide providers with no configured API key when true.
386
+ favoritesPinnedAndSticky: config.settings?.favoritesPinnedAndSticky === true, // 📖 false by default: favorites follow normal sort/filter rules until Y enables pinned+sticky mode.
386
387
  scrollOffset: 0, // 📖 First visible model index in viewport
387
388
  terminalRows: process.stdout.rows || 24, // 📖 Current terminal height
388
389
  terminalCols: process.stdout.columns || 80, // 📖 Current terminal width
@@ -409,10 +410,11 @@ export async function runApp(cliArgs, config) {
409
410
  commandPaletteScrollOffset: 0, // 📖 Vertical scroll offset for the command palette result viewport.
410
411
  commandPaletteResults: [], // 📖 Cached fuzzy-filtered command entries for the command palette.
411
412
  commandPaletteFrozenTable: null, // 📖 Frozen table snapshot rendered behind the command palette overlay.
413
+ commandPaletteExpandedIds: new Set(['filters', 'actions']), // 📖 Expanded category IDs (filters + actions open by default for quick access).
412
414
  helpVisible: false, // 📖 Whether the help overlay (K key) is active
413
415
  settingsScrollOffset: 0, // 📖 Vertical scroll offset for Settings overlay viewport
414
416
  helpScrollOffset: 0, // 📖 Vertical scroll offset for Help overlay viewport
415
- // 📖 Install Endpoints overlay state (Y key opens it)
417
+ // 📖 Install Endpoints overlay state (opened from Settings or Command Palette)
416
418
  installEndpointsOpen: false, // 📖 Whether the install-endpoints overlay is active
417
419
  installEndpointsPhase: 'providers', // 📖 providers | tools | scope | models | result
418
420
  installEndpointsCursor: 0, // 📖 Selected row within the current install phase
@@ -457,6 +459,8 @@ export async function runApp(cliArgs, config) {
457
459
  changelogPhase: 'index', // 📖 'index' (all versions) | 'details' (specific version)
458
460
  changelogCursor: 0, // 📖 Selected row in index phase
459
461
  changelogSelectedVersion: null, // 📖 Which version to show details for
462
+ // 📖 Custom text filter (Ctrl+P palette → type text → Enter). Ephemeral — not saved to config.
463
+ customTextFilter: null, // 📖 Active free-text filter string (null = off). Matches model name, ctx, provider key/name.
460
464
  }
461
465
 
462
466
  // 📖 Re-clamp viewport on terminal resize
@@ -675,8 +679,8 @@ export async function runApp(cliArgs, config) {
675
679
  const activeTier = TIER_CYCLE[state.tierFilterMode]
676
680
  const activeOrigin = ORIGIN_CYCLE[state.originFilterMode]
677
681
  state.results.forEach(r => {
678
- // 📖 Favorites stay visible and pinned regardless of configured-only, tier, or provider filters.
679
- if (r.isFavorite) {
682
+ // 📖 Sticky-favorites mode keeps favorites visible regardless of configured-only, tier, or provider filters.
683
+ if (state.favoritesPinnedAndSticky && r.isFavorite) {
680
684
  r.hidden = false
681
685
  return
682
686
  }
@@ -690,8 +694,22 @@ export async function runApp(cliArgs, config) {
690
694
  const allowedTiers = (activeTier && TIER_LETTER_MAP[activeTier]) ? TIER_LETTER_MAP[activeTier] : [activeTier]
691
695
  const tierHide = activeTier !== null && !allowedTiers.includes(r.tier)
692
696
  const originHide = activeOrigin !== null && r.providerKey !== activeOrigin
693
- r.hidden = tierHide || originHide
694
-
697
+ if (tierHide || originHide) {
698
+ r.hidden = true
699
+ return
700
+ }
701
+ // 📖 Custom text filter — case-insensitive includes match against model name, ctx, provider key, and provider display name.
702
+ if (state.customTextFilter) {
703
+ const q = state.customTextFilter.toLowerCase()
704
+ const providerName = (sources[r.providerKey]?.name || '').toLowerCase()
705
+ const match = (r.label || '').toLowerCase().includes(q)
706
+ || (r.ctx || '').toLowerCase().includes(q)
707
+ || (r.providerKey || '').toLowerCase().includes(q)
708
+ || providerName.includes(q)
709
+ r.hidden = !match
710
+ return
711
+ }
712
+ r.hidden = false
695
713
  })
696
714
  return state.results
697
715
  }
@@ -808,7 +826,7 @@ export async function runApp(cliArgs, config) {
808
826
  if (cliArgs.tierFilter) {
809
827
  const allowed = TIER_LETTER_MAP[cliArgs.tierFilter]
810
828
  state.results.forEach(r => {
811
- r.hidden = r.isFavorite ? false : !allowed.includes(r.tier)
829
+ r.hidden = (state.favoritesPinnedAndSticky && r.isFavorite) ? false : !allowed.includes(r.tier)
812
830
  })
813
831
  }
814
832
 
@@ -846,7 +864,9 @@ export async function runApp(cliArgs, config) {
846
864
  // 📖 Cache visible+sorted models each frame so Enter handler always matches the display
847
865
  if (!state.settingsOpen && !state.installEndpointsOpen && !state.toolInstallPromptOpen && !state.recommendOpen && !state.feedbackOpen && !state.changelogOpen && !state.commandPaletteOpen) {
848
866
  const visible = state.results.filter(r => !r.hidden)
849
- state.visibleSorted = sortResultsWithPinnedFavorites(visible, state.sortColumn, state.sortDirection)
867
+ state.visibleSorted = sortResultsWithPinnedFavorites(visible, state.sortColumn, state.sortDirection, {
868
+ pinFavorites: state.favoritesPinnedAndSticky,
869
+ })
850
870
  }
851
871
  let tableContent = null
852
872
  if (state.commandPaletteOpen) {
@@ -879,7 +899,9 @@ export async function runApp(cliArgs, config) {
879
899
  state.settingsUpdateLatestVersion,
880
900
  false,
881
901
  state.startupLatestVersion,
882
- state.versionAlertsEnabled
902
+ state.versionAlertsEnabled,
903
+ state.favoritesPinnedAndSticky,
904
+ state.customTextFilter
883
905
  )
884
906
  }
885
907
  tableContent = state.commandPaletteFrozenTable
@@ -911,7 +933,9 @@ export async function runApp(cliArgs, config) {
911
933
  state.settingsUpdateLatestVersion,
912
934
  false,
913
935
  state.startupLatestVersion,
914
- state.versionAlertsEnabled
936
+ state.versionAlertsEnabled,
937
+ state.favoritesPinnedAndSticky,
938
+ state.customTextFilter
915
939
  )
916
940
  }
917
941
 
@@ -947,9 +971,11 @@ export async function runApp(cliArgs, config) {
947
971
 
948
972
  // 📖 Populate visibleSorted before the first frame so Enter works immediately
949
973
  const initialVisible = state.results.filter(r => !r.hidden)
950
- state.visibleSorted = sortResultsWithPinnedFavorites(initialVisible, state.sortColumn, state.sortDirection)
974
+ state.visibleSorted = sortResultsWithPinnedFavorites(initialVisible, state.sortColumn, state.sortDirection, {
975
+ pinFavorites: state.favoritesPinnedAndSticky,
976
+ })
951
977
 
952
- process.stdout.write(ALT_HOME + renderTable(state.results, state.pendingPings, state.frame, state.cursor, state.sortColumn, state.sortDirection, state.pingInterval, state.lastPingTime, state.mode, state.tierFilterMode, state.scrollOffset, state.terminalRows, state.terminalCols, state.originFilterMode, null, state.pingMode, state.pingModeSource, state.hideUnconfiguredModels, state.widthWarningStartedAt, state.widthWarningDismissed, state.widthWarningShowCount, state.settingsUpdateState, state.settingsUpdateLatestVersion, false, state.startupLatestVersion, state.versionAlertsEnabled))
978
+ process.stdout.write(ALT_HOME + renderTable(state.results, state.pendingPings, state.frame, state.cursor, state.sortColumn, state.sortDirection, state.pingInterval, state.lastPingTime, state.mode, state.tierFilterMode, state.scrollOffset, state.terminalRows, state.terminalCols, state.originFilterMode, null, state.pingMode, state.pingModeSource, state.hideUnconfiguredModels, state.widthWarningStartedAt, state.widthWarningDismissed, state.widthWarningShowCount, state.settingsUpdateState, state.settingsUpdateLatestVersion, false, state.startupLatestVersion, state.versionAlertsEnabled, state.favoritesPinnedAndSticky, state.customTextFilter))
953
979
  if (process.stdout.isTTY) {
954
980
  process.stdout.flush && process.stdout.flush()
955
981
  }