free-coding-models 0.5.59 โ†’ 0.5.61

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.
@@ -0,0 +1,302 @@
1
+ {
2
+ "_meta": {
3
+ "schemaVersion": 1,
4
+ "lastUpdated": "2026-07-25",
5
+ "source": "Artificial Analysis + curated manual overlay",
6
+ "notes": "Curated seed dataset for ~30 well-known models. Refreshed by scripts/update-benchmarks.mjs before each release. Fields with null are not yet measured."
7
+ },
8
+ "deepseek-ai/deepseek-v3.2": {
9
+ "codingIndex": 65.4, "mathIndex": 70.2, "agenticIndex": 58.0, "reasoningIndex": 68.5,
10
+ "mmluPro": 75.3, "gpqa": 52.0, "hle": 8.4, "contextWindow": 160000,
11
+ "supportsReasoning": true, "supportsVision": false,
12
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek V3.2"
13
+ },
14
+ "deepseek-ai/deepseek-v4-pro": {
15
+ "codingIndex": 81.2, "mathIndex": 84.5, "agenticIndex": 74.8, "reasoningIndex": 80.1,
16
+ "mmluPro": 86.4, "gpqa": 65.7, "hle": 14.2, "contextWindow": 1000000,
17
+ "supportsReasoning": true, "supportsVision": false,
18
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek V4 Pro"
19
+ },
20
+ "deepseek-ai/deepseek-v4-flash": {
21
+ "codingIndex": 78.9, "mathIndex": 80.1, "agenticIndex": 71.5, "reasoningIndex": 77.0,
22
+ "mmluPro": 83.2, "gpqa": 60.4, "hle": 12.8, "contextWindow": 1000000,
23
+ "supportsReasoning": true, "supportsVision": false,
24
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek V4 Flash"
25
+ },
26
+ "deepseek-ai/deepseek-r1": {
27
+ "codingIndex": 52.0, "mathIndex": 90.4, "agenticIndex": 48.5, "reasoningIndex": 78.6,
28
+ "mmluPro": 84.0, "gpqa": 71.5, "hle": 9.9, "contextWindow": 128000,
29
+ "supportsReasoning": true, "supportsVision": false,
30
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek R1"
31
+ },
32
+ "deepseek/deepseek-r1": {
33
+ "codingIndex": 52.0, "mathIndex": 90.4, "agenticIndex": 48.5, "reasoningIndex": 78.6,
34
+ "mmluPro": 84.0, "gpqa": 71.5, "hle": 9.9, "contextWindow": 128000,
35
+ "supportsReasoning": true, "supportsVision": false,
36
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek R1"
37
+ },
38
+ "DeepSeek-V3.1": {
39
+ "codingIndex": 68.0, "mathIndex": 73.0, "agenticIndex": 60.5, "reasoningIndex": 70.0,
40
+ "mmluPro": 76.5, "gpqa": 53.2, "hle": 9.1, "contextWindow": 128000,
41
+ "supportsReasoning": true, "supportsVision": false,
42
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek V3.1"
43
+ },
44
+ "DeepSeek-V3.2": {
45
+ "codingIndex": 70.5, "mathIndex": 75.0, "agenticIndex": 62.0, "reasoningIndex": 72.0,
46
+ "mmluPro": 78.0, "gpqa": 54.5, "hle": 9.5, "contextWindow": 32000,
47
+ "supportsReasoning": true, "supportsVision": false,
48
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek V3.2"
49
+ },
50
+ "deepseek/deepseek-chat": {
51
+ "codingIndex": 65.0, "mathIndex": 70.0, "agenticIndex": 58.0, "reasoningIndex": 68.0,
52
+ "mmluPro": 75.0, "gpqa": 52.0, "hle": 8.4, "contextWindow": 128000,
53
+ "supportsReasoning": false, "supportsVision": false,
54
+ "lastUpdated": "2026-07-20", "originalModel": "DeepSeek Chat"
55
+ },
56
+ "z-ai/glm-5.2": {
57
+ "codingIndex": 82.4, "mathIndex": 79.0, "agenticIndex": 76.1, "reasoningIndex": 78.9,
58
+ "mmluPro": 84.2, "gpqa": 61.8, "hle": 13.5, "contextWindow": 128000,
59
+ "supportsReasoning": true, "supportsVision": false,
60
+ "lastUpdated": "2026-07-20", "originalModel": "GLM 5.2"
61
+ },
62
+ "zai-glm-4.7": {
63
+ "codingIndex": 75.0, "mathIndex": 73.5, "agenticIndex": 68.4, "reasoningIndex": 72.0,
64
+ "mmluPro": 78.5, "gpqa": 55.2, "hle": 10.8, "contextWindow": 128000,
65
+ "supportsReasoning": true, "supportsVision": false,
66
+ "lastUpdated": "2026-07-20", "originalModel": "GLM 4.7"
67
+ },
68
+ "@cf/zai-org/glm-4.7-flash": {
69
+ "codingIndex": 70.0, "mathIndex": 69.0, "agenticIndex": 62.0, "reasoningIndex": 66.0,
70
+ "mmluPro": 73.0, "gpqa": 50.0, "hle": 9.0, "contextWindow": 128000,
71
+ "supportsReasoning": false, "supportsVision": false,
72
+ "lastUpdated": "2026-07-20", "originalModel": "GLM 4.7 Flash"
73
+ },
74
+ "moonshotai/kimi-k2.6": {
75
+ "codingIndex": 79.5, "mathIndex": 77.0, "agenticIndex": 73.2, "reasoningIndex": 76.4,
76
+ "mmluPro": 82.0, "gpqa": 59.0, "hle": 12.4, "contextWindow": 262000,
77
+ "supportsReasoning": true, "supportsVision": false,
78
+ "lastUpdated": "2026-07-20", "originalModel": "Kimi K2.6"
79
+ },
80
+ "@cf/moonshotai/kimi-k2.6": {
81
+ "codingIndex": 79.5, "mathIndex": 77.0, "agenticIndex": 73.2, "reasoningIndex": 76.4,
82
+ "mmluPro": 82.0, "gpqa": 59.0, "hle": 12.4, "contextWindow": 262000,
83
+ "supportsReasoning": true, "supportsVision": false,
84
+ "lastUpdated": "2026-07-20", "originalModel": "Kimi K2.6"
85
+ },
86
+ "@cf/moonshotai/kimi-k2.7-code": {
87
+ "codingIndex": 81.0, "mathIndex": 76.5, "agenticIndex": 74.0, "reasoningIndex": 75.5,
88
+ "mmluPro": 81.5, "gpqa": 58.0, "hle": 12.0, "contextWindow": 262000,
89
+ "supportsReasoning": false, "supportsVision": false,
90
+ "lastUpdated": "2026-07-20", "originalModel": "Kimi K2.7 Code"
91
+ },
92
+ "minimaxai/minimax-m2.7": {
93
+ "codingIndex": 77.5, "mathIndex": 75.0, "agenticIndex": 70.0, "reasoningIndex": 74.5,
94
+ "mmluPro": 80.5, "gpqa": 56.0, "hle": 11.5, "contextWindow": 200000,
95
+ "supportsReasoning": true, "supportsVision": false,
96
+ "lastUpdated": "2026-07-20", "originalModel": "MiniMax M2.7"
97
+ },
98
+ "minimaxai/minimax-m3": {
99
+ "codingIndex": 78.0, "mathIndex": 76.0, "agenticIndex": 71.0, "reasoningIndex": 75.0,
100
+ "mmluPro": 81.0, "gpqa": 57.0, "hle": 12.0, "contextWindow": 1000000,
101
+ "supportsReasoning": true, "supportsVision": true,
102
+ "lastUpdated": "2026-07-20", "originalModel": "MiniMax M3"
103
+ },
104
+ "MiniMax-M2.7": {
105
+ "codingIndex": 77.5, "mathIndex": 75.0, "agenticIndex": 70.0, "reasoningIndex": 74.5,
106
+ "mmluPro": 80.5, "gpqa": 56.0, "hle": 11.5, "contextWindow": 192000,
107
+ "supportsReasoning": true, "supportsVision": false,
108
+ "lastUpdated": "2026-07-20", "originalModel": "MiniMax M2.7"
109
+ },
110
+ "stepfun-ai/step-3.7-flash": {
111
+ "codingIndex": 73.5, "mathIndex": 74.0, "agenticIndex": 68.0, "reasoningIndex": 72.0,
112
+ "mmluPro": 78.0, "gpqa": 53.0, "hle": 10.5, "contextWindow": 256000,
113
+ "supportsReasoning": true, "supportsVision": false,
114
+ "lastUpdated": "2026-07-20", "originalModel": "Step 3.7 Flash"
115
+ },
116
+ "openai/gpt-oss-120b": {
117
+ "codingIndex": 62.0, "mathIndex": 64.0, "agenticIndex": 58.0, "reasoningIndex": 63.0,
118
+ "mmluPro": 70.0, "gpqa": 52.0, "hle": 9.0, "contextWindow": 128000,
119
+ "supportsReasoning": true, "supportsVision": false,
120
+ "lastUpdated": "2026-07-20", "originalModel": "GPT OSS 120B"
121
+ },
122
+ "gpt-oss-120b": {
123
+ "codingIndex": 62.0, "mathIndex": 64.0, "agenticIndex": 58.0, "reasoningIndex": 63.0,
124
+ "mmluPro": 70.0, "gpqa": 52.0, "hle": 9.0, "contextWindow": 128000,
125
+ "supportsReasoning": true, "supportsVision": false,
126
+ "lastUpdated": "2026-07-20", "originalModel": "GPT OSS 120B"
127
+ },
128
+ "openai/gpt-oss-20b": {
129
+ "codingIndex": 50.0, "mathIndex": 52.0, "agenticIndex": 46.0, "reasoningIndex": 51.0,
130
+ "mmluPro": 58.0, "gpqa": 42.0, "hle": 6.5, "contextWindow": 128000,
131
+ "supportsReasoning": true, "supportsVision": false,
132
+ "lastUpdated": "2026-07-20", "originalModel": "GPT OSS 20B"
133
+ },
134
+ "gpt-oss-20b": {
135
+ "codingIndex": 50.0, "mathIndex": 52.0, "agenticIndex": 46.0, "reasoningIndex": 51.0,
136
+ "mmluPro": 58.0, "gpqa": 42.0, "hle": 6.5, "contextWindow": 128000,
137
+ "supportsReasoning": true, "supportsVision": false,
138
+ "lastUpdated": "2026-07-20", "originalModel": "GPT OSS 20B"
139
+ },
140
+ "meta/llama-4-maverick-17b-128e-instruct": {
141
+ "codingIndex": 73.5, "mathIndex": 70.0, "agenticIndex": 65.0, "reasoningIndex": 71.0,
142
+ "mmluPro": 78.0, "gpqa": 53.0, "hle": 10.0, "contextWindow": 1000000,
143
+ "supportsReasoning": false, "supportsVision": true,
144
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 4 Maverick"
145
+ },
146
+ "meta-llama/llama-4-scout-17b-16e-instruct": {
147
+ "codingIndex": 28.0, "mathIndex": 25.0, "agenticIndex": 22.0, "reasoningIndex": 26.0,
148
+ "mmluPro": 30.0, "gpqa": 18.0, "hle": 2.0, "contextWindow": 10000000,
149
+ "supportsReasoning": false, "supportsVision": true,
150
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 4 Scout"
151
+ },
152
+ "@cf/meta/llama-4-scout-17b-16e-instruct": {
153
+ "codingIndex": 28.0, "mathIndex": 25.0, "agenticIndex": 22.0, "reasoningIndex": 26.0,
154
+ "mmluPro": 30.0, "gpqa": 18.0, "hle": 2.0, "contextWindow": 10000000,
155
+ "supportsReasoning": false, "supportsVision": true,
156
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 4 Scout"
157
+ },
158
+ "meta/llama-3.3-70b-versatile": {
159
+ "codingIndex": 22.0, "mathIndex": 24.0, "agenticIndex": 18.0, "reasoningIndex": 23.0,
160
+ "mmluPro": 28.0, "gpqa": 16.0, "hle": 1.5, "contextWindow": 131072,
161
+ "supportsReasoning": false, "supportsVision": false,
162
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 3.3 70B Versatile"
163
+ },
164
+ "llama-3.3-70b-versatile": {
165
+ "codingIndex": 22.0, "mathIndex": 24.0, "agenticIndex": 18.0, "reasoningIndex": 23.0,
166
+ "mmluPro": 28.0, "gpqa": 16.0, "hle": 1.5, "contextWindow": 131072,
167
+ "supportsReasoning": false, "supportsVision": false,
168
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 3.3 70B Versatile"
169
+ },
170
+ "Meta-Llama-3.3-70B-Instruct": {
171
+ "codingIndex": 22.0, "mathIndex": 24.0, "agenticIndex": 18.0, "reasoningIndex": 23.0,
172
+ "mmluPro": 28.0, "gpqa": 16.0, "hle": 1.5, "contextWindow": 128000,
173
+ "supportsReasoning": false, "supportsVision": false,
174
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 3.3 70B Instruct"
175
+ },
176
+ "llama-3.1-8b-instant": {
177
+ "codingIndex": 18.0, "mathIndex": 19.0, "agenticIndex": 14.0, "reasoningIndex": 17.0,
178
+ "mmluPro": 22.0, "gpqa": 12.0, "hle": 1.0, "contextWindow": 131072,
179
+ "supportsReasoning": false, "supportsVision": false,
180
+ "lastUpdated": "2026-07-20", "originalModel": "Llama 3.1 8B Instant"
181
+ },
182
+ "qwen/qwen3.6-27b": {
183
+ "codingIndex": 76.5, "mathIndex": 74.0, "agenticIndex": 70.0, "reasoningIndex": 73.0,
184
+ "mmluPro": 79.0, "gpqa": 55.0, "hle": 11.0, "contextWindow": 131072,
185
+ "supportsReasoning": true, "supportsVision": false,
186
+ "lastUpdated": "2026-07-20", "originalModel": "Qwen3.6 27B"
187
+ },
188
+ "qwen/qwen2.5-coder-32b-instruct": {
189
+ "codingIndex": 48.0, "mathIndex": 45.0, "agenticIndex": 42.0, "reasoningIndex": 44.0,
190
+ "mmluPro": 52.0, "gpqa": 32.0, "hle": 4.0, "contextWindow": 128000,
191
+ "supportsReasoning": false, "supportsVision": false,
192
+ "lastUpdated": "2026-07-20", "originalModel": "Qwen2.5 Coder 32B"
193
+ },
194
+ "qwen/qwen3-30b-a3b-fp8": {
195
+ "codingIndex": 65.0, "mathIndex": 64.0, "agenticIndex": 58.0, "reasoningIndex": 63.0,
196
+ "mmluPro": 70.0, "gpqa": 48.0, "hle": 8.0, "contextWindow": 131072,
197
+ "supportsReasoning": true, "supportsVision": false,
198
+ "lastUpdated": "2026-07-20", "originalModel": "Qwen3 30B A3B"
199
+ },
200
+ "mistralai/mistral-medium-3.5-128b": {
201
+ "codingIndex": 76.5, "mathIndex": 74.0, "agenticIndex": 70.5, "reasoningIndex": 73.0,
202
+ "mmluPro": 79.0, "gpqa": 56.0, "hle": 11.2, "contextWindow": 256000,
203
+ "supportsReasoning": false, "supportsVision": false,
204
+ "lastUpdated": "2026-07-20", "originalModel": "Mistral Medium 3.5"
205
+ },
206
+ "mistralai/mistral-small-4-119b-2603": {
207
+ "codingIndex": 60.0, "mathIndex": 58.0, "agenticIndex": 55.0, "reasoningIndex": 57.0,
208
+ "mmluPro": 65.0, "gpqa": 44.0, "hle": 7.0, "contextWindow": 256000,
209
+ "supportsReasoning": false, "supportsVision": false,
210
+ "lastUpdated": "2026-07-20", "originalModel": "Mistral Small 4"
211
+ },
212
+ "mistralai/mistral-large-3-675b-instruct-2512": {
213
+ "codingIndex": 58.0, "mathIndex": 56.0, "agenticIndex": 52.0, "reasoningIndex": 55.0,
214
+ "mmluPro": 63.0, "gpqa": 42.0, "hle": 6.5, "contextWindow": 256000,
215
+ "supportsReasoning": false, "supportsVision": false,
216
+ "lastUpdated": "2026-07-20", "originalModel": "Mistral Large 675B"
217
+ },
218
+ "mistralai/ministral-14b-instruct-2512": {
219
+ "codingIndex": 34.0, "mathIndex": 32.0, "agenticIndex": 28.0, "reasoningIndex": 31.0,
220
+ "mmluPro": 38.0, "gpqa": 22.0, "hle": 3.0, "contextWindow": 32000,
221
+ "supportsReasoning": false, "supportsVision": false,
222
+ "lastUpdated": "2026-07-20", "originalModel": "Ministral 14B"
223
+ },
224
+ "google/gemma-4-31b-it": {
225
+ "codingIndex": 52.0, "mathIndex": 50.0, "agenticIndex": 46.0, "reasoningIndex": 49.0,
226
+ "mmluPro": 58.0, "gpqa": 38.0, "hle": 5.5, "contextWindow": 256000,
227
+ "supportsReasoning": false, "supportsVision": false,
228
+ "lastUpdated": "2026-07-20", "originalModel": "Gemma 4 31B"
229
+ },
230
+ "gemma-4-31b": {
231
+ "codingIndex": 52.0, "mathIndex": 50.0, "agenticIndex": 46.0, "reasoningIndex": 49.0,
232
+ "mmluPro": 58.0, "gpqa": 38.0, "hle": 5.5, "contextWindow": 128000,
233
+ "supportsReasoning": false, "supportsVision": false,
234
+ "lastUpdated": "2026-07-20", "originalModel": "Gemma 4 31B"
235
+ },
236
+ "@cf/google/gemma-4-26b-a4b-it": {
237
+ "codingIndex": 48.0, "mathIndex": 46.0, "agenticIndex": 42.0, "reasoningIndex": 45.0,
238
+ "mmluPro": 54.0, "gpqa": 35.0, "hle": 5.0, "contextWindow": 128000,
239
+ "supportsReasoning": false, "supportsVision": false,
240
+ "lastUpdated": "2026-07-20", "originalModel": "Gemma 4 26B"
241
+ },
242
+ "nvidia/nemotron-3-ultra-550b-a55b": {
243
+ "codingIndex": 71.0, "mathIndex": 70.0, "agenticIndex": 65.0, "reasoningIndex": 69.0,
244
+ "mmluPro": 75.0, "gpqa": 52.0, "hle": 9.5, "contextWindow": 1000000,
245
+ "supportsReasoning": true, "supportsVision": false,
246
+ "lastUpdated": "2026-07-20", "originalModel": "Nemotron 3 Ultra"
247
+ },
248
+ "nvidia/nemotron-3-super-120b-a12b": {
249
+ "codingIndex": 60.0, "mathIndex": 59.0, "agenticIndex": 54.0, "reasoningIndex": 58.0,
250
+ "mmluPro": 65.0, "gpqa": 44.0, "hle": 7.0, "contextWindow": 128000,
251
+ "supportsReasoning": true, "supportsVision": false,
252
+ "lastUpdated": "2026-07-20", "originalModel": "Nemotron 3 Super"
253
+ },
254
+ "nvidia/nemotron-3-nano-30b-a3b": {
255
+ "codingIndex": 38.0, "mathIndex": 36.0, "agenticIndex": 32.0, "reasoningIndex": 35.0,
256
+ "mmluPro": 42.0, "gpqa": 26.0, "hle": 3.5, "contextWindow": 1000000,
257
+ "supportsReasoning": false, "supportsVision": false,
258
+ "lastUpdated": "2026-07-20", "originalModel": "Nemotron 3 Nano"
259
+ },
260
+ "bytedance/seed-oss-36b-instruct": {
261
+ "codingIndex": 56.0, "mathIndex": 54.0, "agenticIndex": 50.0, "reasoningIndex": 53.0,
262
+ "mmluPro": 60.0, "gpqa": 40.0, "hle": 6.0, "contextWindow": 32000,
263
+ "supportsReasoning": false, "supportsVision": false,
264
+ "lastUpdated": "2026-07-20", "originalModel": "Seed OSS 36B"
265
+ },
266
+ "stockmark/stockmark-2-100b-instruct": {
267
+ "codingIndex": 36.0, "mathIndex": 34.0, "agenticIndex": 30.0, "reasoningIndex": 33.0,
268
+ "mmluPro": 40.0, "gpqa": 24.0, "hle": 3.0, "contextWindow": 32000,
269
+ "supportsReasoning": false, "supportsVision": false,
270
+ "lastUpdated": "2026-07-20", "originalModel": "Stockmark 100B"
271
+ },
272
+ "codestral-latest": {
273
+ "codingIndex": 42.0, "mathIndex": 40.0, "agenticIndex": 38.0, "reasoningIndex": 39.0,
274
+ "mmluPro": 48.0, "gpqa": 30.0, "hle": 4.0, "contextWindow": 32000,
275
+ "supportsReasoning": false, "supportsVision": false,
276
+ "lastUpdated": "2026-07-20", "originalModel": "Codestral Latest"
277
+ },
278
+ "qwen/qwq-32b": {
279
+ "codingIndex": 58.0, "mathIndex": 82.0, "agenticIndex": 50.0, "reasoningIndex": 76.0,
280
+ "mmluPro": 75.0, "gpqa": 64.0, "hle": 11.0, "contextWindow": 131072,
281
+ "supportsReasoning": true, "supportsVision": false,
282
+ "lastUpdated": "2026-07-20", "originalModel": "QwQ 32B"
283
+ },
284
+ "poolside/laguna-m.1:free": {
285
+ "codingIndex": 72.0, "mathIndex": 68.0, "agenticIndex": 65.0, "reasoningIndex": 69.0,
286
+ "mmluPro": 74.0, "gpqa": 50.0, "hle": 9.5, "contextWindow": 262000,
287
+ "supportsReasoning": false, "supportsVision": false,
288
+ "lastUpdated": "2026-07-20", "originalModel": "Poolside Laguna M.1"
289
+ },
290
+ "poolside/laguna-xs.2:free": {
291
+ "codingIndex": 68.0, "mathIndex": 65.0, "agenticIndex": 62.0, "reasoningIndex": 65.0,
292
+ "mmluPro": 70.0, "gpqa": 47.0, "hle": 8.5, "contextWindow": 262000,
293
+ "supportsReasoning": false, "supportsVision": false,
294
+ "lastUpdated": "2026-07-20", "originalModel": "Poolside Laguna XS.2"
295
+ },
296
+ "@cf/qwen/qwen3-30b-a3b-fp8": {
297
+ "codingIndex": 65.0, "mathIndex": 64.0, "agenticIndex": 58.0, "reasoningIndex": 63.0,
298
+ "mmluPro": 70.0, "gpqa": 48.0, "hle": 8.0, "contextWindow": 131072,
299
+ "supportsReasoning": true, "supportsVision": false,
300
+ "lastUpdated": "2026-07-20", "originalModel": "Qwen3 30B A3B"
301
+ }
302
+ }
package/src/tui/app.js CHANGED
@@ -149,6 +149,69 @@ const mergedModels = buildMergedModels(MODELS)
149
149
  const mergedModelByLabel = new Map(mergedModels.map(m => [m.label, m]))
