free-coding-models 0.3.6 β 0.3.9
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 +11 -0
- package/README.md +43 -0
- package/bin/free-coding-models.js +45 -3
- package/package.json +1 -1
- package/src/cli-help.js +8 -0
- package/src/overlays.js +6 -3
- package/src/token-usage-reader.js +53 -11
- package/src/utils.js +39 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## 0.3.9
|
|
6
|
+
|
|
7
|
+
### Improved
|
|
8
|
+
- **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.
|
|
9
|
+
- **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.
|
|
10
|
+
- **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.
|
|
11
|
+
- **Pretty Provider Labels**: The request log page now uses human-readable provider labels (e.g., "NVIDIA NIM", "SambaNova") instead of raw internal keys.
|
|
12
|
+
- **Fixed Tier Filtering Family Logic**: Updated `--tier S` behavior to correctly include both **S** and **S+** models (matching documentation).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
5
16
|
## 0.3.6
|
|
6
17
|
|
|
7
18
|
### 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 |
|
|
@@ -203,6 +203,22 @@ async function main() {
|
|
|
203
203
|
// π User declined auto-fix or it failed β continue anyway, just warned
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
// π Apply CLI overrides for settings
|
|
207
|
+
if (cliArgs.sortColumn) config.settings.sortColumn = cliArgs.sortColumn
|
|
208
|
+
if (cliArgs.sortDirection) config.settings.sortAsc = cliArgs.sortDirection === 'asc'
|
|
209
|
+
if (cliArgs.originFilter) config.settings.originFilter = cliArgs.originFilter
|
|
210
|
+
if (cliArgs.pingInterval) config.settings.pingInterval = cliArgs.pingInterval
|
|
211
|
+
if (cliArgs.hideUnconfigured) config.settings.hideUnconfiguredModels = true
|
|
212
|
+
if (cliArgs.showUnconfigured) config.settings.hideUnconfiguredModels = false
|
|
213
|
+
if (cliArgs.disableWidthsWarning) config.settings.disableWidthsWarning = true
|
|
214
|
+
|
|
215
|
+
// π Apply premium mode: show only Sβtier models sorted by verdict
|
|
216
|
+
if (cliArgs.premiumMode) {
|
|
217
|
+
config.settings.tierFilter = 'S'
|
|
218
|
+
config.settings.sortColumn = 'verdict'
|
|
219
|
+
config.settings.sortAsc = true
|
|
220
|
+
}
|
|
221
|
+
|
|
206
222
|
if (cliArgs.cleanProxyMode) {
|
|
207
223
|
const cleaned = cleanupOpenCodeProxyConfig()
|
|
208
224
|
console.log()
|
|
@@ -499,8 +515,9 @@ async function main() {
|
|
|
499
515
|
mode, // π 'opencode' or 'openclaw' β controls Enter action
|
|
500
516
|
tierFilterMode: 0, // π Index into TIER_CYCLE (0=All, 1=S+, 2=S, ...)
|
|
501
517
|
originFilterMode: 0, // π Index into ORIGIN_CYCLE (0=All, then providers)
|
|
502
|
-
|
|
503
|
-
|
|
518
|
+
premiumMode: cliArgs.premiumMode, // π Special elite-only mode: S/S+ only, Health UP only, Perfect/Normal/Slow verdict only.
|
|
519
|
+
hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true || config.settings?.hideUnconfiguredModels === true, // π Hide providers with no configured API key when true.
|
|
520
|
+
disableWidthsWarning: config.settings?.disableWidthsWarning ?? false, // π Disable widths warning toggle (default off)
|
|
504
521
|
scrollOffset: 0, // π First visible model index in viewport
|
|
505
522
|
terminalRows: process.stdout.rows || 24, // π Current terminal height
|
|
506
523
|
terminalCols: process.stdout.columns || 80, // π Current terminal width
|
|
@@ -756,6 +773,17 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
|
|
|
756
773
|
outputResults = outputResults.filter(r => ['S+', 'S', 'A+'].includes(r.tier))
|
|
757
774
|
}
|
|
758
775
|
|
|
776
|
+
// π Apply premium mode filter if specified: elite-only (S/S+, UP, Good Verdict)
|
|
777
|
+
if (cliArgs.premiumMode) {
|
|
778
|
+
outputResults = outputResults.filter(r => {
|
|
779
|
+
const isEliteTier = r.tier === 'S' || r.tier === 'S+'
|
|
780
|
+
const isHealthUp = r.status === 'up'
|
|
781
|
+
const verdict = getVerdict(r)
|
|
782
|
+
const isGoodVerdict = ['Perfect', 'Normal', 'Slow'].includes(verdict)
|
|
783
|
+
return isEliteTier && isHealthUp && isGoodVerdict
|
|
784
|
+
})
|
|
785
|
+
}
|
|
786
|
+
|
|
759
787
|
// π Sort by avg ping (ascending)
|
|
760
788
|
outputResults = sortResults(outputResults, 'avg', 'asc')
|
|
761
789
|
|
|
@@ -805,9 +833,23 @@ hideUnconfiguredModels: startupProfileSettings?.hideUnconfiguredModels === true
|
|
|
805
833
|
return
|
|
806
834
|
}
|
|
807
835
|
// π Apply both tier and origin filters β model is hidden if it fails either
|
|
808
|
-
|
|
836
|
+
// π TIER_LETTER_MAP is used so --tier S also includes S+ models (tier family behavior).
|
|
837
|
+
const allowedTiers = (activeTier && TIER_LETTER_MAP[activeTier]) ? TIER_LETTER_MAP[activeTier] : [activeTier]
|
|
838
|
+
const tierHide = activeTier !== null && !allowedTiers.includes(r.tier)
|
|
809
839
|
const originHide = activeOrigin !== null && r.providerKey !== activeOrigin
|
|
810
840
|
r.hidden = tierHide || originHide
|
|
841
|
+
|
|
842
|
+
// π Premium Mode: elite-only constraints (Health UP, Good Verdict, S/S+ only)
|
|
843
|
+
if (state.premiumMode && !r.hidden) {
|
|
844
|
+
const isEliteTier = r.tier === 'S' || r.tier === 'S+'
|
|
845
|
+
const isHealthUp = r.status === 'up'
|
|
846
|
+
const verdict = getVerdict(r)
|
|
847
|
+
const isGoodVerdict = ['Perfect', 'Normal', 'Slow'].includes(verdict)
|
|
848
|
+
|
|
849
|
+
if (!isEliteTier || !isHealthUp || !isGoodVerdict) {
|
|
850
|
+
r.hidden = true
|
|
851
|
+
}
|
|
852
|
+
}
|
|
811
853
|
})
|
|
812
854
|
return state.results
|
|
813
855
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "free-coding-models",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
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,6 +26,14 @@ 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 = [
|
package/src/overlays.js
CHANGED
|
@@ -736,7 +736,8 @@ const profileStartIdx = updateRowIdx + 5
|
|
|
736
736
|
} catch { /* keep raw */ }
|
|
737
737
|
|
|
738
738
|
const requestedModelLabel = row.requestedModel || ''
|
|
739
|
-
|
|
739
|
+
// π Always show "requested β actual" if they differ, not just when switched
|
|
740
|
+
const displayModel = requestedModelLabel && requestedModelLabel !== row.model
|
|
740
741
|
? `${requestedModelLabel} β ${row.model}`
|
|
741
742
|
: row.model
|
|
742
743
|
|
|
@@ -781,9 +782,11 @@ const profileStartIdx = updateRowIdx + 5
|
|
|
781
782
|
const isFailedWithZeroTokens = row.status !== '200' && (!row.tokens || Number(row.tokens) === 0)
|
|
782
783
|
|
|
783
784
|
const timeCell = chalk.dim(timeStr.slice(0, W_TIME).padEnd(W_TIME))
|
|
784
|
-
// π
|
|
785
|
+
// π Provider display: Use pretty label if available, otherwise raw key.
|
|
786
|
+
// π All these logs are from FCM Proxy V2.
|
|
787
|
+
const providerLabel = PROVIDER_METADATA[row.provider]?.label || row.provider
|
|
785
788
|
const providerRgb = PROVIDER_COLOR[row.provider] ?? [105, 190, 245]
|
|
786
|
-
const provCell = chalk.bold.rgb(...providerRgb)(
|
|
789
|
+
const provCell = chalk.bold.rgb(...providerRgb)(providerLabel.slice(0, W_PROV).padEnd(W_PROV))
|
|
787
790
|
|
|
788
791
|
// π Color model based on status - red for failed requests with zero tokens
|
|
789
792
|
let modelCell
|
|
@@ -26,28 +26,70 @@
|
|
|
26
26
|
* @see src/render-table.js
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
30
|
+
import { join } from 'node:path'
|
|
31
|
+
import { homedir } from 'node:os'
|
|
29
32
|
import { loadRecentLogs } from './log-reader.js'
|
|
30
33
|
|
|
34
|
+
const DEFAULT_DATA_DIR = join(homedir(), '.free-coding-models')
|
|
35
|
+
const STATS_FILE = join(DEFAULT_DATA_DIR, 'token-stats.json')
|
|
36
|
+
|
|
31
37
|
// π buildProviderModelTokenKey keeps provider-scoped totals isolated even when
|
|
32
38
|
// π multiple Origins expose the same model ID.
|
|
33
39
|
export function buildProviderModelTokenKey(providerKey, modelId) {
|
|
34
40
|
return `${providerKey}::${modelId}`
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
// π loadTokenUsageByProviderModel
|
|
38
|
-
// π
|
|
39
|
-
export function loadTokenUsageByProviderModel({ logFile, limit = 50_000 } = {}) {
|
|
40
|
-
|
|
43
|
+
// π loadTokenUsageByProviderModel prioritizes token-stats.json for accurate
|
|
44
|
+
// π historical totals. If missing, it falls back to parsing the bounded log history.
|
|
45
|
+
export function loadTokenUsageByProviderModel({ logFile, statsFile = STATS_FILE, limit = 50_000 } = {}) {
|
|
46
|
+
// π If a custom logFile is provided (Test Mode), ONLY use that file.
|
|
47
|
+
if (logFile) {
|
|
48
|
+
const testTotals = {}
|
|
49
|
+
const rows = loadRecentLogs({ logFile, limit })
|
|
50
|
+
for (const row of rows) {
|
|
51
|
+
const key = buildProviderModelTokenKey(row.provider, row.model)
|
|
52
|
+
testTotals[key] = (testTotals[key] || 0) + (Number(row.tokens) || 0)
|
|
53
|
+
}
|
|
54
|
+
return testTotals
|
|
55
|
+
}
|
|
56
|
+
|
|
41
57
|
const totals = {}
|
|
42
58
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
// π Phase 1: Try to load from the aggregated stats file (canonical source for totals)
|
|
60
|
+
try {
|
|
61
|
+
if (existsSync(statsFile)) {
|
|
62
|
+
const stats = JSON.parse(readFileSync(statsFile, 'utf8'))
|
|
63
|
+
// π Aggregate byAccount entries (which use providerKey/slug/keyIdx as ID)
|
|
64
|
+
// π into providerKey::modelId buckets.
|
|
65
|
+
if (stats.byAccount && typeof stats.byAccount === 'object') {
|
|
66
|
+
for (const [accountId, acct] of Object.entries(stats.byAccount)) {
|
|
67
|
+
const tokens = Number(acct.tokens) || 0
|
|
68
|
+
if (tokens <= 0) continue
|
|
69
|
+
|
|
70
|
+
// π Extract providerKey and modelId from accountId (provider/model/index)
|
|
71
|
+
const parts = accountId.split('/')
|
|
72
|
+
if (parts.length >= 2) {
|
|
73
|
+
const providerKey = parts[0]
|
|
74
|
+
const modelId = parts[1]
|
|
75
|
+
const key = buildProviderModelTokenKey(providerKey, modelId)
|
|
76
|
+
totals[key] = (totals[key] || 0) + tokens
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// π Silently fall back to log parsing if stats file is corrupt or unreadable
|
|
83
|
+
}
|
|
48
84
|
|
|
49
|
-
|
|
50
|
-
|
|
85
|
+
// π Phase 2: Supplement with recent log entries if totals are still empty
|
|
86
|
+
// π (e.g. fresh install or token-stats.json deleted)
|
|
87
|
+
if (Object.keys(totals).length === 0) {
|
|
88
|
+
const rows = loadRecentLogs({ limit })
|
|
89
|
+
for (const row of rows) {
|
|
90
|
+
const key = buildProviderModelTokenKey(row.provider, row.model)
|
|
91
|
+
totals[key] = (totals[key] || 0) + (Number(row.tokens) || 0)
|
|
92
|
+
}
|
|
51
93
|
}
|
|
52
94
|
|
|
53
95
|
return totals
|
package/src/utils.js
CHANGED
|
@@ -414,10 +414,29 @@ export function parseArgs(argv) {
|
|
|
414
414
|
? profileIdx + 1
|
|
415
415
|
: -1
|
|
416
416
|
|
|
417
|
+
// New value flags
|
|
418
|
+
const sortIdx = args.findIndex(a => a.toLowerCase() === '--sort')
|
|
419
|
+
const sortValueIdx = (sortIdx !== -1 && args[sortIdx + 1] && !args[sortIdx + 1].startsWith('--'))
|
|
420
|
+
? sortIdx + 1
|
|
421
|
+
: -1
|
|
422
|
+
|
|
423
|
+
const originIdx = args.findIndex(a => a.toLowerCase() === '--origin')
|
|
424
|
+
const originValueIdx = (originIdx !== -1 && args[originIdx + 1] && !args[originIdx + 1].startsWith('--'))
|
|
425
|
+
? originIdx + 1
|
|
426
|
+
: -1
|
|
427
|
+
|
|
428
|
+
const pingIntervalIdx = args.findIndex(a => a.toLowerCase() === '--ping-interval')
|
|
429
|
+
const pingIntervalValueIdx = (pingIntervalIdx !== -1 && args[pingIntervalIdx + 1] && !args[pingIntervalIdx + 1].startsWith('--'))
|
|
430
|
+
? pingIntervalIdx + 1
|
|
431
|
+
: -1
|
|
432
|
+
|
|
417
433
|
// π Set of arg indices that are values for flags (not API keys)
|
|
418
434
|
const skipIndices = new Set()
|
|
419
435
|
if (tierValueIdx !== -1) skipIndices.add(tierValueIdx)
|
|
420
436
|
if (profileValueIdx !== -1) skipIndices.add(profileValueIdx)
|
|
437
|
+
if (sortValueIdx !== -1) skipIndices.add(sortValueIdx)
|
|
438
|
+
if (originValueIdx !== -1) skipIndices.add(originValueIdx)
|
|
439
|
+
if (pingIntervalValueIdx !== -1) skipIndices.add(pingIntervalValueIdx)
|
|
421
440
|
|
|
422
441
|
for (const [i, arg] of args.entries()) {
|
|
423
442
|
if (arg.startsWith('--') || arg === '-h') {
|
|
@@ -448,8 +467,20 @@ export function parseArgs(argv) {
|
|
|
448
467
|
const cleanProxyMode = flags.includes('--clean-proxy') || flags.includes('--proxy-clean')
|
|
449
468
|
const jsonMode = flags.includes('--json')
|
|
450
469
|
const helpMode = flags.includes('--help') || flags.includes('-h')
|
|
470
|
+
const premiumMode = flags.includes('--premium')
|
|
471
|
+
|
|
472
|
+
// New boolean flags
|
|
473
|
+
const sortDesc = flags.includes('--desc')
|
|
474
|
+
const sortAscFlag = flags.includes('--asc')
|
|
475
|
+
const hideUnconfigured = flags.includes('--hide-unconfigured')
|
|
476
|
+
const showUnconfigured = flags.includes('--show-unconfigured')
|
|
477
|
+
const disableWidthsWarning = flags.includes('--disable-widths-warning')
|
|
451
478
|
|
|
452
479
|
let tierFilter = tierValueIdx !== -1 ? args[tierValueIdx].toUpperCase() : null
|
|
480
|
+
let sortColumn = sortValueIdx !== -1 ? args[sortValueIdx].toLowerCase() : null
|
|
481
|
+
let originFilter = originValueIdx !== -1 ? args[originValueIdx] : null
|
|
482
|
+
let pingInterval = pingIntervalValueIdx !== -1 ? parseInt(args[pingIntervalValueIdx], 10) : null
|
|
483
|
+
let sortDirection = sortDesc ? 'desc' : (sortAscFlag ? 'asc' : null)
|
|
453
484
|
|
|
454
485
|
const profileName = profileValueIdx !== -1 ? args[profileValueIdx] : null
|
|
455
486
|
|
|
@@ -478,6 +509,14 @@ export function parseArgs(argv) {
|
|
|
478
509
|
jsonMode,
|
|
479
510
|
helpMode,
|
|
480
511
|
tierFilter,
|
|
512
|
+
sortColumn,
|
|
513
|
+
sortDirection,
|
|
514
|
+
originFilter,
|
|
515
|
+
pingInterval,
|
|
516
|
+
hideUnconfigured,
|
|
517
|
+
showUnconfigured,
|
|
518
|
+
disableWidthsWarning,
|
|
519
|
+
premiumMode,
|
|
481
520
|
profileName,
|
|
482
521
|
recommendMode
|
|
483
522
|
}
|