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,427 +0,0 @@
1
- .overlay {
2
- display: flex;
3
- flex-direction: column;
4
- flex: 1;
5
- min-height: 0;
6
- width: 100%;
7
- padding: 24px;
8
- }
9
-
10
- .modal {
11
- background: var(--color-bg-card, #080908);
12
- border: 1px solid var(--color-border, #161a16);
13
- border-radius: 12px;
14
- width: 100%;
15
- max-width: 680px;
16
- margin: 0 auto;
17
- flex: 1;
18
- display: flex;
19
- flex-direction: column;
20
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
21
- min-height: 0;
22
- }
23
-
24
- .header {
25
- display: flex;
26
- align-items: center;
27
- justify-content: space-between;
28
- padding: 16px 20px;
29
- border-bottom: 1px solid var(--border, #1e1e2e);
30
- }
31
-
32
- .title {
33
- margin: 0;
34
- font-size: 16px;
35
- font-weight: 600;
36
- display: flex;
37
- align-items: center;
38
- gap: 8px;
39
- color: var(--text-primary, #e0e0e0);
40
- }
41
-
42
- .closeBtn {
43
- background: none;
44
- border: none;
45
- color: var(--text-muted, #888);
46
- font-size: 18px;
47
- cursor: pointer;
48
- padding: 4px 8px;
49
- border-radius: 6px;
50
- &:hover { background: var(--bg-hover, #1a1a2e); color: var(--text-primary, #e0e0e0); }
51
- }
52
-
53
- /* Steps */
54
- .steps {
55
- display: flex;
56
- align-items: center;
57
- justify-content: center;
58
- gap: 24px;
59
- padding: 14px 20px;
60
- border-bottom: 1px solid var(--border, #1e1e2e);
61
- }
62
-
63
- .step {
64
- display: flex;
65
- align-items: center;
66
- gap: 6px;
67
- font-size: 12px;
68
- color: var(--text-muted, #555);
69
- }
70
-
71
- .stepActive {
72
- color: var(--text-primary, #e0e0e0);
73
- font-weight: 600;
74
- }
75
-
76
- .stepDone {
77
- color: #00c864;
78
- }
79
-
80
- .stepNum {
81
- display: flex;
82
- align-items: center;
83
- justify-content: center;
84
- width: 22px;
85
- height: 22px;
86
- border-radius: 50%;
87
- font-size: 11px;
88
- font-weight: 700;
89
- background: var(--bg-secondary, #14141f);
90
- border: 1px solid var(--border, #1e1e2e);
91
- }
92
-
93
- .stepActive .stepNum {
94
- background: rgba(0, 200, 100, 0.15);
95
- border-color: rgba(0, 200, 100, 0.3);
96
- color: #00c864;
97
- }
98
-
99
- .stepDone .stepNum {
100
- background: rgba(0, 200, 100, 0.15);
101
- border-color: #00c864;
102
- color: #00c864;
103
- }
104
-
105
- .stepLabel {
106
- text-transform: uppercase;
107
- letter-spacing: 0.3px;
108
- }
109
-
110
- /* Body */
111
- .body {
112
- padding: 20px;
113
- overflow-y: auto;
114
- flex: 1;
115
- min-height: 300px;
116
- }
117
-
118
- .stepContent {}
119
-
120
- .stepDesc {
121
- font-size: 14px;
122
- color: var(--text-secondary, #aaa);
123
- margin: 0 0 16px 0;
124
- }
125
-
126
- .loading, .empty {
127
- color: var(--text-muted, #666);
128
- font-size: 13px;
129
- text-align: center;
130
- padding: 30px 0;
131
- }
132
-
133
- /* Pick Grid (Provider + Tool) */
134
- .grid {
135
- display: grid;
136
- grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
137
- gap: 8px;
138
- }
139
-
140
- .pickCard {
141
- display: flex;
142
- flex-direction: column;
143
- align-items: center;
144
- gap: 4px;
145
- padding: 14px 10px;
146
- background: var(--bg-secondary, #14141f);
147
- border: 1px solid var(--border, #1e1e2e);
148
- border-radius: 8px;
149
- cursor: pointer;
150
- color: var(--text-secondary, #aaa);
151
- font-size: 13px;
152
- transition: all 0.15s ease;
153
- &:hover { border-color: var(--text-muted, #666); color: var(--text-primary, #e0e0e0); }
154
- }
155
-
156
- .pickActive {
157
- border-color: #00c864;
158
- background: rgba(0, 200, 100, 0.08);
159
- color: #00c864;
160
- }
161
-
162
- .pickEmoji {
163
- font-size: 20px;
164
- }
165
-
166
- .pickLabel {
167
- font-weight: 600;
168
- font-size: 12px;
169
- }
170
-
171
- .pickMeta {
172
- font-size: 10px;
173
- color: var(--text-muted, #888);
174
- }
175
-
176
- /* Scope Toggle */
177
- .scopeToggle {
178
- display: flex;
179
- gap: 8px;
180
- margin-bottom: 12px;
181
- }
182
-
183
- .scopeBtn {
184
- padding: 6px 14px;
185
- border: 1px solid var(--border, #1e1e2e);
186
- border-radius: 6px;
187
- background: var(--bg-secondary, #14141f);
188
- color: var(--text-secondary, #aaa);
189
- font-size: 12px;
190
- cursor: pointer;
191
- &:hover { border-color: var(--text-muted, #888); }
192
- }
193
-
194
- .scopeActive {
195
- background: rgba(0, 200, 100, 0.1);
196
- border-color: rgba(0, 200, 100, 0.3);
197
- color: #00c864;
198
- font-weight: 600;
199
- }
200
-
201
- /* Model Selection */
202
- .modelGrid {
203
- display: grid;
204
- grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
205
- gap: 6px;
206
- max-height: 240px;
207
- overflow-y: auto;
208
- }
209
-
210
- .modelCard {
211
- display: flex;
212
- align-items: center;
213
- justify-content: space-between;
214
- padding: 8px 10px;
215
- background: var(--bg-secondary, #14141f);
216
- border: 1px solid var(--border, #1e1e2e);
217
- border-radius: 6px;
218
- cursor: pointer;
219
- color: var(--text-secondary, #aaa);
220
- font-size: 12px;
221
- &:hover { border-color: var(--text-muted, #666); }
222
- }
223
-
224
- .modelSelected {
225
- border-color: #00c864;
226
- background: rgba(0, 200, 100, 0.08);
227
- color: #00c864;
228
- }
229
-
230
- .modelName {
231
- overflow: hidden;
232
- text-overflow: ellipsis;
233
- white-space: nowrap;
234
- }
235
-
236
- .modelTier {
237
- font-size: 10px;
238
- font-weight: 700;
239
- padding: 1px 4px;
240
- background: rgba(0, 200, 255, 0.1);
241
- color: #00c8ff;
242
- border-radius: 3px;
243
- margin-left: 6px;
244
- flex-shrink: 0;
245
- }
246
-
247
- .allNotice {
248
- color: var(--text-muted, #888);
249
- font-size: 13px;
250
- text-align: center;
251
- padding: 30px 0;
252
- }
253
-
254
- /* Install State */
255
- .installingState {
256
- display: flex;
257
- flex-direction: column;
258
- align-items: center;
259
- justify-content: center;
260
- gap: 12px;
261
- padding: 50px 0;
262
- color: var(--text-secondary, #aaa);
263
- }
264
-
265
- .installingLabel {
266
- font-size: 16px;
267
- font-weight: 600;
268
- color: var(--text-primary, #e0e0e0);
269
- }
270
-
271
- .installingSub {
272
- font-size: 12px;
273
- color: var(--text-muted, #888);
274
- }
275
-
276
- .spinner {
277
- animation: spin 0.8s linear infinite;
278
- }
279
-
280
- .doneState {
281
- display: flex;
282
- flex-direction: column;
283
- align-items: center;
284
- gap: 10px;
285
- padding: 40px 0;
286
- text-align: center;
287
- animation: doneFadeIn 0.3s ease;
288
- }
289
-
290
- .doneTitle {
291
- margin: 0;
292
- font-size: 20px;
293
- font-weight: 700;
294
- }
295
-
296
- .doneSub {
297
- margin: 0;
298
- color: var(--text-secondary, #aaa);
299
- font-size: 14px;
300
- line-height: 1.5;
301
- }
302
-
303
- .doneSub strong {
304
- color: var(--text-primary, #e0e0e0);
305
- }
306
-
307
- /* 📖 Animated check circle — scales up with a satisfying bounce */
308
- .checkCircle {
309
- display: flex;
310
- align-items: center;
311
- justify-content: center;
312
- width: 64px;
313
- height: 64px;
314
- border-radius: 50%;
315
- background: rgba(0, 200, 100, 0.12);
316
- color: #00c864;
317
- animation: checkPop 0.5s cubic-bezier(0.16, 1, 0.3, 1);
318
- }
319
-
320
- .errorDot {
321
- display: flex;
322
- align-items: center;
323
- justify-content: center;
324
- width: 64px;
325
- height: 64px;
326
- border-radius: 50%;
327
- background: rgba(220, 53, 69, 0.12);
328
- color: #dc3545;
329
- font-size: 28px;
330
- font-weight: 700;
331
- animation: checkPop 0.5s cubic-bezier(0.16, 1, 0.3, 1);
332
- }
333
-
334
- .installPath {
335
- font-size: 11px;
336
- color: var(--text-muted, #888);
337
- background: var(--bg-secondary, #14141f);
338
- padding: 4px 10px;
339
- border-radius: 4px;
340
- max-width: 100%;
341
- overflow: hidden;
342
- text-overflow: ellipsis;
343
- }
344
-
345
- @keyframes doneFadeIn {
346
- from { opacity: 0; transform: translateY(8px); }
347
- to { opacity: 1; transform: translateY(0); }
348
- }
349
-
350
- @keyframes donePop {
351
- 0% { transform: scale(0.5); opacity: 0; }
352
- 60% { transform: scale(1.1); opacity: 1; }
353
- 100% { transform: scale(1); opacity: 1; }
354
- }
355
-
356
- @keyframes checkPop {
357
- 0% { transform: scale(0); opacity: 0; }
358
- 50% { transform: scale(1.2); }
359
- 100% { transform: scale(1); opacity: 1; }
360
- }
361
-
362
- /* Footer */
363
- .footer {
364
- display: flex;
365
- justify-content: space-between;
366
- padding: 14px 20px;
367
- border-top: 1px solid var(--border, #1e1e2e);
368
- }
369
-
370
- .backBtn {
371
- display: flex;
372
- align-items: center;
373
- gap: 4px;
374
- padding: 8px 14px;
375
- background: var(--bg-secondary, #14141f);
376
- border: 1px solid var(--border, #1e1e2e);
377
- border-radius: 8px;
378
- color: var(--text-secondary, #aaa);
379
- font-size: 13px;
380
- cursor: pointer;
381
- &:hover { color: var(--text-primary, #e0e0e0); }
382
- }
383
-
384
- .nextBtn {
385
- display: flex;
386
- align-items: center;
387
- gap: 4px;
388
- padding: 8px 18px;
389
- background: #00c864;
390
- color: #000;
391
- border: none;
392
- border-radius: 8px;
393
- font-size: 13px;
394
- font-weight: 600;
395
- cursor: pointer;
396
- margin-left: auto;
397
- &:hover { background: #00d874; }
398
- &:disabled { opacity: 0.4; cursor: not-allowed; }
399
- }
400
-
401
- .doneBtn {
402
- display: flex;
403
- align-items: center;
404
- gap: 6px;
405
- padding: 10px 28px;
406
- background: #00c864;
407
- color: #000;
408
- border: none;
409
- border-radius: 8px;
410
- font-size: 14px;
411
- font-weight: 700;
412
- cursor: pointer;
413
- margin-left: auto;
414
- transition: transform 0.15s ease, background 0.15s ease;
415
- &:hover { background: #00d874; transform: scale(1.02); }
416
- &:active { transform: scale(0.98); }
417
- }
418
-
419
- @keyframes fadeIn {
420
- from { opacity: 0; }
421
- to { opacity: 1; }
422
- }
423
-
424
- @keyframes spin {
425
- from { transform: rotate(0deg); }
426
- to { transform: rotate(360deg); }
427
- }
@@ -1,89 +0,0 @@
1
- /**
2
- * @file web/src/components/installed/InstalledModelsView.jsx
3
- * @description Installed Models modal — scans all tool configs, shows models, soft-delete.
4
- * 📖 M4: Full TUI parity for installed models management.
5
- */
6
- import { useInstalledModels } from '../../hooks/useInstalledModels.js'
7
- import { IconFolders, IconTrash, IconRefresh } from '@tabler/icons-react'
8
- import styles from './InstalledModelsView.module.css'
9
-
10
- export default function InstalledModelsView({ onClose, onToast }) {
11
- const { results, loading, refresh, disableModel } = useInstalledModels()
12
-
13
- const handleDisable = async (toolMode, modelId) => {
14
- try {
15
- const result = await disableModel(toolMode, modelId)
16
- if (result.success) {
17
- onToast?.(`Disabled ${modelId} in ${toolMode}.`, 'success')
18
- } else {
19
- onToast?.(`Failed: ${result.error || 'unknown error'}`, 'error')
20
- }
21
- } catch (err) {
22
- onToast?.(`Error: ${err.message}`, 'error')
23
- }
24
- }
25
-
26
- const totalModels = results.reduce((sum, r) => sum + r.models.length, 0)
27
-
28
- return (
29
- <div className={styles.overlay} onClick={(e) => e.target === e.currentTarget && onClose()}>
30
- <div className={styles.modal}>
31
- <div className={styles.header}>
32
- <h2 className={styles.title}>
33
- <IconFolders size={20} stroke={1.5} />
34
- Installed Models
35
- {!loading && <span className={styles.count}>{totalModels}</span>}
36
- </h2>
37
- <div className={styles.headerActions}>
38
- <button className={styles.refreshBtn} onClick={refresh} title="Refresh">
39
- <IconRefresh size={14} />
40
- </button>
41
- <button className={styles.closeBtn} onClick={onClose} aria-label="Close">✕</button>
42
- </div>
43
- </div>
44
-
45
- <div className={styles.body}>
46
- {loading && <div className={styles.empty}>Scanning tool configs…</div>}
47
-
48
- {!loading && totalModels === 0 && (
49
- <div className={styles.empty}>
50
- No models found in tool configs.
51
- <br />
52
- <span className={styles.hint}>Use "Install Endpoints" to configure models for your tools.</span>
53
- </div>
54
- )}
55
-
56
- {!loading && results.map((tool) => (
57
- <div key={tool.toolMode} className={styles.toolGroup}>
58
- <div className={styles.toolHeader}>
59
- <span className={styles.toolEmoji}>{tool.toolEmoji}</span>
60
- <span className={styles.toolLabel}>{tool.toolLabel}</span>
61
- <span className={styles.toolCount}>{tool.models.length} model{tool.models.length !== 1 ? 's' : ''}</span>
62
- {!tool.isValid && <span className={styles.toolMissing}>Not installed</span>}
63
- </div>
64
- {tool.models.length > 0 && (
65
- <div className={styles.modelList}>
66
- {tool.models.map((model) => (
67
- <div key={`${tool.toolMode}-${model.modelId}`} className={styles.modelRow}>
68
- <span className={styles.modelIcon}>{model.isExternal ? '🔗' : '✅'}</span>
69
- <span className={styles.modelName}>{model.label}</span>
70
- {model.tier && model.tier !== '-' && <span className={styles.modelTier}>{model.tier}</span>}
71
- <span className={styles.modelId} title={model.modelId}>{model.modelId}</span>
72
- <button
73
- className={styles.disableBtn}
74
- onClick={() => handleDisable(tool.toolMode, model.modelId)}
75
- title="Remove model from config (backup saved)"
76
- >
77
- <IconTrash size={12} />
78
- </button>
79
- </div>
80
- ))}
81
- </div>
82
- )}
83
- </div>
84
- ))}
85
- </div>
86
- </div>
87
- </div>
88
- )
89
- }
@@ -1,200 +0,0 @@
1
- .overlay {
2
- display: flex;
3
- flex-direction: column;
4
- flex: 1;
5
- min-height: 0;
6
- width: 100%;
7
- padding: 24px;
8
- }
9
-
10
- .modal {
11
- background: var(--color-bg-card, #080908);
12
- border: 1px solid var(--color-border, #161a16);
13
- border-radius: 12px;
14
- width: 100%;
15
- max-width: 640px;
16
- margin: 0 auto;
17
- flex: 1;
18
- display: flex;
19
- flex-direction: column;
20
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
21
- min-height: 0;
22
- }
23
-
24
- .header {
25
- display: flex;
26
- align-items: center;
27
- justify-content: space-between;
28
- padding: 16px 20px;
29
- border-bottom: 1px solid var(--border, #1e1e2e);
30
- }
31
-
32
- .title {
33
- margin: 0;
34
- font-size: 16px;
35
- font-weight: 600;
36
- display: flex;
37
- align-items: center;
38
- gap: 8px;
39
- color: var(--text-primary, #e0e0e0);
40
- }
41
-
42
- .count {
43
- font-size: 12px;
44
- background: var(--bg-secondary, #14141f);
45
- border: 1px solid var(--border, #1e1e2e);
46
- border-radius: 10px;
47
- padding: 2px 8px;
48
- color: var(--text-muted, #888);
49
- }
50
-
51
- .headerActions {
52
- display: flex;
53
- align-items: center;
54
- gap: 6px;
55
- }
56
-
57
- .refreshBtn {
58
- display: flex;
59
- align-items: center;
60
- justify-content: center;
61
- width: 28px;
62
- height: 28px;
63
- background: var(--bg-secondary, #14141f);
64
- border: 1px solid var(--border, #1e1e2e);
65
- border-radius: 6px;
66
- color: var(--text-muted, #888);
67
- cursor: pointer;
68
- &:hover { color: var(--text-primary, #e0e0e0); }
69
- }
70
-
71
- .closeBtn {
72
- background: none;
73
- border: none;
74
- color: var(--text-muted, #888);
75
- font-size: 18px;
76
- cursor: pointer;
77
- padding: 4px 8px;
78
- border-radius: 6px;
79
- &:hover { background: var(--bg-hover, #1a1a2e); color: var(--text-primary, #e0e0e0); }
80
- }
81
-
82
- .body {
83
- padding: 16px 20px;
84
- overflow-y: auto;
85
- flex: 1;
86
- }
87
-
88
- .empty {
89
- color: var(--text-muted, #666);
90
- font-size: 13px;
91
- padding: 30px 0;
92
- text-align: center;
93
- line-height: 1.6;
94
- }
95
-
96
- .hint {
97
- font-size: 12px;
98
- color: var(--text-muted, #555);
99
- }
100
-
101
- /* Tool Groups */
102
- .toolGroup {
103
- margin-bottom: 16px;
104
- }
105
-
106
- .toolHeader {
107
- display: flex;
108
- align-items: center;
109
- gap: 8px;
110
- margin-bottom: 6px;
111
- }
112
-
113
- .toolEmoji {
114
- font-size: 16px;
115
- }
116
-
117
- .toolLabel {
118
- font-size: 14px;
119
- font-weight: 600;
120
- color: var(--text-primary, #e0e0e0);
121
- }
122
-
123
- .toolCount {
124
- font-size: 11px;
125
- color: var(--text-muted, #888);
126
- }
127
-
128
- .toolMissing {
129
- font-size: 10px;
130
- padding: 2px 6px;
131
- background: rgba(255, 140, 0, 0.15);
132
- color: #ff8c00;
133
- border-radius: 4px;
134
- text-transform: uppercase;
135
- letter-spacing: 0.3px;
136
- }
137
-
138
- /* Model Rows */
139
- .modelList {
140
- display: flex;
141
- flex-direction: column;
142
- gap: 3px;
143
- padding-left: 24px;
144
- }
145
-
146
- .modelRow {
147
- display: flex;
148
- align-items: center;
149
- gap: 8px;
150
- padding: 6px 8px;
151
- border-radius: 6px;
152
- font-size: 12px;
153
- background: var(--bg-secondary, #14141f);
154
- &:hover { background: var(--bg-hover, #1a1a2e); }
155
- }
156
-
157
- .modelIcon {
158
- font-size: 12px;
159
- }
160
-
161
- .modelName {
162
- color: var(--text-primary, #e0e0e0);
163
- min-width: 120px;
164
- }
165
-
166
- .modelTier {
167
- font-size: 10px;
168
- font-weight: 700;
169
- padding: 1px 5px;
170
- background: rgba(0, 200, 255, 0.1);
171
- color: #00c8ff;
172
- border-radius: 3px;
173
- }
174
-
175
- .modelId {
176
- flex: 1;
177
- color: var(--text-muted, #888);
178
- font-family: 'SF Mono', monospace;
179
- overflow: hidden;
180
- text-overflow: ellipsis;
181
- white-space: nowrap;
182
- font-size: 11px;
183
- }
184
-
185
- .disableBtn {
186
- background: none;
187
- border: none;
188
- color: var(--text-muted, #666);
189
- cursor: pointer;
190
- padding: 4px;
191
- border-radius: 4px;
192
- display: flex;
193
- align-items: center;
194
- &:hover { color: #dc3545; background: rgba(220, 53, 69, 0.1); }
195
- }
196
-
197
- @keyframes fadeIn {
198
- from { opacity: 0; }
199
- to { opacity: 1; }
200
- }