free-coding-models 0.1.49 → 0.1.50

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.
@@ -810,88 +810,87 @@ function checkNvidiaNimConfig() {
810
810
  }
811
811
 
812
812
  // ─── Start OpenCode ────────────────────────────────────────────────────────────
813
- // 📖 Launches OpenCode with the selected NVIDIA NIM model
814
- // 📖 If NVIDIA NIM is configured, use --model flag, otherwise show install prompt
815
- // 📖 Model format: { modelId, label, tier }
813
+ // 📖 Launches OpenCode with the selected model.
814
+ // 📖 Handles all 3 providers: nvidia (needs custom provider config), groq & cerebras (built-in in OpenCode).
815
+ // 📖 For nvidia: checks if NIM is configured, sets provider.models entry, spawns with nvidia/model-id.
816
+ // 📖 For groq/cerebras: OpenCode has built-in support — just sets model in config and spawns.
817
+ // 📖 Model format: { modelId, label, tier, providerKey }
816
818
  async function startOpenCode(model) {
817
- const hasNim = checkNvidiaNimConfig()
819
+ const providerKey = model.providerKey ?? 'nvidia'
820
+ // 📖 Full model reference string used in OpenCode config and --model flag
821
+ const modelRef = `${providerKey}/${model.modelId}`
818
822
 
819
- if (hasNim) {
820
- // 📖 NVIDIA NIM already configured - launch with model flag
821
- console.log(chalk.green(` 🚀 Setting ${chalk.bold(model.label)} as default…`))
822
- console.log(chalk.dim(` Model: nvidia/${model.modelId}`))
823
- console.log()
823
+ if (providerKey === 'nvidia') {
824
+ // 📖 NVIDIA NIM needs a custom provider block in OpenCode config (not built-in)
825
+ const hasNim = checkNvidiaNimConfig()
824
826
 
825
- const config = loadOpenCodeConfig()
826
- const backupPath = `${getOpenCodeConfigPath()}.backup-${Date.now()}`
827
+ if (hasNim) {
828
+ console.log(chalk.green(` 🚀 Setting ${chalk.bold(model.label)} as default…`))
829
+ console.log(chalk.dim(` Model: ${modelRef}`))
830
+ console.log()
827
831
 
828
- // 📖 Backup current config
829
- if (existsSync(getOpenCodeConfigPath())) {
830
- copyFileSync(getOpenCodeConfigPath(), backupPath)
831
- console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
832
- }
832
+ const config = loadOpenCodeConfig()
833
+ const backupPath = `${getOpenCodeConfigPath()}.backup-${Date.now()}`
834
+
835
+ if (existsSync(getOpenCodeConfigPath())) {
836
+ copyFileSync(getOpenCodeConfigPath(), backupPath)
837
+ console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
838
+ }
833
839
 
834
- // 📖 Update default model to nvidia/model_id
835
- config.model = `nvidia/${model.modelId}`
840
+ config.model = modelRef
836
841
 
837
- // 📖 Register the model in the nvidia provider's models section
838
- // 📖 OpenCode requires models to be explicitly listed in provider.models
839
- // 📖 to recognize them — without this, it falls back to the previous default
840
- if (config.provider?.nvidia) {
841
- if (!config.provider.nvidia.models) config.provider.nvidia.models = {}
842
- config.provider.nvidia.models[model.modelId] = {
843
- name: model.label,
842
+ // 📖 Register the model in the nvidia provider's models section
843
+ // 📖 OpenCode requires models to be explicitly listed in provider.models
844
+ // 📖 to recognize them — without this, it falls back to the previous default
845
+ if (config.provider?.nvidia) {
846
+ if (!config.provider.nvidia.models) config.provider.nvidia.models = {}
847
+ config.provider.nvidia.models[model.modelId] = { name: model.label }
844
848
  }
845
- }
846
849
 
847
- saveOpenCodeConfig(config)
850
+ saveOpenCodeConfig(config)
848
851
 
849
- // 📖 Verify config was saved correctly
850
- const savedConfig = loadOpenCodeConfig()
851
- console.log(chalk.dim(` 📝 Config saved to: ${getOpenCodeConfigPath()}`))
852
- console.log(chalk.dim(` 📝 Default model in config: ${savedConfig.model || 'NOT SET'}`))
853
- console.log()
854
-
855
- if (savedConfig.model === config.model) {
856
- console.log(chalk.green(` ✓ Default model set to: nvidia/${model.modelId}`))
857
- } else {
858
- console.log(chalk.yellow(` ⚠ Config might not have been saved correctly`))
859
- }
860
- console.log()
861
- console.log(chalk.dim(' Starting OpenCode…'))
862
- console.log()
852
+ const savedConfig = loadOpenCodeConfig()
853
+ console.log(chalk.dim(` 📝 Config saved to: ${getOpenCodeConfigPath()}`))
854
+ console.log(chalk.dim(` 📝 Default model in config: ${savedConfig.model || 'NOT SET'}`))
855
+ console.log()
863
856
 
864
- // 📖 Launch OpenCode and wait for it
865
- // 📖 Use --model flag to ensure the model is selected
866
- const { spawn } = await import('child_process')
867
- const child = spawn('opencode', ['--model', `nvidia/${model.modelId}`], {
868
- stdio: 'inherit',
869
- shell: true,
870
- detached: false
871
- })
857
+ if (savedConfig.model === config.model) {
858
+ console.log(chalk.green(` ✓ Default model set to: ${modelRef}`))
859
+ } else {
860
+ console.log(chalk.yellow(` ⚠ Config might not have been saved correctly`))
861
+ }
862
+ console.log()
863
+ console.log(chalk.dim(' Starting OpenCode…'))
864
+ console.log()
872
865
 
873
- // 📖 Wait for OpenCode to exit
874
- await new Promise((resolve, reject) => {
875
- child.on('exit', resolve)
876
- child.on('error', (err) => {
877
- if (err.code === 'ENOENT') {
878
- console.error(chalk.red('\n ✗ Could not find "opencode" — is it installed and in your PATH?'))
879
- console.error(chalk.dim(' Install: npm i -g opencode or see https://opencode.ai'))
880
- resolve(1)
881
- } else {
882
- reject(err)
883
- }
866
+ const { spawn } = await import('child_process')
867
+ const child = spawn('opencode', ['--model', modelRef], {
868
+ stdio: 'inherit',
869
+ shell: true,
870
+ detached: false
884
871
  })
885
- })
886
- } else {
887
- // 📖 NVIDIA NIM not configured - show install prompt and launch
888
- console.log(chalk.yellow(' ⚠ NVIDIA NIM not configured in OpenCode'))
889
- console.log()
890
- console.log(chalk.dim(' Starting OpenCode with installation prompt…'))
891
- console.log()
892
872
 
893
- const configPath = getOpenCodeConfigPath()
894
- const installPrompt = `Please install NVIDIA NIM provider in OpenCode by adding this to ${configPath}:
873
+ await new Promise((resolve, reject) => {
874
+ child.on('exit', resolve)
875
+ child.on('error', (err) => {
876
+ if (err.code === 'ENOENT') {
877
+ console.error(chalk.red('\n ✗ Could not find "opencode" — is it installed and in your PATH?'))
878
+ console.error(chalk.dim(' Install: npm i -g opencode or see https://opencode.ai'))
879
+ resolve(1)
880
+ } else {
881
+ reject(err)
882
+ }
883
+ })
884
+ })
885
+ } else {
886
+ // 📖 NVIDIA NIM not configured — show install prompt
887
+ console.log(chalk.yellow(' ⚠ NVIDIA NIM not configured in OpenCode'))
888
+ console.log()
889
+ console.log(chalk.dim(' Starting OpenCode with installation prompt…'))
890
+ console.log()
891
+
892
+ const configPath = getOpenCodeConfigPath()
893
+ const installPrompt = `Please install NVIDIA NIM provider in OpenCode by adding this to ${configPath}:
895
894
 
896
895
  {
897
896
  "provider": {
@@ -908,21 +907,73 @@ async function startOpenCode(model) {
908
907
 
909
908
  ${isWindows ? 'set NVIDIA_API_KEY=your_key_here' : 'export NVIDIA_API_KEY=your_key_here'}
910
909
 
911
- After installation, you can use: opencode --model nvidia/${model.modelId}`
910
+ After installation, you can use: opencode --model ${modelRef}`
911
+
912
+ console.log(chalk.cyan(installPrompt))
913
+ console.log()
914
+ console.log(chalk.dim(' Starting OpenCode…'))
915
+ console.log()
916
+
917
+ const { spawn } = await import('child_process')
918
+ const child = spawn('opencode', [], {
919
+ stdio: 'inherit',
920
+ shell: true,
921
+ detached: false
922
+ })
912
923
 
913
- console.log(chalk.cyan(installPrompt))
924
+ await new Promise((resolve, reject) => {
925
+ child.on('exit', resolve)
926
+ child.on('error', (err) => {
927
+ if (err.code === 'ENOENT') {
928
+ console.error(chalk.red('\n ✗ Could not find "opencode" — is it installed and in your PATH?'))
929
+ console.error(chalk.dim(' Install: npm i -g opencode or see https://opencode.ai'))
930
+ resolve(1)
931
+ } else {
932
+ reject(err)
933
+ }
934
+ })
935
+ })
936
+ }
937
+ } else {
938
+ // 📖 Groq and Cerebras are built-in OpenCode providers — no custom provider config needed.
939
+ // 📖 OpenCode discovers them via GROQ_API_KEY / CEREBRAS_API_KEY env vars automatically.
940
+ // 📖 Just set the model in config and launch with --model groq/model-id.
941
+ console.log(chalk.green(` 🚀 Setting ${chalk.bold(model.label)} as default…`))
942
+ console.log(chalk.dim(` Model: ${modelRef}`))
943
+ console.log()
944
+
945
+ const config = loadOpenCodeConfig()
946
+ const backupPath = `${getOpenCodeConfigPath()}.backup-${Date.now()}`
947
+
948
+ if (existsSync(getOpenCodeConfigPath())) {
949
+ copyFileSync(getOpenCodeConfigPath(), backupPath)
950
+ console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
951
+ }
952
+
953
+ config.model = modelRef
954
+ saveOpenCodeConfig(config)
955
+
956
+ const savedConfig = loadOpenCodeConfig()
957
+ console.log(chalk.dim(` 📝 Config saved to: ${getOpenCodeConfigPath()}`))
958
+ console.log(chalk.dim(` 📝 Default model in config: ${savedConfig.model || 'NOT SET'}`))
959
+ console.log()
960
+
961
+ if (savedConfig.model === config.model) {
962
+ console.log(chalk.green(` ✓ Default model set to: ${modelRef}`))
963
+ } else {
964
+ console.log(chalk.yellow(` ⚠ Config might not have been saved correctly`))
965
+ }
914
966
  console.log()
915
967
  console.log(chalk.dim(' Starting OpenCode…'))
916
968
  console.log()
917
969
 
918
970
  const { spawn } = await import('child_process')
919
- const child = spawn('opencode', [], {
971
+ const child = spawn('opencode', ['--model', modelRef], {
920
972
  stdio: 'inherit',
921
973
  shell: true,
922
974
  detached: false
923
975
  })
924
976
 
925
- // 📖 Wait for OpenCode to exit
926
977
  await new Promise((resolve, reject) => {
927
978
  child.on('exit', resolve)
928
979
  child.on('error', (err) => {
@@ -941,67 +992,25 @@ After installation, you can use: opencode --model nvidia/${model.modelId}`
941
992
  // ─── Start OpenCode Desktop ─────────────────────────────────────────────────────
942
993
  // 📖 startOpenCodeDesktop: Same config logic as startOpenCode, but opens the Desktop app.
943
994
  // 📖 OpenCode Desktop shares config at the same location as CLI.
995
+ // 📖 Handles all 3 providers: nvidia (needs custom provider config), groq & cerebras (built-in).
944
996
  // 📖 No need to wait for exit — Desktop app stays open independently.
945
997
  async function startOpenCodeDesktop(model) {
946
- const hasNim = checkNvidiaNimConfig()
947
-
948
- if (hasNim) {
949
- console.log(chalk.green(` 🖥 Setting ${chalk.bold(model.label)} as default for OpenCode Desktop…`))
950
- console.log(chalk.dim(` Model: nvidia/${model.modelId}`))
951
- console.log()
952
-
953
- const config = loadOpenCodeConfig()
954
- const backupPath = `${getOpenCodeConfigPath()}.backup-${Date.now()}`
955
-
956
- if (existsSync(getOpenCodeConfigPath())) {
957
- copyFileSync(getOpenCodeConfigPath(), backupPath)
958
- console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
959
- }
960
-
961
- config.model = `nvidia/${model.modelId}`
962
-
963
- if (config.provider?.nvidia) {
964
- if (!config.provider.nvidia.models) config.provider.nvidia.models = {}
965
- config.provider.nvidia.models[model.modelId] = {
966
- name: model.label,
967
- }
968
- }
998
+ const providerKey = model.providerKey ?? 'nvidia'
999
+ // 📖 Full model reference string used in OpenCode config and --model flag
1000
+ const modelRef = `${providerKey}/${model.modelId}`
969
1001
 
970
- saveOpenCodeConfig(config)
971
-
972
- // 📖 Verify config was saved correctly
973
- const savedConfig = loadOpenCodeConfig()
974
- console.log(chalk.dim(` 📝 Config saved to: ${getOpenCodeConfigPath()}`))
975
- console.log(chalk.dim(` 📝 Default model in config: ${savedConfig.model || 'NOT SET'}`))
976
- console.log()
977
-
978
- if (savedConfig.model === config.model) {
979
- console.log(chalk.green(` ✓ Default model set to: nvidia/${model.modelId}`))
980
- } else {
981
- console.log(chalk.yellow(` ⚠ Config might not have been saved correctly`))
982
- }
983
- console.log()
984
- console.log(chalk.dim(' Opening OpenCode Desktop…'))
985
- console.log()
986
-
987
- // 📖 Launch Desktop app based on platform
1002
+ // 📖 Helper to open the Desktop app based on platform
1003
+ const launchDesktop = async () => {
988
1004
  const { exec } = await import('child_process')
989
-
990
1005
  let command
991
1006
  if (isMac) {
992
1007
  command = 'open -a OpenCode'
993
1008
  } else if (isWindows) {
994
- // 📖 On Windows, try common installation paths
995
- // 📖 User installation: %LOCALAPPDATA%\Programs\OpenCode\OpenCode.exe
996
- // 📖 System installation: C:\Program Files\OpenCode\OpenCode.exe
997
1009
  command = 'start "" "%LOCALAPPDATA%\\Programs\\OpenCode\\OpenCode.exe" 2>nul || start "" "%PROGRAMFILES%\\OpenCode\\OpenCode.exe" 2>nul || start OpenCode'
998
1010
  } else if (isLinux) {
999
- // 📖 On Linux, try different methods with model flag
1000
- // 📖 Check if opencode-desktop exists, otherwise try xdg-open
1001
- command = `opencode-desktop --model nvidia/${model.modelId} 2>/dev/null || flatpak run ai.opencode.OpenCode --model nvidia/${model.modelId} 2>/dev/null || snap run opencode --model nvidia/${model.modelId} 2>/dev/null || xdg-open /usr/share/applications/opencode.desktop 2>/dev/null || echo "OpenCode not found"`
1011
+ command = `opencode-desktop --model ${modelRef} 2>/dev/null || flatpak run ai.opencode.OpenCode --model ${modelRef} 2>/dev/null || snap run opencode --model ${modelRef} 2>/dev/null || xdg-open /usr/share/applications/opencode.desktop 2>/dev/null || echo "OpenCode not found"`
1002
1012
  }
1003
-
1004
- exec(command, (err, stdout, stderr) => {
1013
+ exec(command, (err) => {
1005
1014
  if (err) {
1006
1015
  console.error(chalk.red(' ✗ Could not open OpenCode Desktop'))
1007
1016
  if (isWindows) {
@@ -1014,13 +1023,56 @@ async function startOpenCodeDesktop(model) {
1014
1023
  }
1015
1024
  }
1016
1025
  })
1017
- } else {
1018
- console.log(chalk.yellow(' ⚠ NVIDIA NIM not configured in OpenCode'))
1019
- console.log(chalk.dim(' Please configure it first. Config is shared between CLI and Desktop.'))
1020
- console.log()
1021
-
1022
- const configPath = getOpenCodeConfigPath()
1023
- const installPrompt = `Add this to ${configPath}:
1026
+ }
1027
+
1028
+ if (providerKey === 'nvidia') {
1029
+ // 📖 NVIDIA NIM needs a custom provider block in OpenCode config (not built-in)
1030
+ const hasNim = checkNvidiaNimConfig()
1031
+
1032
+ if (hasNim) {
1033
+ console.log(chalk.green(` 🖥 Setting ${chalk.bold(model.label)} as default for OpenCode Desktop…`))
1034
+ console.log(chalk.dim(` Model: ${modelRef}`))
1035
+ console.log()
1036
+
1037
+ const config = loadOpenCodeConfig()
1038
+ const backupPath = `${getOpenCodeConfigPath()}.backup-${Date.now()}`
1039
+
1040
+ if (existsSync(getOpenCodeConfigPath())) {
1041
+ copyFileSync(getOpenCodeConfigPath(), backupPath)
1042
+ console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
1043
+ }
1044
+
1045
+ config.model = modelRef
1046
+
1047
+ if (config.provider?.nvidia) {
1048
+ if (!config.provider.nvidia.models) config.provider.nvidia.models = {}
1049
+ config.provider.nvidia.models[model.modelId] = { name: model.label }
1050
+ }
1051
+
1052
+ saveOpenCodeConfig(config)
1053
+
1054
+ const savedConfig = loadOpenCodeConfig()
1055
+ console.log(chalk.dim(` 📝 Config saved to: ${getOpenCodeConfigPath()}`))
1056
+ console.log(chalk.dim(` 📝 Default model in config: ${savedConfig.model || 'NOT SET'}`))
1057
+ console.log()
1058
+
1059
+ if (savedConfig.model === config.model) {
1060
+ console.log(chalk.green(` ✓ Default model set to: ${modelRef}`))
1061
+ } else {
1062
+ console.log(chalk.yellow(` ⚠ Config might not have been saved correctly`))
1063
+ }
1064
+ console.log()
1065
+ console.log(chalk.dim(' Opening OpenCode Desktop…'))
1066
+ console.log()
1067
+
1068
+ await launchDesktop()
1069
+ } else {
1070
+ console.log(chalk.yellow(' ⚠ NVIDIA NIM not configured in OpenCode'))
1071
+ console.log(chalk.dim(' Please configure it first. Config is shared between CLI and Desktop.'))
1072
+ console.log()
1073
+
1074
+ const configPath = getOpenCodeConfigPath()
1075
+ const installPrompt = `Add this to ${configPath}:
1024
1076
 
1025
1077
  {
1026
1078
  "provider": {
@@ -1036,8 +1088,41 @@ async function startOpenCodeDesktop(model) {
1036
1088
  }
1037
1089
 
1038
1090
  ${isWindows ? 'set NVIDIA_API_KEY=your_key_here' : 'export NVIDIA_API_KEY=your_key_here'}`
1039
- console.log(chalk.cyan(installPrompt))
1091
+ console.log(chalk.cyan(installPrompt))
1092
+ console.log()
1093
+ }
1094
+ } else {
1095
+ // 📖 Groq and Cerebras are built-in OpenCode providers — just set model and open Desktop.
1096
+ console.log(chalk.green(` 🖥 Setting ${chalk.bold(model.label)} as default for OpenCode Desktop…`))
1097
+ console.log(chalk.dim(` Model: ${modelRef}`))
1040
1098
  console.log()
1099
+
1100
+ const config = loadOpenCodeConfig()
1101
+ const backupPath = `${getOpenCodeConfigPath()}.backup-${Date.now()}`
1102
+
1103
+ if (existsSync(getOpenCodeConfigPath())) {
1104
+ copyFileSync(getOpenCodeConfigPath(), backupPath)
1105
+ console.log(chalk.dim(` 💾 Backup: ${backupPath}`))
1106
+ }
1107
+
1108
+ config.model = modelRef
1109
+ saveOpenCodeConfig(config)
1110
+
1111
+ const savedConfig = loadOpenCodeConfig()
1112
+ console.log(chalk.dim(` 📝 Config saved to: ${getOpenCodeConfigPath()}`))
1113
+ console.log(chalk.dim(` 📝 Default model in config: ${savedConfig.model || 'NOT SET'}`))
1114
+ console.log()
1115
+
1116
+ if (savedConfig.model === config.model) {
1117
+ console.log(chalk.green(` ✓ Default model set to: ${modelRef}`))
1118
+ } else {
1119
+ console.log(chalk.yellow(` ⚠ Config might not have been saved correctly`))
1120
+ }
1121
+ console.log()
1122
+ console.log(chalk.dim(' Opening OpenCode Desktop…'))
1123
+ console.log()
1124
+
1125
+ await launchDesktop()
1041
1126
  }
1042
1127
  }
1043
1128
 
@@ -1673,7 +1758,7 @@ async function main() {
1673
1758
  const sorted = sortResults(results, state.sortColumn, state.sortDirection)
1674
1759
  const selected = sorted[state.cursor]
1675
1760
  // 📖 Allow selecting ANY model (even timeout/down) - user knows what they're doing
1676
- userSelected = { modelId: selected.modelId, label: selected.label, tier: selected.tier }
1761
+ userSelected = { modelId: selected.modelId, label: selected.label, tier: selected.tier, providerKey: selected.providerKey }
1677
1762
 
1678
1763
  // 📖 Stop everything and act on selection immediately
1679
1764
  clearInterval(ticker)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-coding-models",
3
- "version": "0.1.49",
3
+ "version": "0.1.50",
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",