free-coding-models 0.1.16 → 0.1.18
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 +12 -5
- package/bin/free-coding-models.js +116 -12
- package/lib/utils.js +4 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<img src="https://img.shields.io/npm/v/free-coding-models?color=76b900&label=npm&logo=npm" alt="npm version">
|
|
3
3
|
<img src="https://img.shields.io/node/v/free-coding-models?color=76b900&logo=node.js" alt="node version">
|
|
4
4
|
<img src="https://img.shields.io/npm/l/free-coding-models?color=76b900" alt="license">
|
|
5
|
-
<img src="https://img.shields.io/badge/
|
|
5
|
+
<img src="https://img.shields.io/badge/nvidia%20nim%20models-44-76b900?logo=nvidia" alt="models count">
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
8
|
<h1 align="center">free-coding-models</h1>
|
|
@@ -100,9 +100,12 @@ bunx free-coding-models YOUR_API_KEY
|
|
|
100
100
|
# Just run it — shows a startup menu to pick OpenCode or OpenClaw, prompts for API key if not set
|
|
101
101
|
free-coding-models
|
|
102
102
|
|
|
103
|
-
# Explicitly target OpenCode (
|
|
103
|
+
# Explicitly target OpenCode CLI (TUI + Enter launches OpenCode CLI)
|
|
104
104
|
free-coding-models --opencode
|
|
105
105
|
|
|
106
|
+
# Explicitly target OpenCode Desktop (TUI + Enter sets model & opens Desktop app)
|
|
107
|
+
free-coding-models --opencode-desktop
|
|
108
|
+
|
|
106
109
|
# Explicitly target OpenClaw (TUI + Enter sets model as default in OpenClaw)
|
|
107
110
|
free-coding-models --openclaw
|
|
108
111
|
|
|
@@ -130,8 +133,11 @@ When you run `free-coding-models` without `--opencode` or `--openclaw`, you get
|
|
|
130
133
|
```
|
|
131
134
|
⚡ Free Coding Models — Choose your tool
|
|
132
135
|
|
|
133
|
-
❯ 💻 OpenCode
|
|
134
|
-
Press Enter on a model → launch OpenCode with it as default
|
|
136
|
+
❯ 💻 OpenCode CLI
|
|
137
|
+
Press Enter on a model → launch OpenCode CLI with it as default
|
|
138
|
+
|
|
139
|
+
🖥 OpenCode Desktop
|
|
140
|
+
Press Enter on a model → set model & open OpenCode Desktop app
|
|
135
141
|
|
|
136
142
|
🦞 OpenClaw
|
|
137
143
|
Press Enter on a model → set it as default in OpenClaw config
|
|
@@ -417,7 +423,8 @@ This script:
|
|
|
417
423
|
| Flag | Description |
|
|
418
424
|
|------|-------------|
|
|
419
425
|
| *(none)* | Show startup menu to choose OpenCode or OpenClaw |
|
|
420
|
-
| `--opencode` | OpenCode mode — Enter launches OpenCode with selected model |
|
|
426
|
+
| `--opencode` | OpenCode CLI mode — Enter launches OpenCode CLI with selected model |
|
|
427
|
+
| `--opencode-desktop` | OpenCode Desktop mode — Enter sets model & opens OpenCode Desktop app |
|
|
421
428
|
| `--openclaw` | OpenClaw mode — Enter sets selected model as default in OpenClaw |
|
|
422
429
|
| `--best` | Show only top-tier models (A+, S, S+) |
|
|
423
430
|
| `--fiable` | Analyze 10 seconds, output the most reliable model as `provider/model_id` |
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* - Best-per-tier highlighting with medals (🥇🥈🥉)
|
|
17
17
|
* - Interactive navigation with arrow keys directly in the table
|
|
18
18
|
* - Instant OpenCode OR OpenClaw action on Enter key press
|
|
19
|
-
* - Startup mode menu (OpenCode vs OpenClaw) when no flag is given
|
|
19
|
+
* - Startup mode menu (OpenCode CLI vs OpenCode Desktop vs OpenClaw) when no flag is given
|
|
20
20
|
* - Automatic config detection and model setup for both tools
|
|
21
21
|
* - Persistent API key storage in ~/.free-coding-models
|
|
22
22
|
* - Multi-source support via sources.js (easily add new providers)
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
* - `getUptime`: Calculate uptime percentage from ping history
|
|
36
36
|
* - `sortResults`: Sort models by various columns
|
|
37
37
|
* - `checkNvidiaNimConfig`: Check if NVIDIA NIM provider is configured in OpenCode
|
|
38
|
-
* - `startOpenCode`: Launch OpenCode with selected model (configures if needed)
|
|
38
|
+
* - `startOpenCode`: Launch OpenCode CLI with selected model (configures if needed)
|
|
39
|
+
* - `startOpenCodeDesktop`: Set model in shared config & open OpenCode Desktop app
|
|
39
40
|
* - `loadOpenClawConfig` / `saveOpenClawConfig`: Manage ~/.openclaw/openclaw.json
|
|
40
41
|
* - `startOpenClaw`: Set selected model as default in OpenClaw config (remote, no launch)
|
|
41
42
|
* - `filterByTier`: Filter models by tier letter prefix (S, A, B, C)
|
|
@@ -58,7 +59,8 @@
|
|
|
58
59
|
*
|
|
59
60
|
* 🚀 CLI flags:
|
|
60
61
|
* - (no flag): Show startup menu → choose OpenCode or OpenClaw
|
|
61
|
-
* - --opencode: OpenCode mode (launch with selected model)
|
|
62
|
+
* - --opencode: OpenCode CLI mode (launch CLI with selected model)
|
|
63
|
+
* - --opencode-desktop: OpenCode Desktop mode (set model & open Desktop app)
|
|
62
64
|
* - --openclaw: OpenClaw mode (set selected model as default in OpenClaw)
|
|
63
65
|
* - --best: Show only top-tier models (A+, S, S+)
|
|
64
66
|
* - --fiable: Analyze 10s and output the most reliable model
|
|
@@ -166,9 +168,14 @@ async function promptApiKey() {
|
|
|
166
168
|
async function promptModeSelection(latestVersion) {
|
|
167
169
|
const options = [
|
|
168
170
|
{
|
|
169
|
-
label: 'OpenCode',
|
|
171
|
+
label: 'OpenCode CLI',
|
|
170
172
|
icon: '💻',
|
|
171
|
-
description: 'Press Enter on a model → launch OpenCode with it as default',
|
|
173
|
+
description: 'Press Enter on a model → launch OpenCode CLI with it as default',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
label: 'OpenCode Desktop',
|
|
177
|
+
icon: '🖥',
|
|
178
|
+
description: 'Press Enter on a model → set model & open OpenCode Desktop app',
|
|
172
179
|
},
|
|
173
180
|
{
|
|
174
181
|
label: 'OpenClaw',
|
|
@@ -185,6 +192,15 @@ async function promptModeSelection(latestVersion) {
|
|
|
185
192
|
})
|
|
186
193
|
}
|
|
187
194
|
|
|
195
|
+
// 📖 Add "Read Changelogs" option when an update is available or was just updated
|
|
196
|
+
if (latestVersion) {
|
|
197
|
+
options.push({
|
|
198
|
+
label: 'Read Changelogs',
|
|
199
|
+
icon: '📋',
|
|
200
|
+
description: 'Open the GitHub releases page in your browser',
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
188
204
|
return new Promise((resolve) => {
|
|
189
205
|
let selected = 0
|
|
190
206
|
|
|
@@ -237,8 +253,9 @@ async function promptModeSelection(latestVersion) {
|
|
|
237
253
|
if (process.stdin.isTTY) process.stdin.setRawMode(false)
|
|
238
254
|
process.stdin.removeListener('keypress', onKey)
|
|
239
255
|
process.stdin.pause()
|
|
240
|
-
const choices = ['opencode', 'openclaw']
|
|
256
|
+
const choices = ['opencode', 'opencode-desktop', 'openclaw']
|
|
241
257
|
if (latestVersion) choices.push('update')
|
|
258
|
+
if (latestVersion) choices.push('changelogs')
|
|
242
259
|
resolve(choices[selected])
|
|
243
260
|
}
|
|
244
261
|
}
|
|
@@ -324,9 +341,14 @@ function renderTable(results, pendingPings, frame, cursor = null, sortColumn = '
|
|
|
324
341
|
: chalk.dim(`next ping ${secondsUntilNext}s`)
|
|
325
342
|
|
|
326
343
|
// 📖 Mode badge shown in header so user knows what Enter will do
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
344
|
+
let modeBadge
|
|
345
|
+
if (mode === 'openclaw') {
|
|
346
|
+
modeBadge = chalk.bold.rgb(255, 100, 50)(' [🦞 OpenClaw]')
|
|
347
|
+
} else if (mode === 'opencode-desktop') {
|
|
348
|
+
modeBadge = chalk.bold.rgb(0, 200, 255)(' [🖥 Desktop]')
|
|
349
|
+
} else {
|
|
350
|
+
modeBadge = chalk.bold.rgb(0, 200, 255)(' [💻 CLI]')
|
|
351
|
+
}
|
|
330
352
|
|
|
331
353
|
// 📖 Column widths (generous spacing with margins)
|
|
332
354
|
const W_RANK = 6
|
|
@@ -527,7 +549,9 @@ function renderTable(results, pendingPings, frame, cursor = null, sortColumn = '
|
|
|
527
549
|
// 📖 Footer hints adapt based on active mode
|
|
528
550
|
const actionHint = mode === 'openclaw'
|
|
529
551
|
? chalk.rgb(255, 100, 50)('Enter→SetOpenClaw')
|
|
530
|
-
:
|
|
552
|
+
: mode === 'opencode-desktop'
|
|
553
|
+
? chalk.rgb(0, 200, 255)('Enter→OpenDesktop')
|
|
554
|
+
: chalk.rgb(0, 200, 255)('Enter→OpenCode')
|
|
531
555
|
lines.push(chalk.dim(` ↑↓ Navigate • `) + actionHint + chalk.dim(` • R/T/O/M/P/A/S/V/U Sort • W↓/X↑ Interval (${intervalSec}s) • Ctrl+C Exit`))
|
|
532
556
|
lines.push('')
|
|
533
557
|
lines.push(chalk.dim(' made with ') + '🩷' + chalk.dim(' by vava-nessa • ') + chalk.dim.underline('https://github.com/vava-nessa/free-coding-models'))
|
|
@@ -710,6 +734,74 @@ After installation, you can use: opencode --model nvidia/${model.modelId}`
|
|
|
710
734
|
}
|
|
711
735
|
}
|
|
712
736
|
|
|
737
|
+
// ─── Start OpenCode Desktop ─────────────────────────────────────────────────────
|
|
738
|
+
// 📖 startOpenCodeDesktop: Same config logic as startOpenCode, but opens the Desktop app.
|
|
739
|
+
// 📖 OpenCode Desktop (/Applications/OpenCode.app) shares config at ~/.config/opencode/opencode.json.
|
|
740
|
+
// 📖 No need to wait for exit — Desktop app stays open independently.
|
|
741
|
+
async function startOpenCodeDesktop(model) {
|
|
742
|
+
const hasNim = checkNvidiaNimConfig()
|
|
743
|
+
|
|
744
|
+
if (hasNim) {
|
|
745
|
+
console.log(chalk.green(` 🖥 Setting ${chalk.bold(model.label)} as default for OpenCode Desktop…`))
|
|
746
|
+
console.log(chalk.dim(` Model: nvidia/${model.modelId}`))
|
|
747
|
+
console.log()
|
|
748
|
+
|
|
749
|
+
const config = loadOpenCodeConfig()
|
|
750
|
+
const backupPath = `${OPENCODE_CONFIG}.backup-${Date.now()}`
|
|
751
|
+
|
|
752
|
+
if (existsSync(OPENCODE_CONFIG)) {
|
|
753
|
+
copyFileSync(OPENCODE_CONFIG, backupPath)
|
|
754
|
+
console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
config.model = `nvidia/${model.modelId}`
|
|
758
|
+
|
|
759
|
+
if (config.provider?.nvidia) {
|
|
760
|
+
if (!config.provider.nvidia.models) config.provider.nvidia.models = {}
|
|
761
|
+
config.provider.nvidia.models[model.modelId] = {
|
|
762
|
+
name: model.label,
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
saveOpenCodeConfig(config)
|
|
767
|
+
|
|
768
|
+
console.log(chalk.green(` ✓ Default model set to: nvidia/${model.modelId}`))
|
|
769
|
+
console.log()
|
|
770
|
+
console.log(chalk.dim(' Opening OpenCode Desktop…'))
|
|
771
|
+
console.log()
|
|
772
|
+
|
|
773
|
+
// 📖 Launch Desktop app — no need to wait, it stays open independently
|
|
774
|
+
const { exec } = await import('child_process')
|
|
775
|
+
exec('open -a OpenCode', (err) => {
|
|
776
|
+
if (err) {
|
|
777
|
+
console.error(chalk.red(' ✗ Could not open OpenCode Desktop — is it installed at /Applications/OpenCode.app?'))
|
|
778
|
+
}
|
|
779
|
+
})
|
|
780
|
+
} else {
|
|
781
|
+
console.log(chalk.yellow(' ⚠ NVIDIA NIM not configured in OpenCode'))
|
|
782
|
+
console.log(chalk.dim(' Please configure it first. Config is shared between CLI and Desktop.'))
|
|
783
|
+
console.log()
|
|
784
|
+
const installPrompt = `Add this to ~/.config/opencode/opencode.json:
|
|
785
|
+
|
|
786
|
+
{
|
|
787
|
+
"provider": {
|
|
788
|
+
"nvidia": {
|
|
789
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
790
|
+
"name": "NVIDIA NIM",
|
|
791
|
+
"options": {
|
|
792
|
+
"baseURL": "https://integrate.api.nvidia.com/v1",
|
|
793
|
+
"apiKey": "{env:NVIDIA_API_KEY}"
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
Then set env var: export NVIDIA_API_KEY=your_key_here`
|
|
800
|
+
console.log(chalk.cyan(installPrompt))
|
|
801
|
+
console.log()
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
713
805
|
// ─── OpenClaw integration ──────────────────────────────────────────────────────
|
|
714
806
|
// 📖 OpenClaw config: ~/.openclaw/openclaw.json (JSON format, may be JSON5 in newer versions)
|
|
715
807
|
// 📖 To set a model: set agents.defaults.model.primary = "nvidia/model-id"
|
|
@@ -892,7 +984,7 @@ async function main() {
|
|
|
892
984
|
// 📖 Parse CLI arguments using shared parseArgs utility
|
|
893
985
|
const parsed = parseArgs(process.argv)
|
|
894
986
|
let apiKey = parsed.apiKey
|
|
895
|
-
const { bestMode, fiableMode, openCodeMode, openClawMode, tierFilter } = parsed
|
|
987
|
+
const { bestMode, fiableMode, openCodeMode, openCodeDesktopMode, openClawMode, tierFilter } = parsed
|
|
896
988
|
|
|
897
989
|
// 📖 Priority: CLI arg > env var > saved config > wizard
|
|
898
990
|
if (!apiKey) {
|
|
@@ -925,6 +1017,8 @@ async function main() {
|
|
|
925
1017
|
let mode
|
|
926
1018
|
if (openClawMode) {
|
|
927
1019
|
mode = 'openclaw'
|
|
1020
|
+
} else if (openCodeDesktopMode) {
|
|
1021
|
+
mode = 'opencode-desktop'
|
|
928
1022
|
} else if (openCodeMode) {
|
|
929
1023
|
mode = 'opencode'
|
|
930
1024
|
} else {
|
|
@@ -937,8 +1031,16 @@ async function main() {
|
|
|
937
1031
|
runUpdate()
|
|
938
1032
|
}
|
|
939
1033
|
|
|
1034
|
+
// 📖 Handle "Read Changelogs" selection — open GitHub releases in browser
|
|
1035
|
+
if (mode === 'changelogs') {
|
|
1036
|
+
const { exec } = await import('child_process')
|
|
1037
|
+
exec('open https://github.com/vava-nessa/free-coding-models/releases')
|
|
1038
|
+
console.log(chalk.dim(' 📋 Opening changelogs in browser…'))
|
|
1039
|
+
process.exit(0)
|
|
1040
|
+
}
|
|
1041
|
+
|
|
940
1042
|
// 📖 When using flags (--opencode/--openclaw), show update warning in terminal
|
|
941
|
-
if (latestVersion && (openCodeMode || openClawMode)) {
|
|
1043
|
+
if (latestVersion && (openCodeMode || openCodeDesktopMode || openClawMode)) {
|
|
942
1044
|
console.log(chalk.red(` ⚠ New version available (v${latestVersion}), please run npm i -g free-coding-models to install`))
|
|
943
1045
|
console.log()
|
|
944
1046
|
}
|
|
@@ -1079,6 +1181,8 @@ async function main() {
|
|
|
1079
1181
|
// 📖 Dispatch to the correct integration based on active mode
|
|
1080
1182
|
if (state.mode === 'openclaw') {
|
|
1081
1183
|
await startOpenClaw(userSelected, apiKey)
|
|
1184
|
+
} else if (state.mode === 'opencode-desktop') {
|
|
1185
|
+
await startOpenCodeDesktop(userSelected)
|
|
1082
1186
|
} else {
|
|
1083
1187
|
await startOpenCode(userSelected)
|
|
1084
1188
|
}
|
package/lib/utils.js
CHANGED
|
@@ -242,11 +242,11 @@ export function findBestModel(results) {
|
|
|
242
242
|
//
|
|
243
243
|
// 📖 Argument types:
|
|
244
244
|
// - API key: first positional arg that doesn't start with "--" (e.g., "nvapi-xxx")
|
|
245
|
-
// - Boolean flags: --best, --fiable, --opencode, --openclaw (case-insensitive)
|
|
245
|
+
// - Boolean flags: --best, --fiable, --opencode, --opencode-desktop, --openclaw (case-insensitive)
|
|
246
246
|
// - Value flag: --tier <letter> (the next non-flag arg is the tier value)
|
|
247
247
|
//
|
|
248
248
|
// 📖 Returns:
|
|
249
|
-
// { apiKey, bestMode, fiableMode, openCodeMode, openClawMode, tierFilter }
|
|
249
|
+
// { apiKey, bestMode, fiableMode, openCodeMode, openCodeDesktopMode, openClawMode, tierFilter }
|
|
250
250
|
//
|
|
251
251
|
// 📖 Note: apiKey may be null here — the main CLI falls back to env vars and saved config.
|
|
252
252
|
export function parseArgs(argv) {
|
|
@@ -265,6 +265,7 @@ export function parseArgs(argv) {
|
|
|
265
265
|
const bestMode = flags.includes('--best')
|
|
266
266
|
const fiableMode = flags.includes('--fiable')
|
|
267
267
|
const openCodeMode = flags.includes('--opencode')
|
|
268
|
+
const openCodeDesktopMode = flags.includes('--opencode-desktop')
|
|
268
269
|
const openClawMode = flags.includes('--openclaw')
|
|
269
270
|
|
|
270
271
|
// 📖 --tier requires a value after it (e.g., --tier S)
|
|
@@ -275,5 +276,5 @@ export function parseArgs(argv) {
|
|
|
275
276
|
tierFilter = args[tierIdx + 1].toUpperCase()
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
return { apiKey, bestMode, fiableMode, openCodeMode, openClawMode, tierFilter }
|
|
279
|
+
return { apiKey, bestMode, fiableMode, openCodeMode, openCodeDesktopMode, openClawMode, tierFilter }
|
|
279
280
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "free-coding-models",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
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",
|