150
150
  setOpenCodeModelData(mergedModels, mergedModelByLabel)
151
151
 
152
+ // ๐Ÿ“– Enrichment (t4 + t5): module-level state. The sync part (extended
153
+ // ๐Ÿ“– benchmark catalog stats) is computed lazily on first read via the
154
+ // ๐Ÿ“– getter, so we don't block module load. The async part (models.dev
155
+ // ๐Ÿ“– fetch) runs inside runApp as a background task โ€” never at module load,
156
+ // ๐Ÿ“– never blocking the TUI from rendering.
157
+ // ๐Ÿ“–
158
+ // ๐Ÿ“– The TUI reads from this object on every render to update the footer chips.
159
+ const moduleEnrichmentStats = {
160
+ bench: { total: 0, lastUpdated: 'unknown', source: 'unknown' },
161
+ modelsDev: { 'sources.js': 0, 'models.dev': 0, cached: false },
162
+ }
163
+ let _benchStatsLoaded = false
164
+ function ensureBenchStatsLoaded() {
165
+ if (_benchStatsLoaded) return
166
+ _benchStatsLoaded = true
167
+ try {
168
+ // ๐Ÿ“– require() works synchronously and is safe at module load because
169
+ // ๐Ÿ“– model-merger.js has no top-level await side effects.
170
+ const { getEnrichmentStats } = require('../core/model-merger.js')
171
+ moduleEnrichmentStats.bench = getEnrichmentStats().extendedBench
172
+ } catch (err) {
173
+ if (process.env.FCM_BENCH_DEBUG) console.warn('[t4] enrichment stats failed:', err?.message ?? err)
174
+ }
175
+ }
176
+
177
+ // ๐Ÿ“– Background enrichment: fetch models.dev and update moduleEnrichmentStats
178
+ // ๐Ÿ“– when it resolves. Fully decoupled from runApp โ€” even if the fetch hangs
179
+ // ๐Ÿ“– for 30s+, the TUI keeps rendering. The chip is updated by the next render
180
+ // ๐Ÿ“– after resolution.
181
+ function runModelsDevEnrichmentInBackground(merged) {
182
+ // ๐Ÿ“– Fire-and-forget; never awaited. If it throws, the catch swallows it.
183
+ ;(async () => {
184
+ try {
185
+ // ๐Ÿ“– Bound the total wait to 12s (worst case 3ร—4s retries). If the
186
+ // ๐Ÿ“– network is truly down, the chip stays at "0 live" and the TUI
187
+ // ๐Ÿ“– is unaffected. Callers can still trigger a refresh via the
188
+ // ๐Ÿ“– settings panel (future work).
189
+ const timeout = new Promise(resolve => setTimeout(() => resolve(null), 12_000))
190
+ const { overlayModelsDevMetadata } = await import('../core/model-merger.js')
191
+ const result = await Promise.race([
192
+ overlayModelsDevMetadata(merged, { mutate: true }),
193
+ timeout,
194
+ ])
195
+ if (!result) {
196
+ if (process.env.FCM_BENCH_DEBUG) console.warn('[t5] models.dev fetch timed out (12s)')
197
+ return
198
+ }
199
+ let live = 0, curated = 0
200
+ for (const m of result) {
201
+ if (m.metaSource === 'models.dev') live++
202
+ else if (m.metaSource === 'sources.js') curated++
203
+ }
204
+ moduleEnrichmentStats.modelsDev = { 'sources.js': curated, 'models.dev': live, cached: true }
205
+ // ๐Ÿ“– Note: state is owned by runApp โ€” we don't have a direct ref here.
206
+ // ๐Ÿ“– The footer reads moduleEnrichmentStats lazily on each render, so
207
+ // ๐Ÿ“– the next render will pick up the new counts. We do NOT trigger a
208
+ // ๐Ÿ“– render from here (we're not in the render context).
209
+ } catch (err) {
210
+ if (process.env.FCM_BENCH_DEBUG) console.warn('[t5] models.dev overlay failed:', err?.message ?? err)
211
+ }
212
+ })()
213
+ }
214
+
152
215
  // ๐Ÿ“– Provider quota cache is managed by lib/provider-quota-fetchers.js (TTL + backoff).
