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