free-coding-models 0.3.6 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  ---
4
4
 
5
+ ## 0.3.11
6
+
7
+ ### Fixed
8
+ - Added early 404 response when a requested model has no registered accounts, ensuring clear error handling.
9
+
10
+ ### Removed
11
+ - **Profile system**: Entire profile system removed to ensure API keys persist permanently across all sessions. No more profile switching causing API key loss.
12
+
13
+ ### Added
14
+ - **`--proxy` foreground mode**: New `--proxy` flag starts FCM Proxy V2 in the current terminal with a live dashboard showing status, accounts, provider breakdown, and real-time request log. No daemon install needed — works from dev checkout too.
15
+
16
+ ### Fixed
17
+ - **Claude Code proxy auth**: Proxy now accepts `x-api-key` header (used by Anthropic SDK / Claude Code) in addition to `Authorization: Bearer`
18
+ - **Claude model fallback**: When `anthropicRouting` is all null, Claude model names now fall back to the first available account instead of returning "Model not found"
19
+ - **Proxy sync for Claude Code**: Added `claude-code` to `PROXY_SYNCABLE_TOOLS` so the env file is properly written/updated by proxy sync
20
+ - **Correct env var name**: Claude Code env file now exports `ANTHROPIC_API_KEY` (SDK standard) instead of `ANTHROPIC_AUTH_TOKEN`
21
+ - **Auto-source shell profile**: Claude Code env file is now automatically sourced in `.zshrc` / `.bashrc` / `.bash_profile`
22
+ - **Removed deleted profile functions from tests**: Cleaned up test imports after profile system removal from config.js
23
+
24
+ ---
25
+
26
+ ## 0.3.9
27
+
28
+ ### Improved
29
+ - **Enhanced `--premium` flag**: Now applies strict elite-only constraints. Shows only **S/S+** tier models with perfect health (**UP**) and a good verdict (**Perfect**, **Normal**, or **Slow**). Models with 429 errors, auth failures, or poor performance are automatically hidden.
30
+ - **Accurate Token Usage Tracking**: The "Used" column now uses the persistent `token-stats.json` file as the source of truth, providing accurate historical totals instead of only the most recent logs.
31
+ - **Enhanced Log Transparency**: The request log page now always shows the requested model and the actual upstream model (e.g., `llama-3.1-405b → meta/llama-3.1-405b-instruct`) whenever they differ.
32
+ - **Pretty Provider Labels**: The request log page now uses human-readable provider labels (e.g., "NVIDIA NIM", "SambaNova") instead of raw internal keys.
33
+ - **Fixed Tier Filtering Family Logic**: Updated `--tier S` behavior to correctly include both **S** and **S+** models (matching documentation).
34
+
35
+ ---
36
+
5
37
  ## 0.3.6
6
38
 
7
39
  ### Added
package/README.md CHANGED
@@ -200,6 +200,30 @@ free-coding-models
200
200
  # Explicitly target OpenCode CLI (TUI + Enter launches OpenCode CLI)
201
201
  free-coding-models --opencode
202
202
 
203
+ ## 📋 CLI Flags (expanded)
204
+
205
+ The tool now supports a comprehensive set of flags to fine‑tune its behavior. All flags can be combined in any order.
206
+
207
+ | Flag | Type | Description |
208
+ |------|------|-------------|
209
+ | `--best` | boolean | Show only top‑tier models (A+, S, S+). |
210
+ | `--fiable` | boolean | Run a 10 s reliability analysis and output the most reliable model. |
211
+ | `--json` | boolean | Output results as JSON for scripting/automation. |
212
+ | `--tier <S|A|B|C>` | value | Filter models by tier family (e.g. `S` shows S+ and S). |
213
+ | `--recommend` | boolean | Open Smart Recommend mode immediately on startup. |
214
+ | `--sort <column>` | value | Sort by a specific column (`rank`, `tier`, `origin`, `model`, `ping`, `avg`, `swe`, `ctx`, `condition`, `verdict`, `uptime`, `stability`, `usage`). |
215
+ | `--desc` / `--asc` | boolean | Set sort direction explicitly (descending or ascending). |
216
+ | `--origin <provider>` | value | Filter models by provider origin (e.g. `nvidia`, `groq`). |
217
+ | `--ping-interval <ms>` | value | Override the ping interval in milliseconds (affects live monitoring speed). |
218
+ | `--hide-unconfigured` | boolean | Hide models whose providers have no configured API key. |
219
+ | `--show-unconfigured` | boolean | Show all models regardless of API key configuration. |
220
+ | `--disable-widths-warning` | boolean | Disable the terminal width warning banner. |
221
+ | `--profile <name>` | value | Load a saved configuration profile before startup. |
222
+ | `--no-telemetry` | boolean | Disable anonymous telemetry for this run. |
223
+ | `--clean-proxy`, `--proxy-clean` | boolean | Remove persisted FCM proxy configuration from OpenCode. |
224
+ | `--help`, `-h` | boolean | Print the complete help text and exit. |
225
+
226
+ These flags are also reflected in the built‑in help (`free-coding-models --help`).
203
227
  # Explicitly target OpenCode Desktop (TUI + Enter sets model & opens Desktop app)
