free-coding-models 0.5.0 → 0.5.4

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 (145) hide show
  1. package/README.md +40 -6
  2. package/bin/free-coding-models.js +10 -0
  3. package/changelog/v0.5.1.md +24 -0
  4. package/changelog/v0.5.4.md +24 -0
  5. package/package.json +11 -3
  6. package/sources.js +2 -0
  7. package/src/core/router-daemon.js +166 -1
  8. package/src/core/utils.js +2 -0
  9. package/src/tui/cli-help.js +2 -0
  10. package/src/tui/key-handler.js +1 -1
  11. package/src/tui/render-table.js +1 -1
  12. package/web/README.md +8 -5
  13. package/web/assets/providers/aistudio/aistudio-text.svg +1 -0
  14. package/web/assets/providers/aistudio/aistudio.svg +1 -0
  15. package/web/assets/providers/cerebras/cerebras-brand-color.svg +1 -0
  16. package/web/assets/providers/cerebras/cerebras-brand.svg +1 -0
  17. package/web/assets/providers/cerebras/cerebras-color.svg +1 -0
  18. package/web/assets/providers/cerebras/cerebras-text.svg +1 -0
  19. package/web/assets/providers/cerebras/cerebras.svg +1 -0
  20. package/web/assets/providers/cloudflare/cloudflare-color.svg +1 -0
  21. package/web/assets/providers/cloudflare/cloudflare-text.svg +1 -0
  22. package/web/assets/providers/cloudflare/cloudflare.svg +1 -0
  23. package/web/assets/providers/gemini/gemini-color.svg +1 -0
  24. package/web/assets/providers/gemini/gemini-text.svg +1 -0
  25. package/web/assets/providers/gemini/gemini.svg +1 -0
  26. package/web/assets/providers/github/github-text.svg +1 -0
  27. package/web/assets/providers/github/github.svg +1 -0
  28. package/web/assets/providers/groq/groq-text.svg +1 -0
  29. package/web/assets/providers/groq/groq.svg +1 -0
  30. package/web/assets/providers/mistral/mistral-color.svg +1 -0
  31. package/web/assets/providers/mistral/mistral-text.svg +1 -0
  32. package/web/assets/providers/mistral/mistral.svg +1 -0
  33. package/web/assets/providers/nvidia/nvidia-color.svg +1 -0
  34. package/web/assets/providers/nvidia/nvidia-text.svg +1 -0
  35. package/web/assets/providers/nvidia/nvidia.svg +1 -0
  36. package/web/assets/providers/opencode/opencode-text.svg +1 -0
  37. package/web/assets/providers/opencode/opencode.svg +1 -0
  38. package/web/assets/providers/openrouter/openrouter (1).svg +1 -0
  39. package/web/assets/providers/openrouter/openrouter-text.svg +1 -0
  40. package/web/assets/providers/openrouter/openrouter.svg +1 -0
  41. package/web/assets/providers/ovhcloud/ovhcloud.svg +12 -0
  42. package/web/assets/providers/qwen/qwen-color.svg +1 -0
  43. package/web/assets/providers/qwen/qwen-text.svg +1 -0
  44. package/web/assets/providers/qwen/qwen.svg +1 -0
  45. package/web/assets/providers/sambanova/sambanova-color.svg +1 -0
  46. package/web/assets/providers/sambanova/sambanova-text.svg +1 -0
  47. package/web/assets/providers/sambanova/sambanova.svg +1 -0
  48. package/web/assets/providers/scalewaylogo/ScalewayLogo.svg +13 -0
  49. package/web/assets/providers/zai/zai-text.svg +1 -0
  50. package/web/assets/providers/zai/zai.svg +1 -0
  51. package/web/dist/assets/index-BoWmUveV.js +39 -0
  52. package/web/dist/assets/index-BrpHevg4.css +1 -0
  53. package/web/dist/favicon.ico +0 -0
  54. package/web/dist/favicons/apple-touch-icon.png +0 -0
  55. package/web/dist/favicons/browserconfig.xml +12 -0
  56. package/web/dist/favicons/favicon-16x16.png +0 -0
  57. package/web/dist/favicons/favicon-192x192.png +0 -0
  58. package/web/dist/favicons/favicon-32x32.png +0 -0
  59. package/web/dist/favicons/favicon-48x48.png +0 -0
  60. package/web/dist/favicons/favicon-512x512.png +0 -0
  61. package/web/dist/favicons/favicon-96x96.png +0 -0
  62. package/web/dist/favicons/favicon.ico +0 -0
  63. package/web/dist/favicons/mstile-150x150.png +0 -0
  64. package/web/dist/favicons/mstile-310x150.png +0 -0
  65. package/web/dist/favicons/mstile-310x310.png +0 -0
  66. package/web/dist/favicons/mstile-512x512.png +0 -0
  67. package/web/dist/favicons/mstile-70x70.png +0 -0
  68. package/web/dist/favicons/site.webmanifest +25 -0
  69. package/web/dist/index.html +42 -6
  70. package/web/index.html +40 -4
  71. package/web/package.json +11 -0
  72. package/web/public/favicon.ico +0 -0
  73. package/web/public/favicons/apple-touch-icon.png +0 -0
  74. package/web/public/favicons/browserconfig.xml +12 -0
  75. package/web/public/favicons/favicon-16x16.png +0 -0
  76. package/web/public/favicons/favicon-192x192.png +0 -0
  77. package/web/public/favicons/favicon-32x32.png +0 -0
  78. package/web/public/favicons/favicon-48x48.png +0 -0
  79. package/web/public/favicons/favicon-512x512.png +0 -0
  80. package/web/public/favicons/favicon-96x96.png +0 -0
  81. package/web/public/favicons/favicon.ico +0 -0
  82. package/web/public/favicons/mstile-150x150.png +0 -0
  83. package/web/public/favicons/mstile-310x150.png +0 -0
  84. package/web/public/favicons/mstile-310x310.png +0 -0
  85. package/web/public/favicons/mstile-512x512.png +0 -0
  86. package/web/public/favicons/mstile-70x70.png +0 -0
  87. package/web/public/favicons/site.webmanifest +25 -0
  88. package/web/server.js +676 -211
  89. package/web/src/App.jsx +233 -71
  90. package/web/src/components/analytics/AnalyticsView.jsx +40 -6
  91. package/web/src/components/analytics/AnalyticsView.module.css +4 -0
  92. package/web/src/components/atoms/AILatencyCell.jsx +38 -0
  93. package/web/src/components/atoms/AILatencyCell.module.css +51 -0
  94. package/web/src/components/atoms/HealthCell.jsx +138 -0
  95. package/web/src/components/atoms/HealthCell.module.css +56 -0
  96. package/web/src/components/atoms/LastPingCell.jsx +35 -0
  97. package/web/src/components/atoms/LastPingCell.module.css +45 -0
  98. package/web/src/components/atoms/MoodCell.jsx +25 -0
  99. package/web/src/components/atoms/MoodCell.module.css +6 -0
  100. package/web/src/components/atoms/NoKeyIcon.jsx +65 -0
  101. package/web/src/components/atoms/NoKeyIcon.module.css +30 -0
  102. package/web/src/components/atoms/ProviderLogo.jsx +188 -0
  103. package/web/src/components/atoms/ProviderLogo.module.css +103 -0
  104. package/web/src/components/atoms/RankCell.jsx +9 -0
  105. package/web/src/components/atoms/RankCell.module.css +9 -0
  106. package/web/src/components/atoms/Sparkline.jsx +21 -2
  107. package/web/src/components/atoms/StabilityCell.module.css +5 -0
  108. package/web/src/components/atoms/StatusDot.module.css +7 -0
  109. package/web/src/components/atoms/TPSCell.jsx +36 -0
  110. package/web/src/components/atoms/TPSCell.module.css +44 -0
  111. package/web/src/components/atoms/TierBadge.module.css +11 -0
  112. package/web/src/components/atoms/Toast.module.css +6 -0
  113. package/web/src/components/atoms/VerdictBadge.jsx +30 -7
  114. package/web/src/components/atoms/VerdictBadge.module.css +36 -15
  115. package/web/src/components/dashboard/DetailPanel.jsx +63 -2
  116. package/web/src/components/dashboard/DetailPanel.module.css +130 -0
  117. package/web/src/components/dashboard/ExportModal.jsx +9 -4
  118. package/web/src/components/dashboard/FilterBar.jsx +228 -33
  119. package/web/src/components/dashboard/FilterBar.module.css +187 -22
  120. package/web/src/components/dashboard/ModelTable.jsx +500 -54
  121. package/web/src/components/dashboard/ModelTable.module.css +318 -31
  122. package/web/src/components/layout/Footer.jsx +1 -1
  123. package/web/src/components/layout/Header.jsx +171 -9
  124. package/web/src/components/layout/Header.module.css +223 -25
  125. package/web/src/components/palette/CommandPalette.jsx +146 -0
  126. package/web/src/components/palette/CommandPalette.module.css +121 -0
  127. package/web/src/components/settings/SettingsView.jsx +24 -6
  128. package/web/src/components/settings/SettingsView.module.css +0 -1
  129. package/web/src/global.css +118 -84
  130. package/web/src/hooks/useColumnSizing.js +211 -0
  131. package/web/src/hooks/useFavorites.js +150 -0
  132. package/web/src/hooks/useFilter.js +262 -37
  133. package/web/src/hooks/useSSE.js +33 -9
  134. package/web/src/hooks/useSocket.js +200 -0
  135. package/web/src/hooks/useTheme.js +72 -16
  136. package/web/src/hooks/useUrlState.js +93 -0
  137. package/web/vite.config.js +41 -0
  138. package/web/dist/assets/index-CGN-0_A0.css +0 -1
  139. package/web/dist/assets/index-CvMUM9Jr.js +0 -11
  140. package/web/src/components/dashboard/StatsBar.jsx +0 -40
  141. package/web/src/components/dashboard/StatsBar.module.css +0 -28
  142. package/web/src/components/layout/Sidebar.jsx +0 -42
  143. package/web/src/components/layout/Sidebar.module.css +0 -76
  144. package/web/src/components/map/MapView.jsx +0 -17
  145. package/web/src/components/map/MapView.module.css +0 -25
