free-coding-models 0.3.37 → 0.3.40
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.
- package/CHANGELOG.md +10 -1794
- package/README.md +4 -1
- package/bin/free-coding-models.js +8 -0
- package/package.json +13 -3
- package/src/app.js +3 -0
- package/src/cli-help.js +2 -0
- package/src/command-palette.js +3 -0
- package/src/endpoint-installer.js +1 -1
- package/src/tool-bootstrap.js +34 -0
- package/src/tool-launchers.js +137 -1
- package/src/tool-metadata.js +9 -0
- package/src/utils.js +10 -0
- package/web/app.legacy.js +900 -0
- package/web/index.html +20 -0
- package/web/server.js +382 -0
- package/web/src/App.jsx +150 -0
- package/web/src/components/analytics/AnalyticsView.jsx +109 -0
- package/web/src/components/analytics/AnalyticsView.module.css +186 -0
- package/web/src/components/atoms/Sparkline.jsx +44 -0
- package/web/src/components/atoms/StabilityCell.jsx +18 -0
- package/web/src/components/atoms/StabilityCell.module.css +8 -0
- package/web/src/components/atoms/StatusDot.jsx +10 -0
- package/web/src/components/atoms/StatusDot.module.css +17 -0
- package/web/src/components/atoms/TierBadge.jsx +10 -0
- package/web/src/components/atoms/TierBadge.module.css +18 -0
- package/web/src/components/atoms/Toast.jsx +25 -0
- package/web/src/components/atoms/Toast.module.css +35 -0
- package/web/src/components/atoms/ToastContainer.jsx +16 -0
- package/web/src/components/atoms/ToastContainer.module.css +10 -0
- package/web/src/components/atoms/VerdictBadge.jsx +13 -0
- package/web/src/components/atoms/VerdictBadge.module.css +19 -0
- package/web/src/components/dashboard/DetailPanel.jsx +131 -0
- package/web/src/components/dashboard/DetailPanel.module.css +99 -0
- package/web/src/components/dashboard/ExportModal.jsx +79 -0
- package/web/src/components/dashboard/ExportModal.module.css +99 -0
- package/web/src/components/dashboard/FilterBar.jsx +73 -0
- package/web/src/components/dashboard/FilterBar.module.css +43 -0
- package/web/src/components/dashboard/ModelTable.jsx +86 -0
- package/web/src/components/dashboard/ModelTable.module.css +46 -0
- package/web/src/components/dashboard/StatsBar.jsx +40 -0
- package/web/src/components/dashboard/StatsBar.module.css +28 -0
- package/web/src/components/layout/Footer.jsx +19 -0
- package/web/src/components/layout/Footer.module.css +10 -0
- package/web/src/components/layout/Header.jsx +38 -0
- package/web/src/components/layout/Header.module.css +73 -0
- package/web/src/components/layout/Sidebar.jsx +41 -0
- package/web/src/components/layout/Sidebar.module.css +76 -0
- package/web/src/components/settings/SettingsView.jsx +264 -0
- package/web/src/components/settings/SettingsView.module.css +377 -0
- package/web/src/global.css +199 -0
- package/web/src/hooks/useFilter.js +83 -0
- package/web/src/hooks/useSSE.js +49 -0
- package/web/src/hooks/useTheme.js +27 -0
- package/web/src/main.jsx +15 -0
- package/web/src/utils/download.js +15 -0
- package/web/src/utils/format.js +42 -0
- package/web/src/utils/ranks.js +37 -0
- package/web/styles.legacy.css +963 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file web/src/hooks/useTheme.js
|
|
3
|
+
* @description React hook for dark/light theme toggle.
|
|
4
|
+
* 📖 Persists theme on <html data-theme="dark|light">. Reads initial from DOM.
|
|
5
|
+
* → useTheme
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useCallback, useEffect } from 'react'
|
|
8
|
+
|
|
9
|
+
export function useTheme() {
|
|
10
|
+
const [theme, setTheme] = useState(() => {
|
|
11
|
+
return document.documentElement.getAttribute('data-theme') || 'dark'
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const toggle = useCallback(() => {
|
|
15
|
+
setTheme((prev) => {
|
|
16
|
+
const next = prev === 'dark' ? 'light' : 'dark'
|
|
17
|
+
document.documentElement.setAttribute('data-theme', next)
|
|
18
|
+
return next
|
|
19
|
+
})
|
|
20
|
+
}, [])
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
document.documentElement.setAttribute('data-theme', theme)
|
|
24
|
+
}, [theme])
|
|
25
|
+
|
|
26
|
+
return { theme, toggle }
|
|
27
|
+
}
|
package/web/src/main.jsx
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file web/src/main.jsx
|
|
3
|
+
* @description React application entry point — mounts the App component into the DOM.
|
|
4
|
+
* 📖 Imports global CSS (design tokens, base styles, background effects), then renders <App />.
|
|
5
|
+
*/
|
|
6
|
+
import { StrictMode } from 'react'
|
|
7
|
+
import { createRoot } from 'react-dom/client'
|
|
8
|
+
import App from './App.jsx'
|
|
9
|
+
import './global.css'
|
|
10
|
+
|
|
11
|
+
createRoot(document.getElementById('root')).render(
|
|
12
|
+
<StrictMode>
|
|
13
|
+
<App />
|
|
14
|
+
</StrictMode>,
|
|
15
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file web/src/utils/download.js
|
|
3
|
+
* @description File download helper for export functionality.
|
|
4
|
+
* → downloadFile
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function downloadFile(content, filename, type) {
|
|
8
|
+
const blob = new Blob([content], { type })
|
|
9
|
+
const url = URL.createObjectURL(blob)
|
|
10
|
+
const a = document.createElement('a')
|
|
11
|
+
a.href = url
|
|
12
|
+
a.download = filename
|
|
13
|
+
a.click()
|
|
14
|
+
URL.revokeObjectURL(url)
|
|
15
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file web/src/utils/format.js
|
|
3
|
+
* @description Shared formatting utilities for the web dashboard.
|
|
4
|
+
* → formatPing, formatAvg, formatCtx, maskKey, escapeHtml
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function formatPing(ms, code) {
|
|
8
|
+
if (ms == null) return { text: '—', cls: 'pingNone' }
|
|
9
|
+
if (code === '429') return { text: '429', cls: 'pingSlow' }
|
|
10
|
+
if (code === '000') return { text: 'TIMEOUT', cls: 'pingSlow' }
|
|
11
|
+
return { text: `${ms}ms`, cls: pingClass(ms) }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function formatAvg(avg) {
|
|
15
|
+
if (avg == null || avg === Infinity || avg > 99000) return { text: '—', cls: 'pingNone' }
|
|
16
|
+
return { text: `${avg}ms`, cls: pingClass(avg) }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function pingClass(ms) {
|
|
20
|
+
if (ms == null || ms === Infinity) return 'pingNone'
|
|
21
|
+
if (ms < 500) return 'pingFast'
|
|
22
|
+
if (ms < 1500) return 'pingMedium'
|
|
23
|
+
return 'pingSlow'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function formatCtx(c) {
|
|
27
|
+
if (!c || c === '—') return 0
|
|
28
|
+
const s = c.toLowerCase()
|
|
29
|
+
if (s.includes('m')) return parseFloat(s) * 1000
|
|
30
|
+
if (s.includes('k')) return parseFloat(s)
|
|
31
|
+
return 0
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function maskKey(key) {
|
|
35
|
+
if (!key || key.length < 8) return '••••••••'
|
|
36
|
+
return '••••••••' + key.slice(-4)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function escapeHtml(str) {
|
|
40
|
+
if (!str) return ''
|
|
41
|
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')
|
|
42
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file web/src/utils/ranks.js
|
|
3
|
+
* @description Tier, verdict, and SWE ranking maps and helpers.
|
|
4
|
+
* → tierRank, verdictRank, parseSwe, sweClass
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const TIER_RANKS = { 'S+': 0, S: 1, 'A+': 2, A: 3, 'A-': 4, 'B+': 5, B: 6, C: 7 }
|
|
8
|
+
const VERDICT_RANKS = {
|
|
9
|
+
Perfect: 0, Normal: 1, Slow: 2, Spiky: 3,
|
|
10
|
+
'Very Slow': 4, Overloaded: 5, Unstable: 6,
|
|
11
|
+
'Not Active': 7, Pending: 8,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function tierRank(tier) { return TIER_RANKS[tier] ?? 99 }
|
|
15
|
+
export function verdictRank(verdict) { return VERDICT_RANKS[verdict] ?? 99 }
|
|
16
|
+
|
|
17
|
+
export function parseSwe(s) {
|
|
18
|
+
if (!s || s === '—') return 0
|
|
19
|
+
return parseFloat(s.replace('%', '')) || 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function sweClass(swe) {
|
|
23
|
+
const val = parseSwe(swe)
|
|
24
|
+
if (val >= 65) return 'sweHigh'
|
|
25
|
+
if (val >= 40) return 'sweMid'
|
|
26
|
+
return 'sweLow'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function verdictCls(verdict) {
|
|
30
|
+
if (!verdict) return 'pending'
|
|
31
|
+
const map = {
|
|
32
|
+
perfect: 'perfect', normal: 'normal', slow: 'slow',
|
|
33
|
+
spiky: 'spiky', veryslow: 'veryslow', overloaded: 'overloaded',
|
|
34
|
+
unstable: 'unstable', notactive: 'notactive', pending: 'pending',
|
|
35
|
+
}
|
|
36
|
+
return map[verdict.toLowerCase().replace(/\s+/g, '')] || 'pending'
|
|
37
|
+
}
|