204
228
  free-coding-models --opencode-desktop
205
229
 
@@ -920,6 +944,25 @@ This script:
920
944
 
921
945
  ## 📋 API Reference
922
946
 
947
+ ### 🎁 Premium Flag
948
+
949
+ The `--premium` flag provides a quick view of only the elite **S/S+ tier** models with perfect health (**UP**) and a good verdict (**Perfect**, **Normal**, or **Slow**). This is useful when you want to focus exclusively on the highest‑quality, most reliable models that are currently available.
950
+
951
+ ```bash
952
+ free-coding-models --premium
953
+ ```
954
+
955
+ What it does under the hood:
956
+ - Sets `tierFilter` to `S` (showing only S+ and S tier models).
957
+ - Filters out any model that is not currently **UP** (hides 429, 410, auth fail, timeouts, etc.).
958
+ - Filters out models with poor verdicts (hides **Spiky**, **Very Slow**, **Overloaded**, **Unstable**, etc.).
959
+ - Forces the sort column to `verdict` with ascending order, so the best‑rated models appear at the top.
960
+ - Leaves other settings untouched, so you can still combine it with flags like `--json` for scripting.
961
+
962
+ You can combine `--premium` with other flags (e.g., `--json --hide-unconfigured`) to further tailor the output.
963
+
964
+ ---
965
+
923
966
  **Environment variables (override config file):**
924
967
 
925
968
  | Variable | Description |
@@ -99,7 +99,7 @@ import { homedir } from 'os'
99
99
  import { join, dirname } from 'path'
100
100
  import { MODELS, sources } from '../sources.js'
101
101
  import { getAvg, getVerdict, getUptime, getP95, getJitter, getStabilityScore, sortResults, filterByTier, findBestModel, parseArgs, TIER_ORDER, VERDICT_ORDER, TIER_LETTER_MAP, scoreModelForTask, getTopRecommendations, TASK_TYPES, PRIORITY_TYPES, CONTEXT_BUDGETS, formatCtxWindow, labelFromId, getProxyStatusInfo, formatResultsAsJSON } from '../src/utils.js'
102
- import { loadConfig, saveConfig, getApiKey, getProxySettings, resolveApiKeys, addApiKey, removeApiKey, isProviderEnabled, saveAsProfile, loadProfile, listProfiles, deleteProfile, getActiveProfileName, setActiveProfile, _emptyProfileSettings, persistApiKeysForProvider } from '../src/config.js'
102
+ import { loadConfig, saveConfig, getApiKey, getProxySettings, resolveApiKeys, addApiKey, removeApiKey, isProviderEnabled, persistApiKeysForProvider } from '../src/config.js'
103
103
  import { buildMergedModels } from '../src/model-merger.js'
104
104
  import { ProxyServer } from '../src/proxy-server.js'
105
105
  import { loadOpenCodeConfig, saveOpenCodeConfig, syncToOpenCode, restoreOpenCodeBackup, cleanupOpenCodeProxyConfig } from '../src/opencode-sync.js'
@@ -126,6 +126,7 @@ import { createOverlayRenderers } from '../src/overlays.js'
126
126
  import { createKeyHandler } from '../src/key-handler.js'
127
127
  import { getToolModeOrder, getToolMeta } from '../src/tool-metadata.js'
128
128
  import { startExternalTool } from '../src/tool-launchers.js'