@@ -1,40 +0,0 @@
1
- /**
2
- * @file web/src/components/dashboard/StatsBar.jsx
3
- * @description Stats cards row showing total models, online count, avg latency, fastest model, providers.
4
- */
5
- import { useMemo } from 'react'
6
- import styles from './StatsBar.module.css'
7
-
8
- export default function StatsBar({ models }) {
9
- const stats = useMemo(() => {
10
- const total = models.length
11
- const online = models.filter(m => m.status === 'up').length
12
- const onlineWithPing = models.filter(m => m.status === 'up' && m.avg !== Infinity && m.avg < 99000)
13
- const avgLatency = onlineWithPing.length > 0
14
- ? Math.round(onlineWithPing.reduce((s, m) => s + m.avg, 0) / onlineWithPing.length)
15
- : null
16
- const fastest = [...onlineWithPing].sort((a, b) => a.avg - b.avg)[0]
17
- const providers = new Set(models.map(m => m.providerKey)).size
18
- return [
19
- { icon: '📊', value: total, label: 'Total Models' },
20
- { icon: '🟢', value: online, label: 'Online' },
21
- { icon: '⚡', value: avgLatency != null ? `${avgLatency}ms` : '—', label: 'Avg Latency' },
22
- { icon: '🏆', value: fastest ? fastest.label : '—', label: 'Fastest Model' },
23
- { icon: '🌐', value: providers, label: 'Providers' },
24
- ]
25
- }, [models])
26
-
27
- return (
28
- <section className={styles.statsBar}>
29
- {stats.map(s => (
30
- <div key={s.label} className={styles.card}>
31
- <div className={styles.icon}>{s.icon}</div>
32
- <div className={styles.body}>
33
- <div className={styles.value}>{s.value}</div>
34
- <div className={styles.label}>{s.label}</div>
35
- </div>
36
- </div>
37
- ))}
38
- </section>
39
- )
40
- }
@@ -1,28 +0,0 @@
1
- .statsBar {
2
- position: relative; z-index: 1;
3
- display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px;
4
- padding: 20px 24px 0;
5
- }
6
- .card {
7
- display: flex; align-items: center; gap: 12px;
8
- background: var(--color-bg-card);
9
- backdrop-filter: blur(12px);
10
- -webkit-backdrop-filter: blur(12px);
11
- border: 1px solid var(--color-border);
12
- border-radius: 16px;
13
- padding: 16px 18px;
14
- transition: all 250ms cubic-bezier(0.16, 1, 0.3, 1);
15
- }
16
- .card:hover {
17
- border-color: var(--color-border-hover);
18
- transform: translateY(-2px);
19
- box-shadow: var(--shadow-md);
20
- }
21
- .icon { font-size: 28px; }
22
- .body { flex: 1; }
23
- .value { font-size: 22px; font-weight: 800; font-family: var(--font-mono); line-height: 1; }
24
- .label { font-size: 11px; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 500; margin-top: 2px; }
25
-
26
- @media (max-width: 1024px) { .statsBar { grid-template-columns: repeat(3, 1fr); } }
27
- @media (max-width: 768px) { .statsBar { grid-template-columns: repeat(2, 1fr); } }
28
- @media (max-width: 480px) { .statsBar { grid-template-columns: 1fr; } }
@@ -1,42 +0,0 @@
1
- /**
2
- * @file web/src/components/layout/Sidebar.jsx
3
- * @description Collapsible sidebar navigation with Dashboard / Settings / Analytics links + theme toggle.
4
- */
5
- import styles from './Sidebar.module.css'
6
-
7
- const NAV_ITEMS = [
8
- { id: 'dashboard', icon: '▤', label: 'Dashboard' },
9
- { id: 'settings', icon: '⚙', label: 'Settings' },
10
- { id: 'analytics', icon: '▌▌', label: 'Analytics' },
11
- { id: 'map', icon: '🌍', label: 'Map' },
12
- ]
13
-
14
- export default function Sidebar({ currentView, onNavigate, onToggleTheme }) {
15
- return (
16
- <aside className={styles.sidebar}>
17
- <div className={styles.logo}>
18
- <span className={styles.logoIcon}>⚡</span>
19
- <span className={styles.logoText}>FCM</span>
20
- </div>
21
- <nav className={styles.nav}>
22
- {NAV_ITEMS.map(({ id, icon, label }) => (
23
- <button
24
- key={id}
25
- className={`${styles.navItem} ${currentView === id ? styles.active : ''}`}
26
- onClick={() => onNavigate(id)}
27
- title={label}
28
- >
29
- <span className={styles.navIcon}>{icon}</span>
30
- <span className={styles.navLabel}>{label}</span>
31
- </button>
32
- ))}
33
- </nav>
34
- <div className={styles.bottom}>
35
- <button className={styles.navItem} onClick={onToggleTheme} title="Toggle Theme">
36
- <span className={styles.navIcon}>☽</span>
37
- <span className={styles.navLabel}>Theme</span>
38
- </button>
39
- </div>
40
- </aside>
41
- )
42
- }
@@ -1,76 +0,0 @@
1
- .sidebar {
2
- position: fixed;
3
- left: 0; top: 0; bottom: 0;
4
- width: 64px;
5
- z-index: 200;
6
- background: var(--color-bg-elevated);
7
- border-right: 1px solid var(--color-border);
8
- display: flex;
9
- flex-direction: column;
10
- padding: 12px 0;
11
- transition: width 250ms cubic-bezier(0.16, 1, 0.3, 1);
12
- overflow: hidden;
13
- }
14
- .sidebar:hover { width: 200px; }
15
-
16
- .logo {
17
- display: flex;
18
- align-items: center;
19
- gap: 10px;
20
- padding: 8px 18px;
21
- margin-bottom: 16px;
22
- white-space: nowrap;
23
- overflow: hidden;
24
- }
25
- .logoIcon { font-size: 24px; flex-shrink: 0; }
26
- .logoText {
27
- font-size: 16px;
28
- font-weight: 800;
29
- background: linear-gradient(135deg, var(--color-accent), #06b6d4);
30
- -webkit-background-clip: text;
31
- -webkit-text-fill-color: transparent;
32
- background-clip: text;
33
- opacity: 0;
34
- transition: opacity 250ms cubic-bezier(0.16, 1, 0.3, 1);
35
- }
36
- .sidebar:hover .logoText { opacity: 1; }
37
-
38
- .nav { flex: 1; display: flex; flex-direction: column; gap: 4px; }
39
- .bottom { display: flex; flex-direction: column; gap: 4px; }
40
-
41
- .navItem {
42
- display: flex;
43
- align-items: center;
44
- gap: 12px;
45
- padding: 10px 20px;
46
- border: none;
47
- background: none;
48
- color: var(--color-text-muted);
49
- cursor: pointer;
50
- white-space: nowrap;
51
- overflow: hidden;
52
- font-family: var(--font-sans);
53
- font-size: 13px;
54
- font-weight: 500;
55
- transition: all 150ms cubic-bezier(0.16, 1, 0.3, 1);
56
- }
57
- .navItem:hover {
58
- color: var(--color-text);
59
- background: var(--color-bg-hover);
60
- }
61
- .navIcon {
62
- width: 20px;
63
- text-align: center;
64
- flex-shrink: 0;
65
- font-size: 16px;
66
- }
67
- .navLabel {
68
- opacity: 0;
69
- transition: opacity 250ms cubic-bezier(0.16, 1, 0.3, 1);
70
- }
71
- .sidebar:hover .navLabel { opacity: 1; }
72
- .active {
73
- color: var(--color-accent) !important;
74
- background: var(--color-accent-dim) !important;
75
- border-right: 3px solid var(--color-accent);
76
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * @file web/src/components/map/MapView.jsx
3
- * @description WIP - Live map view showing users location and activity.
4
- * @exports MapView → placeholder component for user map visualization
5
- */
6
- import styles from './MapView.module.css'
7
-
8
- export default function MapView() {
9
- return (
10
- <div className={styles.container}>
11
- <div className={styles.wip}>
12
- <h1>WIP : map users live</h1>
13
- <p>Coming soon...</p>
14
- </div>
15
- </div>
16
- )
17
- }
@@ -1,25 +0,0 @@
1
- .container {
2
- padding: 2rem;
3
- width: 100%;
4
- }
5
-
6
- .wip {
7
- display: flex;
8
- flex-direction: column;
9
- align-items: center;
10
- justify-content: center;
11
- min-height: 60vh;
12
- text-align: center;
13
- }
14
-
15
- .wip h1 {
16
- font-size: 2rem;
17
- font-weight: 700;
18
- color: var(--text-primary);
19
- margin-bottom: 1rem;
20
- }
21
-
22
- .wip p {
23
- font-size: 1.125rem;
24
- color: var(--text-secondary);
25
- }