free-coding-models 0.5.86 → 0.5.88

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 (165) hide show
  1. package/README.md +109 -888
  2. package/bin/free-coding-models.js +4 -1
  3. package/changelog/v0.5.87.md +48 -0
  4. package/changelog/v0.5.88.md +16 -0
  5. package/package.json +13 -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/security.js +170 -24
  26. package/src/core/shared-helpers.js +12 -1
  27. package/src/core/shell-env.js +3 -1
  28. package/src/core/telemetry.js +18 -5
  29. package/src/core/tool-launchers.js +9 -6
  30. package/src/core/updater.js +28 -2
  31. package/src/core/utils.js +173 -71
  32. package/src/tui/app.js +38 -14
  33. package/src/tui/command-palette.js +22 -2
  34. package/src/tui/key-handler.js +123 -179
  35. package/src/tui/overlays.js +21 -71
  36. package/src/tui/render-helpers.js +62 -4
  37. package/src/tui/render-table.js +34 -3
  38. package/src/tui/theme.js +36 -5
  39. package/src/tui/tui-filters.js +28 -8
  40. package/src/tui/tui-state.js +22 -6
  41. package/web/dist/assets/index-CAzFIt8P.css +1 -0
  42. package/web/dist/assets/index-DFg1h0Nd.js +44 -0
  43. package/web/dist/index.html +5 -9
  44. package/web/index.html +3 -7
  45. package/web/server.js +97 -23
  46. package/web/vite.config.js +8 -0
  47. package/web/app.legacy.js +0 -900
  48. package/web/dist/assets/index-C5-Ywvv3.css +0 -1
  49. package/web/dist/assets/index-Dm-Xfby9.js +0 -40
  50. package/web/public/favicon.ico +0 -0
  51. package/web/public/favicons/apple-touch-icon.png +0 -0
  52. package/web/public/favicons/browserconfig.xml +0 -12
  53. package/web/public/favicons/favicon-16x16.png +0 -0
  54. package/web/public/favicons/favicon-192x192.png +0 -0
  55. package/web/public/favicons/favicon-32x32.png +0 -0
  56. package/web/public/favicons/favicon-48x48.png +0 -0
  57. package/web/public/favicons/favicon-512x512.png +0 -0
  58. package/web/public/favicons/favicon-96x96.png +0 -0
  59. package/web/public/favicons/favicon.ico +0 -0
  60. package/web/public/favicons/mstile-150x150.png +0 -0
  61. package/web/public/favicons/mstile-310x150.png +0 -0
  62. package/web/public/favicons/mstile-310x310.png +0 -0
  63. package/web/public/favicons/mstile-512x512.png +0 -0
  64. package/web/public/favicons/mstile-70x70.png +0 -0
  65. package/web/public/favicons/site.webmanifest +0 -25
  66. package/web/src/App.jsx +0 -521
  67. package/web/src/components/analytics/AnalyticsView.jsx +0 -147
  68. package/web/src/components/analytics/AnalyticsView.module.css +0 -190
  69. package/web/src/components/analytics/TokenUsagePanel.jsx +0 -105
  70. package/web/src/components/analytics/TokenUsagePanel.module.css +0 -126
  71. package/web/src/components/atoms/AILatencyCell.jsx +0 -38
  72. package/web/src/components/atoms/AILatencyCell.module.css +0 -51
  73. package/web/src/components/atoms/HealthCell.jsx +0 -143
  74. package/web/src/components/atoms/HealthCell.module.css +0 -60
  75. package/web/src/components/atoms/LastPingCell.jsx +0 -35
  76. package/web/src/components/atoms/LastPingCell.module.css +0 -45
  77. package/web/src/components/atoms/MoodCell.jsx +0 -25
  78. package/web/src/components/atoms/MoodCell.module.css +0 -6
  79. package/web/src/components/atoms/NoKeyIcon.jsx +0 -65
  80. package/web/src/components/atoms/NoKeyIcon.module.css +0 -30
  81. package/web/src/components/atoms/ProviderLogo.jsx +0 -187
  82. package/web/src/components/atoms/ProviderLogo.module.css +0 -103
  83. package/web/src/components/atoms/RankCell.jsx +0 -9
  84. package/web/src/components/atoms/RankCell.module.css +0 -9
  85. package/web/src/components/atoms/Sparkline.jsx +0 -63
  86. package/web/src/components/atoms/StabilityCell.jsx +0 -18
  87. package/web/src/components/atoms/StabilityCell.module.css +0 -13
  88. package/web/src/components/atoms/StatusDot.jsx +0 -13
  89. package/web/src/components/atoms/StatusDot.module.css +0 -29
  90. package/web/src/components/atoms/TPSCell.jsx +0 -36
  91. package/web/src/components/atoms/TPSCell.module.css +0 -44
  92. package/web/src/components/atoms/TierBadge.jsx +0 -10
  93. package/web/src/components/atoms/TierBadge.module.css +0 -29
  94. package/web/src/components/atoms/Toast.jsx +0 -25
  95. package/web/src/components/atoms/Toast.module.css +0 -41
  96. package/web/src/components/atoms/ToastContainer.jsx +0 -16
  97. package/web/src/components/atoms/ToastContainer.module.css +0 -10
  98. package/web/src/components/atoms/VerdictBadge.jsx +0 -36
  99. package/web/src/components/atoms/VerdictBadge.module.css +0 -40
  100. package/web/src/components/changelog/ChangelogView.jsx +0 -135
  101. package/web/src/components/changelog/ChangelogView.module.css +0 -159
  102. package/web/src/components/dashboard/DetailPanel.jsx +0 -217
  103. package/web/src/components/dashboard/DetailPanel.module.css +0 -260
  104. package/web/src/components/dashboard/ExpandedDetailRow.jsx +0 -361
  105. package/web/src/components/dashboard/ExpandedDetailRow.module.css +0 -356
  106. package/web/src/components/dashboard/ExportModal.jsx +0 -84
  107. package/web/src/components/dashboard/ExportModal.module.css +0 -99
  108. package/web/src/components/dashboard/FilterBar.jsx +0 -338
  109. package/web/src/components/dashboard/FilterBar.module.css +0 -342
  110. package/web/src/components/dashboard/ModelTable.jsx +0 -672
  111. package/web/src/components/dashboard/ModelTable.module.css +0 -446
  112. package/web/src/components/dashboard/ProviderDropdown.jsx +0 -156
  113. package/web/src/components/dashboard/ProviderDropdown.module.css +0 -248
  114. package/web/src/components/help/HelpView.jsx +0 -201
  115. package/web/src/components/help/HelpView.module.css +0 -156
  116. package/web/src/components/install/InstallEndpointsView.jsx +0 -309
  117. package/web/src/components/install/InstallEndpointsView.module.css +0 -427
  118. package/web/src/components/installed/InstalledModelsView.jsx +0 -89
  119. package/web/src/components/installed/InstalledModelsView.module.css +0 -200
  120. package/web/src/components/launch/IncompatibleFallbackModal.jsx +0 -69
  121. package/web/src/components/launch/LaunchButton.jsx +0 -30
  122. package/web/src/components/launch/LaunchButton.module.css +0 -35
  123. package/web/src/components/launch/LaunchModal.module.css +0 -125
  124. package/web/src/components/layout/Footer.jsx +0 -19
  125. package/web/src/components/layout/Footer.module.css +0 -10
  126. package/web/src/components/layout/Header.jsx +0 -265
  127. package/web/src/components/layout/Header.module.css +0 -357
  128. package/web/src/components/palette/CommandPalette.jsx +0 -301
  129. package/web/src/components/palette/CommandPalette.module.css +0 -121
  130. package/web/src/components/playground/PlaygroundChat.jsx +0 -527
  131. package/web/src/components/playground/PlaygroundChat.module.css +0 -382
  132. package/web/src/components/playground/PlaygroundView.jsx +0 -371
  133. package/web/src/components/playground/PlaygroundView.module.css +0 -504
  134. package/web/src/components/recommend/RecommendView.jsx +0 -121
  135. package/web/src/components/recommend/RecommendView.module.css +0 -57
  136. package/web/src/components/router/RouterView.jsx +0 -1212
  137. package/web/src/components/router/RouterView.module.css +0 -1289
  138. package/web/src/components/settings/SettingsView.jsx +0 -555
  139. package/web/src/components/settings/SettingsView.module.css +0 -550
  140. package/web/src/components/tools/ToolPicker.jsx +0 -86
  141. package/web/src/components/tools/ToolPicker.module.css +0 -97
  142. package/web/src/components/update/UpdateChip.jsx +0 -104
  143. package/web/src/components/update/UpdateChip.module.css +0 -146
  144. package/web/src/global.css +0 -298
  145. package/web/src/hooks/urlState.constants.js +0 -28
  146. package/web/src/hooks/useChangelog.js +0 -51
  147. package/web/src/hooks/useColumnSizing.js +0 -211
  148. package/web/src/hooks/useFavorites.js +0 -150
  149. package/web/src/hooks/useFilter.js +0 -310
  150. package/web/src/hooks/useInstalledModels.js +0 -42
  151. package/web/src/hooks/useRecommend.js +0 -67
  152. package/web/src/hooks/useRouterDashboard.js +0 -133
  153. package/web/src/hooks/useSSE.js +0 -73
  154. package/web/src/hooks/useSocket.js +0 -203
  155. package/web/src/hooks/useTheme.js +0 -83
  156. package/web/src/hooks/useTokenUsage.js +0 -103
  157. package/web/src/hooks/useToolMode.js +0 -77
  158. package/web/src/hooks/useUpdateChecker.js +0 -91
  159. package/web/src/hooks/useUrlState.js +0 -170
  160. package/web/src/main.jsx +0 -15
  161. package/web/src/utils/download.js +0 -15
  162. package/web/src/utils/format.js +0 -42
  163. package/web/src/utils/m3.js +0 -57
  164. package/web/src/utils/ranks.js +0 -37
  165. 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
- }