129
+ import { startForegroundProxy } from '../src/proxy-foreground.js'
129
130
  import { getConfiguredInstallableProviders, installProviderEndpoints, refreshInstalledEndpoints, getInstallTargetModes, getProviderCatalogModels, CONNECTION_MODES } from '../src/endpoint-installer.js'
130
131
  import { loadCache, saveCache, clearCache, getCacheAge } from '../src/cache.js'
131
132
  import { checkConfigSecurity } from '../src/security.js'
@@ -203,6 +204,22 @@ async function main() {
203
204
  // 📖 User declined auto-fix or it failed — continue anyway, just warned
204
205
  }
205
206
 
207
+ // 📖 Apply CLI overrides for settings
208
+ if (cliArgs.sortColumn) config.settings.sortColumn = cliArgs.sortColumn
209
+ if (cliArgs.sortDirection) config.settings.sortAsc = cliArgs.sortDirection === 'asc'
210
+ if (cliArgs.originFilter) config.settings.originFilter = cliArgs.originFilter
211
+ if (cliArgs.pingInterval) config.settings.pingInterval = cliArgs.pingInterval
212
+ if (cliArgs.hideUnconfigured) config.settings.hideUnconfiguredModels = true
213
+ if (cliArgs.showUnconfigured) config.settings.hideUnconfiguredModels = false
214
+ if (cliArgs.disableWidthsWarning) config.settings.disableWidthsWarning = true
215
+
216
+ // 📖 Apply premium mode: show only S‑tier models sorted by verdict
217
+ if (cliArgs.premiumMode) {
218
+ config.settings.tierFilter = 'S'
219
+ config.settings.sortColumn = 'verdict'
220
+ config.settings.sortAsc = true
221
+ }
222
+
206
223
  if (cliArgs.cleanProxyMode) {
207
224
  const cleaned = cleanupOpenCodeProxyConfig()
208
225
  console.log()
@@ -213,6 +230,12 @@ async function main() {
213
230
  process.exit(0)
214
231
  }
215
232
 
233
+ // 📖 Foreground proxy mode — starts the proxy in the current terminal with live dashboard
234
+ if (cliArgs.proxyForegroundMode) {
235
+ await startForegroundProxy(config, chalk)
236
+ return // 📖 startForegroundProxy keeps the process alive via signal handlers
237
+ }
238
+
216
239
  // 📖 CLI subcommand: free-coding-models daemon <action>
217
240
  const daemonSubcmd = process.argv[2] === 'daemon' ? (process.argv[3] || 'status') : null
218
241
  if (daemonSubcmd) {
@@ -299,19 +322,7 @@ async function main() {
299
322
  process.exit(1)
300
323
  }
301
324
 
302
- // 📖 If --profile <name> was passed, load that profile into the live config
303
- let startupProfileSettings = null
304
- if (cliArgs.profileName) {
305
- startupProfileSettings = loadProfile(config, cliArgs.profileName)
306
- if (!startupProfileSettings) {
307
- console.error(chalk.red(` Unknown profile "${cliArgs.profileName}". Available: ${listProfiles(config).join(', ') || '(none)'}`))
308
- process.exit(1)
309
- }
310
- saveConfig(config, {
311
- replaceApiKeys: true,
312
- replaceFavorites: true,
313
- })
314
- }
325
+ // 📖 Profile system removed - API keys now persist permanently across all sessions
315
326
 
316
327
  // 📖 Check if any provider has a key — if not, run the first-time setup wizard
317
328
  const hasAnyKey = Object.keys(sources).some(pk => !!getApiKey(config, pk))
@@ -478,15 +489,15 @@ async function main() {
478
489
  return 'normal'
479
490
  }
480
491
 
481
- // 📖 tierFilter: current tier filter letter (null = all, 'S' = S+/S, 'A' = A+/A/A-, etc.)
492
+ // 📖 tierFilter: current tier filter letter (null = all, 'S' = S+/S, 'A' = A+/A/A-, etc.)
482
493
  const state = {
483
494
  results,
484
495
  pendingPings: 0,
485
496
  frame: 0,
486
497
  cursor: 0,
487
498
  selectedModel: null,
488
- sortColumn: startupProfileSettings?.sortColumn ?? config.settings?.sortColumn ?? 'avg',
489
- sortDirection: (startupProfileSettings?.sortAsc ?? config.settings?.sortAsc ?? true) ? 'asc' : 'desc',
499
+ sortColumn: config.settings?.sortColumn ?? 'avg',
500
+ sortDirection: (config.settings?.sortAsc ?? true) ? 'asc' : 'desc',
490
501
  pingInterval: PING_MODE_INTERVALS.speed, // 📖 Effective live interval derived from the active ping mode.
491
502
  pingMode: 'speed', // 📖 Current ping mode: speed | normal | slow | forced.
492
503
  pingModeSource: 'startup', // 📖 Why this mode is active: startup | manual | auto | idle | activity.
@@ -499,8 +510,9 @@ async function main() {
499
510
  mode, // 📖 'opencode' or 'openclaw' — controls Enter action
500
511
  tierFilterMode: 0, // 📖 Index into TIER_CYCLE (0=All, 1=S+, 2=S, ...)
501
512
  originFilterMode: 0, // 📖 Index into ORIGIN_CYCLE (0=All, then providers)
502
- hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true || config.settings?.hideUnconfiguredModels === true, // 📖 Hide providers with no configured API key when true.
503
- disableWidthsWarning: config.settings?.disableWidthsWarning ?? false, // 📖 Disable widths warning toggle (default off)
513
+ premiumMode: cliArgs.premiumMode, // 📖 Special elite-only mode: S/S+ only, Health UP only, Perfect/Normal/Slow verdict only.
514
+ hideUnconfiguredModels: config.settings?.hideUnconfiguredModels === true, // 📖 Hide providers with no configured API key when true.
515
+ disableWidthsWarning: config.settings?.disableWidthsWarning ?? false, // 📖 Disable widths warning toggle (default off)
504
516
  scrollOffset: 0, // 📖 First visible model index in viewport
505
517
  terminalRows: process.stdout.rows || 24, // 📖 Current terminal height
506
518
  terminalCols: process.stdout.columns || 80, // 📖 Current terminal width
@@ -557,10 +569,6 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
557
569
  recommendAnalysisTimer: null, // 📖 setInterval handle for the 10s analysis phase
558
570
  recommendPingTimer: null, // 📖 setInterval handle for 2 pings/sec during analysis
559
571
  recommendedKeys: new Set(), // 📖 Set of "providerKey/modelId" for recommended models (shown in main table)
560
- // 📖 Config Profiles state
561
- activeProfile: getActiveProfileName(config), // 📖 Currently loaded profile name (or null)
562
- profileSaveMode: false, // 📖 Whether the inline "Save profile" name input is active
563
- profileSaveBuffer: '', // 📖 Typed characters for the profile name being saved
564
572
  // 📖 Feedback state (J/I keys open it)
565
573
  feedbackOpen: false, // 📖 Whether the feedback overlay is active
566
574
  bugReportBuffer: '', // 📖 Typed characters for the feedback message
@@ -756,6 +764,17 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
756
764
  outputResults = outputResults.filter(r => ['S+', 'S', 'A+'].includes(r.tier))
757
765
  }
758
766
 
767
+ // 📖 Apply premium mode filter if specified: elite-only (S/S+, UP, Good Verdict)
768
+ if (cliArgs.premiumMode) {
769
+ outputResults = outputResults.filter(r => {
770
+ const isEliteTier = r.tier === 'S' || r.tier === 'S+'
771
+ const isHealthUp = r.status === 'up'
772
+ const verdict = getVerdict(r)
773
+ const isGoodVerdict = ['Perfect', 'Normal', 'Slow'].includes(verdict)
774
+ return isEliteTier && isHealthUp && isGoodVerdict
775
+ })
776
+ }
777
+
759
778
  // 📖 Sort by avg ping (ascending)
760
779
  outputResults = sortResults(outputResults, 'avg', 'asc')
761
780
 
@@ -770,6 +789,9 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
770
789
 
771
790
  // 📖 Enter alternate screen — animation runs here, zero scrollback pollution
772
791
  process.stdout.write(ALT_ENTER)
792
+ if (process.stdout.isTTY) {
793
+ process.stdout.flush && process.stdout.flush()
794
+ }
773
795
 
774
796
  // 📖 Ensure we always leave alt screen cleanly (Ctrl+C, crash, normal exit)
775
797
  const exit = (code = 0) => {
@@ -778,6 +800,9 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
778
800
  clearInterval(ticker)
779
801
  clearTimeout(state.pingIntervalObj)
780
802
  process.stdout.write(ALT_LEAVE)
803
+ if (process.stdout.isTTY) {
804
+ process.stdout.flush && process.stdout.flush()
805
+ }
781
806
  process.exit(code)
782
807
  }
783
808
  process.on('SIGINT', () => exit(0))
@@ -785,7 +810,7 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
785
810
 
786
811
  // 📖 originFilterMode: index into ORIGIN_CYCLE, 0=All, then each provider key in order
787
812
  const ORIGIN_CYCLE = [null, ...Object.keys(sources)]
788
- const resolvedTierFilter = startupProfileSettings?.tierFilter ?? config.settings?.tierFilter
813
+ const resolvedTierFilter = config.settings?.tierFilter
789
814
  state.tierFilterMode = resolvedTierFilter ? Math.max(0, TIER_CYCLE.indexOf(resolvedTierFilter)) : 0
790
815
  const resolvedOriginFilter = config.settings?.originFilter
791
816
  state.originFilterMode = resolvedOriginFilter ? Math.max(0, ORIGIN_CYCLE.indexOf(resolvedOriginFilter)) : 0
@@ -805,9 +830,23 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
805
830
  return
806
831
  }
807
832
  // 📖 Apply both tier and origin filters — model is hidden if it fails either
808
- const tierHide = activeTier !== null && r.tier !== activeTier
833
+ // 📖 TIER_LETTER_MAP is used so --tier S also includes S+ models (tier family behavior).
834
+ const allowedTiers = (activeTier && TIER_LETTER_MAP[activeTier]) ? TIER_LETTER_MAP[activeTier] : [activeTier]
835
+ const tierHide = activeTier !== null && !allowedTiers.includes(r.tier)
809
836
  const originHide = activeOrigin !== null && r.providerKey !== activeOrigin
810
837
  r.hidden = tierHide || originHide
838
+
839
+ // 📖 Premium Mode: elite-only constraints (Health UP, Good Verdict, S/S+ only)
840
+ if (state.premiumMode && !r.hidden) {
841
+ const isEliteTier = r.tier === 'S' || r.tier === 'S+'
842
+ const isHealthUp = r.status === 'up'
843
+ const verdict = getVerdict(r)
844
+ const isGoodVerdict = ['Perfect', 'Normal', 'Slow'].includes(verdict)
845
+
846
+ if (!isEliteTier || !isHealthUp || !isGoodVerdict) {
847
+ r.hidden = true
848
+ }
849
+ }
811
850
  })
