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 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-150-76b900?logo=nvidia" alt="models count">
6
- <img src="https://img.shields.io/badge/providers-19-blue" alt="providers count">
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
- # Disable anonymous analytics for this run
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
- Analytics toggle is in the same Settings screen (`P`) as a dedicated row (toggle with Enter or Space).
269
- Manual update is in the same Settings screen (`P`) under **Maintenance** (Enter to check, Enter again to install when an update is available).
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
- FREE_CODING_MODELS_TELEMETRY=0 free-coding-models
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
- **150 coding models** across 19 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.
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
- | `FREE_CODING_MODELS_TELEMETRY` | `0` disables analytics, `1` enables analytics |
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
- "favorites": [
800
- "nvidia/deepseek-ai/deepseek-v3.2"
801
- ],
802
- "telemetry": {
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
- | `--no-telemetry` | Disable anonymous analytics for this run |
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, analytics toggle, manual update, profiles)
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, analytics row, maintenance row, and profile rows
855
- - **Enter** โ€” Edit API key inline, toggle analytics, check/install update, or load a profile
856
- - **Space** โ€” Toggle provider enabled/disabled, or toggle analytics
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, analytics, and manual updates
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: null, consentVersion: 0, anonymousId: null }
243
+ config.telemetry = { enabled: true, anonymousId: null }
256
244
  }
257
- if (typeof config.telemetry.enabled !== 'boolean') config.telemetry.enabled = null
258
- if (typeof config.telemetry.consentVersion !== 'number') config.telemetry.consentVersion = 0
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 > config file > disabled by default.
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 config.telemetry.enabled === true
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 telemetryRowIdx = providerKeys.length
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, analytics, manual update)')}`)
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 / toggle analytics / check-install update`)
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 telemetryRowIdx = providerKeys.length
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 === telemetryRowIdx || state.settingsCursor === updateRowIdx) return
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.78",
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',