free-coding-models 0.1.17 → 0.1.19

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
@@ -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/models-44-76b900?logo=nvidia" alt="models count">
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 (current default behavior — TUI + Enter launches 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
@@ -95,19 +97,23 @@ async function checkForUpdate() {
95
97
  return null
96
98
  }
97
99
 
98
- function runUpdate() {
100
+ function runUpdate(latestVersion) {
99
101
  const { execSync } = require('child_process')
100
102
  console.log()
101
- console.log(chalk.bold.cyan(' ⬆ Updating free-coding-models...'))
103
+ console.log(chalk.bold.cyan(' ⬆ Updating free-coding-models to v' + latestVersion + '...'))
102
104
  console.log()
103
105
  try {
104
- execSync('npm i -g free-coding-models', { stdio: 'inherit' })
106
+ // 📖 Force install from npm registry (ignore local cache)
107
+ // 📖 Use --prefer-online to ensure we get the latest published version
108
+ execSync(`npm i -g free-coding-models@${latestVersion} --prefer-online`, { stdio: 'inherit' })
105
109
  console.log()
106
- console.log(chalk.green(' ✅ Update complete! Please restart free-coding-models.'))
110
+ console.log(chalk.green(' ✅ Update complete! Version ' + latestVersion + ' installed.'))
107
111
  console.log()
108
- } catch {
112
+ console.log(chalk.dim(' 📝 Please restart free-coding-models to use the new version.'))
113
+ console.log()
114
+ } catch (err) {
109
115
  console.log()
110
- console.log(chalk.red(' ✖ Update failed. Try manually: npm i -g free-coding-models'))
116
+ console.log(chalk.red(' ✖ Update failed. Try manually: npm i -g free-coding-models@' + latestVersion))
111
117
  console.log()
112
118
  }
113
119
  process.exit(0)
@@ -166,9 +172,14 @@ async function promptApiKey() {
166
172
  async function promptModeSelection(latestVersion) {
167
173
  const options = [
168
174
  {
169
- label: 'OpenCode',
175
+ label: 'OpenCode CLI',
170
176
  icon: '💻',
171
- description: 'Press Enter on a model → launch OpenCode with it as default',
177
+ description: 'Press Enter on a model → launch OpenCode CLI with it as default',
178
+ },
179
+ {
180
+ label: 'OpenCode Desktop',
181
+ icon: '🖥',
182
+ description: 'Press Enter on a model → set model & open OpenCode Desktop app',
172
183
  },
173
184
  {
174
185
  label: 'OpenClaw',
@@ -185,6 +196,15 @@ async function promptModeSelection(latestVersion) {
185
196
  })
186
197
  }
187
198
 
199
+ // 📖 Add "Read Changelogs" option when an update is available or was just updated
200
+ if (latestVersion) {
201
+ options.push({
202
+ label: 'Read Changelogs',
203
+ icon: '📋',
204
+ description: 'Open the GitHub releases page in your browser',
205
+ })
206
+ }
207
+
188
208
  return new Promise((resolve) => {
189
209
  let selected = 0
190
210
 
@@ -237,8 +257,9 @@ async function promptModeSelection(latestVersion) {
237
257
  if (process.stdin.isTTY) process.stdin.setRawMode(false)
238
258
  process.stdin.removeListener('keypress', onKey)
239
259
  process.stdin.pause()
240
- const choices = ['opencode', 'openclaw']
260
+ const choices = ['opencode', 'opencode-desktop', 'openclaw']
241
261
  if (latestVersion) choices.push('update')
262
+ if (latestVersion) choices.push('changelogs')
242
263
  resolve(choices[selected])
243
264
  }
244
265
  }
@@ -324,9 +345,14 @@ function renderTable(results, pendingPings, frame, cursor = null, sortColumn = '
324
345
  : chalk.dim(`next ping ${secondsUntilNext}s`)
325
346
 
326
347
  // 📖 Mode badge shown in header so user knows what Enter will do
327
- const modeBadge = mode === 'openclaw'
328
- ? chalk.bold.rgb(255, 100, 50)(' [🦞 OpenClaw]')
329
- : chalk.bold.rgb(0, 200, 255)(' [💻 OpenCode]')
348
+ let modeBadge
349
+ if (mode === 'openclaw') {
350
+ modeBadge = chalk.bold.rgb(255, 100, 50)(' [🦞 OpenClaw]')
351
+ } else if (mode === 'opencode-desktop') {
352
+ modeBadge = chalk.bold.rgb(0, 200, 255)(' [🖥 Desktop]')
353
+ } else {
354
+ modeBadge = chalk.bold.rgb(0, 200, 255)(' [💻 CLI]')
355
+ }
330
356
 
331
357
  // 📖 Column widths (generous spacing with margins)
332
358
  const W_RANK = 6
@@ -527,7 +553,9 @@ function renderTable(results, pendingPings, frame, cursor = null, sortColumn = '
527
553
  // 📖 Footer hints adapt based on active mode
528
554
  const actionHint = mode === 'openclaw'
529
555
  ? chalk.rgb(255, 100, 50)('Enter→SetOpenClaw')
530
- : chalk.rgb(0, 200, 255)('Enter→OpenCode')
556
+ : mode === 'opencode-desktop'
557
+ ? chalk.rgb(0, 200, 255)('Enter→OpenDesktop')
558
+ : chalk.rgb(0, 200, 255)('Enter→OpenCode')
531
559
  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
560
  lines.push('')
533
561
  lines.push(chalk.dim(' made with ') + '🩷' + chalk.dim(' by vava-nessa • ') + chalk.dim.underline('https://github.com/vava-nessa/free-coding-models'))
@@ -710,6 +738,74 @@ After installation, you can use: opencode --model nvidia/${model.modelId}`
710
738
  }
711
739
  }
712
740
 
741
+ // ─── Start OpenCode Desktop ─────────────────────────────────────────────────────
742
+ // 📖 startOpenCodeDesktop: Same config logic as startOpenCode, but opens the Desktop app.
743
+ // 📖 OpenCode Desktop (/Applications/OpenCode.app) shares config at ~/.config/opencode/opencode.json.
744
+ // 📖 No need to wait for exit — Desktop app stays open independently.
745
+ async function startOpenCodeDesktop(model) {
746
+ const hasNim = checkNvidiaNimConfig()
747
+
748
+ if (hasNim) {
749
+ console.log(chalk.green(` 🖥 Setting ${chalk.bold(model.label)} as default for OpenCode Desktop…`))
750
+ console.log(chalk.dim(` Model: nvidia/${model.modelId}`))
751
+ console.log()
752
+
753
+ const config = loadOpenCodeConfig()
754
+ const backupPath = `${OPENCODE_CONFIG}.backup-${Date.now()}`
755
+
756
+ if (existsSync(OPENCODE_CONFIG)) {
757
+ copyFileSync(OPENCODE_CONFIG, backupPath)
758
+ console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
759
+ }
760
+
761
+ config.model = `nvidia/${model.modelId}`
762
+
763
+ if (config.provider?.nvidia) {
764
+ if (!config.provider.nvidia.models) config.provider.nvidia.models = {}
765
+ config.provider.nvidia.models[model.modelId] = {
766
+ name: model.label,
767
+ }
768
+ }
769
+
770
+ saveOpenCodeConfig(config)
771
+
772
+ console.log(chalk.green(` ✓ Default model set to: nvidia/${model.modelId}`))
773
+ console.log()
774
+ console.log(chalk.dim(' Opening OpenCode Desktop…'))
775
+ console.log()
776
+
777
+ // 📖 Launch Desktop app — no need to wait, it stays open independently
778
+ const { exec } = await import('child_process')
779
+ exec('open -a OpenCode', (err) => {
780
+ if (err) {
781
+ console.error(chalk.red(' ✗ Could not open OpenCode Desktop — is it installed at /Applications/OpenCode.app?'))
782
+ }
783
+ })
784
+ } else {
785
+ console.log(chalk.yellow(' ⚠ NVIDIA NIM not configured in OpenCode'))
786
+ console.log(chalk.dim(' Please configure it first. Config is shared between CLI and Desktop.'))
787
+ console.log()
788
+ const installPrompt = `Add this to ~/.config/opencode/opencode.json:
789
+
790
+ {
791
+ "provider": {
792
+ "nvidia": {
793
+ "npm": "@ai-sdk/openai-compatible",
794
+ "name": "NVIDIA NIM",
795
+ "options": {
796
+ "baseURL": "https://integrate.api.nvidia.com/v1",
797
+ "apiKey": "{env:NVIDIA_API_KEY}"
798
+ }
799
+ }
800
+ }
801
+ }
802
+
803
+ Then set env var: export NVIDIA_API_KEY=your_key_here`
804
+ console.log(chalk.cyan(installPrompt))
805
+ console.log()
806
+ }
807
+ }
808
+
713
809
  // ─── OpenClaw integration ──────────────────────────────────────────────────────
714
810
  // 📖 OpenClaw config: ~/.openclaw/openclaw.json (JSON format, may be JSON5 in newer versions)
715
811
  // 📖 To set a model: set agents.defaults.model.primary = "nvidia/model-id"
@@ -892,7 +988,7 @@ async function main() {
892
988
  // 📖 Parse CLI arguments using shared parseArgs utility
893
989
  const parsed = parseArgs(process.argv)
894
990
  let apiKey = parsed.apiKey
895
- const { bestMode, fiableMode, openCodeMode, openClawMode, tierFilter } = parsed
991
+ const { bestMode, fiableMode, openCodeMode, openCodeDesktopMode, openClawMode, tierFilter } = parsed
896
992
 
897
993
  // 📖 Priority: CLI arg > env var > saved config > wizard
898
994
  if (!apiKey) {
@@ -925,6 +1021,8 @@ async function main() {
925
1021
  let mode
926
1022
  if (openClawMode) {
927
1023
  mode = 'openclaw'
1024
+ } else if (openCodeDesktopMode) {
1025
+ mode = 'opencode-desktop'
928
1026
  } else if (openCodeMode) {
929
1027
  mode = 'opencode'
930
1028
  } else {
@@ -934,11 +1032,19 @@ async function main() {
934
1032
 
935
1033
  // 📖 Handle "update now" selection from the menu
936
1034
  if (mode === 'update') {
937
- runUpdate()
1035
+ runUpdate(latestVersion)
1036
+ }
1037
+
1038
+ // 📖 Handle "Read Changelogs" selection — open GitHub releases in browser
1039
+ if (mode === 'changelogs') {
1040
+ const { exec } = await import('child_process')
1041
+ exec('open https://github.com/vava-nessa/free-coding-models/releases')
1042
+ console.log(chalk.dim(' 📋 Opening changelogs in browser…'))
1043
+ process.exit(0)
938
1044
  }
939
1045
 
940
1046
  // 📖 When using flags (--opencode/--openclaw), show update warning in terminal
941
- if (latestVersion && (openCodeMode || openClawMode)) {
1047
+ if (latestVersion && (openCodeMode || openCodeDesktopMode || openClawMode)) {
942
1048
  console.log(chalk.red(` ⚠ New version available (v${latestVersion}), please run npm i -g free-coding-models to install`))
943
1049
  console.log()
944
1050
  }
@@ -1079,6 +1185,8 @@ async function main() {
1079
1185
  // 📖 Dispatch to the correct integration based on active mode
1080
1186
  if (state.mode === 'openclaw') {
1081
1187
  await startOpenClaw(userSelected, apiKey)
1188
+ } else if (state.mode === 'opencode-desktop') {
1189
+ await startOpenCodeDesktop(userSelected)
1082
1190
  } else {
1083
1191
  await startOpenCode(userSelected)
1084
1192
  }
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.17",
3
+ "version": "0.1.19",
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",