812
851
  return state.results
813
852
  }
@@ -823,6 +862,9 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
823
862
  if (process.stdin.isTTY && resetRawMode) process.stdin.setRawMode(false)
824
863
  process.stdin.pause()
825
864
  process.stdout.write(ALT_LEAVE)
865
+ if (process.stdout.isTTY) {
866
+ process.stdout.flush && process.stdout.flush()
867
+ }
826
868
  }
827
869
 
828
870
  const overlays = createOverlayRenderers(state, {
@@ -835,7 +877,6 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
835
877
  getProxySettings,
836
878
  resolveApiKeys,
837
879
  isProviderEnabled,
838
- listProfiles,
839
880
  TIER_CYCLE,
840
881
  SETTINGS_OVERLAY_BG,
841
882
  HELP_OVERLAY_BG,
@@ -877,11 +918,6 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
877
918
  removeApiKey,
878
919
  persistApiKeysForProvider,
879
920
  isProviderEnabled,
880
- listProfiles,
881
- loadProfile,
882
- deleteProfile,
883
- saveAsProfile,
884
- setActiveProfile,
885
921
  saveConfig,
886
922
  getConfiguredInstallableProviders,
887
923
  getInstallTargetModes,
@@ -980,15 +1016,21 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
980
1016
  ? overlays.renderLog()
981
1017
  : state.changelogOpen
982
1018
  ? overlays.renderChangelog()
983
- : 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, state.activeProfile, state.profileSaveMode, state.profileSaveBuffer, state.proxyStartupStatus, state.pingMode, state.pingModeSource, state.hideUnconfiguredModels, state.widthWarningStartedAt, state.widthWarningDismissed, state.widthWarningShowCount, state.settingsUpdateState, state.settingsUpdateLatestVersion, getProxySettings(state.config).enabled === true, state.startupLatestVersion, state.versionAlertsEnabled)
1019
+ : 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, state.proxyStartupStatus, state.pingMode, state.pingModeSource, state.hideUnconfiguredModels, state.widthWarningStartedAt, state.widthWarningDismissed, state.widthWarningShowCount, state.settingsUpdateState, state.settingsUpdateLatestVersion, getProxySettings(state.config).enabled === true, state.startupLatestVersion, state.versionAlertsEnabled)
984
1020
  process.stdout.write(ALT_HOME + content)