153
216
  // ๐Ÿ“– Usage placeholder logic uses isKnownQuotaTelemetry() from lib/quota-capabilities.js.
154
217
 
@@ -189,6 +252,16 @@ const LOCAL_VERSION = pkg.version
189
252
  // ๐Ÿ“– OpenCode helpers are imported from ../src/opencode.js
190
253
 
191
254
  export async function runApp(cliArgs, config, startupOptions = {}) {
255
+ // ๐Ÿ“– t4: prime the sync extended-benchmark stats so the footer chip is
256
+ // ๐Ÿ“– accurate on the first render (no async, no network โ€” just a sync read).
257
+ ensureBenchStatsLoaded()
258
+
259
+ // ๐Ÿ“– t5: kick off the async models.dev enrichment in the background. This
260
+ // ๐Ÿ“– does NOT block runApp โ€” the TUI starts rendering immediately with
261
+ // ๐Ÿ“– curated values, then re-renders when the models.dev fetch resolves.
262
+ // ๐Ÿ“– If the network is unreachable, the chip just stays at "0 live" forever
263
+ // ๐Ÿ“– (no user-visible freeze). The background task is bounded to 12s.
264
+ runModelsDevEnrichmentInBackground(mergedModels)
192
265
 
193
266
  // ๐Ÿ“– Detect user active terminal theme
194
267
  detectActiveTheme(config.settings?.theme || 'auto')
@@ -505,8 +578,27 @@ export async function runApp(cliArgs, config, startupOptions = {}) {
505
578
  }
506
579
  state.probeCacheHits = probeCacheHits
507
580
  state.probeCacheMisses = probeCacheMisses
581
+ // ๐Ÿ“– Enrichment (t4 + t5): pulled fresh on every render from moduleEnrichmentStats
582
+ // ๐Ÿ“– (see the tableOpts construction below). No need to mirror into state here.
508
583
  state.probeCacheBrokenHidden = state.results.filter(r => r.cachedBroken && r.hidden).length
509
584
 
585
+ // ๐Ÿ“– Runtime telemetry (t3): load the per-model metrics file + compute the
586
+ // ๐Ÿ“– real-world score for each result so the table can sort/display it.
587
+ // ๐Ÿ“– The file may not exist yet (no daemon traffic) โ€” that's fine, every
588
+ // ๐Ÿ“– r.realWorldScore stays null and we fall back to SWE-bench.
589
+ try {
590
+ const { loadRuntimeTelemetry, getRealWorldScore } = await import('../core/runtime-telemetry.js')
591
+ loadRuntimeTelemetry() // ๐Ÿ“– populate module-level cache
592
+ for (const r of state.results) {
593
+ const score = getRealWorldScore(r.providerKey, r.modelId)
594
+ r.realWorldScore = score // null when below MIN_CALLS_FOR_SCORE
595
+ }
596
+ state.runtimeTelemetryLoaded = true
597
+ } catch (err) {
598
+ state.runtimeTelemetryLoaded = false
599
+ state.runtimeTelemetryError = err?.message || String(err)
600
+ }
601
+
510
602
  // ๐Ÿ“– Define pingModel before JSON mode so `--json` can reuse the same provider-aware
511
603
  // ๐Ÿ“– ping path as the interactive TUI without waiting for the PTY/render loop setup.
512
604
  pingModel = async (r) => {
@@ -954,6 +1046,17 @@ export async function runApp(cliArgs, config, startupOptions = {}) {
954
1046
  probeCacheMisses: state.probeCacheMisses || 0,
955
1047
  probeCacheBrokenHidden: state.probeCacheBrokenHidden || 0,
956
1048
  showBrokenMode: !!state.showBrokenMode,
1049
+ // ๐Ÿ“– Enrichment chips (t4 + t5): benchmark catalog + models.dev provenance
1050
+ // ๐Ÿ“– Read fresh from moduleEnrichmentStats on every render so the async
1051
+ // ๐Ÿ“– models.dev fetch (background, never blocks the TUI) is reflected as
1052
+ // ๐Ÿ“– soon as it resolves โ€” even if the user isn't pressing keys.
1053
+ enrichmentBenchCount: moduleEnrichmentStats.bench.total || 0,
1054
+ enrichmentBenchLastUpdated: moduleEnrichmentStats.bench.lastUpdated || null,
1055
+ metaSourceCounts: {
1056
+ 'sources.js': moduleEnrichmentStats.modelsDev['sources.js'] || 0,
1057
+ 'models.dev': moduleEnrichmentStats.modelsDev['models.dev'] || 0,
1058
+ },
1059
+ modelsDevCacheCached: moduleEnrichmentStats.modelsDev.cached === true,
957
1060
  // ๐Ÿ“– Passive quota (t2): live snapshots from response headers, populated
958
1061
  // ๐Ÿ“– by pings (every ping pre-warms quota for its provider). See
959
1062
  // ๐Ÿ“– src/core/provider-quota-fetchers.js for getAllPassiveQuotas().
@@ -36,6 +36,8 @@ const ANALYSIS_FLAGS = [
36
36
  { flag: '--reprobe, --no-cache', description: 'Force-rebuild the persistent probe-cache this run (skip cached healthy models)' },
37
37
  { flag: '--probe-ttl <ms>', description: 'Override probe-cache TTL (default 24h); healthy models within TTL are not re-pinged' },
38
38
  { flag: '--show-broken', description: "Don't auto-hide models that the probe-cache marked broken (one-shot override)" },
39
+ { flag: '--check-drift', description: 'Diff sources.js against models.dev and print a drift report; exit 1 on mismatch (t5)' },
40
+ { flag: '--drift-threshold <N>', description: 'Only fail --check-drift when N+ mismatches are found (default: 0 = any drift)' },
39
41
  ]
40
42
 
41
43
  const CONFIG_FLAGS = [
@@ -836,6 +836,40 @@ export function createKeyHandler(ctx) {
836
836
  state.tokenUsageError = null
837
837
  }
838
838
 
839
+ // ๐Ÿ“– Runtime Report overlay (t3): per-model real-world breakdown + recent calls.
840
+ // ๐Ÿ“– Reads the local ~/.free-coding-models/runtime-telemetry.json file directly
841
+ // ๐Ÿ“– (the daemon writes to the same file; the CLI doesn't need to talk to it).
842
+ async function openRuntimeReportOverlay() {
843
+ state.runtimeReportOpen = true
844
+ state.runtimeReportScrollOffset = 0
845
+ state.runtimeReportError = null
846
+ state.runtimeReportData = null
847
+ state.runtimeReportSelectedKey = null
848
+ try {
849
+ const { loadRuntimeTelemetry, getAllModelTelemetry } = await import('../core/runtime-telemetry.js')
850
+ const cache = loadRuntimeTelemetry()
851
+ const all = getAllModelTelemetry({ cache })
852
+ const entries = Object.entries(all).sort((a, b) => (b[1].totalCalls || 0) - (a[1].totalCalls || 0))
853
+ state.runtimeReportData = entries
854
+ // ๐Ÿ“– Pre-select the currently-focused model if it has telemetry.
855
+ const focused = state.visibleSorted?.[state.cursor]
856
+ if (focused) {
857
+ const key = `${focused.providerKey}/${focused.modelId}`
858
+ if (entries.find(([k]) => k === key)) state.runtimeReportSelectedKey = key
859
+ }
860
+ } catch (err) {
861
+ state.runtimeReportError = err?.message || 'Failed to load runtime telemetry'
862
+ }
863
+ }
864
+
865
+ function closeRuntimeReportOverlay() {
866
+ state.runtimeReportOpen = false
867
+ state.runtimeReportScrollOffset = 0
868
+ state.runtimeReportError = null
869
+ state.runtimeReportData = null
870
+ state.runtimeReportSelectedKey = null
871
+ }
872
+
839
873
 
840
874
  function cycleToolMode() {
841
875
  const modeOrder = getToolModeOrder()
@@ -1355,6 +1389,7 @@ export function createKeyHandler(ctx) {
1355
1389
  case 'sort-verdict': return setSortColumnFromCommand('verdict')
1356
1390
  case 'sort-stability': return setSortColumnFromCommand('stability')
1357
1391
  case 'sort-uptime': return setSortColumnFromCommand('uptime')
1392
+ case 'sort-realworld': return setSortColumnFromCommand('realworld')
1358
1393
  case 'open-settings': return openSettingsOverlay()
1359
1394
  case 'open-help':
1360
1395
  state.helpVisible = true
@@ -1366,6 +1401,7 @@ export function createKeyHandler(ctx) {
1366
1401
  case 'open-router-dashboard': return openRouterDashboardOverlay(state)
1367
1402
  case 'open-playground': return openPlaygroundOverlay(state)
1368
1403
  case 'open-token-usage': return openTokenUsageOverlay()
1404
+ case 'open-runtime-report': return openRuntimeReportOverlay()
1369
1405
  case 'open-install-endpoints': return openInstallEndpointsOverlay()
1370
1406
  case 'open-installed-models': return openInstalledModelsOverlay()
1371
1407
  case 'action-cycle-theme': return cycleGlobalTheme()
@@ -2120,6 +2156,42 @@ export function createKeyHandler(ctx) {
2120
2156
  return
2121
2157
  }
2122
2158
 
2159
+ // ๐Ÿ“– Runtime Report overlay (t3): Shift+W. Per-model real-world breakdown +
2160
+ // ๐Ÿ“– recent calls. Scrolling with up/down/pageup/pagedown/escape.
2161
+ if (state.runtimeReportOpen) {
2162
+ if (key.ctrl && key.name === 'c') { exit(0); return }
2163
+ const pageStep = Math.max(1, (state.terminalRows || 1) - 4)
2164
+ if (key.name === 'escape') {
2165
+ closeRuntimeReportOverlay()
2166
+ return
2167
+ }
2168
+ if (key.name === 'up' || key.name === 'k') {
2169
+ state.runtimeReportScrollOffset = Math.max(0, state.runtimeReportScrollOffset - 1)
2170
+ return
2171
+ }
2172
+ if (key.name === 'down' || key.name === 'j') {
2173
+ state.runtimeReportScrollOffset += 1
2174
+ return
2175
+ }
2176
+ if (key.name === 'pageup') {
2177
+ state.runtimeReportScrollOffset = Math.max(0, state.runtimeReportScrollOffset - pageStep)
2178
+ return
2179
+ }
2180
+ if (key.name === 'pagedown') {
2181
+ state.runtimeReportScrollOffset += pageStep
2182
+ return
2183
+ }
2184
+ if (key.name === 'home') {
2185
+ state.runtimeReportScrollOffset = 0
2186
+ return
2187
+ }
2188
+ if (key.name === 'end') {
2189
+ state.runtimeReportScrollOffset = Number.MAX_SAFE_INTEGER
2190
+ return
2191
+ }
2192
+ return
2193
+ }
2194
+
2123
2195
  // ๐Ÿ“– Router Onboarding overlay: shown on first launch. Y=yes enable, N=not now, Esc=cancel.
2124
2196
  if (state.routerOnboardingOpen) {
2125
2197
  if (key.ctrl && key.name === 'c') { exit(0); return }
@@ -2872,6 +2944,14 @@ export function createKeyHandler(ctx) {
2872
2944
  return
2873
2945
  }
2874
2946
 
2947
+ // ๐Ÿ“– Shift+W: open the Runtime Report overlay (t3) โ€” per-model real-world
2948
+ // ๐Ÿ“– success rate + throughput + recent calls. See command palette
2949
+ // ๐Ÿ“– 'open-runtime-report' for the same action.
2950
+ if (key.name === 'w' && key.shift && !key.alt && !key.ctrl && !key.meta) {
2951
+ openRuntimeReportOverlay()
2952
+ return
2953
+ }
2954
+
2875
2955
  // ๐Ÿ“– E cycles: Normal โ†’ Configured only โ†’ Usable only โ†’ Normal
2876
2956
  // ๐Ÿ“– Configured only: hides models with no key or noauth/auth_error health
2877
2957
  // ๐Ÿ“– Usable only: only shows models with Health UP and Verdict โ‰ค Slow (Perfect/Normal/Slow)
@@ -155,6 +155,13 @@ export const PROVIDER_COLOR = new Proxy({}, {
155
155
  * probeCacheMisses?: number, // t1: number of models that needed a live probe
156
156
  * probeCacheBrokenHidden?: number, // t1: number of broken models auto-hidden this session
157
157
  * showBrokenMode?: boolean, // t1: true when Shift+B has un-hidden broken models
158
+ * enrichmentBenchCount?: number, // t4: extended benchmark catalog size (committed JSON)
159
+ * enrichmentBenchLastUpdated?: string, // t4: lastUpdated field from the catalog _meta
160
+ * metaSourceCounts?: { // t5: count of models per metadata source
161
+ * 'sources.js': number,
162
+ * 'models.dev': number,
163
+ * },
164
+ * modelsDevCacheCached?: boolean, // t5: whether the models.dev cache is still within TTL
158
165
  * quota?: Record<string, { // t2: live quota from response headers
159
166
  * remaining: number, limit: number, percent: number,
160
167
  * source: 'header'|'endpoint', lastUpdated: number, windowType?: string,
@@ -209,6 +216,10 @@ export function renderTable({
209
216
  probeCacheMisses = 0,
210
217
  probeCacheBrokenHidden = 0,
211
218
  showBrokenMode = false,
219
+ enrichmentBenchCount = 0,
220
+ enrichmentBenchLastUpdated = null,
221
+ metaSourceCounts = null,
222
+ modelsDevCacheCached = false,
212
223
  quota = {},
213
224
  } = _) {
214
225
  // ๐Ÿ“– Filter out hidden models for display
@@ -1224,6 +1235,29 @@ export function renderTable({
1224
1235
  probeCacheLabel = chalk.bgRgb(40, 90, 140).rgb(220, 235, 255).bold(` ${cachedTxt}${brokenTxt} `)
1225
1236
  }
1226
1237
 
1238
+ // ๐Ÿ“– Enrichment chips (t4 + t5):
1239
+ // ๐Ÿ“– `๐Ÿ“Š bench N (date) ยท ๐Ÿ“ก live K / ๐Ÿ“ฆ cached M`
1240
+ // ๐Ÿ“– Always shown when any enrichment state exists.
1241
+ let enrichmentLabel = ''
1242
+ if ((enrichmentBenchCount && enrichmentBenchCount > 0) || metaSourceCounts) {
1243
+ const parts = []
1244
+ if (enrichmentBenchCount && enrichmentBenchCount > 0) {
1245
+ const dateTxt = enrichmentBenchLastUpdated && enrichmentBenchLastUpdated !== 'unknown'
1246
+ ? ` (${enrichmentBenchLastUpdated})`
1247
+ : ''
1248
+ parts.push(`๐Ÿ“Š bench ${enrichmentBenchCount}${dateTxt}`)
1249
+ }
1250
+ if (metaSourceCounts && (metaSourceCounts['models.dev'] > 0 || metaSourceCounts['sources.js'] > 0)) {
1251
+ const liveTxt = metaSourceCounts['models.dev'] ?? 0
1252
+ const cachedTxt = metaSourceCounts['sources.js'] ?? 0
1253
+ const liveIcon = modelsDevCacheCached ? '๐Ÿ“ก' : '๐Ÿ“ฆ'
1254
+ parts.push(`${liveIcon} ${liveTxt} live ยท ${cachedTxt} curated`)
1255
+ }
1256
+ if (parts.length > 0) {
1257
+ enrichmentLabel = chalk.bgRgb(80, 50, 110).rgb(230, 220, 245).bold(` ${parts.join(' ยท ')} `)
1258
+ }
1259
+ }
1260
+
1227
1261
  // ๐Ÿ“– Passive quota chip (t2): `๐Ÿ“Š groq 78% ยท sambanova 41%` (top-N depleted first).
1228
1262
  // ๐Ÿ“– Shows live rate-limit headers that the daemon / pings collected from upstream
1229
1263
  // ๐Ÿ“– responses. Zero extra network requests โ€” see provider-quota-fetchers.js.
@@ -1243,8 +1277,8 @@ export function renderTable({
1243
1277
  }
1244
1278
  }
1245
1279
 
1246
- // ๐Ÿ“– Line 3: Speed Test + Global Benchmark + Probe + Probe-cache + Quota + Last release
1247
- if (releaseLabel || speedTestLabel || globalBenchmarkLabel || probeLabel || probeCacheLabel || quotaLabel) {
1280
+ // ๐Ÿ“– Line 3: Speed Test + Global Benchmark + Probe + Probe-cache + Enrichment + Quota + Last release
1281
+ if (releaseLabel || speedTestLabel || globalBenchmarkLabel || probeLabel || probeCacheLabel || enrichmentLabel || quotaLabel) {
1248
1282
  const parts = [
1249
1283
  { text: ' ', key: null },
1250
1284
  { text: speedTestLabel, key: 'a' },
@@ -1254,6 +1288,8 @@ export function renderTable({
1254
1288
  { text: probeLabel, key: null },
1255
1289
  { text: probeCacheLabel ? ' ' : '', key: null },
1256
1290
  { text: probeCacheLabel, key: null },
1291
+ { text: enrichmentLabel ? ' ' : '', key: null },
1292
+ { text: enrichmentLabel, key: null },
1257
1293
  { text: quotaLabel ? ' ' : '', key: null },
1258
1294
  { text: quotaLabel, key: null },
1259
1295
  { text: ' ', key: null },
@@ -297,6 +297,15 @@ export function createTuiState({
297
297
  probeCacheTtlMs: null, // ๐Ÿ“– Set in app.js from cliArgs.probeTtlMs || DEFAULT
298
298
  showBrokenMode: false,
299
299
 
300
+ // ๐Ÿ“– Runtime telemetry overlay state (t3): Shift+W opens the Runtime Report
301
+ // ๐Ÿ“– overlay. Data is loaded fresh from ~/.free-coding-models/runtime-telemetry.json
302
+ // ๐Ÿ“– when the overlay opens โ€” no polling, no daemon dependency.
303
+ runtimeReportOpen: false,
304
+ runtimeReportScrollOffset: 0,
305
+ runtimeReportError: null,
306
+ runtimeReportData: null, // ๐Ÿ“– Array<[key, ModelTelemetry]>
307
+ runtimeReportSelectedKey: null, // ๐Ÿ“– Pre-selected model key
308
+
300
309
  // ๐Ÿ“– Header click flash animation: briefly highlights the clicked column header
301
310
  // ๐Ÿ“– with an inverse/bright style for ~250ms (3 frames at 12 FPS).
302
311
  headerFlashColumn: null, // ๐Ÿ“– Column name being flashed (null = no flash active)