free-coding-models 0.5.85 → 0.5.87

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.
Files changed (164) hide show
  1. package/README.md +110 -881
  2. package/bin/free-coding-models.js +4 -1
  3. package/changelog/v0.5.86.md +10 -0
  4. package/changelog/v0.5.87.md +48 -0
  5. package/package.json +8 -5
  6. package/sources.js +4 -4
  7. package/src/core/cache.js +3 -1
  8. package/src/core/config.js +43 -5
  9. package/src/core/endpoint-installer.js +23 -12
  10. package/src/core/installed-models-manager.js +43 -20
  11. package/src/core/kilo-config.js +51 -5
  12. package/src/core/kilo.js +5 -3
  13. package/src/core/legacy-proxy-cleanup.js +22 -5
  14. package/src/core/model-merger.js +4 -0
  15. package/src/core/models-drift.js +9 -0
  16. package/src/core/opencode-config.js +57 -5
  17. package/src/core/opencode.js +67 -41
  18. package/src/core/playground.js +7 -0
  19. package/src/core/probe-cache.js +35 -4
  20. package/src/core/provider-key-tester.js +10 -2
  21. package/src/core/provider-metadata.js +10 -0
  22. package/src/core/provider-quota-fetchers.js +14 -7
  23. package/src/core/router-daemon.js +208 -26
  24. package/src/core/runtime-telemetry.js +27 -1
  25. package/src/core/shared-helpers.js +12 -1
  26. package/src/core/shell-env.js +3 -1
  27. package/src/core/telemetry.js +18 -5
  28. package/src/core/tool-launchers.js +9 -6
  29. package/src/core/updater.js +28 -2
  30. package/src/core/utils.js +76 -71
  31. package/src/tui/app.js +47 -16
  32. package/src/tui/command-palette.js +22 -2
  33. package/src/tui/key-handler.js +123 -179
  34. package/src/tui/overlays.js +35 -75
  35. package/src/tui/render-helpers.js +62 -4
  36. package/src/tui/render-table.js +46 -5
  37. package/src/tui/theme.js +36 -5
  38. package/src/tui/tui-filters.js +28 -8
  39. package/src/tui/tui-state.js +22 -6
  40. package/web/dist/assets/index-BpTpPS0g.js +44 -0
  41. package/web/dist/assets/index-CAzFIt8P.css +1 -0
  42. package/web/dist/index.html +5 -9
  43. package/web/index.html +3 -7
  44. package/web/server.js +97 -23
  45. package/web/vite.config.js +8 -0
  46. package/web/app.legacy.js +0 -900
  47. package/web/dist/assets/index-C5-Ywvv3.css +0 -1
  48. package/web/dist/assets/index-DWUely84.js +0 -40
  49. package/web/public/favicon.ico +0 -0
  50. package/web/public/favicons/apple-touch-icon.png +0 -0
  51. package/web/public/favicons/browserconfig.xml +0 -12
  52. package/web/public/favicons/favicon-16x16.png +0 -0
  53. package/web/public/favicons/favicon-192x192.png +0 -0
  54. package/web/public/favicons/favicon-32x32.png +0 -0
  55. package/web/public/favicons/favicon-48x48.png +0 -0
  56. package/web/public/favicons/favicon-512x512.png +0 -0
  57. package/web/public/favicons/favicon-96x96.png +0 -0
  58. package/web/public/favicons/favicon.ico +0 -0
  59. package/web/public/favicons/mstile-150x150.png +0 -0
  60. package/web/public/favicons/mstile-310x150.png +0 -0
  61. package/web/public/favicons/mstile-310x310.png +0 -0
  62. package/web/public/favicons/mstile-512x512.png +0 -0
  63. package/web/public/favicons/mstile-70x70.png +0 -0
  64. package/web/public/favicons/site.webmanifest +0 -25
  65. package/web/src/App.jsx +0 -521
  66. package/web/src/components/analytics/AnalyticsView.jsx +0 -147
  67. package/web/src/components/analytics/AnalyticsView.module.css +0 -190
  68. package/web/src/components/analytics/TokenUsagePanel.jsx +0 -105
  69. package/web/src/components/analytics/TokenUsagePanel.module.css +0 -126
  70. package/web/src/components/atoms/AILatencyCell.jsx +0 -38
  71. package/web/src/components/atoms/AILatencyCell.module.css +0 -51
  72. package/web/src/components/atoms/HealthCell.jsx +0 -143
  73. package/web/src/components/atoms/HealthCell.module.css +0 -60
  74. package/web/src/components/atoms/LastPingCell.jsx +0 -35
  75. package/web/src/components/atoms/LastPingCell.module.css +0 -45
  76. package/web/src/components/atoms/MoodCell.jsx +0 -25
  77. package/web/src/components/atoms/MoodCell.module.css +0 -6
  78. package/web/src/components/atoms/NoKeyIcon.jsx +0 -65
  79. package/web/src/components/atoms/NoKeyIcon.module.css +0 -30
  80. package/web/src/components/atoms/ProviderLogo.jsx +0 -187
  81. package/web/src/components/atoms/ProviderLogo.module.css +0 -103
  82. package/web/src/components/atoms/RankCell.jsx +0 -9
  83. package/web/src/components/atoms/RankCell.module.css +0 -9
  84. package/web/src/components/atoms/Sparkline.jsx +0 -63
  85. package/web/src/components/atoms/StabilityCell.jsx +0 -18
  86. package/web/src/components/atoms/StabilityCell.module.css +0 -13
  87. package/web/src/components/atoms/StatusDot.jsx +0 -13
  88. package/web/src/components/atoms/StatusDot.module.css +0 -29
  89. package/web/src/components/atoms/TPSCell.jsx +0 -36
  90. package/web/src/components/atoms/TPSCell.module.css +0 -44
  91. package/web/src/components/atoms/TierBadge.jsx +0 -10
  92. package/web/src/components/atoms/TierBadge.module.css +0 -29
  93. package/web/src/components/atoms/Toast.jsx +0 -25
  94. package/web/src/components/atoms/Toast.module.css +0 -41
  95. package/web/src/components/atoms/ToastContainer.jsx +0 -16
  96. package/web/src/components/atoms/ToastContainer.module.css +0 -10
  97. package/web/src/components/atoms/VerdictBadge.jsx +0 -36
  98. package/web/src/components/atoms/VerdictBadge.module.css +0 -40
  99. package/web/src/components/changelog/ChangelogView.jsx +0 -135
  100. package/web/src/components/changelog/ChangelogView.module.css +0 -159
  101. package/web/src/components/dashboard/DetailPanel.jsx +0 -217
  102. package/web/src/components/dashboard/DetailPanel.module.css +0 -260
  103. package/web/src/components/dashboard/ExpandedDetailRow.jsx +0 -361
  104. package/web/src/components/dashboard/ExpandedDetailRow.module.css +0 -356
  105. package/web/src/components/dashboard/ExportModal.jsx +0 -84
  106. package/web/src/components/dashboard/ExportModal.module.css +0 -99
  107. package/web/src/components/dashboard/FilterBar.jsx +0 -338
  108. package/web/src/components/dashboard/FilterBar.module.css +0 -342
  109. package/web/src/components/dashboard/ModelTable.jsx +0 -672
  110. package/web/src/components/dashboard/ModelTable.module.css +0 -446
  111. package/web/src/components/dashboard/ProviderDropdown.jsx +0 -156
  112. package/web/src/components/dashboard/ProviderDropdown.module.css +0 -248
  113. package/web/src/components/help/HelpView.jsx +0 -201
  114. package/web/src/components/help/HelpView.module.css +0 -156
  115. package/web/src/components/install/InstallEndpointsView.jsx +0 -309
  116. package/web/src/components/install/InstallEndpointsView.module.css +0 -427
  117. package/web/src/components/installed/InstalledModelsView.jsx +0 -89
  118. package/web/src/components/installed/InstalledModelsView.module.css +0 -200
  119. package/web/src/components/launch/IncompatibleFallbackModal.jsx +0 -69
  120. package/web/src/components/launch/LaunchButton.jsx +0 -30
  121. package/web/src/components/launch/LaunchButton.module.css +0 -35
  122. package/web/src/components/launch/LaunchModal.module.css +0 -125
  123. package/web/src/components/layout/Footer.jsx +0 -19
  124. package/web/src/components/layout/Footer.module.css +0 -10
  125. package/web/src/components/layout/Header.jsx +0 -265
  126. package/web/src/components/layout/Header.module.css +0 -357
  127. package/web/src/components/palette/CommandPalette.jsx +0 -301
  128. package/web/src/components/palette/CommandPalette.module.css +0 -121
  129. package/web/src/components/playground/PlaygroundChat.jsx +0 -527
  130. package/web/src/components/playground/PlaygroundChat.module.css +0 -382
  131. package/web/src/components/playground/PlaygroundView.jsx +0 -371
  132. package/web/src/components/playground/PlaygroundView.module.css +0 -504
  133. package/web/src/components/recommend/RecommendView.jsx +0 -121
  134. package/web/src/components/recommend/RecommendView.module.css +0 -57
  135. package/web/src/components/router/RouterView.jsx +0 -1212
  136. package/web/src/components/router/RouterView.module.css +0 -1289
  137. package/web/src/components/settings/SettingsView.jsx +0 -555
  138. package/web/src/components/settings/SettingsView.module.css +0 -550
  139. package/web/src/components/tools/ToolPicker.jsx +0 -86
  140. package/web/src/components/tools/ToolPicker.module.css +0 -97
  141. package/web/src/components/update/UpdateChip.jsx +0 -104
  142. package/web/src/components/update/UpdateChip.module.css +0 -146
  143. package/web/src/global.css +0 -298
  144. package/web/src/hooks/urlState.constants.js +0 -28
  145. package/web/src/hooks/useChangelog.js +0 -51
  146. package/web/src/hooks/useColumnSizing.js +0 -211
  147. package/web/src/hooks/useFavorites.js +0 -150
  148. package/web/src/hooks/useFilter.js +0 -310
  149. package/web/src/hooks/useInstalledModels.js +0 -42
  150. package/web/src/hooks/useRecommend.js +0 -67
  151. package/web/src/hooks/useRouterDashboard.js +0 -133
  152. package/web/src/hooks/useSSE.js +0 -73
  153. package/web/src/hooks/useSocket.js +0 -203
  154. package/web/src/hooks/useTheme.js +0 -83
  155. package/web/src/hooks/useTokenUsage.js +0 -103
  156. package/web/src/hooks/useToolMode.js +0 -77
  157. package/web/src/hooks/useUpdateChecker.js +0 -91
  158. package/web/src/hooks/useUrlState.js +0 -170
  159. package/web/src/main.jsx +0 -15
  160. package/web/src/utils/download.js +0 -15
  161. package/web/src/utils/format.js +0 -42
  162. package/web/src/utils/m3.js +0 -57
  163. package/web/src/utils/ranks.js +0 -37
  164. package/web/styles.legacy.css +0 -963