1021
+ if (process.stdout.isTTY) {
1022
+ process.stdout.flush && process.stdout.flush()
1023
+ }
985
1024
  }, Math.round(1000 / FPS))
986
1025
 
987
1026
  // 📖 Populate visibleSorted before the first frame so Enter works immediately
988
1027
  const initialVisible = state.results.filter(r => !r.hidden)
989
1028
  state.visibleSorted = sortResultsWithPinnedFavorites(initialVisible, state.sortColumn, state.sortDirection)
990
1029
 
991
- 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, state.activeProfile, state.profileSaveMode, state.profileSaveBuffer, state.proxyStartupStatus, state.pingMode, state.pingModeSource, state.hideUnconfiguredModels, state.widthWarningStartedAt, state.widthWarningDismissed, state.widthWarningShowCount, state.settingsUpdateState, state.settingsUpdateLatestVersion, getProxySettings(state.config).enabled === true, state.startupLatestVersion, state.versionAlertsEnabled))
1030
+ 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, state.proxyStartupStatus, state.pingMode, state.pingModeSource, state.hideUnconfiguredModels, state.widthWarningStartedAt, state.widthWarningDismissed, state.widthWarningShowCount, state.settingsUpdateState, state.settingsUpdateLatestVersion, getProxySettings(state.config).enabled === true, state.startupLatestVersion, state.versionAlertsEnabled))
1031
+ if (process.stdout.isTTY) {
1032
+ process.stdout.flush && process.stdout.flush()
1033
+ }
992
1034
 
