free-coding-models 0.1.78 โ 0.1.79
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 +61 -64
- package/bin/free-coding-models.js +18 -178
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/sources.js +25 -0
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
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-
|
|
6
|
-
<img src="https://img.shields.io/badge/providers-
|
|
5
|
+
<img src="https://img.shields.io/badge/models-158-76b900?logo=nvidia" alt="models count">
|
|
6
|
+
<img src="https://img.shields.io/badge/providers-20-blue" alt="providers count">
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<h1 align="center">free-coding-models</h1>
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
## โจ Features
|
|
65
65
|
|
|
66
66
|
- **๐ฏ Coding-focused** โ Only LLM models optimized for code generation, not chat or vision
|
|
67
|
-
- **๐ Multi-provider** โ Models from NVIDIA NIM, Groq, Cerebras, SambaNova, OpenRouter, Hugging Face Inference, Replicate, DeepInfra, Fireworks AI, Codestral, Hyperbolic, Scaleway, Google AI, SiliconFlow, Together AI, Cloudflare Workers AI, Perplexity API, and ZAI
|
|
67
|
+
- **๐ Multi-provider** โ Models from NVIDIA NIM, Groq, Cerebras, SambaNova, OpenRouter, Hugging Face Inference, Replicate, DeepInfra, Fireworks AI, Codestral, Hyperbolic, Scaleway, Google AI, SiliconFlow, Together AI, Cloudflare Workers AI, Perplexity API, Alibaba Cloud (DashScope), and ZAI
|
|
68
68
|
- **โ๏ธ Settings screen** โ Press `P` to manage provider API keys, enable/disable providers, test keys live, and manually check/install updates
|
|
69
69
|
- **๐ Parallel pings** โ All models tested simultaneously via native `fetch`
|
|
70
70
|
- **๐ Real-time animation** โ Watch latency appear live in alternate screen buffer
|
|
@@ -80,12 +80,11 @@
|
|
|
80
80
|
- **๐ฆ OpenClaw integration** โ Sets selected model as default provider in `~/.openclaw/openclaw.json`
|
|
81
81
|
- **๐ Feature Request (J key)** โ Send anonymous feedback directly to the project team via a full-screen overlay with multi-line input (includes anonymous OS/terminal metadata in message footer only)
|
|
82
82
|
- **๐ Bug Report (I key)** โ Send anonymous bug reports directly to the project team via a full-screen overlay with multi-line input (includes anonymous OS/terminal metadata in message footer only)
|
|
83
|
-
- **๐จ Clean output** โ Zero scrollback pollution, interface stays open until Ctrl+C
|
|
84
|
-
- **๐ถ Status indicators** โ UP โ
ยท No Key ๐ ยท Timeout โณ ยท Overloaded ๐ฅ ยท Not Found ๐ซ
|
|
85
|
-
- **๐ Keyless latency** โ Models are pinged even without an API key โ a `๐ NO KEY` status confirms the server is reachable with real latency shown, so you can compare providers before committing to a key
|
|
86
|
-
- **๐ท Tier filtering** โ Filter models by tier letter (S, A, B, C) with `--tier` flag or dynamically with `T` key
|
|
87
|
-
- **โญ Persistent favorites** โ Press `F` on a selected row to pin/unpin it; favorites stay at top with a dark orange background and a star before the model name
|
|
88
|
-
- **๐ Privacy-first analytics (optional)** โ anonymous PostHog events with explicit consent + opt-out
|
|
83
|
+
- **๐จ Clean output** โ Zero scrollback pollution, interface stays open until Ctrl+C
|
|
84
|
+
- **๐ถ Status indicators** โ UP โ
ยท No Key ๐ ยท Timeout โณ ยท Overloaded ๐ฅ ยท Not Found ๐ซ
|
|
85
|
+
- **๐ Keyless latency** โ Models are pinged even without an API key โ a `๐ NO KEY` status confirms the server is reachable with real latency shown, so you can compare providers before committing to a key
|
|
86
|
+
- **๐ท Tier filtering** โ Filter models by tier letter (S, A, B, C) with `--tier` flag or dynamically with `T` key
|
|
87
|
+
- **โญ Persistent favorites** โ Press `F` on a selected row to pin/unpin it; favorites stay at top with a dark orange background and a star before the model name
|
|
89
88
|
|
|
90
89
|
---
|
|
91
90
|
|
|
@@ -158,13 +157,10 @@ free-coding-models --openclaw
|
|
|
158
157
|
# Show only top-tier models (A+, S, S+)
|
|
159
158
|
free-coding-models --best
|
|
160
159
|
|
|
161
|
-
# Analyze for 10 seconds and output the most reliable model
|
|
162
|
-
free-coding-models --fiable
|
|
160
|
+
# Analyze for 10 seconds and output the most reliable model
|
|
161
|
+
free-coding-models --fiable
|
|
163
162
|
|
|
164
|
-
#
|
|
165
|
-
free-coding-models --no-telemetry
|
|
166
|
-
|
|
167
|
-
# Filter models by tier letter
|
|
163
|
+
# Filter models by tier letter
|
|
168
164
|
free-coding-models --tier S # S+ and S only
|
|
169
165
|
free-coding-models --tier A # A+, A, A- only
|
|
170
166
|
free-coding-models --tier B # B+, B only
|
|
@@ -263,11 +259,10 @@ Press **`P`** to open the Settings screen at any time:
|
|
|
263
259
|
- **U** โ manually check npm for a newer version
|
|
264
260
|
- **Esc** โ close settings and reload models list
|
|
265
261
|
|
|
266
|
-
Keys are saved to `~/.free-coding-models.json` (permissions `0600`).
|
|
262
|
+
Keys are saved to `~/.free-coding-models.json` (permissions `0600`).
|
|
267
263
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
Favorites are also persisted in the same config file and survive restarts.
|
|
264
|
+
Manual update is in the same Settings screen (`P`) under **Maintenance** (Enter to check, Enter again to install when an update is available).
|
|
265
|
+
Favorites are also persisted in the same config file and survive restarts.
|
|
271
266
|
|
|
272
267
|
### Environment variable overrides
|
|
273
268
|
|
|
@@ -284,23 +279,13 @@ DEEPINFRA_API_KEY=di_xxx free-coding-models
|
|
|
284
279
|
FIREWORKS_API_KEY=fw_xxx free-coding-models
|
|
285
280
|
SILICONFLOW_API_KEY=sk_xxx free-coding-models
|
|
286
281
|
TOGETHER_API_KEY=together_xxx free-coding-models
|
|
287
|
-
CLOUDFLARE_API_TOKEN=cf_xxx CLOUDFLARE_ACCOUNT_ID=your_account_id free-coding-models
|
|
288
|
-
PERPLEXITY_API_KEY=pplx_xxx free-coding-models
|
|
289
|
-
ZAI_API_KEY=zai-xxx free-coding-models
|
|
290
|
-
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Telemetry env vars:
|
|
294
|
-
|
|
295
|
-
- `FREE_CODING_MODELS_TELEMETRY=0|1` โ force disable/enable analytics
|
|
296
|
-
- `FREE_CODING_MODELS_POSTHOG_KEY` โ PostHog project API key (required to send events)
|
|
297
|
-
- `FREE_CODING_MODELS_POSTHOG_HOST` โ optional ingest host (`https://eu.i.posthog.com` default)
|
|
298
|
-
- `FREE_CODING_MODELS_TELEMETRY_DEBUG=1` โ optional stderr debug logs for telemetry troubleshooting
|
|
299
|
-
|
|
300
|
-
On first run (or when consent policy changes), the CLI asks users to accept or decline anonymous analytics.
|
|
301
|
-
When enabled, telemetry events include: event name, app version, selected mode, system (`macOS`/`Windows`/`Linux`), and terminal family (`Terminal.app`, `iTerm2`, `kitty`, `Warp`, `WezTerm`, etc., with generic fallback from `TERM_PROGRAM`/`TERM`).
|
|
282
|
+
CLOUDFLARE_API_TOKEN=cf_xxx CLOUDFLARE_ACCOUNT_ID=your_account_id free-coding-models
|
|
283
|
+
PERPLEXITY_API_KEY=pplx_xxx free-coding-models
|
|
284
|
+
ZAI_API_KEY=zai-xxx free-coding-models
|
|
285
|
+
DASHSCOPE_API_KEY=sk-xxx free-coding-models
|
|
286
|
+
```
|
|
302
287
|
|
|
303
|
-
### Get your free API keys
|
|
288
|
+
### Get your free API keys
|
|
304
289
|
|
|
305
290
|
**NVIDIA NIM** (44 models, S+ โ C tier):
|
|
306
291
|
1. Sign up at [build.nvidia.com](https://build.nvidia.com)
|
|
@@ -369,6 +354,11 @@ When enabled, telemetry events include: event name, app version, selected mode,
|
|
|
369
354
|
1. Sign up at [perplexity.ai/settings/api](https://www.perplexity.ai/settings/api)
|
|
370
355
|
2. Create API key (`PERPLEXITY_API_KEY`)
|
|
371
356
|
|
|
357
|
+
**Alibaba Cloud (DashScope)** (8 models, Qwen3-Coder family):
|
|
358
|
+
1. Sign up at [dashscope.console.alibabacloud.com](https://dashscope.console.alibabacloud.com)
|
|
359
|
+
2. Activate Model Studio (1M free tokens per model, Singapore region, 90 days)
|
|
360
|
+
3. Create API key (`DASHSCOPE_API_KEY`)
|
|
361
|
+
|
|
372
362
|
**ZAI** (5 models, GLM family):
|
|
373
363
|
1. Sign up at [z.ai](https://z.ai)
|
|
374
364
|
2. Subscribe to Coding Plan
|
|
@@ -380,7 +370,16 @@ When enabled, telemetry events include: event name, app version, selected mode,
|
|
|
380
370
|
|
|
381
371
|
## ๐ค Coding Models
|
|
382
372
|
|
|
383
|
-
**
|
|
373
|
+
**158 coding models** across 20 providers and 8 tiers, ranked by [SWE-bench Verified](https://www.swebench.com) โ the industry-standard benchmark measuring real GitHub issue resolution. Scores are self-reported by providers unless noted.
|
|
374
|
+
|
|
375
|
+
### Alibaba Cloud (DashScope) (8 models)
|
|
376
|
+
|
|
377
|
+
| Tier | SWE-bench | Model |
|
|
378
|
+
|------|-----------|-------|
|
|
379
|
+
| **S+** โฅ70% | Qwen3 Coder Plus (69.6%), Qwen3 Coder 480B (70.6%) |
|
|
380
|
+
| **S** 60โ70% | Qwen3 Coder Max (67.0%), Qwen3 Coder Next (65.0%), Qwen3 235B (70.0%), Qwen3 80B Instruct (65.0%) |
|
|
381
|
+
| **A+** 50โ60% | Qwen3 32B (50.0%) |
|
|
382
|
+
| **A** 40โ50% | Qwen2.5 Coder 32B (46.0%) |
|
|
384
383
|
|
|
385
384
|
### ZAI Coding Plan (5 models)
|
|
386
385
|
|
|
@@ -757,12 +756,10 @@ This script:
|
|
|
757
756
|
| `SILICONFLOW_API_KEY` | SiliconFlow key |
|
|
758
757
|
| `TOGETHER_API_KEY` | Together AI key |
|
|
759
758
|
| `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_API_KEY` | Cloudflare Workers AI token/key |
|
|
760
|
-
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID (required for Workers AI endpoint URL) |
|
|
761
|
-
| `PERPLEXITY_API_KEY` / `PPLX_API_KEY` | Perplexity API key |
|
|
762
|
-
| `ZAI_API_KEY` | ZAI key |
|
|
763
|
-
| `
|
|
764
|
-
| `FREE_CODING_MODELS_POSTHOG_KEY` | PostHog project API key used for anonymous event capture |
|
|
765
|
-
| `FREE_CODING_MODELS_POSTHOG_HOST` | Optional PostHog ingest host (`https://eu.i.posthog.com` default) |
|
|
759
|
+
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare account ID (required for Workers AI endpoint URL) |
|
|
760
|
+
| `PERPLEXITY_API_KEY` / `PPLX_API_KEY` | Perplexity API key |
|
|
761
|
+
| `ZAI_API_KEY` | ZAI key |
|
|
762
|
+
| `DASHSCOPE_API_KEY` | Alibaba Cloud (DashScope) API key |
|
|
766
763
|
|
|
767
764
|
**Config file:** `~/.free-coding-models.json` (created automatically, permissions `0600`)
|
|
768
765
|
|
|
@@ -795,16 +792,11 @@ This script:
|
|
|
795
792
|
"cloudflare": { "enabled": true },
|
|
796
793
|
"perplexity": { "enabled": true },
|
|
797
794
|
"zai": { "enabled": true }
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
"enabled": true,
|
|
804
|
-
"consentVersion": 1,
|
|
805
|
-
"anonymousId": "anon_550e8400-e29b-41d4-a716-446655440000"
|
|
806
|
-
}
|
|
807
|
-
}
|
|
795
|
+
},
|
|
796
|
+
"favorites": [
|
|
797
|
+
"nvidia/deepseek-ai/deepseek-v3.2"
|
|
798
|
+
]
|
|
799
|
+
}
|
|
808
800
|
```
|
|
809
801
|
|
|
810
802
|
**Configuration:**
|
|
@@ -818,12 +810,11 @@ This script:
|
|
|
818
810
|
|------|-------------|
|
|
819
811
|
| *(none)* | Show startup menu to choose OpenCode or OpenClaw |
|
|
820
812
|
| `--opencode` | OpenCode CLI mode โ Enter launches OpenCode CLI with selected model |
|
|
821
|
-
| `--opencode-desktop` | OpenCode Desktop mode โ Enter sets model & opens OpenCode Desktop app |
|
|
822
|
-
| `--openclaw` | OpenClaw mode โ Enter sets selected model as default in OpenClaw |
|
|
823
|
-
| `--best` | Show only top-tier models (A+, S, S+) |
|
|
824
|
-
| `--fiable` | Analyze 10 seconds, output the most reliable model as `provider/model_id` |
|
|
825
|
-
| `--
|
|
826
|
-
| `--tier S` | Show only S+ and S tier models |
|
|
813
|
+
| `--opencode-desktop` | OpenCode Desktop mode โ Enter sets model & opens OpenCode Desktop app |
|
|
814
|
+
| `--openclaw` | OpenClaw mode โ Enter sets selected model as default in OpenClaw |
|
|
815
|
+
| `--best` | Show only top-tier models (A+, S, S+) |
|
|
816
|
+
| `--fiable` | Analyze 10 seconds, output the most reliable model as `provider/model_id` |
|
|
817
|
+
| `--tier S` | Show only S+ and S tier models |
|
|
827
818
|
| `--tier A` | Show only A+, A, A- tier models |
|
|
828
819
|
| `--tier B` | Show only B+, B tier models |
|
|
829
820
|
| `--tier C` | Show only C tier models |
|
|
@@ -837,7 +828,7 @@ This script:
|
|
|
837
828
|
- **F** โ Toggle favorite on selected model (โญ in Model column, pinned at top)
|
|
838
829
|
- **T** โ Cycle tier filter (All โ S+ โ S โ A+ โ A โ A- โ B+ โ B โ C โ All)
|
|
839
830
|
- **Z** โ Cycle mode (OpenCode CLI โ OpenCode Desktop โ OpenClaw)
|
|
840
|
-
- **P** โ Open Settings (manage API keys, provider toggles,
|
|
831
|
+
- **P** โ Open Settings (manage API keys, provider toggles, manual update, profiles)
|
|
841
832
|
- **Shift+P** โ Cycle through saved profiles (switches live TUI settings)
|
|
842
833
|
- **Shift+S** โ Save current TUI settings as a named profile (inline prompt)
|
|
843
834
|
- **Q** โ Open Smart Recommend overlay (find the best model for your task)
|
|
@@ -850,10 +841,10 @@ This script:
|
|
|
850
841
|
|
|
851
842
|
Pressing **K** now shows a full in-app reference: main hotkeys, settings hotkeys, and CLI flags with usage examples.
|
|
852
843
|
|
|
853
|
-
**Keyboard shortcuts (Settings screen โ `P` key):**
|
|
854
|
-
- **โโ** โ Navigate providers,
|
|
855
|
-
- **Enter** โ Edit API key inline,
|
|
856
|
-
- **Space** โ Toggle provider enabled/disabled
|
|
844
|
+
**Keyboard shortcuts (Settings screen โ `P` key):**
|
|
845
|
+
- **โโ** โ Navigate providers, maintenance row, and profile rows
|
|
846
|
+
- **Enter** โ Edit API key inline, check/install update, or load a profile
|
|
847
|
+
- **Space** โ Toggle provider enabled/disabled
|
|
857
848
|
- **T** โ Test current provider's API key (fires a live ping)
|
|
858
849
|
- **U** โ Check for updates manually from settings
|
|
859
850
|
- **Backspace** โ Delete the selected profile (only on profile rows)
|
|
@@ -943,4 +934,10 @@ We welcome contributions! Feel free to open issues, submit pull requests, or get
|
|
|
943
934
|
|
|
944
935
|
For questions or issues, open a [GitHub issue](https://github.com/vava-nessa/free-coding-models/issues).
|
|
945
936
|
|
|
946
|
-
๐ฌ Let's talk about the project on Discord: https://discord.gg/5MbTnDC3Md
|
|
937
|
+
๐ฌ Let's talk about the project on Discord: https://discord.gg/5MbTnDC3Md
|
|
938
|
+
|
|
939
|
+
---
|
|
940
|
+
|
|
941
|
+
<p align="center">
|
|
942
|
+
<sub>We collect anonymous usage data to improve the tool and fix bugs. No personal information is ever collected.</sub>
|
|
943
|
+
</p>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* - Automatic config detection and model setup for both tools
|
|
21
21
|
* - JSON config stored in ~/.free-coding-models.json (auto-migrates from old plain-text)
|
|
22
22
|
* - Multi-provider support via sources.js (NIM/Groq/Cerebras/OpenRouter/Hugging Face/Replicate/DeepInfra/... โ extensible)
|
|
23
|
-
* - Settings screen (P key) to manage API keys, provider toggles,
|
|
23
|
+
* - Settings screen (P key) to manage API keys, provider toggles, and manual updates
|
|
24
24
|
* - Favorites system: toggle with F, pin rows to top, persist between sessions
|
|
25
25
|
* - Uptime percentage tracking (successful pings / total pings)
|
|
26
26
|
* - Sortable columns (R/Y/O/M/L/A/S/N/H/V/B/U keys)
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
*
|
|
29
29
|
* โ Functions:
|
|
30
30
|
* - `loadConfig` / `saveConfig` / `getApiKey`: Multi-provider JSON config via lib/config.js
|
|
31
|
-
* - `promptTelemetryConsent`: First-run consent flow for anonymous analytics
|
|
32
31
|
* - `getTelemetryDistinctId`: Generate/reuse a stable anonymous ID for telemetry
|
|
33
32
|
* - `getTelemetryTerminal`: Infer terminal family (Terminal.app, iTerm2, kitty, etc.)
|
|
34
33
|
* - `isTelemetryDebugEnabled` / `telemetryDebug`: Optional runtime telemetry diagnostics via env
|
|
@@ -105,20 +104,9 @@ const readline = require('readline')
|
|
|
105
104
|
// โโโ Version check โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
106
105
|
const pkg = require('../package.json')
|
|
107
106
|
const LOCAL_VERSION = pkg.version
|
|
108
|
-
const TELEMETRY_CONSENT_VERSION = 1
|
|
109
107
|
const TELEMETRY_TIMEOUT = 1_200
|
|
110
108
|
const POSTHOG_CAPTURE_PATH = '/i/v0/e/'
|
|
111
109
|
const POSTHOG_DEFAULT_HOST = 'https://eu.i.posthog.com'
|
|
112
|
-
// ๐ Consent ASCII banner shown before telemetry choice to make first-run intent explicit.
|
|
113
|
-
const TELEMETRY_CONSENT_ASCII = [
|
|
114
|
-
'โโโโโโโ โโโโโโ โโโโโโโ โโโโโโโ โโโโโโ โโโโโโ โโโโโโ โโ โโโ โโ โโโโโโ โโโ โโโ โโโโโโ โโโโโโ โโโโโโโ โโ โโโโโโโ',
|
|
115
|
-
'โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโโโ โโ โโ โโโโ โโโโ โโ โโ โโ โโ โโ โโ โโ',
|
|
116
|
-
'โโโโโ โโโโโโ โโโโโ โโโโโ โโโโโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโโ โโโโโ โโ โโโโ โโ โโ โโ โโ โโ โโโโโ โโ โโโโโโโ',
|
|
117
|
-
'โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ โโ',
|
|
118
|
-
'โโ โโ โโ โโโโโโโ โโโโโโโ โโโโโโ โโโโโโ โโโโโโ โโ โโ โโโโ โโโโโโ โโ โโ โโโโโโ โโโโโโ โโโโโโโ โโโโโโโ โโโโโโโ',
|
|
119
|
-
'',
|
|
120
|
-
'',
|
|
121
|
-
]
|
|
122
110
|
// ๐ Maintainer defaults for global npm telemetry (safe to publish: project key is a public ingest token).
|
|
123
111
|
const POSTHOG_PROJECT_KEY_DEFAULT = 'phc_5P1n8HaLof6nHM0tKJYt4bV5pj2XPb272fLVigwf1YQ'
|
|
124
112
|
const POSTHOG_HOST_DEFAULT = 'https://eu.i.posthog.com'
|
|
@@ -252,10 +240,10 @@ function telemetryDebug(message, meta = null) {
|
|
|
252
240
|
// ๐ Ensure telemetry config shape exists even on old config files.
|
|
253
241
|
function ensureTelemetryConfig(config) {
|
|
254
242
|
if (!config.telemetry || typeof config.telemetry !== 'object') {
|
|
255
|
-
config.telemetry = { enabled:
|
|
243
|
+
config.telemetry = { enabled: true, anonymousId: null }
|
|
256
244
|
}
|
|
257
|
-
|
|
258
|
-
|
|
245
|
+
// ๐ Always force telemetry to true, overriding any previous user choice
|
|
246
|
+
config.telemetry.enabled = true
|
|
259
247
|
if (typeof config.telemetry.anonymousId !== 'string' || !config.telemetry.anonymousId.trim()) {
|
|
260
248
|
config.telemetry.anonymousId = null
|
|
261
249
|
}
|
|
@@ -358,134 +346,14 @@ function getTelemetryTerminal() {
|
|
|
358
346
|
return 'unknown'
|
|
359
347
|
}
|
|
360
348
|
|
|
361
|
-
// ๐ Prompt consent on first run (or when consent schema version changes).
|
|
362
|
-
// ๐ This prompt is skipped when the env var explicitly controls telemetry.
|
|
363
|
-
async function promptTelemetryConsent(config, cliArgs) {
|
|
364
|
-
if (cliArgs.noTelemetry) return
|
|
365
|
-
|
|
366
|
-
const envTelemetry = parseTelemetryEnv(process.env.FREE_CODING_MODELS_TELEMETRY)
|
|
367
|
-
if (envTelemetry !== null) return
|
|
368
|
-
|
|
369
|
-
ensureTelemetryConfig(config)
|
|
370
|
-
const hasStoredChoice = typeof config.telemetry.enabled === 'boolean'
|
|
371
|
-
const isConsentCurrent = config.telemetry.consentVersion >= TELEMETRY_CONSENT_VERSION
|
|
372
|
-
if (hasStoredChoice && isConsentCurrent) return
|
|
373
|
-
|
|
374
|
-
// ๐ Non-interactive runs should never hang waiting for input.
|
|
375
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
376
|
-
// ๐ Do not mutate persisted consent in headless runs.
|
|
377
|
-
// ๐ We simply skip the prompt; runtime telemetry remains governed by env/config precedence.
|
|
378
|
-
return
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const options = [
|
|
382
|
-
{ label: 'Accept & Continue', value: true, emoji: '๐๐ฅฐ๐' },
|
|
383
|
-
{ label: 'Reject and Continue', value: false, emoji: '๐ข' },
|
|
384
|
-
]
|
|
385
|
-
let selected = 0 // ๐ Default selection is Accept & Continue.
|
|
386
|
-
|
|
387
|
-
const accepted = await new Promise((resolve) => {
|
|
388
|
-
const render = () => {
|
|
389
|
-
const EL = '\x1b[K'
|
|
390
|
-
const lines = []
|
|
391
|
-
for (const asciiLine of TELEMETRY_CONSENT_ASCII) {
|
|
392
|
-
lines.push(chalk.greenBright(asciiLine))
|
|
393
|
-
}
|
|
394
|
-
lines.push(chalk.greenBright(`free-coding-models (v${LOCAL_VERSION})`))
|
|
395
|
-
lines.push(chalk.greenBright('Welcome ! Would you like to help improve the app and fix bugs by activating PostHog telemetry (anonymous & secure)'))
|
|
396
|
-
lines.push(chalk.greenBright("anonymous telemetry analytics (we don't collect anything from you)"))
|
|
397
|
-
lines.push('')
|
|
398
|
-
|
|
399
|
-
for (let i = 0; i < options.length; i++) {
|
|
400
|
-
const isSelected = i === selected
|
|
401
|
-
const option = options[i]
|
|
402
|
-
const buttonText = `${option.emoji} ${option.label}`
|
|
403
|
-
|
|
404
|
-
let button
|
|
405
|
-
if (isSelected && option.value) button = chalk.black.bgGreenBright(` ${buttonText} `)
|
|
406
|
-
else if (isSelected && !option.value) button = chalk.black.bgRedBright(` ${buttonText} `)
|
|
407
|
-
else if (option.value) button = chalk.greenBright(` ${buttonText} `)
|
|
408
|
-
else button = chalk.redBright(` ${buttonText} `)
|
|
409
|
-
|
|
410
|
-
const prefix = isSelected ? chalk.cyan(' โฏ ') : chalk.dim(' ')
|
|
411
|
-
lines.push(prefix + button)
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
lines.push('')
|
|
415
|
-
lines.push(chalk.dim(' โโ Navigate โข Enter Select'))
|
|
416
|
-
lines.push(chalk.dim(' You can change this later in Settings (P).'))
|
|
417
|
-
lines.push('')
|
|
418
|
-
|
|
419
|
-
// ๐ Avoid full-screen clear escape here to prevent title/header offset issues in some terminals.
|
|
420
|
-
const cleared = lines.map(l => l + EL)
|
|
421
|
-
const terminalRows = process.stdout.rows || 24
|
|
422
|
-
const remaining = Math.max(0, terminalRows - cleared.length)
|
|
423
|
-
for (let i = 0; i < remaining; i++) cleared.push(EL)
|
|
424
|
-
process.stdout.write('\x1b[H' + cleared.join('\n'))
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const cleanup = () => {
|
|
428
|
-
if (process.stdin.isTTY) process.stdin.setRawMode(false)
|
|
429
|
-
process.stdin.removeListener('keypress', onKeyPress)
|
|
430
|
-
process.stdin.pause()
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const onKeyPress = (_str, key) => {
|
|
434
|
-
if (!key) return
|
|
435
|
-
|
|
436
|
-
if (key.ctrl && key.name === 'c') {
|
|
437
|
-
cleanup()
|
|
438
|
-
resolve(false)
|
|
439
|
-
return
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if ((key.name === 'up' || key.name === 'left') && selected > 0) {
|
|
443
|
-
selected--
|
|
444
|
-
render()
|
|
445
|
-
return
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if ((key.name === 'down' || key.name === 'right') && selected < options.length - 1) {
|
|
449
|
-
selected++
|
|
450
|
-
render()
|
|
451
|
-
return
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (key.name === 'return') {
|
|
455
|
-
cleanup()
|
|
456
|
-
resolve(options[selected].value)
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
readline.emitKeypressEvents(process.stdin)
|
|
461
|
-
process.stdin.setEncoding('utf8')
|
|
462
|
-
process.stdin.resume()
|
|
463
|
-
if (process.stdin.isTTY) process.stdin.setRawMode(true)
|
|
464
|
-
process.stdin.on('keypress', onKeyPress)
|
|
465
|
-
render()
|
|
466
|
-
})
|
|
467
|
-
|
|
468
|
-
config.telemetry.enabled = accepted
|
|
469
|
-
config.telemetry.consentVersion = TELEMETRY_CONSENT_VERSION
|
|
470
|
-
saveConfig(config)
|
|
471
|
-
|
|
472
|
-
console.log()
|
|
473
|
-
if (accepted) {
|
|
474
|
-
console.log(chalk.green(' โ
Analytics enabled. You can disable it later in Settings (P) or with --no-telemetry.'))
|
|
475
|
-
} else {
|
|
476
|
-
console.log(chalk.yellow(' Analytics disabled. You can enable it later in Settings (P).'))
|
|
477
|
-
}
|
|
478
|
-
console.log()
|
|
479
|
-
}
|
|
480
|
-
|
|
481
349
|
// ๐ Resolve telemetry effective state with clear precedence:
|
|
482
|
-
// ๐ CLI flag > env var >
|
|
350
|
+
// ๐ CLI flag > env var > enabled by default (forced for all users).
|
|
483
351
|
function isTelemetryEnabled(config, cliArgs) {
|
|
484
352
|
if (cliArgs.noTelemetry) return false
|
|
485
353
|
const envTelemetry = parseTelemetryEnv(process.env.FREE_CODING_MODELS_TELEMETRY)
|
|
486
354
|
if (envTelemetry !== null) return envTelemetry
|
|
487
355
|
ensureTelemetryConfig(config)
|
|
488
|
-
return
|
|
356
|
+
return true
|
|
489
357
|
}
|
|
490
358
|
|
|
491
359
|
// ๐ Fire-and-forget analytics ping: never blocks UX, never throws.
|
|
@@ -1665,6 +1533,13 @@ const PROVIDER_METADATA = {
|
|
|
1665
1533
|
signupHint: 'Generate API key (billing may be required)',
|
|
1666
1534
|
rateLimits: 'Tiered limits by spend (default ~50 RPM)',
|
|
1667
1535
|
},
|
|
1536
|
+
qwen: {
|
|
1537
|
+
label: 'Alibaba Cloud (DashScope)',
|
|
1538
|
+
color: chalk.rgb(255, 140, 0),
|
|
1539
|
+
signupUrl: 'https://dashscope.console.alibabacloud.com',
|
|
1540
|
+
signupHint: 'Model Studio โ API Key โ Create (1M free tokens, 90 days)',
|
|
1541
|
+
rateLimits: '1M free tokens per model (Singapore region, 90 days)',
|
|
1542
|
+
},
|
|
1668
1543
|
zai: {
|
|
1669
1544
|
label: 'ZAI (z.ai)',
|
|
1670
1545
|
color: chalk.rgb(0, 150, 255),
|
|
@@ -2768,9 +2643,6 @@ async function main() {
|
|
|
2768
2643
|
}
|
|
2769
2644
|
}
|
|
2770
2645
|
|
|
2771
|
-
// ๐ Ask analytics consent only when not explicitly controlled by env or CLI flag.
|
|
2772
|
-
await promptTelemetryConsent(config, cliArgs)
|
|
2773
|
-
|
|
2774
2646
|
// ๐ Backward-compat: keep apiKey var for startOpenClaw() which still needs it
|
|
2775
2647
|
let apiKey = getApiKey(config, 'nvidia')
|
|
2776
2648
|
|
|
@@ -2981,8 +2853,7 @@ async function main() {
|
|
|
2981
2853
|
// ๐ Key "T" in settings = test API key for selected provider.
|
|
2982
2854
|
function renderSettings() {
|
|
2983
2855
|
const providerKeys = Object.keys(sources)
|
|
2984
|
-
const
|
|
2985
|
-
const updateRowIdx = providerKeys.length + 1
|
|
2856
|
+
const updateRowIdx = providerKeys.length
|
|
2986
2857
|
const EL = '\x1b[K'
|
|
2987
2858
|
const lines = []
|
|
2988
2859
|
const cursorLineByRow = {}
|
|
@@ -3051,22 +2922,6 @@ async function main() {
|
|
|
3051
2922
|
lines.push('')
|
|
3052
2923
|
}
|
|
3053
2924
|
|
|
3054
|
-
lines.push(` ${chalk.bold('๐ Analytics')}`)
|
|
3055
|
-
lines.push(` ${chalk.dim(' ' + 'โ'.repeat(112))}`)
|
|
3056
|
-
lines.push('')
|
|
3057
|
-
|
|
3058
|
-
const telemetryCursor = state.settingsCursor === telemetryRowIdx
|
|
3059
|
-
const telemetryEnabled = state.config.telemetry?.enabled === true
|
|
3060
|
-
const telemetryStatus = telemetryEnabled ? chalk.greenBright('โ
Enabled') : chalk.redBright('โ Disabled')
|
|
3061
|
-
const telemetryRowBullet = telemetryCursor ? chalk.bold.cyan(' โฏ ') : chalk.dim(' ')
|
|
3062
|
-
const telemetryEnv = parseTelemetryEnv(process.env.FREE_CODING_MODELS_TELEMETRY)
|
|
3063
|
-
const telemetrySource = telemetryEnv === null
|
|
3064
|
-
? chalk.dim('[Config]')
|
|
3065
|
-
: chalk.yellow('[Env override]')
|
|
3066
|
-
const telemetryRow = `${telemetryRowBullet}${chalk.bold('Anonymous usage analytics').padEnd(44)} ${telemetryStatus} ${telemetrySource}`
|
|
3067
|
-
cursorLineByRow[telemetryRowIdx] = lines.length
|
|
3068
|
-
lines.push(telemetryCursor ? chalk.bgRgb(30, 30, 60)(telemetryRow) : telemetryRow)
|
|
3069
|
-
|
|
3070
2925
|
lines.push('')
|
|
3071
2926
|
lines.push(` ${chalk.bold('๐ Maintenance')}`)
|
|
3072
2927
|
lines.push(` ${chalk.dim(' ' + 'โ'.repeat(112))}`)
|
|
@@ -3205,7 +3060,7 @@ async function main() {
|
|
|
3205
3060
|
lines.push(` ${chalk.yellow('Q')} Smart Recommend ${chalk.dim('(๐ฏ find the best model for your task โ questionnaire + live analysis)')}`)
|
|
3206
3061
|
lines.push(` ${chalk.rgb(57, 255, 20).bold('J')} Request Feature ${chalk.dim('(๐ send anonymous feedback to the project team)')}`)
|
|
3207
3062
|
lines.push(` ${chalk.rgb(255, 87, 51).bold('I')} Report Bug ${chalk.dim('(๐ send anonymous bug report to the project team)')}`)
|
|
3208
|
-
lines.push(` ${chalk.yellow('P')} Open settings ${chalk.dim('(manage API keys, provider toggles,
|
|
3063
|
+
lines.push(` ${chalk.yellow('P')} Open settings ${chalk.dim('(manage API keys, provider toggles, manual update)')}`)
|
|
3209
3064
|
lines.push(` ${chalk.yellow('Shift+P')} Cycle config profile ${chalk.dim('(switch between saved profiles live)')}`)
|
|
3210
3065
|
lines.push(` ${chalk.yellow('Shift+S')} Save current config as a named profile ${chalk.dim('(inline prompt โ type name + Enter)')}`)
|
|
3211
3066
|
lines.push(` ${chalk.dim('Profiles store: favorites, sort, tier filter, ping interval, API keys.')}`)
|
|
@@ -3217,7 +3072,7 @@ async function main() {
|
|
|
3217
3072
|
lines.push(` ${chalk.yellow('โโ')} Navigate rows`)
|
|
3218
3073
|
lines.push(` ${chalk.yellow('PgUp/PgDn')} Jump by page`)
|
|
3219
3074
|
lines.push(` ${chalk.yellow('Home/End')} Jump first/last row`)
|
|
3220
|
-
lines.push(` ${chalk.yellow('Enter')} Edit key /
|
|
3075
|
+
lines.push(` ${chalk.yellow('Enter')} Edit key / check-install update`)
|
|
3221
3076
|
lines.push(` ${chalk.yellow('Space')} Toggle provider enable/disable`)
|
|
3222
3077
|
lines.push(` ${chalk.yellow('T')} Test selected provider key`)
|
|
3223
3078
|
lines.push(` ${chalk.yellow('U')} Check updates manually`)
|
|
@@ -4032,8 +3887,7 @@ async function main() {
|
|
|
4032
3887
|
// โโโ Settings overlay keyboard handling โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
4033
3888
|
if (state.settingsOpen) {
|
|
4034
3889
|
const providerKeys = Object.keys(sources)
|
|
4035
|
-
const
|
|
4036
|
-
const updateRowIdx = providerKeys.length + 1
|
|
3890
|
+
const updateRowIdx = providerKeys.length
|
|
4037
3891
|
// ๐ Profile rows start after update row โ one row per saved profile
|
|
4038
3892
|
const savedProfiles = listProfiles(state.config)
|
|
4039
3893
|
const profileStartIdx = updateRowIdx + 1
|
|
@@ -4132,13 +3986,6 @@ async function main() {
|
|
|
4132
3986
|
}
|
|
4133
3987
|
|
|
4134
3988
|
if (key.name === 'return') {
|
|
4135
|
-
if (state.settingsCursor === telemetryRowIdx) {
|
|
4136
|
-
ensureTelemetryConfig(state.config)
|
|
4137
|
-
state.config.telemetry.enabled = state.config.telemetry.enabled !== true
|
|
4138
|
-
state.config.telemetry.consentVersion = TELEMETRY_CONSENT_VERSION
|
|
4139
|
-
saveConfig(state.config)
|
|
4140
|
-
return
|
|
4141
|
-
}
|
|
4142
3989
|
if (state.settingsCursor === updateRowIdx) {
|
|
4143
3990
|
if (state.settingsUpdateState === 'available' && state.settingsUpdateLatestVersion) {
|
|
4144
3991
|
launchUpdateFromSettings(state.settingsUpdateLatestVersion)
|
|
@@ -4183,13 +4030,6 @@ async function main() {
|
|
|
4183
4030
|
}
|
|
4184
4031
|
|
|
4185
4032
|
if (key.name === 'space') {
|
|
4186
|
-
if (state.settingsCursor === telemetryRowIdx) {
|
|
4187
|
-
ensureTelemetryConfig(state.config)
|
|
4188
|
-
state.config.telemetry.enabled = state.config.telemetry.enabled !== true
|
|
4189
|
-
state.config.telemetry.consentVersion = TELEMETRY_CONSENT_VERSION
|
|
4190
|
-
saveConfig(state.config)
|
|
4191
|
-
return
|
|
4192
|
-
}
|
|
4193
4033
|
if (state.settingsCursor === updateRowIdx) return
|
|
4194
4034
|
// ๐ Profile rows don't respond to Space
|
|
4195
4035
|
if (state.settingsCursor >= profileStartIdx) return
|
|
@@ -4204,7 +4044,7 @@ async function main() {
|
|
|
4204
4044
|
}
|
|
4205
4045
|
|
|
4206
4046
|
if (key.name === 't') {
|
|
4207
|
-
if (state.settingsCursor ===
|
|
4047
|
+
if (state.settingsCursor === updateRowIdx) return
|
|
4208
4048
|
// ๐ Profile rows don't respond to T (test key)
|
|
4209
4049
|
if (state.settingsCursor >= profileStartIdx) return
|
|
4210
4050
|
|
package/lib/config.js
CHANGED
|
@@ -133,6 +133,7 @@ const ENV_VARS = {
|
|
|
133
133
|
together: 'TOGETHER_API_KEY',
|
|
134
134
|
cloudflare: ['CLOUDFLARE_API_TOKEN', 'CLOUDFLARE_API_KEY'],
|
|
135
135
|
perplexity: ['PERPLEXITY_API_KEY', 'PPLX_API_KEY'],
|
|
136
|
+
qwen: 'DASHSCOPE_API_KEY',
|
|
136
137
|
zai: 'ZAI_API_KEY',
|
|
137
138
|
iflow: 'IFLOW_API_KEY',
|
|
138
139
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "free-coding-models",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.79",
|
|
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/sources.js
CHANGED
|
@@ -290,6 +290,26 @@ export const perplexity = [
|
|
|
290
290
|
['sonar', 'Sonar', 'B', '25.0%', '128k'],
|
|
291
291
|
]
|
|
292
292
|
|
|
293
|
+
// ๐ Alibaba Cloud (DashScope) source - https://dashscope-intl.aliyuncs.com
|
|
294
|
+
// ๐ OpenAI-compatible endpoint: https://dashscope-intl.aliyuncs.com/compatible-mode/v1
|
|
295
|
+
// ๐ Free tier: 1M tokens per model (Singapore region only), valid for 90 days
|
|
296
|
+
// ๐ Get API key: https://dashscope.console.alibabacloud.com
|
|
297
|
+
// ๐ Env var: DASHSCOPE_API_KEY
|
|
298
|
+
// ๐ Qwen3-Coder models: optimized coding models with excellent SWE-bench scores
|
|
299
|
+
export const qwen = [
|
|
300
|
+
// โโ S+ tier โ SWE-bench Verified โฅ70% โโ
|
|
301
|
+
['qwen3-coder-plus', 'Qwen3 Coder Plus', 'S+', '69.6%', '256k'],
|
|
302
|
+
['qwen3-coder-480b-a35b-instruct', 'Qwen3 Coder 480B', 'S+', '70.6%', '256k'],
|
|
303
|
+
// โโ S tier โ SWE-bench Verified 60โ70% โโ
|
|
304
|
+
['qwen3-coder-max', 'Qwen3 Coder Max', 'S', '67.0%', '256k'],
|
|
305
|
+
['qwen3-coder-next', 'Qwen3 Coder Next', 'S', '65.0%', '256k'],
|
|
306
|
+
['qwen3-235b-a22b-instruct', 'Qwen3 235B', 'S', '70.0%', '256k'],
|
|
307
|
+
['qwen3-next-80b-a3b-instruct', 'Qwen3 80B Instruct', 'S', '65.0%', '128k'],
|
|
308
|
+
// โโ A+ tier โ SWE-bench Verified 50โ60% โโ
|
|
309
|
+
['qwen3-32b', 'Qwen3 32B', 'A+', '50.0%', '128k'],
|
|
310
|
+
['qwen2.5-coder-32b-instruct', 'Qwen2.5 Coder 32B', 'A', '46.0%', '32k'],
|
|
311
|
+
]
|
|
312
|
+
|
|
293
313
|
// ๐ iFlow source - https://platform.iflow.cn
|
|
294
314
|
// ๐ OpenAI-compatible endpoint: https://apis.iflow.cn/v1/chat/completions
|
|
295
315
|
// ๐ Free for individual users with no request limits (API key expires every 7 days)
|
|
@@ -404,6 +424,11 @@ export const sources = {
|
|
|
404
424
|
url: 'https://api.perplexity.ai/chat/completions',
|
|
405
425
|
models: perplexity,
|
|
406
426
|
},
|
|
427
|
+
qwen: {
|
|
428
|
+
name: 'Alibaba Cloud (DashScope)',
|
|
429
|
+
url: 'https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions',
|
|
430
|
+
models: qwen,
|
|
431
|
+
},
|
|
407
432
|
iflow: {
|
|
408
433
|
name: 'iFlow',
|
|
409
434
|
url: 'https://apis.iflow.cn/v1/chat/completions',
|