@@ -1,309 +0,0 @@
1
- /**
2
- * @file web/src/components/install/InstallEndpointsView.jsx
3
- * @description Install Endpoints wizard — 4-step modal: provider → tool → models → install.
4
- * 📖 M4: Full TUI parity for the install endpoints overlay.
5
- * 📖 Uses existing /api/install-endpoints/providers, /api/install-endpoints/catalog,
6
- * 📖 and /api/install-endpoints/wizard endpoints.
7
- */
8
- import { useState, useEffect, useCallback } from 'react'
9
- import {
10
- IconPlug, IconChevronRight, IconChevronLeft, IconCheck,
11
- IconLoader,
12
- } from '@tabler/icons-react'
13
- import styles from './InstallEndpointsView.module.css'
14
-
15
- const STEPS = ['Provider', 'Tool', 'Models', 'Install']
16
-
17
- export default function InstallEndpointsView({ onClose, onToast }) {
18
- const [step, setStep] = useState(0)
19
- const [providers, setProviders] = useState([])
20
- const [selectedProvider, setSelectedProvider] = useState(null)
21
- const [catalogModels, setCatalogModels] = useState([])
22
- const [selectedTool, setSelectedTool] = useState(null)
23
- const [selectedModels, setSelectedModels] = useState([])
24
- const [scope, setScope] = useState('all')
25
- const [installing, setInstalling] = useState(false)
26
- const [installResult, setInstallResult] = useState(null)
27
- const [loading, setLoading] = useState(true)
28
-
29
- // 📖 Available install targets from ToolPicker's mode list
30
- const TOOLS = [
31
- { id: 'opencode', label: 'OpenCode CLI', emoji: '💻' },
32
- { id: 'opencode-desktop', label: 'OpenCode Desktop', emoji: '🖥️' },
33
- { id: 'openclaw', label: 'OpenClaw', emoji: '🦞' },
34
- { id: 'crush', label: 'Crush', emoji: '💘' },
35
- { id: 'goose', label: 'Goose', emoji: '🪿' },
36
- { id: 'pi', label: 'Pi', emoji: 'π' },
37
- { id: 'aider', label: 'Aider', emoji: '🛠' },
38
- { id: 'qwen', label: 'Qwen', emoji: '🐉' },
39
- { id: 'openhands', label: 'OpenHands', emoji: '🤲' },
40
- { id: 'amp', label: 'Amp', emoji: '⚡' },
41
- { id: 'forgecode', label: 'ForgeCode', emoji: '🔥' },
42
- { id: 'zcode', label: 'ZCode', emoji: '🧊' },
43
- { id: 'fcm_router', label: 'FCM Router', emoji: '🔄' },
44
- ]
45
-
46
- // Load providers on mount
47
- useEffect(() => {
48
- fetch('/api/install-endpoints/providers')
49
- .then(r => r.json())
50
- .then(data => {
51
- setProviders(data.providers || [])
52
- setLoading(false)
53
- })
54
- .catch(() => setLoading(false))
55
- }, [])
56
-
57
- // Load catalog when provider selected
58
- useEffect(() => {
59
- if (!selectedProvider) return
60
- fetch(`/api/install-endpoints/catalog?provider=${selectedProvider.providerKey}`)
61
- .then(r => r.json())
62
- .then(data => setCatalogModels(data.models || []))
63
- .catch(() => setCatalogModels([]))
64
- }, [selectedProvider])
65
-
66
- const toggleModel = useCallback((modelId) => {
67
- setSelectedModels(prev =>
68
- prev.includes(modelId)
69
- ? prev.filter(id => id !== modelId)
70
- : [...prev, modelId]
71
- )
72
- }, [])
73
-
74
- const selectAll = useCallback(() => {
75
- setSelectedModels(catalogModels.map(m => m.modelId))
76
- setScope('all')
77
- }, [catalogModels])
78
-
79
- const selectNone = useCallback(() => {
80
- setSelectedModels([])
81
- setScope('selected')
82
- }, [])
83
-
84
- const canNext = () => {
85
- if (step === 0) return !!selectedProvider
86
- if (step === 1) return !!selectedTool
87
- if (step === 2) return scope === 'all' || selectedModels.length > 0
88
- return true
89
- }
90
-
91
- const handleInstall = async () => {
92
- // 📖 Avance au step 3 d'abord (animation "installing"), puis lance l'install
93
- setStep(3)
94
- setInstalling(true)
95
- setInstallResult(null)
96
- try {
97
- const resp = await fetch('/api/install-endpoints/wizard', {
98
- method: 'POST',
99
- headers: { 'Content-Type': 'application/json' },
100
- body: JSON.stringify({
101
- providerKey: selectedProvider.providerKey,
102
- toolMode: selectedTool,
103
- scope,
104
- modelIds: scope === 'selected' ? selectedModels : [],
105
- }),
106
- })
107
- const data = await resp.json()
108
- if (data.success) {
109
- setInstallResult(data)
110
- onToast?.(`Installed ${data.modelCount} models for ${selectedProvider.label} into ${TOOLS.find(t => t.id === selectedTool)?.label || selectedTool}.`, 'success')
111
- } else {
112
- setInstallResult(null)
113
- onToast?.(`Install failed: ${data.error || 'unknown'}`, 'error')
114
- // 📖 Retour au step 2 si l'install échoue pour laisser réessayer
115
- setStep(2)
116
- }
117
- } catch (err) {
118
- setInstallResult(null)
119
- onToast?.(`Install error: ${err.message}`, 'error')
120
- setStep(2)
121
- } finally {
122
- setInstalling(false)
123
- }
124
- }
125
-
126
- const handleNext = () => {
127
- if (step === 2) {
128
- handleInstall()
129
- return
130
- }
131
- setStep(s => Math.min(s + 1, 3))
132
- }
133
-
134
- const handleBack = () => {
135
- setStep(s => Math.max(s - 1, 0))
136
- }
137
-
138
- return (
139
- <div className={styles.overlay} onClick={(e) => e.target === e.currentTarget && onClose()}>
140
- <div className={styles.modal}>
141
- <div className={styles.header}>
142
- <h2 className={styles.title}>
143
- <IconPlug size={20} stroke={1.5} />
144
- Install Endpoints
145
- </h2>
146
- <button className={styles.closeBtn} onClick={onClose} aria-label="Close">✕</button>
147
- </div>
148
-
149
- {/* Step indicator */}
150
- <div className={styles.steps}>
151
- {STEPS.map((label, i) => (
152
- <div key={i} className={`${styles.step} ${i === step ? styles.stepActive : i < step ? styles.stepDone : ''}`}>
153
- <span className={styles.stepNum}>{i < step ? <IconCheck size={12} /> : i + 1}</span>
154
- <span className={styles.stepLabel}>{label}</span>
155
- </div>
156
- ))}
157
- </div>
158
-
159
- <div className={styles.body}>
160
- {/* Step 0: Select Provider */}
161
- {step === 0 && (
162
- <div className={styles.stepContent}>
163
- <p className={styles.stepDesc}>Choose a provider with a configured API key.</p>
164
- {loading && <div className={styles.loading}>Loading providers…</div>}
165
- {!loading && providers.length === 0 && (
166
- <div className={styles.empty}>No configured providers found. Add API keys in Settings first.</div>
167
- )}
168
- <div className={styles.grid}>
169
- {providers.map((p) => (
170
- <button
171
- key={p.providerKey}
172
- className={`${styles.pickCard} ${selectedProvider?.providerKey === p.providerKey ? styles.pickActive : ''}`}
173
- onClick={() => { setSelectedProvider(p); setStep(1) }}
174
- >
175
- <span className={styles.pickLabel}>{p.label}</span>
176
- <span className={styles.pickMeta}>{p.modelCount} models</span>
177
- </button>
178
- ))}
179
- </div>
180
- </div>
181
- )}
182
-
183
- {/* Step 1: Select Tool */}
184
- {step === 1 && (
185
- <div className={styles.stepContent}>
186
- <p className={styles.stepDesc}>
187
- Install <strong>{selectedProvider?.label}</strong> models into which tool?
188
- </p>
189
- <div className={styles.grid}>
190
- {TOOLS.map((tool) => (
191
- <button
192
- key={tool.id}
193
- className={`${styles.pickCard} ${selectedTool === tool.id ? styles.pickActive : ''}`}
194
- onClick={() => { setSelectedTool(tool.id); setStep(2) }}
195
- >
196
- <span className={styles.pickEmoji}>{tool.emoji}</span>
197
- <span className={styles.pickLabel}>{tool.label}</span>
198
- </button>
199
- ))}
200
- </div>
201
- </div>
202
- )}
203
-
204
- {/* Step 2: Select Models */}
205
- {step === 2 && (
206
- <div className={styles.stepContent}>
207
- <p className={styles.stepDesc}>
208
- Choose models to install from <strong>{selectedProvider?.label}</strong> into <strong>{TOOLS.find(t => t.id === selectedTool)?.label}</strong>.
209
- </p>
210
- <div className={styles.scopeToggle}>
211
- <button className={`${styles.scopeBtn} ${scope === 'all' ? styles.scopeActive : ''}`} onClick={() => { setScope('all'); selectAll() }}>All Models</button>
212
- <button className={`${styles.scopeBtn} ${scope === 'selected' ? styles.scopeActive : ''}`} onClick={() => setScope('selected')}>Select Models</button>
213
- </div>
214
- {scope === 'selected' && (
215
- <div className={styles.modelGrid}>
216
- {catalogModels.map((model) => (
217
- <button
218
- key={model.modelId}
219
- className={`${styles.modelCard} ${selectedModels.includes(model.modelId) ? styles.modelSelected : ''}`}
220
- onClick={() => toggleModel(model.modelId)}
221
- >
222
- <span className={styles.modelName}>{model.label}</span>
223
- <span className={styles.modelTier}>{model.tier}</span>
224
- </button>
225
- ))}
226
- </div>
227
- )}
228
- {scope === 'all' && (
229
- <div className={styles.allNotice}>
230
- All {catalogModels.length} models from {selectedProvider?.label} will be installed.
231
- </div>
232
- )}
233
- </div>
234
- )}
235
-
236
- {/* Step 3: Installing → Done */}
237
- {step === 3 && (
238
- <div className={styles.stepContent}>
239
- {installing && (
240
- <div className={styles.installingState}>
241
- <IconLoader size={32} className={styles.spinner} />
242
- <span className={styles.installingLabel}>Installing {scope === 'all' ? 'all' : selectedModels.length} model{scope === 'all' && catalogModels.length !== 1 ? 's' : selectedModels.length !== 1 ? 's' : ''}…</span>
243
- <span className={styles.installingSub}>Writing config for {TOOLS.find(t => t.id === selectedTool)?.label}</span>
244
- </div>
245
- )}
246
- {!installing && installResult && (
247
- <div className={styles.doneState}>
248
- <div className={styles.checkCircle}>
249
- <IconCheck size={36} />
250
- </div>
251
- <h3 className={styles.doneTitle}>Installed!</h3>
252
- <p className={styles.doneSub}>
253
- {installResult.modelCount} model{installResult.modelCount !== 1 ? 's' : ''} from <strong>{selectedProvider?.label}</strong> → <strong>{installResult.toolLabel}</strong>
254
- </p>
255
- <code className={styles.installPath}>{installResult.path}</code>
256
- </div>
257
- )}
258
- {!installing && !installResult && (
259
- <div className={styles.doneState}>
260
- <span className={styles.errorDot}>✕</span>
261
- <h3 className={styles.doneTitle}>Install failed</h3>
262
- <p className={styles.doneSub}>Check the toast for details. You can go back and retry.</p>
263
- </div>
264
- )}
265
- </div>
266
- )}
267
- </div>
268
-
269
- {/* Footer nav */}
270
- <div className={styles.footer}>
271
- {step > 0 && step < 3 && (
272
- <button className={styles.backBtn} onClick={handleBack}>
273
- <IconChevronLeft size={14} />
274
- Back
275
- </button>
276
- )}
277
- {/* Step 3 error: show Back to retry */}
278
- {step === 3 && !installing && !installResult && (
279
- <button className={styles.backBtn} onClick={() => setStep(2)}>
280
- <IconChevronLeft size={14} />
281
- Back
282
- </button>
283
- )}
284
- {step < 3 && (
285
- <button className={styles.nextBtn} onClick={handleNext} disabled={!canNext()}>
286
- {step === 2 ? (
287
- <>
288
- <IconPlug size={14} />
289
- Install
290
- </>
291
- ) : (
292
- <>
293
- Next
294
- <IconChevronRight size={14} />
295
- </>
296
- )}
297
- </button>
298
- )}
299
- {step === 3 && !installing && installResult && (
300
- <button className={styles.doneBtn} onClick={onClose}>
301
- <IconCheck size={14} />
302
- Done
303
- </button>
304
- )}
305
- </div>
306
- </div>
307
- </div>
308
- )
309
- }