993
1035
  // 📖 If --recommend was passed, auto-open the Smart Recommend overlay on start
994
1036
  if (cliArgs.recommendMode) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-coding-models",
3
- "version": "0.3.6",
3
+ "version": "0.3.11",
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/cli-help.js CHANGED
@@ -26,10 +26,18 @@ const ANALYSIS_FLAGS = [
26
26
  { flag: '--json', description: 'Output results as JSON for scripts/automation' },
27
27
  { flag: '--tier <S|A|B|C>', description: 'Filter models by tier family' },
28
28
  { flag: '--recommend', description: 'Open Smart Recommend immediately on startup' },
29
+ { flag: '--premium', description: 'Show only S/S+ models with perfect health and good verdict' },
30
+ { flag: '--sort <column>', description: 'Sort by column (rank, tier, origin, model, ping, avg, swe, ctx, condition, verdict, uptime, stability, usage)' },
31
+ { flag: '--desc | --asc', description: 'Set sort direction (descending or ascending)' },
32
+ { flag: '--origin <provider>', description: 'Filter models by provider origin' },
33
+ { flag: '--ping-interval <ms>', description: 'Override ping interval in milliseconds' },
34
+ { flag: '--hide-unconfigured', description: 'Hide models without configured API keys' },
35
+ { flag: '--show-unconfigured', description: 'Show all models regardless of API key config' },
36
+ { flag: '--disable-widths-warning', description: 'Disable terminal width warning' },
29
37
  ]
30
38
 
31
39
  const CONFIG_FLAGS = [
32
- { flag: '--profile <name>', description: 'Load a saved config profile before startup' },
40
+ { flag: '--proxy', description: 'Start FCM Proxy V2 in foreground with live dashboard (no daemon)' },
33
41
  { flag: '--no-telemetry', description: 'Disable anonymous telemetry for this run' },
34
42
  { flag: '--clean-proxy, --proxy-clean', description: 'Remove persisted fcm-proxy config from OpenCode' },
35
43
  { flag: '--help, -h', description: 'Print this help and exit' },