From a5c160d6a4169f42f5665f063e6dddc23637be1e Mon Sep 17 00:00:00 2001 From: devashish Date: Mon, 3 Aug 2026 22:00:43 -0700 Subject: [PATCH 1/4] feat(ui): read-only local SPA for instances, forges, and ledger Adds bin/lmstack-ui, a Node 20+ single-file HTTP server that binds 127.0.0.1:7878 and serves a React SPA (ui/dist/, pre-built) plus a small JSON API over ~/.lmstack/. The UI is strictly read-only: it walks task records, ledger, and run artifacts, intersects with `tmux list-sessions` for liveness, and never mutates state. Real work stays in tmux panes and coding harnesses. Screens: Instances (installed roles + counts), Forges (grouped by status, filterable by role/status), Forge detail (task metadata, brief, judge rounds, ANSI-stripped log tails), Ledger (filterable table). Lifecycle: `lmstack-ui start|stop|status|restart|open|foreground`. `start` daemonizes and is idempotent; PID/port land in ~/.lmstack/. The install skill now runs `lmstack-ui start` at the tail of a successful install so the URL is ready to hand to the user; a missing SPA build prints the build hint but does not abort the install. --- .gitignore | 9 + bin/lmstack-ui | 678 +++++++++++ skills/install/SKILL.md | 24 + ui/dist/assets/index-B6h_u_OQ.js | 41 + ui/dist/assets/index-DKizVbia.css | 1 + ui/dist/index.html | 14 + ui/dist/lmstack.svg | 6 + ui/index.html | 13 + ui/package-lock.json | 1792 +++++++++++++++++++++++++++++ ui/package.json | 22 + ui/public/lmstack.svg | 6 + ui/src/App.tsx | 112 ++ ui/src/api.ts | 119 ++ ui/src/components/StatusBadge.tsx | 16 + ui/src/hooks.ts | 49 + ui/src/main.tsx | 10 + ui/src/routes/ForgeDetail.tsx | 105 ++ ui/src/routes/Forges.tsx | 118 ++ ui/src/routes/Instances.tsx | 44 + ui/src/routes/Ledger.tsx | 101 ++ ui/src/styles.css | 320 ++++++ ui/tsconfig.json | 21 + ui/vite.config.ts | 18 + 23 files changed, 3639 insertions(+) create mode 100755 bin/lmstack-ui create mode 100644 ui/dist/assets/index-B6h_u_OQ.js create mode 100644 ui/dist/assets/index-DKizVbia.css create mode 100644 ui/dist/index.html create mode 100644 ui/dist/lmstack.svg create mode 100644 ui/index.html create mode 100644 ui/package-lock.json create mode 100644 ui/package.json create mode 100644 ui/public/lmstack.svg create mode 100644 ui/src/App.tsx create mode 100644 ui/src/api.ts create mode 100644 ui/src/components/StatusBadge.tsx create mode 100644 ui/src/hooks.ts create mode 100644 ui/src/main.tsx create mode 100644 ui/src/routes/ForgeDetail.tsx create mode 100644 ui/src/routes/Forges.tsx create mode 100644 ui/src/routes/Instances.tsx create mode 100644 ui/src/routes/Ledger.tsx create mode 100644 ui/src/styles.css create mode 100644 ui/tsconfig.json create mode 100644 ui/vite.config.ts diff --git a/.gitignore b/.gitignore index 34099b5..2d15cc4 100644 --- a/.gitignore +++ b/.gitignore @@ -250,3 +250,12 @@ website/.docusaurus/ # Claude Code local runtime state (scheduled task locks, session scratch). .claude/ + +# UI: React + Vite build outputs live under ui/. The Python `dist/` rule +# above would swallow ui/dist/, which we want committed so end users don't +# need Node just to view the UI. +ui/node_modules/ +ui/.vite/ +ui/tsconfig.tsbuildinfo +!ui/dist/ +!ui/dist/** diff --git a/bin/lmstack-ui b/bin/lmstack-ui new file mode 100755 index 0000000..bd171ad --- /dev/null +++ b/bin/lmstack-ui @@ -0,0 +1,678 @@ +#!/usr/bin/env node +// lmstack-ui — read-only local web UI over ~/.lmstack/ +// +// Subcommands: start | stop | status | restart | open | foreground +// Serves ui/dist/ statically and a small JSON API at /api/* on 127.0.0.1. +// Node 20+; no npm deps at runtime. + +import http from 'node:http'; +import { existsSync, readFileSync, statSync, openSync, readSync, closeSync, unlinkSync, mkdirSync } from 'node:fs'; +import { readdir, readFile, stat as statAsync } from 'node:fs/promises'; +import { execFile, spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { dirname, join, resolve, extname } from 'node:path'; +import { homedir } from 'node:os'; +import { promisify } from 'node:util'; + +const execFileP = promisify(execFile); + +const HERE = dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = resolve(HERE, '..'); +const UI_DIST = join(REPO_ROOT, 'ui', 'dist'); + +const LMSTACK_HOME = process.env.LMSTACK_HOME || join(homedir(), '.lmstack'); +const PID_FILE = join(LMSTACK_HOME, 'ui.pid'); +const PORT_FILE = join(LMSTACK_HOME, 'ui.port'); +const LOG_FILE = join(LMSTACK_HOME, 'ui.log'); + +const DEFAULT_PORT = 7878; +const HOST = '127.0.0.1'; + +// ─── subcommand dispatch ──────────────────────────────────────────────────── + +const argv = process.argv.slice(2); +const cmd = argv[0] || 'status'; +const flags = parseFlags(argv.slice(1)); + +function parseFlags(args) { + const out = {}; + for (let i = 0; i < args.length; i++) { + const a = args[i]; + if (a === '--port') out.port = parseInt(args[++i], 10); + else if (a === '--help' || a === '-h') out.help = true; + } + return out; +} + +function usage() { + process.stdout.write([ + 'lmstack-ui — local read-only web UI over ~/.lmstack/', + '', + 'usage: lmstack-ui [--port N]', + '', + 'commands:', + ' start run the server in the background (idempotent)', + ' stop stop the background server', + ' restart stop then start', + ' status print running/stopped and URL', + ' open status + open the URL in a browser', + ' foreground run in the foreground (Ctrl-C to stop)', + '', + ].join('\n')); +} + +switch (cmd) { + case 'help': + case '--help': + case '-h': usage(); process.exit(0); break; + case 'start': await cmdStart(); break; + case 'stop': await cmdStop(); break; + case 'restart': await cmdStop(); await cmdStart(); break; + case 'status': process.exit(await cmdStatus()); break; + case 'open': await cmdOpen(); break; + case 'foreground': await cmdForeground(); break; + case '__daemon': await cmdForeground(); break; // internal + default: usage(); process.exit(2); +} + +// ─── lifecycle ────────────────────────────────────────────────────────────── + +function readPid() { + try { + const pid = parseInt(readFileSync(PID_FILE, 'utf8').trim(), 10); + return Number.isFinite(pid) ? pid : null; + } catch { return null; } +} + +function readPort() { + try { + const p = parseInt(readFileSync(PORT_FILE, 'utf8').trim(), 10); + return Number.isFinite(p) ? p : null; + } catch { return null; } +} + +function isAlive(pid) { + if (!pid) return false; + try { process.kill(pid, 0); return true; } catch { return false; } +} + +async function cmdStart() { + const running = readPid(); + if (isAlive(running)) { + const port = readPort() || DEFAULT_PORT; + process.stdout.write(`lmstack-ui already running (pid ${running}) at http://${HOST}:${port}/\n`); + return; + } + if (!existsSync(join(UI_DIST, 'index.html'))) { + process.stderr.write( + `lmstack-ui: SPA build missing at ${UI_DIST}/index.html\n` + + `run: cd ${join(REPO_ROOT, 'ui')} && npm install && npm run build\n` + ); + process.exit(1); + } + await ensureDir(LMSTACK_HOME); + + const port = flags.port || DEFAULT_PORT; + const out = openSync(LOG_FILE, 'a'); + const child = spawn(process.execPath, [fileURLToPath(import.meta.url), '__daemon', '--port', String(port)], { + detached: true, + stdio: ['ignore', out, out], + env: { ...process.env, LMSTACK_UI_DAEMON: '1' }, + }); + child.unref(); + + // Wait briefly for the child to write PORT_FILE, then report. + const started = await waitFor(() => isAlive(child.pid) && readPort() != null, 3000); + if (!started) { + process.stderr.write(`lmstack-ui: server failed to start; see ${LOG_FILE}\n`); + process.exit(1); + } + const actualPort = readPort() || port; + process.stdout.write(`lmstack-ui started (pid ${child.pid}) at http://${HOST}:${actualPort}/\n`); +} + +async function cmdStop() { + const pid = readPid(); + if (!isAlive(pid)) { + process.stdout.write('lmstack-ui: not running\n'); + try { await rm(PID_FILE); await rm(PORT_FILE); } catch {} + return; + } + try { process.kill(pid, 'SIGTERM'); } catch {} + const gone = await waitFor(() => !isAlive(pid), 3000); + if (!gone) { + try { process.kill(pid, 'SIGKILL'); } catch {} + } + try { await rm(PID_FILE); await rm(PORT_FILE); } catch {} + process.stdout.write(`lmstack-ui stopped (pid ${pid})\n`); +} + +async function cmdStatus() { + const pid = readPid(); + if (isAlive(pid)) { + const port = readPort() || DEFAULT_PORT; + process.stdout.write(`running http://${HOST}:${port}/ (pid ${pid})\n`); + return 0; + } + process.stdout.write('stopped\n'); + return 1; +} + +async function cmdOpen() { + const rc = await cmdStatus(); + if (rc !== 0) { + process.stderr.write('lmstack-ui: not running; run `lmstack-ui start` first\n'); + process.exit(1); + } + const port = readPort() || DEFAULT_PORT; + const url = `http://${HOST}:${port}/`; + const opener = process.platform === 'darwin' ? 'open' : (process.platform === 'win32' ? 'start' : 'xdg-open'); + spawn(opener, [url], { detached: true, stdio: 'ignore' }).unref(); +} + +async function cmdForeground() { + await ensureDir(LMSTACK_HOME); + const startPort = flags.port || DEFAULT_PORT; + const server = http.createServer(onRequest); + + const port = await listenOnFreePort(server, startPort, 10); + // eslint-disable-next-line no-console + console.log(`[${new Date().toISOString()}] listening http://${HOST}:${port}/`); + + await writeFile(PID_FILE, String(process.pid)); + await writeFile(PORT_FILE, String(port)); + + const cleanup = () => { + try { server.close(); } catch {} + try { unlinkSyncSafe(PID_FILE); } catch {} + try { unlinkSyncSafe(PORT_FILE); } catch {} + process.exit(0); + }; + process.on('SIGTERM', cleanup); + process.on('SIGINT', cleanup); +} + +function listenOnFreePort(server, start, tries) { + return new Promise((resolvePromise, reject) => { + let port = start; + let left = tries; + const tryOnce = () => { + const onError = (err) => { + if (err.code === 'EADDRINUSE' && left-- > 0) { port++; server.listen(port, HOST, onListen); } + else reject(err); + }; + const onListen = () => { server.off('error', onError); resolvePromise(port); }; + server.once('error', onError); + server.listen(port, HOST, onListen); + }; + tryOnce(); + }); +} + +// ─── HTTP request handler ─────────────────────────────────────────────────── + +async function onRequest(req, res) { + const started = Date.now(); + try { + const url = new URL(req.url || '/', `http://${HOST}`); + const p = url.pathname; + if (p.startsWith('/api/')) { + await routeApi(req, res, url); + } else { + await serveStatic(req, res, p); + } + } catch (err) { + replyError(res, 500, err instanceof Error ? err.message : String(err)); + } finally { + // eslint-disable-next-line no-console + console.log(`[${new Date().toISOString()}] ${req.method} ${req.url} ${res.statusCode} ${Date.now() - started}ms`); + } +} + +async function routeApi(req, res, url) { + const p = url.pathname; + if (p === '/api/instances') return replyJson(res, await getInstances()); + const instMatch = p.match(/^\/api\/instances\/([^/]+)$/); + if (instMatch) return replyJson(res, await getInstance(decodeURIComponent(instMatch[1]))); + if (p === '/api/forges') { + return replyJson(res, await getForges({ + role: url.searchParams.get('role') || undefined, + status: url.searchParams.get('status') || undefined, + })); + } + const logMatch = p.match(/^\/api\/forges\/(.+)\/log\/(exec|judge)$/); + if (logMatch) { + const key = decodeURIComponent(logMatch[1]); + const which = logMatch[2]; + const tail = parseInt(url.searchParams.get('tail') || '200', 10); + return replyJson(res, await getLog(key, which, tail)); + } + const forgeMatch = p.match(/^\/api\/forges\/(.+)$/); + if (forgeMatch) return replyJson(res, await getForge(decodeURIComponent(forgeMatch[1]))); + if (p === '/api/ledger') { + return replyJson(res, await getLedger({ + limit: parseInt(url.searchParams.get('limit') || '500', 10), + shape: url.searchParams.get('shape') || undefined, + outcome: url.searchParams.get('outcome') || undefined, + role: url.searchParams.get('role') || undefined, + })); + } + replyError(res, 404, 'not found'); +} + +// ─── static ───────────────────────────────────────────────────────────────── + +const MIME = { + '.html': 'text/html; charset=utf-8', + '.js': 'application/javascript; charset=utf-8', + '.mjs': 'application/javascript; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.svg': 'image/svg+xml', + '.png': 'image/png', + '.ico': 'image/x-icon', + '.map': 'application/json; charset=utf-8', + '.woff': 'font/woff', + '.woff2':'font/woff2', +}; + +async function serveStatic(req, res, urlPath) { + let rel = urlPath === '/' ? '/index.html' : urlPath; + const target = resolve(UI_DIST, '.' + rel); + if (!target.startsWith(UI_DIST)) return replyError(res, 403, 'forbidden'); + try { + const s = await statAsync(target); + if (s.isDirectory()) return serveStatic(req, res, join(rel, 'index.html')); + const buf = await readFile(target); + const mime = MIME[extname(target)] || 'application/octet-stream'; + res.writeHead(200, { 'content-type': mime, 'cache-control': 'no-cache' }); + res.end(buf); + } catch { + // SPA fallback: unknown routes serve index.html so hash routing works. + if (urlPath !== '/index.html' && !urlPath.startsWith('/assets/')) { + return serveStatic(req, res, '/index.html'); + } + replyError(res, 404, 'not found'); + } +} + +// ─── data layer ───────────────────────────────────────────────────────────── + +function keyToSlug(key) { + return key.replace(/#/g, '-').replace(/\./g, '-'); +} + +function shortRepo(key) { + const m = /^(.+?)__(.+?)#(\d+)$/.exec(key); + return m ? { owner: m[1], repo: m[2], number: m[3] } : null; +} + +async function ensureDir(p) { + try { mkdirSync(p, { recursive: true }); } catch {} +} + +// Reserved top-level names inside ~/.lmstack/ that are never role directories. +const RESERVED = new Set([ + 'runs', 'worktrees', 'env', 'templates', 'models', 'models-gguf', 'litellm', +]); + +async function listRoles() { + try { + const entries = await readdir(LMSTACK_HOME, { withFileTypes: true }); + const roles = []; + for (const e of entries) { + if (!e.isDirectory()) continue; + if (RESERVED.has(e.name)) continue; + const hasHost = existsSync(join(LMSTACK_HOME, e.name, 'host.yml')); + const hasTasks = existsSync(join(LMSTACK_HOME, e.name, 'tasks')); + if (hasHost || hasTasks) roles.push(e.name); + } + return roles.sort(); + } catch { + return []; + } +} + +// Minimal YAML reader for host.yml — flat key: value plus inline arrays. +// Anything unrecognized falls through as a raw string. host.yml is written by +// our own install skill, so we control the shape. +function parseHostYaml(text) { + const out = {}; + for (const rawLine of text.split(/\r?\n/)) { + const line = rawLine.replace(/#.*$/, '').trim(); + if (!line) continue; + const m = /^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.*)$/.exec(line); + if (!m) continue; + const key = m[1]; + let val = m[2].trim(); + if (val === '') { out[key] = ''; continue; } + // inline array [a, b, c] + const arr = /^\[(.*)\]$/.exec(val); + if (arr) { + out[key] = arr[1] + .split(',') + .map((s) => s.trim().replace(/^["']|["']$/g, '')) + .filter(Boolean); + continue; + } + val = val.replace(/^["']|["']$/g, ''); + out[key] = val; + } + return out; +} + +async function readHostYaml(role) { + try { + const text = await readFile(join(LMSTACK_HOME, role, 'host.yml'), 'utf8'); + return parseHostYaml(text); + } catch { return {}; } +} + +async function readProbeJson(role) { + try { + const text = await readFile(join(LMSTACK_HOME, role, 'probe.json'), 'utf8'); + return JSON.parse(text); + } catch { return null; } +} + +async function readTasksForRole(role) { + const root = join(LMSTACK_HOME, role, 'tasks'); + const records = []; + if (!existsSync(root)) return records; + const repos = await readdir(root, { withFileTypes: true }); + for (const r of repos) { + if (!r.isDirectory()) continue; + const files = await readdir(join(root, r.name), { withFileTypes: true }); + for (const f of files) { + if (!f.isFile() || !f.name.endsWith('.json')) continue; + try { + const raw = await readFile(join(root, r.name, f.name), 'utf8'); + records.push(JSON.parse(raw)); + } catch { /* skip unreadable */ } + } + } + return records; +} + +async function liveTmuxSessions() { + try { + const { stdout } = await execFileP('tmux', ['list-sessions', '-F', '#{session_name}']); + const alive = new Set(); + for (const line of stdout.split(/\r?\n/)) { + const s = line.trim(); + if (s.startsWith('lmstack-')) alive.add(s.slice('lmstack-'.length)); + } + return alive; + } catch { + return new Set(); + } +} + +async function readLedger() { + const path = join(LMSTACK_HOME, 'ledger.jsonl'); + const records = []; + if (!existsSync(path)) return records; + try { + const text = await readFile(path, 'utf8'); + for (const line of text.split(/\r?\n/)) { + const t = line.trim(); + if (!t) continue; + try { records.push(JSON.parse(t)); } catch { /* skip */ } + } + } catch { /* empty */ } + return records; +} + +function deriveStatus(task, aliveSlugs) { + const slug = keyToSlug(task.key); + const declared = task.status || 'queued'; + if (declared === 'running' && !aliveSlugs.has(slug)) return 'stale'; + return declared; +} + +async function collectForges() { + const roles = await listRoles(); + const aliveSlugs = await liveTmuxSessions(); + const all = []; + for (const role of roles) { + const tasks = await readTasksForRole(role); + for (const t of tasks) { + if (!t || !t.key) continue; + const slug = keyToSlug(t.key); + const runInfo = await runMeta(slug); + const status = deriveStatus(t, aliveSlugs); + all.push({ + key: t.key, + role, + status, + tier: t.tier || null, + shape: t.shape || null, + pr: t.pr || null, + title: t.title || null, + url: t.url || null, + judgeRounds: runInfo.judgeCount, + startedAt: runInfo.startedAt, + wallMin: runInfo.wallMin, + }); + } + } + return all; +} + +async function runMeta(slug) { + const runDir = join(LMSTACK_HOME, 'runs', slug); + let startedAt = null; + let endedAt = null; + let judgeCount = 0; + let brief = null; + + if (existsSync(runDir)) { + try { + startedAt = (await readFile(join(runDir, 'started'), 'utf8')).trim() || null; + } catch { /* missing is fine */ } + try { + endedAt = (await readFile(join(runDir, 'ended'), 'utf8')).trim() || null; + } catch { /* missing is fine */ } + try { + brief = await readFile(join(runDir, 'brief.md'), 'utf8'); + } catch { /* missing is fine */ } + try { + const files = await readdir(runDir); + judgeCount = files.filter((n) => /^judge-\d+\.md$/.test(n)).length; + } catch { /* missing */ } + } + + let wallMin = null; + if (startedAt) { + const start = Date.parse(startedAt); + const end = endedAt ? Date.parse(endedAt) : Date.now(); + if (Number.isFinite(start) && Number.isFinite(end) && end >= start) { + wallMin = Math.round((end - start) / 60000); + } + } + return { startedAt, endedAt, wallMin, judgeCount, brief, runDir }; +} + +async function getInstances() { + const roles = await listRoles(); + const all = await collectForges(); + const out = []; + for (const role of roles) { + const host = await readHostYaml(role); + const probe = await readProbeJson(role); + const forges = all.filter((f) => f.role === role); + const counts = countByStatus(forges); + out.push({ + role, + host: host.connection || null, + engine: host.engine || probe?.engine || null, + gpu: host.gpu || probe?.gpu || probe?.gpu_name || null, + models: Array.isArray(host.active_models) ? host.active_models : (host.active_models ? [host.active_models] : []), + probeAt: probe?.probed_at || probe?.timestamp || host.installed_at || null, + verdict: host.verdict || null, + counts, + }); + } + return out; +} + +function countByStatus(forges) { + const c = { running: 0, in_review: 0, queued: 0, merged: 0, failed: 0, cleaned: 0, stale: 0 }; + for (const f of forges) { + if (f.status === 'in-review') c.in_review++; + else if (f.status in c) c[f.status]++; + } + return c; +} + +async function getInstance(role) { + const host = await readHostYaml(role); + const probe = await readProbeJson(role); + return { role, host, probe }; +} + +async function getForges(filters) { + let all = await collectForges(); + if (filters.role) all = all.filter((f) => f.role === filters.role); + if (filters.status) all = all.filter((f) => f.status === filters.status); + // sort: running first, then in-review, then queued, then completed + const order = { running: 0, 'in-review': 1, stale: 2, queued: 3, failed: 4, merged: 5, cleaned: 6 }; + all.sort((a, b) => (order[a.status] ?? 99) - (order[b.status] ?? 99) || a.key.localeCompare(b.key)); + return all; +} + +async function getForge(key) { + const roles = await listRoles(); + let task = null; + let role = null; + for (const r of roles) { + const tasks = await readTasksForRole(r); + const found = tasks.find((t) => t && t.key === key); + if (found) { task = found; role = r; break; } + } + if (!task) { + // Fall back to ledger lookup so a cleaned-up task is still viewable. + const ledger = await readLedger(); + const led = ledger.reverse().find((r) => r.key === key); + if (!led) throw new Error(`unknown forge key: ${key}`); + task = { key, host_role: led.host_role, tier: led.tier, shape: led.shape, pr: led.pr, status: 'cleaned' }; + role = led.host_role; + } + const slug = keyToSlug(key); + const aliveSlugs = await liveTmuxSessions(); + const tmuxAlive = aliveSlugs.has(slug); + const meta = await runMeta(slug); + + // Judge rounds + const judgeRounds = []; + if (existsSync(meta.runDir)) { + const files = (await readdir(meta.runDir)).filter((n) => /^judge-\d+\.md$/.test(n)) + .sort((a, b) => Number(a.match(/\d+/)[0]) - Number(b.match(/\d+/)[0])); + for (const name of files) { + const n = Number(name.match(/\d+/)[0]); + const text = await readFile(join(meta.runDir, name), 'utf8'); + judgeRounds.push({ n, text }); + } + } + + const worktreePath = join(LMSTACK_HOME, 'worktrees', slug); + const worktreeExists = existsSync(worktreePath); + const branch = `lmstack/${slug}`; + + // Ledger record for this key (most recent) + const ledger = await readLedger(); + const led = [...ledger].reverse().find((r) => r.key === key) || null; + + return { + role, + slug, + task, + run: { + exists: existsSync(meta.runDir), + brief: meta.brief, + judgeRounds, + startedAt: meta.startedAt, + endedAt: meta.endedAt, + tmuxAlive, + worktreePath, + worktreeExists, + branch, + }, + ledger: led, + }; +} + +async function getLog(key, which, tail) { + const slug = keyToSlug(key); + const path = join(LMSTACK_HOME, 'runs', slug, `${which}.log`); + if (!existsSync(path)) return { lines: [], sizeBytes: 0, truncated: false, exists: false, path }; + const s = statSync(path); + const size = s.size; + const window = Math.min(size, 64 * 1024); + const start = size - window; + const fd = openSync(path, 'r'); + const buf = Buffer.alloc(window); + readSync(fd, buf, 0, window, start); + closeSync(fd); + const text = stripAnsi(buf.toString('utf8')); + const allLines = text.split(/\r?\n/); + // If we didn't read from byte 0, the first partial line is likely truncated — drop it. + const linesTrimmed = start > 0 && allLines.length > 0 ? allLines.slice(1) : allLines; + const kept = linesTrimmed.slice(-tail).filter((l, i, arr) => !(i === arr.length - 1 && l === '')); + return { lines: kept, sizeBytes: size, truncated: start > 0 || linesTrimmed.length > tail, exists: true, path }; +} + +// Strip CSI/OSC/other ANSI escape sequences that tmux `pipe-pane` emits. +// Terminal transcripts are otherwise unreadable when rendered as plain text. +function stripAnsi(s) { + // CSI sequences: ESC [ ... final-byte + let out = s.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, ''); + // OSC sequences: ESC ] ... BEL or ESC ] ... ESC \ + out = out.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, ''); + // Two-byte escapes (SS2/SS3/RIS/etc.) and stray ESC + out = out.replace(/\x1b[@-Z\\-_]/g, ''); + return out; +} + +async function getLedger(filters) { + const all = await readLedger(); + let out = all.slice().reverse(); // newest first + if (filters.shape) out = out.filter((r) => r.shape === filters.shape); + if (filters.outcome) out = out.filter((r) => r.outcome === filters.outcome); + if (filters.role) out = out.filter((r) => r.host_role === filters.role); + if (filters.limit) out = out.slice(0, filters.limit); + return out; +} + +// ─── reply helpers ────────────────────────────────────────────────────────── + +function replyJson(res, obj) { + res.writeHead(200, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }); + res.end(JSON.stringify(obj)); +} +function replyError(res, code, message) { + res.writeHead(code, { 'content-type': 'application/json; charset=utf-8' }); + res.end(JSON.stringify({ error: message })); +} + +// ─── tiny fs helpers ──────────────────────────────────────────────────────── + +async function writeFile(path, text) { + const fs = await import('node:fs/promises'); + await fs.writeFile(path, text); +} +async function rm(path) { + const fs = await import('node:fs/promises'); + await fs.rm(path, { force: true }); +} +function unlinkSyncSafe(path) { + try { unlinkSync(path); } catch {} +} +async function waitFor(pred, timeoutMs) { + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { if (await pred()) return true; } catch {} + await new Promise((r) => setTimeout(r, 50)); + } + return false; +} diff --git a/skills/install/SKILL.md b/skills/install/SKILL.md index 53b5951..928bff4 100644 --- a/skills/install/SKILL.md +++ b/skills/install/SKILL.md @@ -258,6 +258,30 @@ the local-only story from end to end. Finish by telling the user what they now have and that `/lmstack:harvest` is what turns it into work. +## Phase 7 — Start the read-only UI + +The last step brings up the local web UI so the user can watch instances and +forges without attaching to tmux. It reads only from `~/.lmstack/`; it never +mutates state. + +```bash +"${CLAUDE_PLUGIN_ROOT}/bin/lmstack-ui" start +``` + +`start` is idempotent — if the server is already running (from a prior install +or a manual start) it prints the URL and exits 0. Include the printed +`http://127.0.0.1:/` in the finish message so the user can click through. + +If the command fails because the SPA has not been built (`ui/dist/` missing — +only happens in a source checkout, not in a released plugin), print the error +and the build hint it emits, but **do not abort the install**. The install has +already succeeded; the UI is a convenience layer on top of it. The user can +start it later with `lmstack-ui start` once the SPA is built, or with +`lmstack-ui foreground` to debug. + +The daemon lives until reboot or explicit `lmstack-ui stop`. There is no +systemd/launchd unit — start it again after a reboot if you want it back. + ## Logging Every phase writes one line through `lmstack-log`, which redacts before it diff --git a/ui/dist/assets/index-B6h_u_OQ.js b/ui/dist/assets/index-B6h_u_OQ.js new file mode 100644 index 0000000..9bf721a --- /dev/null +++ b/ui/dist/assets/index-B6h_u_OQ.js @@ -0,0 +1,41 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const i of l)if(i.type==="childList")for(const u of i.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&r(u)}).observe(document,{childList:!0,subtree:!0});function n(l){const i={};return l.integrity&&(i.integrity=l.integrity),l.referrerPolicy&&(i.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?i.credentials="include":l.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(l){if(l.ep)return;l.ep=!0;const i=n(l);fetch(l.href,i)}})();function hc(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var es={exports:{}},rl={},ts={exports:{}},L={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Jn=Symbol.for("react.element"),mc=Symbol.for("react.portal"),vc=Symbol.for("react.fragment"),gc=Symbol.for("react.strict_mode"),yc=Symbol.for("react.profiler"),wc=Symbol.for("react.provider"),kc=Symbol.for("react.context"),xc=Symbol.for("react.forward_ref"),Sc=Symbol.for("react.suspense"),Ec=Symbol.for("react.memo"),jc=Symbol.for("react.lazy"),Au=Symbol.iterator;function Nc(e){return e===null||typeof e!="object"?null:(e=Au&&e[Au]||e["@@iterator"],typeof e=="function"?e:null)}var ns={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},rs=Object.assign,ls={};function sn(e,t,n){this.props=e,this.context=t,this.refs=ls,this.updater=n||ns}sn.prototype.isReactComponent={};sn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};sn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function is(){}is.prototype=sn.prototype;function Hi(e,t,n){this.props=e,this.context=t,this.refs=ls,this.updater=n||ns}var Wi=Hi.prototype=new is;Wi.constructor=Hi;rs(Wi,sn.prototype);Wi.isPureReactComponent=!0;var Bu=Array.isArray,us=Object.prototype.hasOwnProperty,Qi={current:null},os={key:!0,ref:!0,__self:!0,__source:!0};function ss(e,t,n){var r,l={},i=null,u=null;if(t!=null)for(r in t.ref!==void 0&&(u=t.ref),t.key!==void 0&&(i=""+t.key),t)us.call(t,r)&&!os.hasOwnProperty(r)&&(l[r]=t[r]);var o=arguments.length-2;if(o===1)l.children=n;else if(1>>1,X=j[Q];if(0>>1;Ql(Sl,z))gtl(rr,Sl)?(j[Q]=rr,j[gt]=z,Q=gt):(j[Q]=Sl,j[vt]=z,Q=vt);else if(gtl(rr,z))j[Q]=rr,j[gt]=z,Q=gt;else break e}}return P}function l(j,P){var z=j.sortIndex-P.sortIndex;return z!==0?z:j.id-P.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var u=Date,o=u.now();e.unstable_now=function(){return u.now()-o}}var s=[],f=[],v=1,m=null,h=3,y=!1,x=!1,g=!1,O=typeof setTimeout=="function"?setTimeout:null,d=typeof clearTimeout=="function"?clearTimeout:null,c=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(j){for(var P=n(f);P!==null;){if(P.callback===null)r(f);else if(P.startTime<=j)r(f),P.sortIndex=P.expirationTime,t(s,P);else break;P=n(f)}}function w(j){if(g=!1,p(j),!x)if(n(s)!==null)x=!0,kl(E);else{var P=n(f);P!==null&&xl(w,P.startTime-j)}}function E(j,P){x=!1,g&&(g=!1,d(_),_=-1),y=!0;var z=h;try{for(p(P),m=n(s);m!==null&&(!(m.expirationTime>P)||j&&!_e());){var Q=m.callback;if(typeof Q=="function"){m.callback=null,h=m.priorityLevel;var X=Q(m.expirationTime<=P);P=e.unstable_now(),typeof X=="function"?m.callback=X:m===n(s)&&r(s),p(P)}else r(s);m=n(s)}if(m!==null)var nr=!0;else{var vt=n(f);vt!==null&&xl(w,vt.startTime-P),nr=!1}return nr}finally{m=null,h=z,y=!1}}var N=!1,C=null,_=-1,W=5,T=-1;function _e(){return!(e.unstable_now()-Tj||125Q?(j.sortIndex=z,t(f,j),n(s)===null&&j===n(f)&&(g?(d(_),_=-1):g=!0,xl(w,z-Q))):(j.sortIndex=X,t(s,j),x||y||(x=!0,kl(E))),j},e.unstable_shouldYield=_e,e.unstable_wrapCallback=function(j){var P=h;return function(){var z=h;h=P;try{return j.apply(this,arguments)}finally{h=z}}}})(ps);ds.exports=ps;var Fc=ds.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Uc=A,ye=Fc;function k(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Jl=Object.prototype.hasOwnProperty,$c=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Hu={},Wu={};function Ac(e){return Jl.call(Wu,e)?!0:Jl.call(Hu,e)?!1:$c.test(e)?Wu[e]=!0:(Hu[e]=!0,!1)}function Bc(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Vc(e,t,n,r){if(t===null||typeof t>"u"||Bc(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function ae(e,t,n,r,l,i,u){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=u}var te={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){te[e]=new ae(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];te[t]=new ae(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){te[e]=new ae(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){te[e]=new ae(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){te[e]=new ae(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){te[e]=new ae(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){te[e]=new ae(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){te[e]=new ae(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){te[e]=new ae(e,5,!1,e.toLowerCase(),null,!1,!1)});var Yi=/[\-:]([a-z])/g;function Zi(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Yi,Zi);te[t]=new ae(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Yi,Zi);te[t]=new ae(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Yi,Zi);te[t]=new ae(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){te[e]=new ae(e,1,!1,e.toLowerCase(),null,!1,!1)});te.xlinkHref=new ae("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){te[e]=new ae(e,1,!1,e.toLowerCase(),null,!0,!0)});function Gi(e,t,n,r){var l=te.hasOwnProperty(t)?te[t]:null;(l!==null?l.type!==0:r||!(2o||l[u]!==i[o]){var s=` +`+l[u].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=u&&0<=o);break}}}finally{Nl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?xn(e):""}function Hc(e){switch(e.tag){case 5:return xn(e.type);case 16:return xn("Lazy");case 13:return xn("Suspense");case 19:return xn("SuspenseList");case 0:case 2:case 15:return e=Cl(e.type,!1),e;case 11:return e=Cl(e.type.render,!1),e;case 1:return e=Cl(e.type,!0),e;default:return""}}function ti(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Ft:return"Fragment";case Dt:return"Portal";case ql:return"Profiler";case Xi:return"StrictMode";case bl:return"Suspense";case ei:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case vs:return(e.displayName||"Context")+".Consumer";case ms:return(e._context.displayName||"Context")+".Provider";case Ji:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case qi:return t=e.displayName||null,t!==null?t:ti(e.type)||"Memo";case Je:t=e._payload,e=e._init;try{return ti(e(t))}catch{}}return null}function Wc(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ti(t);case 8:return t===Xi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function ft(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ys(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Qc(e){var t=ys(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(u){r=""+u,i.call(this,u)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(u){r=""+u},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ur(e){e._valueTracker||(e._valueTracker=Qc(e))}function ws(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ys(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Mr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ni(e,t){var n=t.checked;return V({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Ku(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=ft(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function ks(e,t){t=t.checked,t!=null&&Gi(e,"checked",t,!1)}function ri(e,t){ks(e,t);var n=ft(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?li(e,t.type,n):t.hasOwnProperty("defaultValue")&&li(e,t.type,ft(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Yu(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function li(e,t,n){(t!=="number"||Mr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Sn=Array.isArray;function Zt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=or.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function In(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Nn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Kc=["Webkit","ms","Moz","O"];Object.keys(Nn).forEach(function(e){Kc.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Nn[t]=Nn[e]})});function js(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Nn.hasOwnProperty(e)&&Nn[e]?(""+t).trim():t+"px"}function Ns(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=js(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Yc=V({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function oi(e,t){if(t){if(Yc[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(k(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(k(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(k(61))}if(t.style!=null&&typeof t.style!="object")throw Error(k(62))}}function si(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var ai=null;function bi(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var ci=null,Gt=null,Xt=null;function Xu(e){if(e=er(e)){if(typeof ci!="function")throw Error(k(280));var t=e.stateNode;t&&(t=sl(t),ci(e.stateNode,e.type,t))}}function Cs(e){Gt?Xt?Xt.push(e):Xt=[e]:Gt=e}function _s(){if(Gt){var e=Gt,t=Xt;if(Xt=Gt=null,Xu(e),t)for(e=0;e>>=0,e===0?32:31-(lf(e)/uf|0)|0}var sr=64,ar=4194304;function En(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Fr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,i=e.pingedLanes,u=n&268435455;if(u!==0){var o=u&~l;o!==0?r=En(o):(i&=u,i!==0&&(r=En(i)))}else u=n&~l,u!==0?r=En(u):i!==0&&(r=En(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,i=t&-t,l>=i||l===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function qn(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Re(t),e[t]=n}function cf(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=_n),io=" ",uo=!1;function Ys(e,t){switch(e){case"keyup":return Uf.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Zs(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ut=!1;function Af(e,t){switch(e){case"compositionend":return Zs(t);case"keypress":return t.which!==32?null:(uo=!0,io);case"textInput":return e=t.data,e===io&&uo?null:e;default:return null}}function Bf(e,t){if(Ut)return e==="compositionend"||!ou&&Ys(e,t)?(e=Qs(),jr=lu=tt=null,Ut=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=co(n)}}function qs(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?qs(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function bs(){for(var e=window,t=Mr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Mr(e.document)}return t}function su(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Xf(e){var t=bs(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&qs(n.ownerDocument.documentElement,n)){if(r!==null&&su(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,i=Math.min(r.start,l);r=r.end===void 0?i:Math.min(r.end,l),!e.extend&&i>r&&(l=r,r=i,i=l),l=fo(n,i);var u=fo(n,r);l&&u&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==u.node||e.focusOffset!==u.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(u.node,u.offset)):(t.setEnd(u.node,u.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,$t=null,vi=null,zn=null,gi=!1;function po(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;gi||$t==null||$t!==Mr(r)||(r=$t,"selectionStart"in r&&su(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),zn&&Bn(zn,r)||(zn=r,r=Ar(vi,"onSelect"),0Vt||(e.current=Ei[Vt],Ei[Vt]=null,Vt--)}function I(e,t){Vt++,Ei[Vt]=e.current,e.current=t}var dt={},ie=ht(dt),de=ht(!1),_t=dt;function tn(e,t){var n=e.type.contextTypes;if(!n)return dt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},i;for(i in n)l[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function pe(e){return e=e.childContextTypes,e!=null}function Vr(){F(de),F(ie)}function ko(e,t,n){if(ie.current!==dt)throw Error(k(168));I(ie,t),I(de,n)}function sa(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(k(108,Wc(e)||"Unknown",l));return V({},n,r)}function Hr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dt,_t=ie.current,I(ie,e),I(de,de.current),!0}function xo(e,t,n){var r=e.stateNode;if(!r)throw Error(k(169));n?(e=sa(e,t,_t),r.__reactInternalMemoizedMergedChildContext=e,F(de),F(ie),I(ie,e)):F(de),I(de,n)}var Be=null,al=!1,Al=!1;function aa(e){Be===null?Be=[e]:Be.push(e)}function sd(e){al=!0,aa(e)}function mt(){if(!Al&&Be!==null){Al=!0;var e=0,t=M;try{var n=Be;for(M=1;e>=u,l-=u,Ve=1<<32-Re(t)+l|n<_?(W=C,C=null):W=C.sibling;var T=h(d,C,p[_],w);if(T===null){C===null&&(C=W);break}e&&C&&T.alternate===null&&t(d,C),c=i(T,c,_),N===null?E=T:N.sibling=T,N=T,C=W}if(_===p.length)return n(d,C),U&&yt(d,_),E;if(C===null){for(;__?(W=C,C=null):W=C.sibling;var _e=h(d,C,T.value,w);if(_e===null){C===null&&(C=W);break}e&&C&&_e.alternate===null&&t(d,C),c=i(_e,c,_),N===null?E=_e:N.sibling=_e,N=_e,C=W}if(T.done)return n(d,C),U&&yt(d,_),E;if(C===null){for(;!T.done;_++,T=p.next())T=m(d,T.value,w),T!==null&&(c=i(T,c,_),N===null?E=T:N.sibling=T,N=T);return U&&yt(d,_),E}for(C=r(d,C);!T.done;_++,T=p.next())T=y(C,d,_,T.value,w),T!==null&&(e&&T.alternate!==null&&C.delete(T.key===null?_:T.key),c=i(T,c,_),N===null?E=T:N.sibling=T,N=T);return e&&C.forEach(function(fn){return t(d,fn)}),U&&yt(d,_),E}function O(d,c,p,w){if(typeof p=="object"&&p!==null&&p.type===Ft&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case ir:e:{for(var E=p.key,N=c;N!==null;){if(N.key===E){if(E=p.type,E===Ft){if(N.tag===7){n(d,N.sibling),c=l(N,p.props.children),c.return=d,d=c;break e}}else if(N.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===Je&&jo(E)===N.type){n(d,N.sibling),c=l(N,p.props),c.ref=yn(d,N,p),c.return=d,d=c;break e}n(d,N);break}else t(d,N);N=N.sibling}p.type===Ft?(c=jt(p.props.children,d.mode,w,p.key),c.return=d,d=c):(w=Rr(p.type,p.key,p.props,null,d.mode,w),w.ref=yn(d,c,p),w.return=d,d=w)}return u(d);case Dt:e:{for(N=p.key;c!==null;){if(c.key===N)if(c.tag===4&&c.stateNode.containerInfo===p.containerInfo&&c.stateNode.implementation===p.implementation){n(d,c.sibling),c=l(c,p.children||[]),c.return=d,d=c;break e}else{n(d,c);break}else t(d,c);c=c.sibling}c=Zl(p,d.mode,w),c.return=d,d=c}return u(d);case Je:return N=p._init,O(d,c,N(p._payload),w)}if(Sn(p))return x(d,c,p,w);if(pn(p))return g(d,c,p,w);vr(d,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,c!==null&&c.tag===6?(n(d,c.sibling),c=l(c,p),c.return=d,d=c):(n(d,c),c=Yl(p,d.mode,w),c.return=d,d=c),u(d)):n(d,c)}return O}var rn=pa(!0),ha=pa(!1),Kr=ht(null),Yr=null,Qt=null,du=null;function pu(){du=Qt=Yr=null}function hu(e){var t=Kr.current;F(Kr),e._currentValue=t}function Ci(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function qt(e,t){Yr=e,du=Qt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(fe=!0),e.firstContext=null)}function Ne(e){var t=e._currentValue;if(du!==e)if(e={context:e,memoizedValue:t,next:null},Qt===null){if(Yr===null)throw Error(k(308));Qt=e,Yr.dependencies={lanes:0,firstContext:e}}else Qt=Qt.next=e;return t}var xt=null;function mu(e){xt===null?xt=[e]:xt.push(e)}function ma(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,mu(t)):(n.next=l.next,l.next=n),t.interleaved=n,Ye(e,r)}function Ye(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var qe=!1;function vu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function va(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function We(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ot(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,R&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Ye(e,n)}return l=r.interleaved,l===null?(t.next=t,mu(r)):(t.next=l.next,l.next=t),r.interleaved=t,Ye(e,n)}function Cr(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tu(e,n)}}function No(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var u={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?l=i=u:i=i.next=u,n=n.next}while(n!==null);i===null?l=i=t:i=i.next=t}else l=i=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Zr(e,t,n,r){var l=e.updateQueue;qe=!1;var i=l.firstBaseUpdate,u=l.lastBaseUpdate,o=l.shared.pending;if(o!==null){l.shared.pending=null;var s=o,f=s.next;s.next=null,u===null?i=f:u.next=f,u=s;var v=e.alternate;v!==null&&(v=v.updateQueue,o=v.lastBaseUpdate,o!==u&&(o===null?v.firstBaseUpdate=f:o.next=f,v.lastBaseUpdate=s))}if(i!==null){var m=l.baseState;u=0,v=f=s=null,o=i;do{var h=o.lane,y=o.eventTime;if((r&h)===h){v!==null&&(v=v.next={eventTime:y,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var x=e,g=o;switch(h=t,y=n,g.tag){case 1:if(x=g.payload,typeof x=="function"){m=x.call(y,m,h);break e}m=x;break e;case 3:x.flags=x.flags&-65537|128;case 0:if(x=g.payload,h=typeof x=="function"?x.call(y,m,h):x,h==null)break e;m=V({},m,h);break e;case 2:qe=!0}}o.callback!==null&&o.lane!==0&&(e.flags|=64,h=l.effects,h===null?l.effects=[o]:h.push(o))}else y={eventTime:y,lane:h,tag:o.tag,payload:o.payload,callback:o.callback,next:null},v===null?(f=v=y,s=m):v=v.next=y,u|=h;if(o=o.next,o===null){if(o=l.shared.pending,o===null)break;h=o,o=h.next,h.next=null,l.lastBaseUpdate=h,l.shared.pending=null}}while(!0);if(v===null&&(s=m),l.baseState=s,l.firstBaseUpdate=f,l.lastBaseUpdate=v,t=l.shared.interleaved,t!==null){l=t;do u|=l.lane,l=l.next;while(l!==t)}else i===null&&(l.shared.lanes=0);Lt|=u,e.lanes=u,e.memoizedState=m}}function Co(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Vl.transition;Vl.transition={};try{e(!1),t()}finally{M=n,Vl.transition=r}}function Ma(){return Ce().memoizedState}function dd(e,t,n){var r=at(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Oa(e))Ia(t,n);else if(n=ma(e,t,n,r),n!==null){var l=oe();Me(n,e,r,l),Da(n,t,r)}}function pd(e,t,n){var r=at(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Oa(e))Ia(t,l);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var u=t.lastRenderedState,o=i(u,n);if(l.hasEagerState=!0,l.eagerState=o,Oe(o,u)){var s=t.interleaved;s===null?(l.next=l,mu(t)):(l.next=s.next,s.next=l),t.interleaved=l;return}}catch{}finally{}n=ma(e,t,l,r),n!==null&&(l=oe(),Me(n,e,r,l),Da(n,t,r))}}function Oa(e){var t=e.alternate;return e===B||t!==null&&t===B}function Ia(e,t){Ln=Xr=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Da(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tu(e,n)}}var Jr={readContext:Ne,useCallback:ne,useContext:ne,useEffect:ne,useImperativeHandle:ne,useInsertionEffect:ne,useLayoutEffect:ne,useMemo:ne,useReducer:ne,useRef:ne,useState:ne,useDebugValue:ne,useDeferredValue:ne,useTransition:ne,useMutableSource:ne,useSyncExternalStore:ne,useId:ne,unstable_isNewReconciler:!1},hd={readContext:Ne,useCallback:function(e,t){return De().memoizedState=[e,t===void 0?null:t],e},useContext:Ne,useEffect:Po,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Pr(4194308,4,Pa.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Pr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Pr(4,2,e,t)},useMemo:function(e,t){var n=De();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=De();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=dd.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var t=De();return e={current:e},t.memoizedState=e},useState:_o,useDebugValue:ju,useDeferredValue:function(e){return De().memoizedState=e},useTransition:function(){var e=_o(!1),t=e[0];return e=fd.bind(null,e[1]),De().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=B,l=De();if(U){if(n===void 0)throw Error(k(407));n=n()}else{if(n=t(),q===null)throw Error(k(349));zt&30||ka(r,t,n)}l.memoizedState=n;var i={value:n,getSnapshot:t};return l.queue=i,Po(Sa.bind(null,r,i,e),[e]),r.flags|=2048,Gn(9,xa.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=De(),t=q.identifierPrefix;if(U){var n=He,r=Ve;n=(r&~(1<<32-Re(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Yn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=u.createElement(n,{is:r.is}):(e=u.createElement(n),n==="select"&&(u=e,r.multiple?u.multiple=!0:r.size&&(u.size=r.size))):e=u.createElementNS(e,n),e[Fe]=t,e[Wn]=r,Ka(e,t,!1,!1),t.stateNode=e;e:{switch(u=si(n,r),n){case"dialog":D("cancel",e),D("close",e),l=r;break;case"iframe":case"object":case"embed":D("load",e),l=r;break;case"video":case"audio":for(l=0;lon&&(t.flags|=128,r=!0,wn(i,!1),t.lanes=4194304)}else{if(!r)if(e=Gr(u),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),wn(i,!0),i.tail===null&&i.tailMode==="hidden"&&!u.alternate&&!U)return re(t),null}else 2*K()-i.renderingStartTime>on&&n!==1073741824&&(t.flags|=128,r=!0,wn(i,!1),t.lanes=4194304);i.isBackwards?(u.sibling=t.child,t.child=u):(n=i.last,n!==null?n.sibling=u:t.child=u,i.last=u)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=K(),t.sibling=null,n=$.current,I($,r?n&1|2:n&1),t):(re(t),null);case 22:case 23:return Lu(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?me&1073741824&&(re(t),t.subtreeFlags&6&&(t.flags|=8192)):re(t),null;case 24:return null;case 25:return null}throw Error(k(156,t.tag))}function Sd(e,t){switch(cu(t),t.tag){case 1:return pe(t.type)&&Vr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ln(),F(de),F(ie),wu(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return yu(t),null;case 13:if(F($),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(k(340));nn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return F($),null;case 4:return ln(),null;case 10:return hu(t.type._context),null;case 22:case 23:return Lu(),null;case 24:return null;default:return null}}var yr=!1,le=!1,Ed=typeof WeakSet=="function"?WeakSet:Set,S=null;function Kt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){H(e,t,r)}else n.current=null}function Ii(e,t,n){try{n()}catch(r){H(e,t,r)}}var $o=!1;function jd(e,t){if(yi=Ur,e=bs(),su(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var u=0,o=-1,s=-1,f=0,v=0,m=e,h=null;t:for(;;){for(var y;m!==n||l!==0&&m.nodeType!==3||(o=u+l),m!==i||r!==0&&m.nodeType!==3||(s=u+r),m.nodeType===3&&(u+=m.nodeValue.length),(y=m.firstChild)!==null;)h=m,m=y;for(;;){if(m===e)break t;if(h===n&&++f===l&&(o=u),h===i&&++v===r&&(s=u),(y=m.nextSibling)!==null)break;m=h,h=m.parentNode}m=y}n=o===-1||s===-1?null:{start:o,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(wi={focusedElem:e,selectionRange:n},Ur=!1,S=t;S!==null;)if(t=S,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,S=e;else for(;S!==null;){t=S;try{var x=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(x!==null){var g=x.memoizedProps,O=x.memoizedState,d=t.stateNode,c=d.getSnapshotBeforeUpdate(t.elementType===t.type?g:ze(t.type,g),O);d.__reactInternalSnapshotBeforeUpdate=c}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(k(163))}}catch(w){H(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,S=e;break}S=t.return}return x=$o,$o=!1,x}function Tn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var i=l.destroy;l.destroy=void 0,i!==void 0&&Ii(t,n,i)}l=l.next}while(l!==r)}}function dl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Di(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Ga(e){var t=e.alternate;t!==null&&(e.alternate=null,Ga(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Fe],delete t[Wn],delete t[Si],delete t[ud],delete t[od])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Xa(e){return e.tag===5||e.tag===3||e.tag===4}function Ao(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Xa(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Fi(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Br));else if(r!==4&&(e=e.child,e!==null))for(Fi(e,t,n),e=e.sibling;e!==null;)Fi(e,t,n),e=e.sibling}function Ui(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ui(e,t,n),e=e.sibling;e!==null;)Ui(e,t,n),e=e.sibling}var b=null,Le=!1;function Xe(e,t,n){for(n=n.child;n!==null;)Ja(e,t,n),n=n.sibling}function Ja(e,t,n){if(Ue&&typeof Ue.onCommitFiberUnmount=="function")try{Ue.onCommitFiberUnmount(ll,n)}catch{}switch(n.tag){case 5:le||Kt(n,t);case 6:var r=b,l=Le;b=null,Xe(e,t,n),b=r,Le=l,b!==null&&(Le?(e=b,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):b.removeChild(n.stateNode));break;case 18:b!==null&&(Le?(e=b,n=n.stateNode,e.nodeType===8?$l(e.parentNode,n):e.nodeType===1&&$l(e,n),$n(e)):$l(b,n.stateNode));break;case 4:r=b,l=Le,b=n.stateNode.containerInfo,Le=!0,Xe(e,t,n),b=r,Le=l;break;case 0:case 11:case 14:case 15:if(!le&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var i=l,u=i.destroy;i=i.tag,u!==void 0&&(i&2||i&4)&&Ii(n,t,u),l=l.next}while(l!==r)}Xe(e,t,n);break;case 1:if(!le&&(Kt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(o){H(n,t,o)}Xe(e,t,n);break;case 21:Xe(e,t,n);break;case 22:n.mode&1?(le=(r=le)||n.memoizedState!==null,Xe(e,t,n),le=r):Xe(e,t,n);break;default:Xe(e,t,n)}}function Bo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Ed),t.forEach(function(r){var l=Md.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Pe(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=u),r&=~i}if(r=l,r=K()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Cd(r/1960))-r,10e?16:e,nt===null)var r=!1;else{if(e=nt,nt=null,el=0,R&6)throw Error(k(331));var l=R;for(R|=4,S=e.current;S!==null;){var i=S,u=i.child;if(S.flags&16){var o=i.deletions;if(o!==null){for(var s=0;sK()-Pu?Et(e,0):_u|=n),he(e,t)}function ic(e,t){t===0&&(e.mode&1?(t=ar,ar<<=1,!(ar&130023424)&&(ar=4194304)):t=1);var n=oe();e=Ye(e,t),e!==null&&(qn(e,t,n),he(e,n))}function Rd(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),ic(e,n)}function Md(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(k(314))}r!==null&&r.delete(t),ic(e,n)}var uc;uc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||de.current)fe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return fe=!1,kd(e,t,n);fe=!!(e.flags&131072)}else fe=!1,U&&t.flags&1048576&&ca(t,Qr,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;zr(e,t),e=t.pendingProps;var l=tn(t,ie.current);qt(t,n),l=xu(null,t,r,e,l,n);var i=Su();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,pe(r)?(i=!0,Hr(t)):i=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,vu(t),l.updater=fl,t.stateNode=l,l._reactInternals=t,Pi(t,r,e,n),t=Ti(null,t,r,!0,i,n)):(t.tag=0,U&&i&&au(t),ue(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(zr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Id(r),e=ze(r,e),l){case 0:t=Li(null,t,r,e,n);break e;case 1:t=Do(null,t,r,e,n);break e;case 11:t=Oo(null,t,r,e,n);break e;case 14:t=Io(null,t,r,ze(r.type,e),n);break e}throw Error(k(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Li(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Do(e,t,r,l,n);case 3:e:{if(Ha(t),e===null)throw Error(k(387));r=t.pendingProps,i=t.memoizedState,l=i.element,va(e,t),Zr(t,r,null,n);var u=t.memoizedState;if(r=u.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:u.cache,pendingSuspenseBoundaries:u.pendingSuspenseBoundaries,transitions:u.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){l=un(Error(k(423)),t),t=Fo(e,t,r,n,l);break e}else if(r!==l){l=un(Error(k(424)),t),t=Fo(e,t,r,n,l);break e}else for(ve=ut(t.stateNode.containerInfo.firstChild),ge=t,U=!0,Te=null,n=ha(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(nn(),r===l){t=Ze(e,t,n);break e}ue(e,t,r,n)}t=t.child}return t;case 5:return ga(t),e===null&&Ni(t),r=t.type,l=t.pendingProps,i=e!==null?e.memoizedProps:null,u=l.children,ki(r,l)?u=null:i!==null&&ki(r,i)&&(t.flags|=32),Va(e,t),ue(e,t,u,n),t.child;case 6:return e===null&&Ni(t),null;case 13:return Wa(e,t,n);case 4:return gu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=rn(t,null,r,n):ue(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Oo(e,t,r,l,n);case 7:return ue(e,t,t.pendingProps,n),t.child;case 8:return ue(e,t,t.pendingProps.children,n),t.child;case 12:return ue(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,i=t.memoizedProps,u=l.value,I(Kr,r._currentValue),r._currentValue=u,i!==null)if(Oe(i.value,u)){if(i.children===l.children&&!de.current){t=Ze(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var o=i.dependencies;if(o!==null){u=i.child;for(var s=o.firstContext;s!==null;){if(s.context===r){if(i.tag===1){s=We(-1,n&-n),s.tag=2;var f=i.updateQueue;if(f!==null){f=f.shared;var v=f.pending;v===null?s.next=s:(s.next=v.next,v.next=s),f.pending=s}}i.lanes|=n,s=i.alternate,s!==null&&(s.lanes|=n),Ci(i.return,n,t),o.lanes|=n;break}s=s.next}}else if(i.tag===10)u=i.type===t.type?null:i.child;else if(i.tag===18){if(u=i.return,u===null)throw Error(k(341));u.lanes|=n,o=u.alternate,o!==null&&(o.lanes|=n),Ci(u,n,t),u=i.sibling}else u=i.child;if(u!==null)u.return=i;else for(u=i;u!==null;){if(u===t){u=null;break}if(i=u.sibling,i!==null){i.return=u.return,u=i;break}u=u.return}i=u}ue(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,qt(t,n),l=Ne(l),r=r(l),t.flags|=1,ue(e,t,r,n),t.child;case 14:return r=t.type,l=ze(r,t.pendingProps),l=ze(r.type,l),Io(e,t,r,l,n);case 15:return Aa(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),zr(e,t),t.tag=1,pe(r)?(e=!0,Hr(t)):e=!1,qt(t,n),Fa(t,r,l),Pi(t,r,l,n),Ti(null,t,r,!0,e,n);case 19:return Qa(e,t,n);case 22:return Ba(e,t,n)}throw Error(k(156,t.tag))};function oc(e,t){return Os(e,t)}function Od(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ee(e,t,n,r){return new Od(e,t,n,r)}function Ru(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Id(e){if(typeof e=="function")return Ru(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Ji)return 11;if(e===qi)return 14}return 2}function ct(e,t){var n=e.alternate;return n===null?(n=Ee(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Rr(e,t,n,r,l,i){var u=2;if(r=e,typeof e=="function")Ru(e)&&(u=1);else if(typeof e=="string")u=5;else e:switch(e){case Ft:return jt(n.children,l,i,t);case Xi:u=8,l|=8;break;case ql:return e=Ee(12,n,t,l|2),e.elementType=ql,e.lanes=i,e;case bl:return e=Ee(13,n,t,l),e.elementType=bl,e.lanes=i,e;case ei:return e=Ee(19,n,t,l),e.elementType=ei,e.lanes=i,e;case gs:return hl(n,l,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case ms:u=10;break e;case vs:u=9;break e;case Ji:u=11;break e;case qi:u=14;break e;case Je:u=16,r=null;break e}throw Error(k(130,e==null?e:typeof e,""))}return t=Ee(u,n,t,l),t.elementType=e,t.type=r,t.lanes=i,t}function jt(e,t,n,r){return e=Ee(7,e,r,t),e.lanes=n,e}function hl(e,t,n,r){return e=Ee(22,e,r,t),e.elementType=gs,e.lanes=n,e.stateNode={isHidden:!1},e}function Yl(e,t,n){return e=Ee(6,e,null,t),e.lanes=n,e}function Zl(e,t,n){return t=Ee(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Dd(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Pl(0),this.expirationTimes=Pl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Pl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Mu(e,t,n,r,l,i,u,o,s){return e=new Dd(e,t,n,o,s),t===1?(t=1,i===!0&&(t|=8)):t=0,i=Ee(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},vu(i),e}function Fd(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(fc)}catch(e){console.error(e)}}fc(),fs.exports=we;var Vd=fs.exports,Go=Vd;Xl.createRoot=Go.createRoot,Xl.hydrateRoot=Go.hydrateRoot;async function It(e){const t=await fetch(e);if(!t.ok)throw new Error(`${e} → ${t.status}`);return t.json()}const Nt={instances:()=>It("/api/instances"),instance:e=>It(`/api/instances/${encodeURIComponent(e)}`),forges:(e={})=>{const t=new URLSearchParams;e.role&&t.set("role",e.role),e.status&&t.set("status",e.status);const n=t.toString();return It("/api/forges"+(n?"?"+n:""))},forge:e=>It(`/api/forges/${encodeURIComponent(e)}`),log:(e,t,n=200)=>It(`/api/forges/${encodeURIComponent(e)}/log/${t}?tail=${n}`),ledger:(e={})=>{const t=new URLSearchParams;e.limit&&t.set("limit",String(e.limit)),e.shape&&t.set("shape",e.shape),e.outcome&&t.set("outcome",e.outcome),e.role&&t.set("role",e.role);const n=t.toString();return It("/api/ledger"+(n?"?"+n:""))}};function Fu(e){if(e==null)return"—";if(e<60)return`${e}m`;const t=Math.floor(e/60),n=e%60;return`${t}h${n?` ${n}m`:""}`}function Uu(e){return e.replace("__","/")}function Ct(e,t=[]){const[n,r]=A.useState(null),[l,i]=A.useState(null),[u,o]=A.useState(!0),[s,f]=A.useState(null),[v,m]=A.useState(0),h=A.useCallback(()=>m(y=>y+1),[]);return A.useEffect(()=>{let y=!1;return o(!0),e().then(x=>{y||(r(x),i(null),f(new Date))}).catch(x=>{y||i(x instanceof Error?x.message:String(x))}).finally(()=>{y||o(!1)}),()=>{y=!0}},[...t,v]),{data:n,error:l,loading:u,loadedAt:s,reload:h}}function wl(e){return e?`loaded ${e.toLocaleTimeString()}`:""}function Hd(){const{data:e,error:t,loading:n,loadedAt:r,reload:l}=Ct(()=>Nt.instances(),[]);return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:"Instances"}),e&&a.jsxs("span",{className:"count",children:["(",e.length," installed)"]}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(r)}),a.jsx("button",{onClick:l,disabled:n,children:"Refresh"})]}),t&&a.jsxs("div",{className:"error",children:["error: ",t]}),!t&&e&&e.length===0&&a.jsx("div",{className:"empty",children:"No instances installed. Run /lmstack:install to add one."}),a.jsx("div",{className:"cards",children:e==null?void 0:e.map(i=>a.jsxs("div",{className:"card",children:[a.jsx("h3",{children:i.role}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"engine"}),a.jsx("strong",{children:i.engine??"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"gpu"}),a.jsx("strong",{children:i.gpu??"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"models"}),a.jsx("strong",{children:i.models.length?i.models.join(", "):"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"probe"}),a.jsx("strong",{children:i.probeAt??"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"verdict"}),a.jsx("strong",{children:i.verdict??"—"})]}),a.jsxs("div",{className:"row",style:{marginTop:6},children:[a.jsx("span",{children:"forges"}),a.jsxs("strong",{children:[i.counts.running," running · ",i.counts.in_review," in-review · ",i.counts.queued," queued · ",i.counts.merged+i.counts.cleaned," done · ",i.counts.failed," failed"]})]}),a.jsx("div",{style:{marginTop:8},children:a.jsx("a",{href:"#/forges",children:"view forges →"})})]},i.role))})]})}const Xo={queued:"○ queued",running:"● running","in-review":"◐ in-review",merged:"✓ merged",failed:"✗ failed",cleaned:"· cleaned",stale:"! stale"};function dc({status:e}){const t=e in Xo?e:"queued";return a.jsx("span",{className:`badge ${t}`,children:Xo[t]??e})}const Wd=[{title:"Running",statuses:["running"]},{title:"In review",statuses:["in-review"]},{title:"Queued",statuses:["queued"]},{title:"Completed",statuses:["merged","cleaned"]},{title:"Failed",statuses:["failed"]},{title:"Stale",statuses:["stale"]}];function Qd(){var h;const[e,t]=A.useState(""),[n,r]=A.useState(""),{data:l,error:i,loading:u,loadedAt:o,reload:s}=Ct(()=>Nt.forges(),[]),f=Ct(()=>Nt.instances(),[]),v=A.useMemo(()=>l?l.filter(y=>!(e&&y.role!==e||n&&y.status!==n)):null,[l,e,n]),m=A.useMemo(()=>v?Wd.map(y=>({title:y.title,forges:v.filter(x=>y.statuses.includes(x.status))})):null,[v]);return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:"Forges"}),v&&a.jsxs("span",{className:"count",children:["(",v.length," shown)"]}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(o)}),a.jsx("button",{onClick:s,disabled:u,children:"Refresh"})]}),a.jsxs("div",{className:"filters",children:[a.jsx("label",{children:"host: "}),a.jsxs("select",{value:e,onChange:y=>t(y.target.value),children:[a.jsx("option",{value:"",children:"all"}),(h=f.data)==null?void 0:h.map(y=>a.jsx("option",{value:y.role,children:y.role},y.role))]}),a.jsx("label",{children:"status: "}),a.jsxs("select",{value:n,onChange:y=>r(y.target.value),children:[a.jsx("option",{value:"",children:"all"}),a.jsx("option",{value:"running",children:"running"}),a.jsx("option",{value:"in-review",children:"in-review"}),a.jsx("option",{value:"queued",children:"queued"}),a.jsx("option",{value:"merged",children:"merged"}),a.jsx("option",{value:"cleaned",children:"cleaned"}),a.jsx("option",{value:"failed",children:"failed"}),a.jsx("option",{value:"stale",children:"stale"})]})]}),i&&a.jsxs("div",{className:"error",children:["error: ",i]}),v&&v.length===0&&!i&&a.jsx("div",{className:"empty",children:"No forges match the current filters."}),m==null?void 0:m.map(y=>y.forges.length>0?a.jsx(Kd,{title:y.title,forges:y.forges},y.title):null)]})}function Kd({title:e,forges:t}){return a.jsxs("div",{style:{marginTop:16},children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:e}),a.jsxs("span",{className:"count",children:["(",t.length,")"]})]}),a.jsxs("table",{className:"table",children:[a.jsx("thead",{children:a.jsxs("tr",{children:[a.jsx("th",{children:"status"}),a.jsx("th",{children:"key"}),a.jsx("th",{children:"shape"}),a.jsx("th",{children:"tier"}),a.jsx("th",{children:"host"}),a.jsx("th",{children:"wall"}),a.jsx("th",{children:"judge"}),a.jsx("th",{children:"pr"})]})}),a.jsx("tbody",{children:t.map(n=>a.jsxs("tr",{onClick:()=>{window.location.hash=`#/forge/${encodeURIComponent(n.key)}`},children:[a.jsx("td",{children:a.jsx(dc,{status:n.status})}),a.jsx("td",{className:"key",children:Uu(n.key)}),a.jsx("td",{children:n.shape??"—"}),a.jsx("td",{children:n.tier??"—"}),a.jsx("td",{children:n.role}),a.jsx("td",{className:"mono",children:Fu(n.wallMin)}),a.jsx("td",{className:"mono",children:n.judgeRounds||"—"}),a.jsx("td",{className:"mono",children:n.pr??"—"})]},n.key))})]})]})}function Yd({forgeKey:e}){const t=Ct(()=>Nt.forge(e),[e]),n=Ct(()=>Nt.log(e,"exec",200),[e]),r=Ct(()=>Nt.log(e,"judge",200),[e]),l=()=>{t.reload(),n.reload(),r.reload()},i=t.loading||n.loading||r.loading;return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("a",{href:"#/forges",children:"← forges"}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(t.loadedAt)}),a.jsx("button",{onClick:l,disabled:i,children:"Refresh"})]}),t.error&&a.jsxs("div",{className:"error",children:["error: ",t.error]}),t.data&&a.jsx(Zd,{data:t.data,execLog:n.data,judgeLog:r.data})]})}function Zd({data:e,execLog:t,judgeLog:n}){const{task:r,run:l,ledger:i}=e,u=r.status??"queued",o=r.url,s=r.pr,f=r.tier,v=r.shape;return a.jsxs(a.Fragment,{children:[a.jsxs("div",{className:"detail-header",children:[a.jsx("span",{className:"title",children:Uu(e.task.key)}),a.jsx(dc,{status:u}),o&&a.jsx("a",{href:o,target:"_blank",rel:"noreferrer",children:"↗ issue"}),s&&a.jsx("a",{href:s,target:"_blank",rel:"noreferrer",children:"↗ pr"})]}),a.jsxs("div",{className:"detail-meta",children:[a.jsx("span",{className:"k",children:"host"}),a.jsx("span",{className:"v",children:e.role}),a.jsx("span",{className:"k",children:"shape"}),a.jsx("span",{className:"v",children:v??"—"}),a.jsx("span",{className:"k",children:"tier"}),a.jsx("span",{className:"v",children:f??"—"}),a.jsx("span",{className:"k",children:"title"}),a.jsx("span",{className:"v",style:{fontFamily:"inherit"},children:r.title??"—"}),a.jsx("span",{className:"k",children:"started"}),a.jsx("span",{className:"v",children:l.startedAt??"—"}),a.jsx("span",{className:"k",children:"ended"}),a.jsx("span",{className:"v",children:l.endedAt??"—"}),a.jsx("span",{className:"k",children:"tmux session"}),a.jsxs("span",{className:"v",children:["lmstack-",e.slug," ",l.tmuxAlive?"(alive ✓)":"(not running)"]}),a.jsx("span",{className:"k",children:"worktree"}),a.jsxs("span",{className:"v",children:[l.worktreePath??"—"," ",l.worktreePath?l.worktreeExists?"":"(missing)":""]}),a.jsx("span",{className:"k",children:"branch"}),a.jsx("span",{className:"v",children:l.branch??"—"}),i&&a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"k",children:"outcome"}),a.jsxs("span",{className:"v",children:[String(i.outcome??"—")," · wall ",Fu(i.wall_min)," · interventions ",String(i.interventions??0)]})]})]}),a.jsxs("div",{className:"panel",children:[a.jsx("h3",{children:"Brief"}),l.brief?a.jsx("pre",{children:l.brief}):a.jsx("div",{className:"empty",children:"no brief.md on disk"})]}),a.jsxs("div",{className:"panel",children:[a.jsxs("h3",{children:["Judge rounds (",l.judgeRounds.length,")"]}),l.judgeRounds.length===0&&a.jsx("div",{className:"empty",children:"(none yet)"}),l.judgeRounds.map(m=>a.jsxs("div",{style:{marginBottom:12},children:[a.jsxs("div",{style:{color:"var(--muted)",fontSize:12,marginBottom:4},children:["round ",m.n]}),a.jsx("pre",{children:m.text})]},m.n))]}),a.jsxs("div",{className:"logs",children:[a.jsx(Jo,{title:"lm-exec",log:t}),a.jsx(Jo,{title:"lm-judge",log:n})]})]})}function Jo({title:e,log:t}){return a.jsxs("div",{className:"log-pane",children:[a.jsxs("h4",{children:[e,t!=null&&t.truncated?" — tail":""]}),!t&&a.jsx("div",{className:"empty",children:"loading…"}),t&&!t.exists&&a.jsxs("div",{className:"empty",children:["no log file at ",t.path]}),t&&t.exists&&t.lines.length===0&&a.jsx("div",{className:"empty",children:"(empty)"}),t&&t.exists&&t.lines.length>0&&a.jsx("pre",{children:t.lines.join(` +`)})]})}function Gd(){const{data:e,error:t,loading:n,loadedAt:r,reload:l}=Ct(()=>Nt.ledger({limit:500}),[]),[i,u]=A.useState(""),[o,s]=A.useState(""),[f,v]=A.useState(""),m=A.useMemo(()=>Gl(e==null?void 0:e.map(g=>g.shape).filter(g=>!!g)),[e]),h=A.useMemo(()=>Gl(e==null?void 0:e.map(g=>g.outcome).filter(g=>!!g)),[e]),y=A.useMemo(()=>Gl(e==null?void 0:e.map(g=>g.host_role).filter(g=>!!g)),[e]),x=A.useMemo(()=>e?e.filter(g=>!(i&&g.shape!==i||o&&g.outcome!==o||f&&g.host_role!==f)):null,[e,i,o,f]);return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:"Ledger"}),x&&a.jsxs("span",{className:"count",children:["(",x.length," of ",(e==null?void 0:e.length)??0," runs)"]}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(r)}),a.jsx("button",{onClick:l,disabled:n,children:"Refresh"})]}),a.jsxs("div",{className:"filters",children:[a.jsx("label",{children:"shape: "}),a.jsxs("select",{value:i,onChange:g=>u(g.target.value),children:[a.jsx("option",{value:"",children:"all"}),m.map(g=>a.jsx("option",{value:g,children:g},g))]}),a.jsx("label",{children:"outcome: "}),a.jsxs("select",{value:o,onChange:g=>s(g.target.value),children:[a.jsx("option",{value:"",children:"all"}),h.map(g=>a.jsx("option",{value:g,children:g},g))]}),a.jsx("label",{children:"role: "}),a.jsxs("select",{value:f,onChange:g=>v(g.target.value),children:[a.jsx("option",{value:"",children:"all"}),y.map(g=>a.jsx("option",{value:g,children:g},g))]})]}),t&&a.jsxs("div",{className:"error",children:["error: ",t]}),x&&x.length===0&&!t&&a.jsx("div",{className:"empty",children:"No ledger entries."}),x&&x.length>0&&a.jsxs("table",{className:"table",children:[a.jsx("thead",{children:a.jsxs("tr",{children:[a.jsx("th",{children:"ended (UTC)"}),a.jsx("th",{children:"key"}),a.jsx("th",{children:"shape"}),a.jsx("th",{children:"tier"}),a.jsx("th",{children:"host"}),a.jsx("th",{children:"outcome"}),a.jsx("th",{children:"wall"}),a.jsx("th",{children:"judge"}),a.jsx("th",{children:"pr"}),a.jsx("th",{children:"int."})]})}),a.jsx("tbody",{children:x.map((g,O)=>a.jsxs("tr",{onClick:()=>{window.location.hash=`#/forge/${encodeURIComponent(g.key)}`},children:[a.jsx("td",{className:"mono",children:Xd(g.ended??g.ts)}),a.jsx("td",{className:"key",children:Uu(g.key)}),a.jsx("td",{children:g.shape??"—"}),a.jsx("td",{children:g.tier??"—"}),a.jsx("td",{children:g.host_role}),a.jsx("td",{children:g.outcome}),a.jsx("td",{className:"mono",children:Fu(g.wall_min)}),a.jsx("td",{className:"mono",children:g.judge_rounds||"—"}),a.jsx("td",{className:"mono",children:g.pr??"—"}),a.jsx("td",{className:"mono",children:g.interventions??0})]},`${g.key}-${g.ts}-${O}`))})]})]})}function Gl(e){return e?Array.from(new Set(e)).sort():[]}function Xd(e){return e?e.replace("T"," ").replace(/\..*Z?$/,"").replace(/Z$/,""):"—"}const Jd="https://github.com/ric03uec/lmstack",qd="https://ric03uec.github.io/lmstack/";function qo(){const e=window.location.hash.replace(/^#\/?/,"");return!e||e==="instances"?{name:"instances"}:e==="forges"?{name:"forges"}:e==="ledger"?{name:"ledger"}:e.startsWith("forge/")?{name:"forge",key:decodeURIComponent(e.slice(6))}:{name:"instances"}}function bd(){const[e,t]=A.useState(qo());A.useEffect(()=>{const r=()=>t(qo());return window.addEventListener("hashchange",r),()=>window.removeEventListener("hashchange",r)},[]);const n=r=>e.name===r||r==="forges"&&e.name==="forge";return a.jsxs("div",{className:"app",children:[a.jsxs("header",{className:"header",children:[a.jsxs("a",{className:"brand",href:"#/instances",children:[a.jsx("img",{src:"./lmstack.svg",alt:""}),a.jsx("span",{className:"name",children:"lmstack"}),a.jsx("span",{className:"tagline",children:"put your GPUs to work"})]}),a.jsx("div",{className:"spacer"}),a.jsxs("div",{className:"links",children:[a.jsxs("a",{href:qd,target:"_blank",rel:"noreferrer",title:"Documentation",children:[a.jsx(bo,{})," Docs"]}),a.jsxs("a",{href:Jd,target:"_blank",rel:"noreferrer",title:"Source on GitHub",children:[a.jsx(ep,{})," GitHub"]})]})]}),a.jsx("aside",{className:"sidebar",children:a.jsxs("nav",{children:[a.jsxs("a",{href:"#/instances",className:n("instances")?"active":"",children:[a.jsx("span",{className:"icon",children:a.jsx(tp,{})})," Instances"]}),a.jsxs("a",{href:"#/forges",className:n("forges")?"active":"",children:[a.jsx("span",{className:"icon",children:a.jsx(np,{})})," Forges"]}),a.jsxs("a",{href:"#/ledger",className:n("ledger")?"active":"",children:[a.jsx("span",{className:"icon",children:a.jsx(bo,{})})," Ledger"]})]})}),a.jsxs("main",{className:"main",children:[e.name==="instances"&&a.jsx(Hd,{}),e.name==="forges"&&a.jsx(Qd,{}),e.name==="forge"&&a.jsx(Yd,{forgeKey:e.key}),e.name==="ledger"&&a.jsx(Gd,{})]})]})}function ep(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M8 0C3.58 0 0 3.58 0 8a8 8 0 0 0 5.47 7.59c.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"})})}function bo(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574Zm1.504-5.076v5.076a3.75 3.75 0 0 1 1.994-.574H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.248l-.004 2.25Z"})})}function tp(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M2 2.75C2 1.784 2.784 1 3.75 1h8.5c.966 0 1.75.784 1.75 1.75v2.5A1.75 1.75 0 0 1 12.25 7h-8.5A1.75 1.75 0 0 1 2 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25Zm-1.75 8c0-.966.784-1.75 1.75-1.75h8.5c.966 0 1.75.784 1.75 1.75v2.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25Zm1.75-.25a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25ZM5 4a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-1 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"})})}function np(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M9.53.22a.75.75 0 0 1 1.06 0l4.19 4.19a.75.75 0 0 1 0 1.06L13.06 7l1.03 1.03a1.75 1.75 0 0 1 0 2.48l-1.55 1.54a1.75 1.75 0 0 1-2.47 0L8 9l-6.42 6.42a.75.75 0 1 1-1.06-1.06L6.94 8 3.85 4.9a.75.75 0 0 1 0-1.06L5.4 2.29a1.75 1.75 0 0 1 2.47 0L9 3.44 9.53.22Zm-3.72 3.13a.25.25 0 0 0-.35 0L4.47 4.35 8.5 8.38l1.35-1.35Z"})})}Xl.createRoot(document.getElementById("root")).render(a.jsx(Lc.StrictMode,{children:a.jsx(bd,{})})); diff --git a/ui/dist/assets/index-DKizVbia.css b/ui/dist/assets/index-DKizVbia.css new file mode 100644 index 0000000..4159d18 --- /dev/null +++ b/ui/dist/assets/index-DKizVbia.css @@ -0,0 +1 @@ +:root{--bg: #f6f8fa;--panel: #ffffff;--panel-hi: #f0f3f6;--border: #d0d7de;--border-strong: #afb8c1;--fg: #1f2328;--muted: #656d76;--accent: #0969da;--accent-soft: #ddf4ff;--ok: #1a7f37;--warn: #9a6700;--err: #cf222e;--run: #0969da;--review: #9a6700;--queued: #656d76;--sidebar-w: 220px;--header-h: 56px;--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--fg);font-family:var(--font-sans);font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}button{background:var(--panel);color:var(--fg);border:1px solid var(--border-strong);padding:6px 14px;border-radius:6px;cursor:pointer;font:inherit;font-size:14px}button:hover{border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}select,input[type=text]{background:var(--panel);color:var(--fg);border:1px solid var(--border-strong);padding:6px 10px;border-radius:6px;font:inherit;font-size:14px}code,pre{font-family:var(--font-mono)}.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;grid-template-rows:var(--header-h) 1fr;grid-template-areas:"header header" "sidebar main";min-height:100vh}.header{grid-area:header;background:var(--panel);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;padding:0 20px}.header .brand{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600;color:var(--fg)}.header .brand img{width:28px;height:28px;display:block}.header .brand .name{letter-spacing:-.01em}.header .brand .tagline{color:var(--muted);font-size:13.5px;font-weight:400;letter-spacing:0;padding-left:10px;margin-left:4px;border-left:1px solid var(--border)}.header .brand a{color:inherit}.header .spacer{flex:1}.header .links{display:flex;align-items:center;gap:16px}.header .links a{color:var(--muted);font-size:14px;display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px}.header .links a:hover{background:var(--panel-hi);color:var(--fg);text-decoration:none}.header .links svg{width:18px;height:18px}.sidebar{grid-area:sidebar;background:var(--panel);border-right:1px solid var(--border);padding:16px 8px}.sidebar nav{display:flex;flex-direction:column;gap:2px}.sidebar nav a{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:6px;color:var(--fg);font-size:15px;font-weight:500}.sidebar nav a:hover{background:var(--panel-hi);text-decoration:none}.sidebar nav a.active{background:var(--accent-soft);color:var(--accent)}.sidebar nav a .icon{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center}.sidebar nav a .icon svg{width:18px;height:18px}.main{grid-area:main;padding:24px 28px;max-width:1400px}.section-title{display:flex;align-items:center;gap:12px;margin:8px 0 14px;font-weight:600;font-size:20px}.section-title .count{color:var(--muted);font-weight:400;font-size:14px}.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:14px}.card{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:16px 18px;box-shadow:0 1px #1f23280a}.card h3{margin:0 0 8px;font-size:17px}.card .row{display:flex;justify-content:space-between;color:var(--muted);font-size:14px;padding:2px 0}.card .row strong{color:var(--fg);font-weight:500;text-align:right;margin-left:12px}.table{width:100%;border-collapse:collapse;font-size:14px;background:var(--panel);border:1px solid var(--border);border-radius:8px;overflow:hidden}.table th,.table td{padding:10px 12px;border-bottom:1px solid var(--border);text-align:left;vertical-align:middle}.table thead th{background:var(--panel-hi);color:var(--muted);font-weight:500;font-size:13px;text-transform:uppercase;letter-spacing:.4px}.table tbody tr{cursor:pointer}.table tbody tr:hover{background:var(--panel-hi)}.table tbody tr:last-child td{border-bottom:0}.table td.key{font-family:var(--font-mono);font-size:13.5px}.table td.mono{font-family:var(--font-mono);color:var(--muted);font-size:13.5px}.badge{display:inline-block;padding:2px 10px;border-radius:12px;font-size:12.5px;font-weight:500;background:var(--panel-hi);border:1px solid var(--border);color:var(--muted);white-space:nowrap}.badge.running{color:var(--run);border-color:var(--run);background:var(--accent-soft)}.badge.in-review{color:var(--review);border-color:var(--review);background:#fff8c5}.badge.queued{color:var(--queued)}.badge.merged,.badge.completed{color:var(--ok);border-color:var(--ok);background:#dcffe4}.badge.failed{color:var(--err);border-color:var(--err);background:#ffebe9}.badge.cleaned{color:var(--muted)}.badge.stale{color:var(--warn);border-color:var(--warn);background:#fff8c5}.filters{display:flex;gap:14px;align-items:center;margin-bottom:14px;flex-wrap:wrap}.filters label{color:var(--muted);font-size:14px}.detail-header{display:flex;align-items:center;gap:14px;margin:4px 0 14px;flex-wrap:wrap}.detail-header .title{font-size:22px;font-weight:600;font-family:var(--font-mono)}.detail-meta{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px 18px;margin-bottom:14px;font-size:14px;display:grid;grid-template-columns:max-content 1fr;gap:6px 16px}.detail-meta .k{color:var(--muted)}.detail-meta .v{font-family:var(--font-mono);font-size:13.5px;word-break:break-all}.panel{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px 18px;margin-bottom:14px}.panel h3{margin:0 0 10px;font-size:13px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.panel pre{margin:0;white-space:pre-wrap;word-break:break-word;font-size:13.5px;color:var(--fg)}.logs{display:grid;grid-template-columns:1fr 1fr;gap:14px}.log-pane{background:#fff;border:1px solid var(--border);border-radius:8px;height:460px;overflow:auto;padding:10px 14px}.log-pane h4{margin:0 0 8px;font-size:12px;color:var(--muted);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.5px}.log-pane pre{margin:0;font-size:13px;color:var(--fg);white-space:pre}.empty{color:var(--muted);font-style:italic;padding:8px 0;font-size:14px}.error{color:var(--err);padding:10px 14px;border:1px solid var(--err);border-radius:6px;background:#ffebe9;margin:12px 0}.refresh-info{color:var(--muted);font-size:13px;margin-right:10px}@media (max-width: 720px){.app{grid-template-columns:1fr;grid-template-areas:"header" "main"}.sidebar{display:none}.main{padding:16px}.logs{grid-template-columns:1fr}} diff --git a/ui/dist/index.html b/ui/dist/index.html new file mode 100644 index 0000000..058a319 --- /dev/null +++ b/ui/dist/index.html @@ -0,0 +1,14 @@ + + + + + + + lmstack — put your GPUs to work + + + + +
+ + diff --git a/ui/dist/lmstack.svg b/ui/dist/lmstack.svg new file mode 100644 index 0000000..eef803a --- /dev/null +++ b/ui/dist/lmstack.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 0000000..978c3bf --- /dev/null +++ b/ui/index.html @@ -0,0 +1,13 @@ + + + + + + + lmstack — put your GPUs to work + + +
+ + + diff --git a/ui/package-lock.json b/ui/package-lock.json new file mode 100644 index 0000000..40a402b --- /dev/null +++ b/ui/package-lock.json @@ -0,0 +1,1792 @@ +{ + "name": "lmstack-ui", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lmstack-ui", + "version": "0.1.0", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "typescript": "^5.6.3", + "vite": "^5.4.11" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", + "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", + "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", + "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", + "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", + "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", + "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", + "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", + "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", + "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", + "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", + "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", + "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", + "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", + "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", + "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", + "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", + "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", + "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", + "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", + "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", + "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", + "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", + "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", + "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", + "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz", + "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.400", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.400.tgz", + "integrity": "sha512-96EWDNjM59SYflgeV5Ylsf4EMiq1a25YjCnJH7cxn/AF2H3pILRweaUnoLax0yKHWdpOzY6JKEu45e8irqZIHA==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.17", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz", + "integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", + "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.4", + "@rollup/rollup-android-arm64": "4.62.4", + "@rollup/rollup-darwin-arm64": "4.62.4", + "@rollup/rollup-darwin-x64": "4.62.4", + "@rollup/rollup-freebsd-arm64": "4.62.4", + "@rollup/rollup-freebsd-x64": "4.62.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", + "@rollup/rollup-linux-arm-musleabihf": "4.62.4", + "@rollup/rollup-linux-arm64-gnu": "4.62.4", + "@rollup/rollup-linux-arm64-musl": "4.62.4", + "@rollup/rollup-linux-loong64-gnu": "4.62.4", + "@rollup/rollup-linux-loong64-musl": "4.62.4", + "@rollup/rollup-linux-ppc64-gnu": "4.62.4", + "@rollup/rollup-linux-ppc64-musl": "4.62.4", + "@rollup/rollup-linux-riscv64-gnu": "4.62.4", + "@rollup/rollup-linux-riscv64-musl": "4.62.4", + "@rollup/rollup-linux-s390x-gnu": "4.62.4", + "@rollup/rollup-linux-x64-gnu": "4.62.4", + "@rollup/rollup-linux-x64-musl": "4.62.4", + "@rollup/rollup-openbsd-x64": "4.62.4", + "@rollup/rollup-openharmony-arm64": "4.62.4", + "@rollup/rollup-win32-arm64-msvc": "4.62.4", + "@rollup/rollup-win32-ia32-msvc": "4.62.4", + "@rollup/rollup-win32-x64-gnu": "4.62.4", + "@rollup/rollup-win32-x64-msvc": "4.62.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 0000000..e9af552 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,22 @@ +{ + "name": "lmstack-ui", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "typescript": "^5.6.3", + "vite": "^5.4.11" + } +} diff --git a/ui/public/lmstack.svg b/ui/public/lmstack.svg new file mode 100644 index 0000000..eef803a --- /dev/null +++ b/ui/public/lmstack.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/ui/src/App.tsx b/ui/src/App.tsx new file mode 100644 index 0000000..c0ec5c0 --- /dev/null +++ b/ui/src/App.tsx @@ -0,0 +1,112 @@ +import { useEffect, useState } from 'react'; +import { Instances } from './routes/Instances'; +import { Forges } from './routes/Forges'; +import { ForgeDetail } from './routes/ForgeDetail'; +import { Ledger } from './routes/Ledger'; + +type Route = + | { name: 'instances' } + | { name: 'forges' } + | { name: 'forge'; key: string } + | { name: 'ledger' }; + +const REPO_URL = 'https://github.com/ric03uec/lmstack'; +const DOCS_URL = 'https://ric03uec.github.io/lmstack/'; + +function parseHash(): Route { + const h = window.location.hash.replace(/^#\/?/, ''); + if (!h || h === 'instances') return { name: 'instances' }; + if (h === 'forges') return { name: 'forges' }; + if (h === 'ledger') return { name: 'ledger' }; + if (h.startsWith('forge/')) return { name: 'forge', key: decodeURIComponent(h.slice('forge/'.length)) }; + return { name: 'instances' }; +} + +export function App() { + const [route, setRoute] = useState(parseHash()); + + useEffect(() => { + const on = () => setRoute(parseHash()); + window.addEventListener('hashchange', on); + return () => window.removeEventListener('hashchange', on); + }, []); + + const isActive = (name: string) => + route.name === name || (name === 'forges' && route.name === 'forge'); + + return ( +
+
+ + + lmstack + put your GPUs to work + +
+ + + +
+ {route.name === 'instances' && } + {route.name === 'forges' && } + {route.name === 'forge' && } + {route.name === 'ledger' && } +
+
+ ); +} + +// ── icons (inline SVG, currentColor) ───────────────────────────────────── + +function GithubIcon() { + return ( + + ); +} + +function BookIcon() { + return ( + + ); +} + +function ServerIcon() { + return ( + + ); +} + +function HammerIcon() { + return ( + + ); +} diff --git a/ui/src/api.ts b/ui/src/api.ts new file mode 100644 index 0000000..3cdc745 --- /dev/null +++ b/ui/src/api.ts @@ -0,0 +1,119 @@ +export type ForgeStatus = + | 'queued' + | 'running' + | 'in-review' + | 'merged' + | 'failed' + | 'cleaned' + | 'stale'; + +export interface Instance { + role: string; + host?: string; + engine?: string; + gpu?: string; + models: string[]; + probeAt?: string; + verdict?: string; + counts: { running: number; in_review: number; queued: number; merged: number; failed: number; cleaned: number; stale: number }; +} + +export interface ForgeSummary { + key: string; + role: string; + status: ForgeStatus; + tier?: string; + shape?: string; + pr?: string; + wallMin?: number | null; + startedAt?: string | null; + judgeRounds: number; + title?: string; + url?: string; +} + +export interface JudgeRound { n: number; text: string; } + +export interface ForgeDetail { + task: Record & { key: string; status?: string; url?: string; title?: string }; + run: { + exists: boolean; + brief: string | null; + judgeRounds: JudgeRound[]; + startedAt: string | null; + endedAt: string | null; + tmuxAlive: boolean; + worktreePath: string | null; + worktreeExists: boolean; + branch: string | null; + }; + ledger: Record | null; + role: string; + slug: string; +} + +export interface LogTail { + lines: string[]; + sizeBytes: number; + truncated: boolean; + exists: boolean; + path: string; +} + +export interface LedgerRecord { + key: string; + host_role: string; + tier: string | null; + shape: string | null; + judge_rounds: number; + outcome: string; + pr: string | null; + started: string | null; + ended: string | null; + wall_min: number | null; + interventions: number; + ts: string; +} + +async function j(path: string): Promise { + const r = await fetch(path); + if (!r.ok) throw new Error(`${path} → ${r.status}`); + return r.json(); +} + +export const api = { + instances: () => j('/api/instances'), + instance: (role: string) => j>(`/api/instances/${encodeURIComponent(role)}`), + forges: (params: { role?: string; status?: string } = {}) => { + const qs = new URLSearchParams(); + if (params.role) qs.set('role', params.role); + if (params.status) qs.set('status', params.status); + const q = qs.toString(); + return j('/api/forges' + (q ? '?' + q : '')); + }, + forge: (key: string) => j(`/api/forges/${encodeURIComponent(key)}`), + log: (key: string, which: 'exec' | 'judge', tail = 200) => + j(`/api/forges/${encodeURIComponent(key)}/log/${which}?tail=${tail}`), + ledger: (params: { limit?: number; shape?: string; outcome?: string; role?: string } = {}) => { + const qs = new URLSearchParams(); + if (params.limit) qs.set('limit', String(params.limit)); + if (params.shape) qs.set('shape', params.shape); + if (params.outcome) qs.set('outcome', params.outcome); + if (params.role) qs.set('role', params.role); + const q = qs.toString(); + return j('/api/ledger' + (q ? '?' + q : '')); + }, +}; + +export function fmtWall(min: number | null | undefined): string { + if (min == null) return '—'; + if (min < 60) return `${min}m`; + const h = Math.floor(min / 60); + const m = min % 60; + return `${h}h${m ? ` ${m}m` : ''}`; +} + +export function shortKey(key: string): string { + // owner__repo#num → owner/repo#num + return key.replace('__', '/'); +} diff --git a/ui/src/components/StatusBadge.tsx b/ui/src/components/StatusBadge.tsx new file mode 100644 index 0000000..3db39e1 --- /dev/null +++ b/ui/src/components/StatusBadge.tsx @@ -0,0 +1,16 @@ +import type { ForgeStatus } from '../api'; + +const LABEL: Record = { + queued: '○ queued', + running: '● running', + 'in-review': '◐ in-review', + merged: '✓ merged', + failed: '✗ failed', + cleaned: '· cleaned', + stale: '! stale', +}; + +export function StatusBadge({ status }: { status: ForgeStatus | string }) { + const key = (status as ForgeStatus) in LABEL ? (status as ForgeStatus) : ('queued' as ForgeStatus); + return {LABEL[key] ?? status}; +} diff --git a/ui/src/hooks.ts b/ui/src/hooks.ts new file mode 100644 index 0000000..3aa0fe8 --- /dev/null +++ b/ui/src/hooks.ts @@ -0,0 +1,49 @@ +import { useCallback, useEffect, useState } from 'react'; + +export interface Loadable { + data: T | null; + error: string | null; + loading: boolean; + loadedAt: Date | null; + reload: () => void; +} + +export function useAsync(fn: () => Promise, deps: unknown[] = []): Loadable { + const [data, setData] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); + const [loadedAt, setLoadedAt] = useState(null); + const [tick, setTick] = useState(0); + + const reload = useCallback(() => setTick((t) => t + 1), []); + + useEffect(() => { + let cancelled = false; + setLoading(true); + fn() + .then((v) => { + if (cancelled) return; + setData(v); + setError(null); + setLoadedAt(new Date()); + }) + .catch((e: unknown) => { + if (cancelled) return; + setError(e instanceof Error ? e.message : String(e)); + }) + .finally(() => { + if (!cancelled) setLoading(false); + }); + return () => { + cancelled = true; + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [...deps, tick]); + + return { data, error, loading, loadedAt, reload }; +} + +export function fmtLoaded(loadedAt: Date | null): string { + if (!loadedAt) return ''; + return `loaded ${loadedAt.toLocaleTimeString()}`; +} diff --git a/ui/src/main.tsx b/ui/src/main.tsx new file mode 100644 index 0000000..ed0dc63 --- /dev/null +++ b/ui/src/main.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import { App } from './App'; +import './styles.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/ui/src/routes/ForgeDetail.tsx b/ui/src/routes/ForgeDetail.tsx new file mode 100644 index 0000000..83628d7 --- /dev/null +++ b/ui/src/routes/ForgeDetail.tsx @@ -0,0 +1,105 @@ +import { api, fmtWall, shortKey } from '../api'; +import { fmtLoaded, useAsync } from '../hooks'; +import { StatusBadge } from '../components/StatusBadge'; + +export function ForgeDetail({ forgeKey }: { forgeKey: string }) { + const detail = useAsync(() => api.forge(forgeKey), [forgeKey]); + const execLog = useAsync(() => api.log(forgeKey, 'exec', 200), [forgeKey]); + const judgeLog = useAsync(() => api.log(forgeKey, 'judge', 200), [forgeKey]); + + const refreshAll = () => { + detail.reload(); + execLog.reload(); + judgeLog.reload(); + }; + + const loading = detail.loading || execLog.loading || judgeLog.loading; + + return ( +
+
+ ← forges +
+ {fmtLoaded(detail.loadedAt)} + +
+ + {detail.error &&
error: {detail.error}
} + {detail.data && } +
+ ); +} + +function Detail({ data, execLog, judgeLog }: { + data: import('../api').ForgeDetail; + execLog: import('../api').LogTail | null; + judgeLog: import('../api').LogTail | null; +}) { + const { task, run, ledger } = data; + const status = (task.status as string) ?? 'queued'; + const url = task.url as string | undefined; + const pr = (task as { pr?: string }).pr; + const tier = (task as { tier?: string }).tier; + const shape = (task as { shape?: string }).shape; + + return ( + <> +
+ {shortKey(data.task.key)} + + {url && ↗ issue} + {pr && ↗ pr} +
+ +
+ host{data.role} + shape{shape ?? '—'} + tier{tier ?? '—'} + title{(task.title as string) ?? '—'} + started{run.startedAt ?? '—'} + ended{run.endedAt ?? '—'} + tmux sessionlmstack-{data.slug} {run.tmuxAlive ? '(alive ✓)' : '(not running)'} + worktree{run.worktreePath ?? '—'} {run.worktreePath ? (run.worktreeExists ? '' : '(missing)') : ''} + branch{run.branch ?? '—'} + {ledger && ( + <> + outcome{String(ledger.outcome ?? '—')} · wall {fmtWall(ledger.wall_min as number | null)} · interventions {String(ledger.interventions ?? 0)} + + )} +
+ +
+

Brief

+ {run.brief ?
{run.brief}
:
no brief.md on disk
} +
+ +
+

Judge rounds ({run.judgeRounds.length})

+ {run.judgeRounds.length === 0 &&
(none yet)
} + {run.judgeRounds.map((r) => ( +
+
round {r.n}
+
{r.text}
+
+ ))} +
+ +
+ + +
+ + ); +} + +function LogPane({ title, log }: { title: string; log: import('../api').LogTail | null }) { + return ( +
+

{title}{log?.truncated ? ' — tail' : ''}

+ {!log &&
loading…
} + {log && !log.exists &&
no log file at {log.path}
} + {log && log.exists && log.lines.length === 0 &&
(empty)
} + {log && log.exists && log.lines.length > 0 &&
{log.lines.join('\n')}
} +
+ ); +} diff --git a/ui/src/routes/Forges.tsx b/ui/src/routes/Forges.tsx new file mode 100644 index 0000000..f003088 --- /dev/null +++ b/ui/src/routes/Forges.tsx @@ -0,0 +1,118 @@ +import { useMemo, useState } from 'react'; +import { api, fmtWall, shortKey, type ForgeStatus, type ForgeSummary } from '../api'; +import { fmtLoaded, useAsync } from '../hooks'; +import { StatusBadge } from '../components/StatusBadge'; + +const GROUPS: { title: string; statuses: ForgeStatus[] }[] = [ + { title: 'Running', statuses: ['running'] }, + { title: 'In review', statuses: ['in-review'] }, + { title: 'Queued', statuses: ['queued'] }, + { title: 'Completed', statuses: ['merged', 'cleaned'] }, + { title: 'Failed', statuses: ['failed'] }, + { title: 'Stale', statuses: ['stale'] }, +]; + +export function Forges() { + const [role, setRole] = useState(''); + const [statusFilter, setStatusFilter] = useState(''); + const { data, error, loading, loadedAt, reload } = useAsync(() => api.forges(), []); + const instancesReq = useAsync(() => api.instances(), []); + + const filtered = useMemo(() => { + if (!data) return null; + return data.filter((f) => { + if (role && f.role !== role) return false; + if (statusFilter && f.status !== statusFilter) return false; + return true; + }); + }, [data, role, statusFilter]); + + const grouped = useMemo(() => { + if (!filtered) return null; + return GROUPS.map((g) => ({ + title: g.title, + forges: filtered.filter((f) => g.statuses.includes(f.status as ForgeStatus)), + })); + }, [filtered]); + + return ( +
+
+ Forges + {filtered && ({filtered.length} shown)} +
+ {fmtLoaded(loadedAt)} + +
+ +
+ + + + +
+ + {error &&
error: {error}
} + {filtered && filtered.length === 0 && !error && ( +
No forges match the current filters.
+ )} + + {grouped?.map((g) => (g.forges.length > 0 ? ( + + ) : null))} +
+ ); +} + +function ForgeGroup({ title, forges }: { title: string; forges: ForgeSummary[] }) { + return ( +
+
+ {title} + ({forges.length}) +
+ + + + + + + + + + + + + + + {forges.map((f) => ( + { window.location.hash = `#/forge/${encodeURIComponent(f.key)}`; }}> + + + + + + + + + + ))} + +
statuskeyshapetierhostwalljudgepr
{shortKey(f.key)}{f.shape ?? '—'}{f.tier ?? '—'}{f.role}{fmtWall(f.wallMin)}{f.judgeRounds || '—'}{f.pr ?? '—'}
+
+ ); +} diff --git a/ui/src/routes/Instances.tsx b/ui/src/routes/Instances.tsx new file mode 100644 index 0000000..7a0d586 --- /dev/null +++ b/ui/src/routes/Instances.tsx @@ -0,0 +1,44 @@ +import { api } from '../api'; +import { fmtLoaded, useAsync } from '../hooks'; + +export function Instances() { + const { data, error, loading, loadedAt, reload } = useAsync(() => api.instances(), []); + + return ( +
+
+ Instances + {data && ({data.length} installed)} +
+ {fmtLoaded(loadedAt)} + +
+ + {error &&
error: {error}
} + {!error && data && data.length === 0 && ( +
No instances installed. Run /lmstack:install to add one.
+ )} +
+ {data?.map((inst) => ( +
+

{inst.role}

+
engine{inst.engine ?? '—'}
+
gpu{inst.gpu ?? '—'}
+
models{inst.models.length ? inst.models.join(', ') : '—'}
+
probe{inst.probeAt ?? '—'}
+
verdict{inst.verdict ?? '—'}
+
+ forges + + {inst.counts.running} running · {inst.counts.in_review} in-review · {inst.counts.queued} queued · {inst.counts.merged + inst.counts.cleaned} done · {inst.counts.failed} failed + +
+ +
+ ))} +
+
+ ); +} diff --git a/ui/src/routes/Ledger.tsx b/ui/src/routes/Ledger.tsx new file mode 100644 index 0000000..c782152 --- /dev/null +++ b/ui/src/routes/Ledger.tsx @@ -0,0 +1,101 @@ +import { useMemo, useState } from 'react'; +import { api, fmtWall, shortKey } from '../api'; +import { fmtLoaded, useAsync } from '../hooks'; + +export function Ledger() { + const { data, error, loading, loadedAt, reload } = useAsync(() => api.ledger({ limit: 500 }), []); + const [shape, setShape] = useState(''); + const [outcome, setOutcome] = useState(''); + const [role, setRole] = useState(''); + + const shapes = useMemo(() => uniq(data?.map((r) => r.shape).filter((v): v is string => !!v)), [data]); + const outcomes = useMemo(() => uniq(data?.map((r) => r.outcome).filter((v): v is string => !!v)), [data]); + const roles = useMemo(() => uniq(data?.map((r) => r.host_role).filter((v): v is string => !!v)), [data]); + + const filtered = useMemo(() => { + if (!data) return null; + return data.filter((r) => { + if (shape && r.shape !== shape) return false; + if (outcome && r.outcome !== outcome) return false; + if (role && r.host_role !== role) return false; + return true; + }); + }, [data, shape, outcome, role]); + + return ( +
+
+ Ledger + {filtered && ({filtered.length} of {data?.length ?? 0} runs)} +
+ {fmtLoaded(loadedAt)} + +
+ +
+ + + + + + +
+ + {error &&
error: {error}
} + {filtered && filtered.length === 0 && !error &&
No ledger entries.
} + {filtered && filtered.length > 0 && ( + + + + + + + + + + + + + + + + + {filtered.map((r, i) => ( + { window.location.hash = `#/forge/${encodeURIComponent(r.key)}`; }}> + + + + + + + + + + + + ))} + +
ended (UTC)keyshapetierhostoutcomewalljudgeprint.
{fmtEnded(r.ended ?? r.ts)}{shortKey(r.key)}{r.shape ?? '—'}{r.tier ?? '—'}{r.host_role}{r.outcome}{fmtWall(r.wall_min)}{r.judge_rounds || '—'}{r.pr ?? '—'}{r.interventions ?? 0}
+ )} +
+ ); +} + +function uniq(arr: string[] | undefined): string[] { + if (!arr) return []; + return Array.from(new Set(arr)).sort(); +} + +function fmtEnded(s: string | null | undefined): string { + if (!s) return '—'; + return s.replace('T', ' ').replace(/\..*Z?$/, '').replace(/Z$/, ''); +} diff --git a/ui/src/styles.css b/ui/src/styles.css new file mode 100644 index 0000000..c9237da --- /dev/null +++ b/ui/src/styles.css @@ -0,0 +1,320 @@ +:root { + --bg: #f6f8fa; + --panel: #ffffff; + --panel-hi: #f0f3f6; + --border: #d0d7de; + --border-strong: #afb8c1; + --fg: #1f2328; + --muted: #656d76; + --accent: #0969da; + --accent-soft: #ddf4ff; + --ok: #1a7f37; + --warn: #9a6700; + --err: #cf222e; + --run: #0969da; + --review: #9a6700; + --queued: #656d76; + --sidebar-w: 220px; + --header-h: 56px; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; +} + +* { box-sizing: border-box; } +html, body, #root { height: 100%; margin: 0; } +body { + background: var(--bg); + color: var(--fg); + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.55; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +a { color: var(--accent); text-decoration: none; } +a:hover { text-decoration: underline; } +button { + background: var(--panel); + color: var(--fg); + border: 1px solid var(--border-strong); + padding: 6px 14px; + border-radius: 6px; + cursor: pointer; + font: inherit; + font-size: 14px; +} +button:hover { border-color: var(--accent); color: var(--accent); } +button:disabled { opacity: 0.5; cursor: default; } +select, input[type="text"] { + background: var(--panel); + color: var(--fg); + border: 1px solid var(--border-strong); + padding: 6px 10px; + border-radius: 6px; + font: inherit; + font-size: 14px; +} +code, pre { font-family: var(--font-mono); } + +/* ─── layout ─────────────────────────────────────────────────────────── */ + +.app { + display: grid; + grid-template-columns: var(--sidebar-w) 1fr; + grid-template-rows: var(--header-h) 1fr; + grid-template-areas: + "header header" + "sidebar main"; + min-height: 100vh; +} + +.header { + grid-area: header; + background: var(--panel); + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + gap: 12px; + padding: 0 20px; +} +.header .brand { + display: flex; align-items: center; gap: 10px; + font-size: 18px; font-weight: 600; + color: var(--fg); +} +.header .brand img { width: 28px; height: 28px; display: block; } +.header .brand .name { letter-spacing: -0.01em; } +.header .brand .tagline { + color: var(--muted); + font-size: 13.5px; + font-weight: 400; + letter-spacing: 0; + padding-left: 10px; + margin-left: 4px; + border-left: 1px solid var(--border); +} +.header .brand a { color: inherit; } +.header .spacer { flex: 1; } +.header .links { display: flex; align-items: center; gap: 16px; } +.header .links a { + color: var(--muted); + font-size: 14px; + display: inline-flex; align-items: center; gap: 6px; + padding: 6px 10px; + border-radius: 6px; +} +.header .links a:hover { background: var(--panel-hi); color: var(--fg); text-decoration: none; } +.header .links svg { width: 18px; height: 18px; } + +.sidebar { + grid-area: sidebar; + background: var(--panel); + border-right: 1px solid var(--border); + padding: 16px 8px; +} +.sidebar nav { display: flex; flex-direction: column; gap: 2px; } +.sidebar nav a { + display: flex; align-items: center; gap: 10px; + padding: 8px 14px; + border-radius: 6px; + color: var(--fg); + font-size: 15px; + font-weight: 500; +} +.sidebar nav a:hover { background: var(--panel-hi); text-decoration: none; } +.sidebar nav a.active { + background: var(--accent-soft); + color: var(--accent); +} +.sidebar nav a .icon { width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; } +.sidebar nav a .icon svg { width: 18px; height: 18px; } + +.main { + grid-area: main; + padding: 24px 28px; + max-width: 1400px; +} + +/* ─── content ────────────────────────────────────────────────────────── */ + +.section-title { + display: flex; + align-items: center; + gap: 12px; + margin: 8px 0 14px; + font-weight: 600; + font-size: 20px; +} +.section-title .count { + color: var(--muted); + font-weight: normal; + font-size: 14px; +} + +.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 14px; } +.card { + background: var(--panel); + border: 1px solid var(--border); + border-radius: 8px; + padding: 16px 18px; + box-shadow: 0 1px 0 rgba(31,35,40,0.04); +} +.card h3 { margin: 0 0 8px; font-size: 17px; } +.card .row { + display: flex; + justify-content: space-between; + color: var(--muted); + font-size: 14px; + padding: 2px 0; +} +.card .row strong { color: var(--fg); font-weight: 500; text-align: right; margin-left: 12px; } + +.table { + width: 100%; + border-collapse: collapse; + font-size: 14px; + background: var(--panel); + border: 1px solid var(--border); + border-radius: 8px; + overflow: hidden; +} +.table th, .table td { + padding: 10px 12px; + border-bottom: 1px solid var(--border); + text-align: left; + vertical-align: middle; +} +.table thead th { + background: var(--panel-hi); + color: var(--muted); + font-weight: 500; + font-size: 13px; + text-transform: uppercase; + letter-spacing: 0.4px; +} +.table tbody tr { cursor: pointer; } +.table tbody tr:hover { background: var(--panel-hi); } +.table tbody tr:last-child td { border-bottom: 0; } +.table td.key { font-family: var(--font-mono); font-size: 13.5px; } +.table td.mono { font-family: var(--font-mono); color: var(--muted); font-size: 13.5px; } + +.badge { + display: inline-block; + padding: 2px 10px; + border-radius: 12px; + font-size: 12.5px; + font-weight: 500; + background: var(--panel-hi); + border: 1px solid var(--border); + color: var(--muted); + white-space: nowrap; +} +.badge.running { color: var(--run); border-color: var(--run); background: var(--accent-soft); } +.badge.in-review { color: var(--review); border-color: var(--review); background: #fff8c5; } +.badge.queued { color: var(--queued); } +.badge.merged, .badge.completed { color: var(--ok); border-color: var(--ok); background: #dcffe4; } +.badge.failed { color: var(--err); border-color: var(--err); background: #ffebe9; } +.badge.cleaned { color: var(--muted); } +.badge.stale { color: var(--warn); border-color: var(--warn); background: #fff8c5; } + +.filters { + display: flex; + gap: 14px; + align-items: center; + margin-bottom: 14px; + flex-wrap: wrap; +} +.filters label { color: var(--muted); font-size: 14px; } + +.detail-header { + display: flex; + align-items: center; + gap: 14px; + margin: 4px 0 14px; + flex-wrap: wrap; +} +.detail-header .title { font-size: 22px; font-weight: 600; font-family: var(--font-mono); } + +.detail-meta { + background: var(--panel); + border: 1px solid var(--border); + border-radius: 8px; + padding: 14px 18px; + margin-bottom: 14px; + font-size: 14px; + display: grid; + grid-template-columns: max-content 1fr; + gap: 6px 16px; +} +.detail-meta .k { color: var(--muted); } +.detail-meta .v { font-family: var(--font-mono); font-size: 13.5px; word-break: break-all; } + +.panel { + background: var(--panel); + border: 1px solid var(--border); + border-radius: 8px; + padding: 14px 18px; + margin-bottom: 14px; +} +.panel h3 { + margin: 0 0 10px; + font-size: 13px; + color: var(--muted); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} +.panel pre { + margin: 0; + white-space: pre-wrap; + word-break: break-word; + font-size: 13.5px; + color: var(--fg); +} + +.logs { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; } +.log-pane { + background: #ffffff; + border: 1px solid var(--border); + border-radius: 8px; + height: 460px; + overflow: auto; + padding: 10px 14px; +} +.log-pane h4 { + margin: 0 0 8px; + font-size: 12px; + color: var(--muted); + font-family: var(--font-mono); + text-transform: uppercase; + letter-spacing: 0.5px; +} +.log-pane pre { + margin: 0; + font-size: 13px; + color: var(--fg); + white-space: pre; +} + +.empty { + color: var(--muted); + font-style: italic; + padding: 8px 0; + font-size: 14px; +} +.error { + color: var(--err); + padding: 10px 14px; + border: 1px solid var(--err); + border-radius: 6px; + background: #ffebe9; + margin: 12px 0; +} +.refresh-info { color: var(--muted); font-size: 13px; margin-right: 10px; } + +@media (max-width: 720px) { + .app { grid-template-columns: 1fr; grid-template-areas: "header" "main"; } + .sidebar { display: none; } + .main { padding: 16px; } + .logs { grid-template-columns: 1fr; } +} diff --git a/ui/tsconfig.json b/ui/tsconfig.json new file mode 100644 index 0000000..c95ee7f --- /dev/null +++ b/ui/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/ui/vite.config.ts b/ui/vite.config.ts new file mode 100644 index 0000000..a5d317e --- /dev/null +++ b/ui/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + base: './', + build: { + outDir: 'dist', + emptyOutDir: true, + sourcemap: false, + }, + server: { + port: 5173, + proxy: { + '/api': 'http://127.0.0.1:7878', + }, + }, +}); From 0ee6aa014f48f91410be8864bf6efc6d9c188c47 Mon Sep 17 00:00:00 2001 From: devashish Date: Mon, 3 Aug 2026 22:08:25 -0700 Subject: [PATCH 2/4] feat(ui): full-width instance card with vendor badge and rich details MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The Instances page now renders one full-width card per role with sections for Hardware, Inference engine, Operating system, and Forge activity, plus a Models table (slug / hf model / context / max seqs / VRAM est / port / tier / active) and blocks for the classifier's memory arithmetic and warnings. - Vendor badge (stylised NVIDIA green N, AMD red A, or generic GPU tile) driven by probe.gpu.vendor, falling back to a role-name heuristic so h1-nvidia / h2-amd cards still show the right badge before probe runs. - Explicit empty-state hint on each card when host.yml / probe.json / classify.json are missing on disk, pointing the user at `/lmstack:analyze `. - Backend `/api/instances` now merges host.yml + probe.json + classify.json into one shape per role, surfaces which source files are present, and enriches the models list with per-model params from classify. Also updates the `analyze` skill so it writes classify.json and a minimal host.yml stub alongside probe.json — the three files a rich card needs. The install skill still overwrites host.yml with the final version. --- bin/lmstack-ui | 121 +++++++++++++-- skills/analyze/SKILL.md | 29 +++- ui/dist/assets/index-B6h_u_OQ.js | 41 ----- ui/dist/assets/index-BqvLn6SF.js | 42 ++++++ ui/dist/assets/index-C39-GzIs.css | 1 + ui/dist/assets/index-DKizVbia.css | 1 - ui/dist/index.html | 4 +- ui/src/api.ts | 33 +++- ui/src/routes/Instances.tsx | 243 +++++++++++++++++++++++++++--- ui/src/styles.css | 151 +++++++++++++++++++ 10 files changed, 580 insertions(+), 86 deletions(-) delete mode 100644 ui/dist/assets/index-B6h_u_OQ.js create mode 100644 ui/dist/assets/index-BqvLn6SF.js create mode 100644 ui/dist/assets/index-C39-GzIs.css delete mode 100644 ui/dist/assets/index-DKizVbia.css diff --git a/bin/lmstack-ui b/bin/lmstack-ui index bd171ad..4e5a529 100755 --- a/bin/lmstack-ui +++ b/bin/lmstack-ui @@ -311,6 +311,16 @@ async function ensureDir(p) { try { mkdirSync(p, { recursive: true }); } catch {} } +// Best-effort vendor from the role name — matches lmstack's `h1-nvidia`, +// `h2-amd` convention. Only used when probe.json is missing so the UI can +// still render a vendor badge. Overridden by probe.gpu.vendor once present. +function inferVendorFromRole(role) { + if (!role) return null; + if (/nvidia/i.test(role)) return 'nvidia'; + if (/amd/i.test(role) || /rocm/i.test(role) || /radeon/i.test(role)) return 'amd'; + return null; +} + // Reserved top-level names inside ~/.lmstack/ that are never role directories. const RESERVED = new Set([ 'runs', 'worktrees', 'env', 'templates', 'models', 'models-gguf', 'litellm', @@ -375,6 +385,13 @@ async function readProbeJson(role) { } catch { return null; } } +async function readClassifyJson(role) { + try { + const text = await readFile(join(LMSTACK_HOME, role, 'classify.json'), 'utf8'); + return JSON.parse(text); + } catch { return null; } +} + async function readTasksForRole(role) { const root = join(LMSTACK_HOME, role, 'tasks'); const records = []; @@ -498,24 +515,100 @@ async function getInstances() { const all = await collectForges(); const out = []; for (const role of roles) { - const host = await readHostYaml(role); - const probe = await readProbeJson(role); - const forges = all.filter((f) => f.role === role); - const counts = countByStatus(forges); - out.push({ - role, - host: host.connection || null, - engine: host.engine || probe?.engine || null, - gpu: host.gpu || probe?.gpu || probe?.gpu_name || null, - models: Array.isArray(host.active_models) ? host.active_models : (host.active_models ? [host.active_models] : []), - probeAt: probe?.probed_at || probe?.timestamp || host.installed_at || null, - verdict: host.verdict || null, - counts, - }); + out.push(await buildInstance(role, all)); } return out; } +// Merge whatever we can read from host.yml / probe.json / classify.json +// into one shape the UI can render as a full-width card. Missing files are +// reported in `sources` so the UI can render an explicit empty-state hint +// rather than a card full of dashes. +async function buildInstance(role, allForges) { + const host = await readHostYaml(role); + const probe = await readProbeJson(role); + const classify = await readClassifyJson(role); + const forges = (allForges || []).filter((f) => f.role === role); + const counts = countByStatus(forges); + + const activeModels = Array.isArray(host.active_models) + ? host.active_models + : (host.active_models ? [host.active_models] : []); + + // Merge classify.models (with per-model params) with active_models + // (which names the ones currently live on the host). + const classifyModels = Array.isArray(classify?.models) ? classify.models : []; + const models = classifyModels.length + ? classifyModels.map((m) => ({ + slug: m.slug || m.name || null, + hfModel: m.hf_model || null, + engine: m.engine || null, + port: m.port ?? null, + contextTokens: m.max_model_len ?? m.context_tokens ?? null, + maxNumSeqs: m.max_num_seqs ?? null, + vramEstimateGib: m.vram_estimate_gib ?? null, + tier: m.tier || null, + quant: m.quant || null, + active: activeModels.includes(m.slug) || activeModels.includes(m.name), + })) + : activeModels.map((slug) => ({ slug, active: true })); + + return { + role, + connection: host.connection || null, + installedAt: host.installed_at || null, + verdict: host.verdict || classify?.supported === false ? host.verdict || 'unsupported' : host.verdict || (classify ? 'supported' : null), + engine: { + kind: host.engine || classify?.engine || null, + reason: classify?.reason || null, + host: classify?.host || null, + }, + gpu: probe?.gpu + ? { + vendor: probe.gpu.vendor || inferVendorFromRole(role), + model: probe.gpu.model || null, + vramGib: probe.gpu.vram_gib ?? null, + gttGib: probe.gpu.gtt_gib ?? null, + driver: probe.gpu.driver || null, + } + : (inferVendorFromRole(role) + ? { vendor: inferVendorFromRole(role), model: null, vramGib: null, gttGib: null, driver: null } + : null), + os: probe?.os + ? { + pretty: probe.os.pretty || null, + kernel: probe.os.kernel || null, + arch: probe.os.arch || null, + } + : null, + memory: probe?.mem_total_gib != null ? { totalGib: probe.mem_total_gib } : null, + docker: probe?.docker + ? { + present: !!probe.docker.present, + usable: !!probe.docker.usable, + version: probe.docker.version || null, + runtimes: Array.isArray(probe.docker.runtimes) ? probe.docker.runtimes : [], + } + : null, + vulkan: probe?.vulkan + ? { + present: !!probe.vulkan.present, + device: probe.vulkan.device || null, + } + : null, + arithmetic: Array.isArray(classify?.arithmetic) ? classify.arithmetic : [], + warnings: Array.isArray(classify?.warnings) ? classify.warnings : [], + activeModels, + models, + counts, + sources: { + hostYaml: existsSync(join(LMSTACK_HOME, role, 'host.yml')), + probeJson: probe != null, + classifyJson: classify != null, + }, + }; +} + function countByStatus(forges) { const c = { running: 0, in_review: 0, queued: 0, merged: 0, failed: 0, cleaned: 0, stale: 0 }; for (const f of forges) { diff --git a/skills/analyze/SKILL.md b/skills/analyze/SKILL.md index 0d48f2a..284d248 100644 --- a/skills/analyze/SKILL.md +++ b/skills/analyze/SKILL.md @@ -80,14 +80,39 @@ If `supported` is `false`, relay `reason` and `remedy`, log the failure, and ## Step 4 — Record and hand off -Write the probe where install will find it. This is the only file this skill -creates: +Write three files into `~/.lmstack//` so downstream commands and the +read-only web UI (`lmstack-ui`) can render the host without re-probing. ```bash mkdir -p "$HOME/.lmstack/" + +# 1. the raw probe — what the machine reported about itself cp /tmp/lmstack-probe.json "$HOME/.lmstack//probe.json" + +# 2. the classifier verdict — engine choice, arithmetic, warnings, models +lmstack-classify --probe /tmp/lmstack-probe.json \ + > "$HOME/.lmstack//classify.json" + +# 3. a minimal host.yml — the identity of this role, so a reader that has +# opened only one file still knows the role, its connection, and the +# engine that will drive it. `install` overwrites this with the final +# version (adding active_models and installed_at) later; this stub is +# for the window between analyze and install. +cat > "$HOME/.lmstack//host.yml" < +connection: +verdict: +engine: +gpu: "" +active_models: [] +YAML ``` +All three files are read-only inputs to the UI and to `install`. Any of them +missing is a "run `/lmstack:analyze ` again" — the UI shows a hint on +the instance card when a file is missing, so a partial write is safe but +visible. + Then log it: ```bash diff --git a/ui/dist/assets/index-B6h_u_OQ.js b/ui/dist/assets/index-B6h_u_OQ.js deleted file mode 100644 index 9bf721a..0000000 --- a/ui/dist/assets/index-B6h_u_OQ.js +++ /dev/null @@ -1,41 +0,0 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const i of l)if(i.type==="childList")for(const u of i.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&r(u)}).observe(document,{childList:!0,subtree:!0});function n(l){const i={};return l.integrity&&(i.integrity=l.integrity),l.referrerPolicy&&(i.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?i.credentials="include":l.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(l){if(l.ep)return;l.ep=!0;const i=n(l);fetch(l.href,i)}})();function hc(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var es={exports:{}},rl={},ts={exports:{}},L={};/** - * @license React - * react.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Jn=Symbol.for("react.element"),mc=Symbol.for("react.portal"),vc=Symbol.for("react.fragment"),gc=Symbol.for("react.strict_mode"),yc=Symbol.for("react.profiler"),wc=Symbol.for("react.provider"),kc=Symbol.for("react.context"),xc=Symbol.for("react.forward_ref"),Sc=Symbol.for("react.suspense"),Ec=Symbol.for("react.memo"),jc=Symbol.for("react.lazy"),Au=Symbol.iterator;function Nc(e){return e===null||typeof e!="object"?null:(e=Au&&e[Au]||e["@@iterator"],typeof e=="function"?e:null)}var ns={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},rs=Object.assign,ls={};function sn(e,t,n){this.props=e,this.context=t,this.refs=ls,this.updater=n||ns}sn.prototype.isReactComponent={};sn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};sn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function is(){}is.prototype=sn.prototype;function Hi(e,t,n){this.props=e,this.context=t,this.refs=ls,this.updater=n||ns}var Wi=Hi.prototype=new is;Wi.constructor=Hi;rs(Wi,sn.prototype);Wi.isPureReactComponent=!0;var Bu=Array.isArray,us=Object.prototype.hasOwnProperty,Qi={current:null},os={key:!0,ref:!0,__self:!0,__source:!0};function ss(e,t,n){var r,l={},i=null,u=null;if(t!=null)for(r in t.ref!==void 0&&(u=t.ref),t.key!==void 0&&(i=""+t.key),t)us.call(t,r)&&!os.hasOwnProperty(r)&&(l[r]=t[r]);var o=arguments.length-2;if(o===1)l.children=n;else if(1>>1,X=j[Q];if(0>>1;Ql(Sl,z))gtl(rr,Sl)?(j[Q]=rr,j[gt]=z,Q=gt):(j[Q]=Sl,j[vt]=z,Q=vt);else if(gtl(rr,z))j[Q]=rr,j[gt]=z,Q=gt;else break e}}return P}function l(j,P){var z=j.sortIndex-P.sortIndex;return z!==0?z:j.id-P.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var u=Date,o=u.now();e.unstable_now=function(){return u.now()-o}}var s=[],f=[],v=1,m=null,h=3,y=!1,x=!1,g=!1,O=typeof setTimeout=="function"?setTimeout:null,d=typeof clearTimeout=="function"?clearTimeout:null,c=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(j){for(var P=n(f);P!==null;){if(P.callback===null)r(f);else if(P.startTime<=j)r(f),P.sortIndex=P.expirationTime,t(s,P);else break;P=n(f)}}function w(j){if(g=!1,p(j),!x)if(n(s)!==null)x=!0,kl(E);else{var P=n(f);P!==null&&xl(w,P.startTime-j)}}function E(j,P){x=!1,g&&(g=!1,d(_),_=-1),y=!0;var z=h;try{for(p(P),m=n(s);m!==null&&(!(m.expirationTime>P)||j&&!_e());){var Q=m.callback;if(typeof Q=="function"){m.callback=null,h=m.priorityLevel;var X=Q(m.expirationTime<=P);P=e.unstable_now(),typeof X=="function"?m.callback=X:m===n(s)&&r(s),p(P)}else r(s);m=n(s)}if(m!==null)var nr=!0;else{var vt=n(f);vt!==null&&xl(w,vt.startTime-P),nr=!1}return nr}finally{m=null,h=z,y=!1}}var N=!1,C=null,_=-1,W=5,T=-1;function _e(){return!(e.unstable_now()-Tj||125Q?(j.sortIndex=z,t(f,j),n(s)===null&&j===n(f)&&(g?(d(_),_=-1):g=!0,xl(w,z-Q))):(j.sortIndex=X,t(s,j),x||y||(x=!0,kl(E))),j},e.unstable_shouldYield=_e,e.unstable_wrapCallback=function(j){var P=h;return function(){var z=h;h=P;try{return j.apply(this,arguments)}finally{h=z}}}})(ps);ds.exports=ps;var Fc=ds.exports;/** - * @license React - * react-dom.production.min.js - * - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */var Uc=A,ye=Fc;function k(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Jl=Object.prototype.hasOwnProperty,$c=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Hu={},Wu={};function Ac(e){return Jl.call(Wu,e)?!0:Jl.call(Hu,e)?!1:$c.test(e)?Wu[e]=!0:(Hu[e]=!0,!1)}function Bc(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Vc(e,t,n,r){if(t===null||typeof t>"u"||Bc(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function ae(e,t,n,r,l,i,u){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=u}var te={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){te[e]=new ae(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];te[t]=new ae(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){te[e]=new ae(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){te[e]=new ae(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){te[e]=new ae(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){te[e]=new ae(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){te[e]=new ae(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){te[e]=new ae(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){te[e]=new ae(e,5,!1,e.toLowerCase(),null,!1,!1)});var Yi=/[\-:]([a-z])/g;function Zi(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Yi,Zi);te[t]=new ae(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Yi,Zi);te[t]=new ae(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Yi,Zi);te[t]=new ae(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){te[e]=new ae(e,1,!1,e.toLowerCase(),null,!1,!1)});te.xlinkHref=new ae("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){te[e]=new ae(e,1,!1,e.toLowerCase(),null,!0,!0)});function Gi(e,t,n,r){var l=te.hasOwnProperty(t)?te[t]:null;(l!==null?l.type!==0:r||!(2o||l[u]!==i[o]){var s=` -`+l[u].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=u&&0<=o);break}}}finally{Nl=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?xn(e):""}function Hc(e){switch(e.tag){case 5:return xn(e.type);case 16:return xn("Lazy");case 13:return xn("Suspense");case 19:return xn("SuspenseList");case 0:case 2:case 15:return e=Cl(e.type,!1),e;case 11:return e=Cl(e.type.render,!1),e;case 1:return e=Cl(e.type,!0),e;default:return""}}function ti(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Ft:return"Fragment";case Dt:return"Portal";case ql:return"Profiler";case Xi:return"StrictMode";case bl:return"Suspense";case ei:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case vs:return(e.displayName||"Context")+".Consumer";case ms:return(e._context.displayName||"Context")+".Provider";case Ji:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case qi:return t=e.displayName||null,t!==null?t:ti(e.type)||"Memo";case Je:t=e._payload,e=e._init;try{return ti(e(t))}catch{}}return null}function Wc(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ti(t);case 8:return t===Xi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function ft(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ys(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Qc(e){var t=ys(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(u){r=""+u,i.call(this,u)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(u){r=""+u},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ur(e){e._valueTracker||(e._valueTracker=Qc(e))}function ws(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ys(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Mr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ni(e,t){var n=t.checked;return V({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Ku(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=ft(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function ks(e,t){t=t.checked,t!=null&&Gi(e,"checked",t,!1)}function ri(e,t){ks(e,t);var n=ft(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?li(e,t.type,n):t.hasOwnProperty("defaultValue")&&li(e,t.type,ft(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Yu(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function li(e,t,n){(t!=="number"||Mr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Sn=Array.isArray;function Zt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=or.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function In(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Nn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Kc=["Webkit","ms","Moz","O"];Object.keys(Nn).forEach(function(e){Kc.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Nn[t]=Nn[e]})});function js(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Nn.hasOwnProperty(e)&&Nn[e]?(""+t).trim():t+"px"}function Ns(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=js(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Yc=V({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function oi(e,t){if(t){if(Yc[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(k(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(k(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(k(61))}if(t.style!=null&&typeof t.style!="object")throw Error(k(62))}}function si(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var ai=null;function bi(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var ci=null,Gt=null,Xt=null;function Xu(e){if(e=er(e)){if(typeof ci!="function")throw Error(k(280));var t=e.stateNode;t&&(t=sl(t),ci(e.stateNode,e.type,t))}}function Cs(e){Gt?Xt?Xt.push(e):Xt=[e]:Gt=e}function _s(){if(Gt){var e=Gt,t=Xt;if(Xt=Gt=null,Xu(e),t)for(e=0;e>>=0,e===0?32:31-(lf(e)/uf|0)|0}var sr=64,ar=4194304;function En(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Fr(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,i=e.pingedLanes,u=n&268435455;if(u!==0){var o=u&~l;o!==0?r=En(o):(i&=u,i!==0&&(r=En(i)))}else u=n&~l,u!==0?r=En(u):i!==0&&(r=En(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,i=t&-t,l>=i||l===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function qn(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Re(t),e[t]=n}function cf(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=_n),io=" ",uo=!1;function Ys(e,t){switch(e){case"keyup":return Uf.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Zs(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Ut=!1;function Af(e,t){switch(e){case"compositionend":return Zs(t);case"keypress":return t.which!==32?null:(uo=!0,io);case"textInput":return e=t.data,e===io&&uo?null:e;default:return null}}function Bf(e,t){if(Ut)return e==="compositionend"||!ou&&Ys(e,t)?(e=Qs(),jr=lu=tt=null,Ut=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=co(n)}}function qs(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?qs(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function bs(){for(var e=window,t=Mr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Mr(e.document)}return t}function su(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Xf(e){var t=bs(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&qs(n.ownerDocument.documentElement,n)){if(r!==null&&su(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,i=Math.min(r.start,l);r=r.end===void 0?i:Math.min(r.end,l),!e.extend&&i>r&&(l=r,r=i,i=l),l=fo(n,i);var u=fo(n,r);l&&u&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==u.node||e.focusOffset!==u.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(u.node,u.offset)):(t.setEnd(u.node,u.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,$t=null,vi=null,zn=null,gi=!1;function po(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;gi||$t==null||$t!==Mr(r)||(r=$t,"selectionStart"in r&&su(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),zn&&Bn(zn,r)||(zn=r,r=Ar(vi,"onSelect"),0Vt||(e.current=Ei[Vt],Ei[Vt]=null,Vt--)}function I(e,t){Vt++,Ei[Vt]=e.current,e.current=t}var dt={},ie=ht(dt),de=ht(!1),_t=dt;function tn(e,t){var n=e.type.contextTypes;if(!n)return dt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},i;for(i in n)l[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function pe(e){return e=e.childContextTypes,e!=null}function Vr(){F(de),F(ie)}function ko(e,t,n){if(ie.current!==dt)throw Error(k(168));I(ie,t),I(de,n)}function sa(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(k(108,Wc(e)||"Unknown",l));return V({},n,r)}function Hr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dt,_t=ie.current,I(ie,e),I(de,de.current),!0}function xo(e,t,n){var r=e.stateNode;if(!r)throw Error(k(169));n?(e=sa(e,t,_t),r.__reactInternalMemoizedMergedChildContext=e,F(de),F(ie),I(ie,e)):F(de),I(de,n)}var Be=null,al=!1,Al=!1;function aa(e){Be===null?Be=[e]:Be.push(e)}function sd(e){al=!0,aa(e)}function mt(){if(!Al&&Be!==null){Al=!0;var e=0,t=M;try{var n=Be;for(M=1;e>=u,l-=u,Ve=1<<32-Re(t)+l|n<_?(W=C,C=null):W=C.sibling;var T=h(d,C,p[_],w);if(T===null){C===null&&(C=W);break}e&&C&&T.alternate===null&&t(d,C),c=i(T,c,_),N===null?E=T:N.sibling=T,N=T,C=W}if(_===p.length)return n(d,C),U&&yt(d,_),E;if(C===null){for(;__?(W=C,C=null):W=C.sibling;var _e=h(d,C,T.value,w);if(_e===null){C===null&&(C=W);break}e&&C&&_e.alternate===null&&t(d,C),c=i(_e,c,_),N===null?E=_e:N.sibling=_e,N=_e,C=W}if(T.done)return n(d,C),U&&yt(d,_),E;if(C===null){for(;!T.done;_++,T=p.next())T=m(d,T.value,w),T!==null&&(c=i(T,c,_),N===null?E=T:N.sibling=T,N=T);return U&&yt(d,_),E}for(C=r(d,C);!T.done;_++,T=p.next())T=y(C,d,_,T.value,w),T!==null&&(e&&T.alternate!==null&&C.delete(T.key===null?_:T.key),c=i(T,c,_),N===null?E=T:N.sibling=T,N=T);return e&&C.forEach(function(fn){return t(d,fn)}),U&&yt(d,_),E}function O(d,c,p,w){if(typeof p=="object"&&p!==null&&p.type===Ft&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case ir:e:{for(var E=p.key,N=c;N!==null;){if(N.key===E){if(E=p.type,E===Ft){if(N.tag===7){n(d,N.sibling),c=l(N,p.props.children),c.return=d,d=c;break e}}else if(N.elementType===E||typeof E=="object"&&E!==null&&E.$$typeof===Je&&jo(E)===N.type){n(d,N.sibling),c=l(N,p.props),c.ref=yn(d,N,p),c.return=d,d=c;break e}n(d,N);break}else t(d,N);N=N.sibling}p.type===Ft?(c=jt(p.props.children,d.mode,w,p.key),c.return=d,d=c):(w=Rr(p.type,p.key,p.props,null,d.mode,w),w.ref=yn(d,c,p),w.return=d,d=w)}return u(d);case Dt:e:{for(N=p.key;c!==null;){if(c.key===N)if(c.tag===4&&c.stateNode.containerInfo===p.containerInfo&&c.stateNode.implementation===p.implementation){n(d,c.sibling),c=l(c,p.children||[]),c.return=d,d=c;break e}else{n(d,c);break}else t(d,c);c=c.sibling}c=Zl(p,d.mode,w),c.return=d,d=c}return u(d);case Je:return N=p._init,O(d,c,N(p._payload),w)}if(Sn(p))return x(d,c,p,w);if(pn(p))return g(d,c,p,w);vr(d,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,c!==null&&c.tag===6?(n(d,c.sibling),c=l(c,p),c.return=d,d=c):(n(d,c),c=Yl(p,d.mode,w),c.return=d,d=c),u(d)):n(d,c)}return O}var rn=pa(!0),ha=pa(!1),Kr=ht(null),Yr=null,Qt=null,du=null;function pu(){du=Qt=Yr=null}function hu(e){var t=Kr.current;F(Kr),e._currentValue=t}function Ci(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function qt(e,t){Yr=e,du=Qt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(fe=!0),e.firstContext=null)}function Ne(e){var t=e._currentValue;if(du!==e)if(e={context:e,memoizedValue:t,next:null},Qt===null){if(Yr===null)throw Error(k(308));Qt=e,Yr.dependencies={lanes:0,firstContext:e}}else Qt=Qt.next=e;return t}var xt=null;function mu(e){xt===null?xt=[e]:xt.push(e)}function ma(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,mu(t)):(n.next=l.next,l.next=n),t.interleaved=n,Ye(e,r)}function Ye(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var qe=!1;function vu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function va(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function We(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function ot(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,R&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Ye(e,n)}return l=r.interleaved,l===null?(t.next=t,mu(r)):(t.next=l.next,l.next=t),r.interleaved=t,Ye(e,n)}function Cr(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tu(e,n)}}function No(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var u={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?l=i=u:i=i.next=u,n=n.next}while(n!==null);i===null?l=i=t:i=i.next=t}else l=i=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Zr(e,t,n,r){var l=e.updateQueue;qe=!1;var i=l.firstBaseUpdate,u=l.lastBaseUpdate,o=l.shared.pending;if(o!==null){l.shared.pending=null;var s=o,f=s.next;s.next=null,u===null?i=f:u.next=f,u=s;var v=e.alternate;v!==null&&(v=v.updateQueue,o=v.lastBaseUpdate,o!==u&&(o===null?v.firstBaseUpdate=f:o.next=f,v.lastBaseUpdate=s))}if(i!==null){var m=l.baseState;u=0,v=f=s=null,o=i;do{var h=o.lane,y=o.eventTime;if((r&h)===h){v!==null&&(v=v.next={eventTime:y,lane:0,tag:o.tag,payload:o.payload,callback:o.callback,next:null});e:{var x=e,g=o;switch(h=t,y=n,g.tag){case 1:if(x=g.payload,typeof x=="function"){m=x.call(y,m,h);break e}m=x;break e;case 3:x.flags=x.flags&-65537|128;case 0:if(x=g.payload,h=typeof x=="function"?x.call(y,m,h):x,h==null)break e;m=V({},m,h);break e;case 2:qe=!0}}o.callback!==null&&o.lane!==0&&(e.flags|=64,h=l.effects,h===null?l.effects=[o]:h.push(o))}else y={eventTime:y,lane:h,tag:o.tag,payload:o.payload,callback:o.callback,next:null},v===null?(f=v=y,s=m):v=v.next=y,u|=h;if(o=o.next,o===null){if(o=l.shared.pending,o===null)break;h=o,o=h.next,h.next=null,l.lastBaseUpdate=h,l.shared.pending=null}}while(!0);if(v===null&&(s=m),l.baseState=s,l.firstBaseUpdate=f,l.lastBaseUpdate=v,t=l.shared.interleaved,t!==null){l=t;do u|=l.lane,l=l.next;while(l!==t)}else i===null&&(l.shared.lanes=0);Lt|=u,e.lanes=u,e.memoizedState=m}}function Co(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Vl.transition;Vl.transition={};try{e(!1),t()}finally{M=n,Vl.transition=r}}function Ma(){return Ce().memoizedState}function dd(e,t,n){var r=at(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Oa(e))Ia(t,n);else if(n=ma(e,t,n,r),n!==null){var l=oe();Me(n,e,r,l),Da(n,t,r)}}function pd(e,t,n){var r=at(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Oa(e))Ia(t,l);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var u=t.lastRenderedState,o=i(u,n);if(l.hasEagerState=!0,l.eagerState=o,Oe(o,u)){var s=t.interleaved;s===null?(l.next=l,mu(t)):(l.next=s.next,s.next=l),t.interleaved=l;return}}catch{}finally{}n=ma(e,t,l,r),n!==null&&(l=oe(),Me(n,e,r,l),Da(n,t,r))}}function Oa(e){var t=e.alternate;return e===B||t!==null&&t===B}function Ia(e,t){Ln=Xr=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Da(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tu(e,n)}}var Jr={readContext:Ne,useCallback:ne,useContext:ne,useEffect:ne,useImperativeHandle:ne,useInsertionEffect:ne,useLayoutEffect:ne,useMemo:ne,useReducer:ne,useRef:ne,useState:ne,useDebugValue:ne,useDeferredValue:ne,useTransition:ne,useMutableSource:ne,useSyncExternalStore:ne,useId:ne,unstable_isNewReconciler:!1},hd={readContext:Ne,useCallback:function(e,t){return De().memoizedState=[e,t===void 0?null:t],e},useContext:Ne,useEffect:Po,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Pr(4194308,4,Pa.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Pr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Pr(4,2,e,t)},useMemo:function(e,t){var n=De();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=De();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=dd.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var t=De();return e={current:e},t.memoizedState=e},useState:_o,useDebugValue:ju,useDeferredValue:function(e){return De().memoizedState=e},useTransition:function(){var e=_o(!1),t=e[0];return e=fd.bind(null,e[1]),De().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=B,l=De();if(U){if(n===void 0)throw Error(k(407));n=n()}else{if(n=t(),q===null)throw Error(k(349));zt&30||ka(r,t,n)}l.memoizedState=n;var i={value:n,getSnapshot:t};return l.queue=i,Po(Sa.bind(null,r,i,e),[e]),r.flags|=2048,Gn(9,xa.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=De(),t=q.identifierPrefix;if(U){var n=He,r=Ve;n=(r&~(1<<32-Re(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Yn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=u.createElement(n,{is:r.is}):(e=u.createElement(n),n==="select"&&(u=e,r.multiple?u.multiple=!0:r.size&&(u.size=r.size))):e=u.createElementNS(e,n),e[Fe]=t,e[Wn]=r,Ka(e,t,!1,!1),t.stateNode=e;e:{switch(u=si(n,r),n){case"dialog":D("cancel",e),D("close",e),l=r;break;case"iframe":case"object":case"embed":D("load",e),l=r;break;case"video":case"audio":for(l=0;lon&&(t.flags|=128,r=!0,wn(i,!1),t.lanes=4194304)}else{if(!r)if(e=Gr(u),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),wn(i,!0),i.tail===null&&i.tailMode==="hidden"&&!u.alternate&&!U)return re(t),null}else 2*K()-i.renderingStartTime>on&&n!==1073741824&&(t.flags|=128,r=!0,wn(i,!1),t.lanes=4194304);i.isBackwards?(u.sibling=t.child,t.child=u):(n=i.last,n!==null?n.sibling=u:t.child=u,i.last=u)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=K(),t.sibling=null,n=$.current,I($,r?n&1|2:n&1),t):(re(t),null);case 22:case 23:return Lu(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?me&1073741824&&(re(t),t.subtreeFlags&6&&(t.flags|=8192)):re(t),null;case 24:return null;case 25:return null}throw Error(k(156,t.tag))}function Sd(e,t){switch(cu(t),t.tag){case 1:return pe(t.type)&&Vr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ln(),F(de),F(ie),wu(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return yu(t),null;case 13:if(F($),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(k(340));nn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return F($),null;case 4:return ln(),null;case 10:return hu(t.type._context),null;case 22:case 23:return Lu(),null;case 24:return null;default:return null}}var yr=!1,le=!1,Ed=typeof WeakSet=="function"?WeakSet:Set,S=null;function Kt(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){H(e,t,r)}else n.current=null}function Ii(e,t,n){try{n()}catch(r){H(e,t,r)}}var $o=!1;function jd(e,t){if(yi=Ur,e=bs(),su(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var u=0,o=-1,s=-1,f=0,v=0,m=e,h=null;t:for(;;){for(var y;m!==n||l!==0&&m.nodeType!==3||(o=u+l),m!==i||r!==0&&m.nodeType!==3||(s=u+r),m.nodeType===3&&(u+=m.nodeValue.length),(y=m.firstChild)!==null;)h=m,m=y;for(;;){if(m===e)break t;if(h===n&&++f===l&&(o=u),h===i&&++v===r&&(s=u),(y=m.nextSibling)!==null)break;m=h,h=m.parentNode}m=y}n=o===-1||s===-1?null:{start:o,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(wi={focusedElem:e,selectionRange:n},Ur=!1,S=t;S!==null;)if(t=S,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,S=e;else for(;S!==null;){t=S;try{var x=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(x!==null){var g=x.memoizedProps,O=x.memoizedState,d=t.stateNode,c=d.getSnapshotBeforeUpdate(t.elementType===t.type?g:ze(t.type,g),O);d.__reactInternalSnapshotBeforeUpdate=c}break;case 3:var p=t.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(k(163))}}catch(w){H(t,t.return,w)}if(e=t.sibling,e!==null){e.return=t.return,S=e;break}S=t.return}return x=$o,$o=!1,x}function Tn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var i=l.destroy;l.destroy=void 0,i!==void 0&&Ii(t,n,i)}l=l.next}while(l!==r)}}function dl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Di(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Ga(e){var t=e.alternate;t!==null&&(e.alternate=null,Ga(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Fe],delete t[Wn],delete t[Si],delete t[ud],delete t[od])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Xa(e){return e.tag===5||e.tag===3||e.tag===4}function Ao(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Xa(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Fi(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Br));else if(r!==4&&(e=e.child,e!==null))for(Fi(e,t,n),e=e.sibling;e!==null;)Fi(e,t,n),e=e.sibling}function Ui(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ui(e,t,n),e=e.sibling;e!==null;)Ui(e,t,n),e=e.sibling}var b=null,Le=!1;function Xe(e,t,n){for(n=n.child;n!==null;)Ja(e,t,n),n=n.sibling}function Ja(e,t,n){if(Ue&&typeof Ue.onCommitFiberUnmount=="function")try{Ue.onCommitFiberUnmount(ll,n)}catch{}switch(n.tag){case 5:le||Kt(n,t);case 6:var r=b,l=Le;b=null,Xe(e,t,n),b=r,Le=l,b!==null&&(Le?(e=b,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):b.removeChild(n.stateNode));break;case 18:b!==null&&(Le?(e=b,n=n.stateNode,e.nodeType===8?$l(e.parentNode,n):e.nodeType===1&&$l(e,n),$n(e)):$l(b,n.stateNode));break;case 4:r=b,l=Le,b=n.stateNode.containerInfo,Le=!0,Xe(e,t,n),b=r,Le=l;break;case 0:case 11:case 14:case 15:if(!le&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var i=l,u=i.destroy;i=i.tag,u!==void 0&&(i&2||i&4)&&Ii(n,t,u),l=l.next}while(l!==r)}Xe(e,t,n);break;case 1:if(!le&&(Kt(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(o){H(n,t,o)}Xe(e,t,n);break;case 21:Xe(e,t,n);break;case 22:n.mode&1?(le=(r=le)||n.memoizedState!==null,Xe(e,t,n),le=r):Xe(e,t,n);break;default:Xe(e,t,n)}}function Bo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Ed),t.forEach(function(r){var l=Md.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function Pe(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=u),r&=~i}if(r=l,r=K()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Cd(r/1960))-r,10e?16:e,nt===null)var r=!1;else{if(e=nt,nt=null,el=0,R&6)throw Error(k(331));var l=R;for(R|=4,S=e.current;S!==null;){var i=S,u=i.child;if(S.flags&16){var o=i.deletions;if(o!==null){for(var s=0;sK()-Pu?Et(e,0):_u|=n),he(e,t)}function ic(e,t){t===0&&(e.mode&1?(t=ar,ar<<=1,!(ar&130023424)&&(ar=4194304)):t=1);var n=oe();e=Ye(e,t),e!==null&&(qn(e,t,n),he(e,n))}function Rd(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),ic(e,n)}function Md(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(k(314))}r!==null&&r.delete(t),ic(e,n)}var uc;uc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||de.current)fe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return fe=!1,kd(e,t,n);fe=!!(e.flags&131072)}else fe=!1,U&&t.flags&1048576&&ca(t,Qr,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;zr(e,t),e=t.pendingProps;var l=tn(t,ie.current);qt(t,n),l=xu(null,t,r,e,l,n);var i=Su();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,pe(r)?(i=!0,Hr(t)):i=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,vu(t),l.updater=fl,t.stateNode=l,l._reactInternals=t,Pi(t,r,e,n),t=Ti(null,t,r,!0,i,n)):(t.tag=0,U&&i&&au(t),ue(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(zr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Id(r),e=ze(r,e),l){case 0:t=Li(null,t,r,e,n);break e;case 1:t=Do(null,t,r,e,n);break e;case 11:t=Oo(null,t,r,e,n);break e;case 14:t=Io(null,t,r,ze(r.type,e),n);break e}throw Error(k(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Li(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Do(e,t,r,l,n);case 3:e:{if(Ha(t),e===null)throw Error(k(387));r=t.pendingProps,i=t.memoizedState,l=i.element,va(e,t),Zr(t,r,null,n);var u=t.memoizedState;if(r=u.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:u.cache,pendingSuspenseBoundaries:u.pendingSuspenseBoundaries,transitions:u.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){l=un(Error(k(423)),t),t=Fo(e,t,r,n,l);break e}else if(r!==l){l=un(Error(k(424)),t),t=Fo(e,t,r,n,l);break e}else for(ve=ut(t.stateNode.containerInfo.firstChild),ge=t,U=!0,Te=null,n=ha(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(nn(),r===l){t=Ze(e,t,n);break e}ue(e,t,r,n)}t=t.child}return t;case 5:return ga(t),e===null&&Ni(t),r=t.type,l=t.pendingProps,i=e!==null?e.memoizedProps:null,u=l.children,ki(r,l)?u=null:i!==null&&ki(r,i)&&(t.flags|=32),Va(e,t),ue(e,t,u,n),t.child;case 6:return e===null&&Ni(t),null;case 13:return Wa(e,t,n);case 4:return gu(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=rn(t,null,r,n):ue(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Oo(e,t,r,l,n);case 7:return ue(e,t,t.pendingProps,n),t.child;case 8:return ue(e,t,t.pendingProps.children,n),t.child;case 12:return ue(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,i=t.memoizedProps,u=l.value,I(Kr,r._currentValue),r._currentValue=u,i!==null)if(Oe(i.value,u)){if(i.children===l.children&&!de.current){t=Ze(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var o=i.dependencies;if(o!==null){u=i.child;for(var s=o.firstContext;s!==null;){if(s.context===r){if(i.tag===1){s=We(-1,n&-n),s.tag=2;var f=i.updateQueue;if(f!==null){f=f.shared;var v=f.pending;v===null?s.next=s:(s.next=v.next,v.next=s),f.pending=s}}i.lanes|=n,s=i.alternate,s!==null&&(s.lanes|=n),Ci(i.return,n,t),o.lanes|=n;break}s=s.next}}else if(i.tag===10)u=i.type===t.type?null:i.child;else if(i.tag===18){if(u=i.return,u===null)throw Error(k(341));u.lanes|=n,o=u.alternate,o!==null&&(o.lanes|=n),Ci(u,n,t),u=i.sibling}else u=i.child;if(u!==null)u.return=i;else for(u=i;u!==null;){if(u===t){u=null;break}if(i=u.sibling,i!==null){i.return=u.return,u=i;break}u=u.return}i=u}ue(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,qt(t,n),l=Ne(l),r=r(l),t.flags|=1,ue(e,t,r,n),t.child;case 14:return r=t.type,l=ze(r,t.pendingProps),l=ze(r.type,l),Io(e,t,r,l,n);case 15:return Aa(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),zr(e,t),t.tag=1,pe(r)?(e=!0,Hr(t)):e=!1,qt(t,n),Fa(t,r,l),Pi(t,r,l,n),Ti(null,t,r,!0,e,n);case 19:return Qa(e,t,n);case 22:return Ba(e,t,n)}throw Error(k(156,t.tag))};function oc(e,t){return Os(e,t)}function Od(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ee(e,t,n,r){return new Od(e,t,n,r)}function Ru(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Id(e){if(typeof e=="function")return Ru(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Ji)return 11;if(e===qi)return 14}return 2}function ct(e,t){var n=e.alternate;return n===null?(n=Ee(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Rr(e,t,n,r,l,i){var u=2;if(r=e,typeof e=="function")Ru(e)&&(u=1);else if(typeof e=="string")u=5;else e:switch(e){case Ft:return jt(n.children,l,i,t);case Xi:u=8,l|=8;break;case ql:return e=Ee(12,n,t,l|2),e.elementType=ql,e.lanes=i,e;case bl:return e=Ee(13,n,t,l),e.elementType=bl,e.lanes=i,e;case ei:return e=Ee(19,n,t,l),e.elementType=ei,e.lanes=i,e;case gs:return hl(n,l,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case ms:u=10;break e;case vs:u=9;break e;case Ji:u=11;break e;case qi:u=14;break e;case Je:u=16,r=null;break e}throw Error(k(130,e==null?e:typeof e,""))}return t=Ee(u,n,t,l),t.elementType=e,t.type=r,t.lanes=i,t}function jt(e,t,n,r){return e=Ee(7,e,r,t),e.lanes=n,e}function hl(e,t,n,r){return e=Ee(22,e,r,t),e.elementType=gs,e.lanes=n,e.stateNode={isHidden:!1},e}function Yl(e,t,n){return e=Ee(6,e,null,t),e.lanes=n,e}function Zl(e,t,n){return t=Ee(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Dd(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Pl(0),this.expirationTimes=Pl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Pl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Mu(e,t,n,r,l,i,u,o,s){return e=new Dd(e,t,n,o,s),t===1?(t=1,i===!0&&(t|=8)):t=0,i=Ee(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},vu(i),e}function Fd(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(fc)}catch(e){console.error(e)}}fc(),fs.exports=we;var Vd=fs.exports,Go=Vd;Xl.createRoot=Go.createRoot,Xl.hydrateRoot=Go.hydrateRoot;async function It(e){const t=await fetch(e);if(!t.ok)throw new Error(`${e} → ${t.status}`);return t.json()}const Nt={instances:()=>It("/api/instances"),instance:e=>It(`/api/instances/${encodeURIComponent(e)}`),forges:(e={})=>{const t=new URLSearchParams;e.role&&t.set("role",e.role),e.status&&t.set("status",e.status);const n=t.toString();return It("/api/forges"+(n?"?"+n:""))},forge:e=>It(`/api/forges/${encodeURIComponent(e)}`),log:(e,t,n=200)=>It(`/api/forges/${encodeURIComponent(e)}/log/${t}?tail=${n}`),ledger:(e={})=>{const t=new URLSearchParams;e.limit&&t.set("limit",String(e.limit)),e.shape&&t.set("shape",e.shape),e.outcome&&t.set("outcome",e.outcome),e.role&&t.set("role",e.role);const n=t.toString();return It("/api/ledger"+(n?"?"+n:""))}};function Fu(e){if(e==null)return"—";if(e<60)return`${e}m`;const t=Math.floor(e/60),n=e%60;return`${t}h${n?` ${n}m`:""}`}function Uu(e){return e.replace("__","/")}function Ct(e,t=[]){const[n,r]=A.useState(null),[l,i]=A.useState(null),[u,o]=A.useState(!0),[s,f]=A.useState(null),[v,m]=A.useState(0),h=A.useCallback(()=>m(y=>y+1),[]);return A.useEffect(()=>{let y=!1;return o(!0),e().then(x=>{y||(r(x),i(null),f(new Date))}).catch(x=>{y||i(x instanceof Error?x.message:String(x))}).finally(()=>{y||o(!1)}),()=>{y=!0}},[...t,v]),{data:n,error:l,loading:u,loadedAt:s,reload:h}}function wl(e){return e?`loaded ${e.toLocaleTimeString()}`:""}function Hd(){const{data:e,error:t,loading:n,loadedAt:r,reload:l}=Ct(()=>Nt.instances(),[]);return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:"Instances"}),e&&a.jsxs("span",{className:"count",children:["(",e.length," installed)"]}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(r)}),a.jsx("button",{onClick:l,disabled:n,children:"Refresh"})]}),t&&a.jsxs("div",{className:"error",children:["error: ",t]}),!t&&e&&e.length===0&&a.jsx("div",{className:"empty",children:"No instances installed. Run /lmstack:install to add one."}),a.jsx("div",{className:"cards",children:e==null?void 0:e.map(i=>a.jsxs("div",{className:"card",children:[a.jsx("h3",{children:i.role}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"engine"}),a.jsx("strong",{children:i.engine??"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"gpu"}),a.jsx("strong",{children:i.gpu??"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"models"}),a.jsx("strong",{children:i.models.length?i.models.join(", "):"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"probe"}),a.jsx("strong",{children:i.probeAt??"—"})]}),a.jsxs("div",{className:"row",children:[a.jsx("span",{children:"verdict"}),a.jsx("strong",{children:i.verdict??"—"})]}),a.jsxs("div",{className:"row",style:{marginTop:6},children:[a.jsx("span",{children:"forges"}),a.jsxs("strong",{children:[i.counts.running," running · ",i.counts.in_review," in-review · ",i.counts.queued," queued · ",i.counts.merged+i.counts.cleaned," done · ",i.counts.failed," failed"]})]}),a.jsx("div",{style:{marginTop:8},children:a.jsx("a",{href:"#/forges",children:"view forges →"})})]},i.role))})]})}const Xo={queued:"○ queued",running:"● running","in-review":"◐ in-review",merged:"✓ merged",failed:"✗ failed",cleaned:"· cleaned",stale:"! stale"};function dc({status:e}){const t=e in Xo?e:"queued";return a.jsx("span",{className:`badge ${t}`,children:Xo[t]??e})}const Wd=[{title:"Running",statuses:["running"]},{title:"In review",statuses:["in-review"]},{title:"Queued",statuses:["queued"]},{title:"Completed",statuses:["merged","cleaned"]},{title:"Failed",statuses:["failed"]},{title:"Stale",statuses:["stale"]}];function Qd(){var h;const[e,t]=A.useState(""),[n,r]=A.useState(""),{data:l,error:i,loading:u,loadedAt:o,reload:s}=Ct(()=>Nt.forges(),[]),f=Ct(()=>Nt.instances(),[]),v=A.useMemo(()=>l?l.filter(y=>!(e&&y.role!==e||n&&y.status!==n)):null,[l,e,n]),m=A.useMemo(()=>v?Wd.map(y=>({title:y.title,forges:v.filter(x=>y.statuses.includes(x.status))})):null,[v]);return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:"Forges"}),v&&a.jsxs("span",{className:"count",children:["(",v.length," shown)"]}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(o)}),a.jsx("button",{onClick:s,disabled:u,children:"Refresh"})]}),a.jsxs("div",{className:"filters",children:[a.jsx("label",{children:"host: "}),a.jsxs("select",{value:e,onChange:y=>t(y.target.value),children:[a.jsx("option",{value:"",children:"all"}),(h=f.data)==null?void 0:h.map(y=>a.jsx("option",{value:y.role,children:y.role},y.role))]}),a.jsx("label",{children:"status: "}),a.jsxs("select",{value:n,onChange:y=>r(y.target.value),children:[a.jsx("option",{value:"",children:"all"}),a.jsx("option",{value:"running",children:"running"}),a.jsx("option",{value:"in-review",children:"in-review"}),a.jsx("option",{value:"queued",children:"queued"}),a.jsx("option",{value:"merged",children:"merged"}),a.jsx("option",{value:"cleaned",children:"cleaned"}),a.jsx("option",{value:"failed",children:"failed"}),a.jsx("option",{value:"stale",children:"stale"})]})]}),i&&a.jsxs("div",{className:"error",children:["error: ",i]}),v&&v.length===0&&!i&&a.jsx("div",{className:"empty",children:"No forges match the current filters."}),m==null?void 0:m.map(y=>y.forges.length>0?a.jsx(Kd,{title:y.title,forges:y.forges},y.title):null)]})}function Kd({title:e,forges:t}){return a.jsxs("div",{style:{marginTop:16},children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:e}),a.jsxs("span",{className:"count",children:["(",t.length,")"]})]}),a.jsxs("table",{className:"table",children:[a.jsx("thead",{children:a.jsxs("tr",{children:[a.jsx("th",{children:"status"}),a.jsx("th",{children:"key"}),a.jsx("th",{children:"shape"}),a.jsx("th",{children:"tier"}),a.jsx("th",{children:"host"}),a.jsx("th",{children:"wall"}),a.jsx("th",{children:"judge"}),a.jsx("th",{children:"pr"})]})}),a.jsx("tbody",{children:t.map(n=>a.jsxs("tr",{onClick:()=>{window.location.hash=`#/forge/${encodeURIComponent(n.key)}`},children:[a.jsx("td",{children:a.jsx(dc,{status:n.status})}),a.jsx("td",{className:"key",children:Uu(n.key)}),a.jsx("td",{children:n.shape??"—"}),a.jsx("td",{children:n.tier??"—"}),a.jsx("td",{children:n.role}),a.jsx("td",{className:"mono",children:Fu(n.wallMin)}),a.jsx("td",{className:"mono",children:n.judgeRounds||"—"}),a.jsx("td",{className:"mono",children:n.pr??"—"})]},n.key))})]})]})}function Yd({forgeKey:e}){const t=Ct(()=>Nt.forge(e),[e]),n=Ct(()=>Nt.log(e,"exec",200),[e]),r=Ct(()=>Nt.log(e,"judge",200),[e]),l=()=>{t.reload(),n.reload(),r.reload()},i=t.loading||n.loading||r.loading;return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("a",{href:"#/forges",children:"← forges"}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(t.loadedAt)}),a.jsx("button",{onClick:l,disabled:i,children:"Refresh"})]}),t.error&&a.jsxs("div",{className:"error",children:["error: ",t.error]}),t.data&&a.jsx(Zd,{data:t.data,execLog:n.data,judgeLog:r.data})]})}function Zd({data:e,execLog:t,judgeLog:n}){const{task:r,run:l,ledger:i}=e,u=r.status??"queued",o=r.url,s=r.pr,f=r.tier,v=r.shape;return a.jsxs(a.Fragment,{children:[a.jsxs("div",{className:"detail-header",children:[a.jsx("span",{className:"title",children:Uu(e.task.key)}),a.jsx(dc,{status:u}),o&&a.jsx("a",{href:o,target:"_blank",rel:"noreferrer",children:"↗ issue"}),s&&a.jsx("a",{href:s,target:"_blank",rel:"noreferrer",children:"↗ pr"})]}),a.jsxs("div",{className:"detail-meta",children:[a.jsx("span",{className:"k",children:"host"}),a.jsx("span",{className:"v",children:e.role}),a.jsx("span",{className:"k",children:"shape"}),a.jsx("span",{className:"v",children:v??"—"}),a.jsx("span",{className:"k",children:"tier"}),a.jsx("span",{className:"v",children:f??"—"}),a.jsx("span",{className:"k",children:"title"}),a.jsx("span",{className:"v",style:{fontFamily:"inherit"},children:r.title??"—"}),a.jsx("span",{className:"k",children:"started"}),a.jsx("span",{className:"v",children:l.startedAt??"—"}),a.jsx("span",{className:"k",children:"ended"}),a.jsx("span",{className:"v",children:l.endedAt??"—"}),a.jsx("span",{className:"k",children:"tmux session"}),a.jsxs("span",{className:"v",children:["lmstack-",e.slug," ",l.tmuxAlive?"(alive ✓)":"(not running)"]}),a.jsx("span",{className:"k",children:"worktree"}),a.jsxs("span",{className:"v",children:[l.worktreePath??"—"," ",l.worktreePath?l.worktreeExists?"":"(missing)":""]}),a.jsx("span",{className:"k",children:"branch"}),a.jsx("span",{className:"v",children:l.branch??"—"}),i&&a.jsxs(a.Fragment,{children:[a.jsx("span",{className:"k",children:"outcome"}),a.jsxs("span",{className:"v",children:[String(i.outcome??"—")," · wall ",Fu(i.wall_min)," · interventions ",String(i.interventions??0)]})]})]}),a.jsxs("div",{className:"panel",children:[a.jsx("h3",{children:"Brief"}),l.brief?a.jsx("pre",{children:l.brief}):a.jsx("div",{className:"empty",children:"no brief.md on disk"})]}),a.jsxs("div",{className:"panel",children:[a.jsxs("h3",{children:["Judge rounds (",l.judgeRounds.length,")"]}),l.judgeRounds.length===0&&a.jsx("div",{className:"empty",children:"(none yet)"}),l.judgeRounds.map(m=>a.jsxs("div",{style:{marginBottom:12},children:[a.jsxs("div",{style:{color:"var(--muted)",fontSize:12,marginBottom:4},children:["round ",m.n]}),a.jsx("pre",{children:m.text})]},m.n))]}),a.jsxs("div",{className:"logs",children:[a.jsx(Jo,{title:"lm-exec",log:t}),a.jsx(Jo,{title:"lm-judge",log:n})]})]})}function Jo({title:e,log:t}){return a.jsxs("div",{className:"log-pane",children:[a.jsxs("h4",{children:[e,t!=null&&t.truncated?" — tail":""]}),!t&&a.jsx("div",{className:"empty",children:"loading…"}),t&&!t.exists&&a.jsxs("div",{className:"empty",children:["no log file at ",t.path]}),t&&t.exists&&t.lines.length===0&&a.jsx("div",{className:"empty",children:"(empty)"}),t&&t.exists&&t.lines.length>0&&a.jsx("pre",{children:t.lines.join(` -`)})]})}function Gd(){const{data:e,error:t,loading:n,loadedAt:r,reload:l}=Ct(()=>Nt.ledger({limit:500}),[]),[i,u]=A.useState(""),[o,s]=A.useState(""),[f,v]=A.useState(""),m=A.useMemo(()=>Gl(e==null?void 0:e.map(g=>g.shape).filter(g=>!!g)),[e]),h=A.useMemo(()=>Gl(e==null?void 0:e.map(g=>g.outcome).filter(g=>!!g)),[e]),y=A.useMemo(()=>Gl(e==null?void 0:e.map(g=>g.host_role).filter(g=>!!g)),[e]),x=A.useMemo(()=>e?e.filter(g=>!(i&&g.shape!==i||o&&g.outcome!==o||f&&g.host_role!==f)):null,[e,i,o,f]);return a.jsxs("div",{children:[a.jsxs("div",{className:"section-title",children:[a.jsx("span",{children:"Ledger"}),x&&a.jsxs("span",{className:"count",children:["(",x.length," of ",(e==null?void 0:e.length)??0," runs)"]}),a.jsx("div",{style:{flex:1}}),a.jsx("span",{className:"refresh-info",children:wl(r)}),a.jsx("button",{onClick:l,disabled:n,children:"Refresh"})]}),a.jsxs("div",{className:"filters",children:[a.jsx("label",{children:"shape: "}),a.jsxs("select",{value:i,onChange:g=>u(g.target.value),children:[a.jsx("option",{value:"",children:"all"}),m.map(g=>a.jsx("option",{value:g,children:g},g))]}),a.jsx("label",{children:"outcome: "}),a.jsxs("select",{value:o,onChange:g=>s(g.target.value),children:[a.jsx("option",{value:"",children:"all"}),h.map(g=>a.jsx("option",{value:g,children:g},g))]}),a.jsx("label",{children:"role: "}),a.jsxs("select",{value:f,onChange:g=>v(g.target.value),children:[a.jsx("option",{value:"",children:"all"}),y.map(g=>a.jsx("option",{value:g,children:g},g))]})]}),t&&a.jsxs("div",{className:"error",children:["error: ",t]}),x&&x.length===0&&!t&&a.jsx("div",{className:"empty",children:"No ledger entries."}),x&&x.length>0&&a.jsxs("table",{className:"table",children:[a.jsx("thead",{children:a.jsxs("tr",{children:[a.jsx("th",{children:"ended (UTC)"}),a.jsx("th",{children:"key"}),a.jsx("th",{children:"shape"}),a.jsx("th",{children:"tier"}),a.jsx("th",{children:"host"}),a.jsx("th",{children:"outcome"}),a.jsx("th",{children:"wall"}),a.jsx("th",{children:"judge"}),a.jsx("th",{children:"pr"}),a.jsx("th",{children:"int."})]})}),a.jsx("tbody",{children:x.map((g,O)=>a.jsxs("tr",{onClick:()=>{window.location.hash=`#/forge/${encodeURIComponent(g.key)}`},children:[a.jsx("td",{className:"mono",children:Xd(g.ended??g.ts)}),a.jsx("td",{className:"key",children:Uu(g.key)}),a.jsx("td",{children:g.shape??"—"}),a.jsx("td",{children:g.tier??"—"}),a.jsx("td",{children:g.host_role}),a.jsx("td",{children:g.outcome}),a.jsx("td",{className:"mono",children:Fu(g.wall_min)}),a.jsx("td",{className:"mono",children:g.judge_rounds||"—"}),a.jsx("td",{className:"mono",children:g.pr??"—"}),a.jsx("td",{className:"mono",children:g.interventions??0})]},`${g.key}-${g.ts}-${O}`))})]})]})}function Gl(e){return e?Array.from(new Set(e)).sort():[]}function Xd(e){return e?e.replace("T"," ").replace(/\..*Z?$/,"").replace(/Z$/,""):"—"}const Jd="https://github.com/ric03uec/lmstack",qd="https://ric03uec.github.io/lmstack/";function qo(){const e=window.location.hash.replace(/^#\/?/,"");return!e||e==="instances"?{name:"instances"}:e==="forges"?{name:"forges"}:e==="ledger"?{name:"ledger"}:e.startsWith("forge/")?{name:"forge",key:decodeURIComponent(e.slice(6))}:{name:"instances"}}function bd(){const[e,t]=A.useState(qo());A.useEffect(()=>{const r=()=>t(qo());return window.addEventListener("hashchange",r),()=>window.removeEventListener("hashchange",r)},[]);const n=r=>e.name===r||r==="forges"&&e.name==="forge";return a.jsxs("div",{className:"app",children:[a.jsxs("header",{className:"header",children:[a.jsxs("a",{className:"brand",href:"#/instances",children:[a.jsx("img",{src:"./lmstack.svg",alt:""}),a.jsx("span",{className:"name",children:"lmstack"}),a.jsx("span",{className:"tagline",children:"put your GPUs to work"})]}),a.jsx("div",{className:"spacer"}),a.jsxs("div",{className:"links",children:[a.jsxs("a",{href:qd,target:"_blank",rel:"noreferrer",title:"Documentation",children:[a.jsx(bo,{})," Docs"]}),a.jsxs("a",{href:Jd,target:"_blank",rel:"noreferrer",title:"Source on GitHub",children:[a.jsx(ep,{})," GitHub"]})]})]}),a.jsx("aside",{className:"sidebar",children:a.jsxs("nav",{children:[a.jsxs("a",{href:"#/instances",className:n("instances")?"active":"",children:[a.jsx("span",{className:"icon",children:a.jsx(tp,{})})," Instances"]}),a.jsxs("a",{href:"#/forges",className:n("forges")?"active":"",children:[a.jsx("span",{className:"icon",children:a.jsx(np,{})})," Forges"]}),a.jsxs("a",{href:"#/ledger",className:n("ledger")?"active":"",children:[a.jsx("span",{className:"icon",children:a.jsx(bo,{})})," Ledger"]})]})}),a.jsxs("main",{className:"main",children:[e.name==="instances"&&a.jsx(Hd,{}),e.name==="forges"&&a.jsx(Qd,{}),e.name==="forge"&&a.jsx(Yd,{forgeKey:e.key}),e.name==="ledger"&&a.jsx(Gd,{})]})]})}function ep(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M8 0C3.58 0 0 3.58 0 8a8 8 0 0 0 5.47 7.59c.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"})})}function bo(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574Zm1.504-5.076v5.076a3.75 3.75 0 0 1 1.994-.574H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.248l-.004 2.25Z"})})}function tp(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M2 2.75C2 1.784 2.784 1 3.75 1h8.5c.966 0 1.75.784 1.75 1.75v2.5A1.75 1.75 0 0 1 12.25 7h-8.5A1.75 1.75 0 0 1 2 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25Zm-1.75 8c0-.966.784-1.75 1.75-1.75h8.5c.966 0 1.75.784 1.75 1.75v2.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25Zm1.75-.25a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25ZM5 4a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-1 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"})})}function np(){return a.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:a.jsx("path",{d:"M9.53.22a.75.75 0 0 1 1.06 0l4.19 4.19a.75.75 0 0 1 0 1.06L13.06 7l1.03 1.03a1.75 1.75 0 0 1 0 2.48l-1.55 1.54a1.75 1.75 0 0 1-2.47 0L8 9l-6.42 6.42a.75.75 0 1 1-1.06-1.06L6.94 8 3.85 4.9a.75.75 0 0 1 0-1.06L5.4 2.29a1.75 1.75 0 0 1 2.47 0L9 3.44 9.53.22Zm-3.72 3.13a.25.25 0 0 0-.35 0L4.47 4.35 8.5 8.38l1.35-1.35Z"})})}Xl.createRoot(document.getElementById("root")).render(a.jsx(Lc.StrictMode,{children:a.jsx(bd,{})})); diff --git a/ui/dist/assets/index-BqvLn6SF.js b/ui/dist/assets/index-BqvLn6SF.js new file mode 100644 index 0000000..9896ea7 --- /dev/null +++ b/ui/dist/assets/index-BqvLn6SF.js @@ -0,0 +1,42 @@ +(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const i of l)if(i.type==="childList")for(const u of i.addedNodes)u.tagName==="LINK"&&u.rel==="modulepreload"&&r(u)}).observe(document,{childList:!0,subtree:!0});function t(l){const i={};return l.integrity&&(i.integrity=l.integrity),l.referrerPolicy&&(i.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?i.credentials="include":l.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(l){if(l.ep)return;l.ep=!0;const i=t(l);fetch(l.href,i)}})();function yc(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var ls={exports:{}},ul={},is={exports:{}},L={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var qt=Symbol.for("react.element"),xc=Symbol.for("react.portal"),wc=Symbol.for("react.fragment"),kc=Symbol.for("react.strict_mode"),Sc=Symbol.for("react.profiler"),jc=Symbol.for("react.provider"),Ec=Symbol.for("react.context"),Nc=Symbol.for("react.forward_ref"),Cc=Symbol.for("react.suspense"),_c=Symbol.for("react.memo"),Pc=Symbol.for("react.lazy"),Hu=Symbol.iterator;function zc(e){return e===null||typeof e!="object"?null:(e=Hu&&e[Hu]||e["@@iterator"],typeof e=="function"?e:null)}var us={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},os=Object.assign,ss={};function at(e,n,t){this.props=e,this.context=n,this.refs=ss,this.updater=t||us}at.prototype.isReactComponent={};at.prototype.setState=function(e,n){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,n,"setState")};at.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function as(){}as.prototype=at.prototype;function Gi(e,n,t){this.props=e,this.context=n,this.refs=ss,this.updater=t||us}var Ki=Gi.prototype=new as;Ki.constructor=Gi;os(Ki,at.prototype);Ki.isPureReactComponent=!0;var Wu=Array.isArray,cs=Object.prototype.hasOwnProperty,Yi={current:null},fs={key:!0,ref:!0,__self:!0,__source:!0};function ds(e,n,t){var r,l={},i=null,u=null;if(n!=null)for(r in n.ref!==void 0&&(u=n.ref),n.key!==void 0&&(i=""+n.key),n)cs.call(n,r)&&!fs.hasOwnProperty(r)&&(l[r]=n[r]);var s=arguments.length-2;if(s===1)l.children=t;else if(1>>1,J=E[G];if(0>>1;Gl(Nl,z))xnl(lr,Nl)?(E[G]=lr,E[xn]=z,G=xn):(E[G]=Nl,E[yn]=z,G=yn);else if(xnl(lr,z))E[G]=lr,E[xn]=z,G=xn;else break e}}return P}function l(E,P){var z=E.sortIndex-P.sortIndex;return z!==0?z:E.id-P.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var u=Date,s=u.now();e.unstable_now=function(){return u.now()-s}}var a=[],f=[],g=1,m=null,h=3,y=!1,x=!1,v=!1,I=typeof setTimeout=="function"?setTimeout:null,d=typeof clearTimeout=="function"?clearTimeout:null,c=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function p(E){for(var P=t(f);P!==null;){if(P.callback===null)r(f);else if(P.startTime<=E)r(f),P.sortIndex=P.expirationTime,n(a,P);else break;P=t(f)}}function w(E){if(v=!1,p(E),!x)if(t(a)!==null)x=!0,jl(j);else{var P=t(f);P!==null&&El(w,P.startTime-E)}}function j(E,P){x=!1,v&&(v=!1,d(_),_=-1),y=!0;var z=h;try{for(p(P),m=t(a);m!==null&&(!(m.expirationTime>P)||E&&!Pe());){var G=m.callback;if(typeof G=="function"){m.callback=null,h=m.priorityLevel;var J=G(m.expirationTime<=P);P=e.unstable_now(),typeof J=="function"?m.callback=J:m===t(a)&&r(a),p(P)}else r(a);m=t(a)}if(m!==null)var rr=!0;else{var yn=t(f);yn!==null&&El(w,yn.startTime-P),rr=!1}return rr}finally{m=null,h=z,y=!1}}var N=!1,C=null,_=-1,Q=5,T=-1;function Pe(){return!(e.unstable_now()-TE||125G?(E.sortIndex=z,n(f,E),t(a)===null&&E===t(f)&&(v?(d(_),_=-1):v=!0,El(w,z-G))):(E.sortIndex=J,n(a,E),x||y||(x=!0,jl(j))),E},e.unstable_shouldYield=Pe,e.unstable_wrapCallback=function(E){var P=h;return function(){var z=h;h=P;try{return E.apply(this,arguments)}finally{h=z}}}})(gs);vs.exports=gs;var Bc=vs.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Vc=A,xe=Bc;function k(e){for(var n="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ei=Object.prototype.hasOwnProperty,Hc=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Gu={},Ku={};function Wc(e){return ei.call(Ku,e)?!0:ei.call(Gu,e)?!1:Hc.test(e)?Ku[e]=!0:(Gu[e]=!0,!1)}function Qc(e,n,t,r){if(t!==null&&t.type===0)return!1;switch(typeof n){case"function":case"symbol":return!0;case"boolean":return r?!1:t!==null?!t.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Gc(e,n,t,r){if(n===null||typeof n>"u"||Qc(e,n,t,r))return!0;if(r)return!1;if(t!==null)switch(t.type){case 3:return!n;case 4:return n===!1;case 5:return isNaN(n);case 6:return isNaN(n)||1>n}return!1}function ce(e,n,t,r,l,i,u){this.acceptsBooleans=n===2||n===3||n===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=t,this.propertyName=e,this.type=n,this.sanitizeURL=i,this.removeEmptyString=u}var te={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){te[e]=new ce(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var n=e[0];te[n]=new ce(n,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){te[e]=new ce(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){te[e]=new ce(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){te[e]=new ce(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){te[e]=new ce(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){te[e]=new ce(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){te[e]=new ce(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){te[e]=new ce(e,5,!1,e.toLowerCase(),null,!1,!1)});var Xi=/[\-:]([a-z])/g;function Ji(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var n=e.replace(Xi,Ji);te[n]=new ce(n,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var n=e.replace(Xi,Ji);te[n]=new ce(n,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var n=e.replace(Xi,Ji);te[n]=new ce(n,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){te[e]=new ce(e,1,!1,e.toLowerCase(),null,!1,!1)});te.xlinkHref=new ce("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){te[e]=new ce(e,1,!1,e.toLowerCase(),null,!0,!0)});function qi(e,n,t,r){var l=te.hasOwnProperty(n)?te[n]:null;(l!==null?l.type!==0:r||!(2s||l[u]!==i[s]){var a=` +`+l[u].replace(" at new "," at ");return e.displayName&&a.includes("")&&(a=a.replace("",e.displayName)),a}while(1<=u&&0<=s);break}}}finally{Pl=!1,Error.prepareStackTrace=t}return(e=e?e.displayName||e.name:"")?St(e):""}function Kc(e){switch(e.tag){case 5:return St(e.type);case 16:return St("Lazy");case 13:return St("Suspense");case 19:return St("SuspenseList");case 0:case 2:case 15:return e=zl(e.type,!1),e;case 11:return e=zl(e.type.render,!1),e;case 1:return e=zl(e.type,!0),e;default:return""}}function li(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case $n:return"Fragment";case Un:return"Portal";case ni:return"Profiler";case bi:return"StrictMode";case ti:return"Suspense";case ri:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case ws:return(e.displayName||"Context")+".Consumer";case xs:return(e._context.displayName||"Context")+".Provider";case eu:var n=e.render;return e=e.displayName,e||(e=n.displayName||n.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case nu:return n=e.displayName||null,n!==null?n:li(e.type)||"Memo";case qe:n=e._payload,e=e._init;try{return li(e(n))}catch{}}return null}function Yc(e){var n=e.type;switch(e.tag){case 24:return"Cache";case 9:return(n.displayName||"Context")+".Consumer";case 10:return(n._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=n.render,e=e.displayName||e.name||"",n.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return n;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return li(n);case 8:return n===bi?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof n=="function")return n.displayName||n.name||null;if(typeof n=="string")return n}return null}function pn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Ss(e){var n=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(n==="checkbox"||n==="radio")}function Zc(e){var n=Ss(e)?"checked":"value",t=Object.getOwnPropertyDescriptor(e.constructor.prototype,n),r=""+e[n];if(!e.hasOwnProperty(n)&&typeof t<"u"&&typeof t.get=="function"&&typeof t.set=="function"){var l=t.get,i=t.set;return Object.defineProperty(e,n,{configurable:!0,get:function(){return l.call(this)},set:function(u){r=""+u,i.call(this,u)}}),Object.defineProperty(e,n,{enumerable:t.enumerable}),{getValue:function(){return r},setValue:function(u){r=""+u},stopTracking:function(){e._valueTracker=null,delete e[n]}}}}function or(e){e._valueTracker||(e._valueTracker=Zc(e))}function js(e){if(!e)return!1;var n=e._valueTracker;if(!n)return!0;var t=n.getValue(),r="";return e&&(r=Ss(e)?e.checked?"true":"false":e.value),e=r,e!==t?(n.setValue(e),!0):!1}function Dr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ii(e,n){var t=n.checked;return V({},n,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:t??e._wrapperState.initialChecked})}function Zu(e,n){var t=n.defaultValue==null?"":n.defaultValue,r=n.checked!=null?n.checked:n.defaultChecked;t=pn(n.value!=null?n.value:t),e._wrapperState={initialChecked:r,initialValue:t,controlled:n.type==="checkbox"||n.type==="radio"?n.checked!=null:n.value!=null}}function Es(e,n){n=n.checked,n!=null&&qi(e,"checked",n,!1)}function ui(e,n){Es(e,n);var t=pn(n.value),r=n.type;if(t!=null)r==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+t):e.value!==""+t&&(e.value=""+t);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}n.hasOwnProperty("value")?oi(e,n.type,t):n.hasOwnProperty("defaultValue")&&oi(e,n.type,pn(n.defaultValue)),n.checked==null&&n.defaultChecked!=null&&(e.defaultChecked=!!n.defaultChecked)}function Xu(e,n,t){if(n.hasOwnProperty("value")||n.hasOwnProperty("defaultValue")){var r=n.type;if(!(r!=="submit"&&r!=="reset"||n.value!==void 0&&n.value!==null))return;n=""+e._wrapperState.initialValue,t||n===e.value||(e.value=n),e.defaultValue=n}t=e.name,t!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,t!==""&&(e.name=t)}function oi(e,n,t){(n!=="number"||Dr(e.ownerDocument)!==e)&&(t==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+t&&(e.defaultValue=""+t))}var jt=Array.isArray;function Xn(e,n,t,r){if(e=e.options,n){n={};for(var l=0;l"+n.valueOf().toString()+"",n=sr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;n.firstChild;)e.appendChild(n.firstChild)}});function Dt(e,n){if(n){var t=e.firstChild;if(t&&t===e.lastChild&&t.nodeType===3){t.nodeValue=n;return}}e.textContent=n}var Ct={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Xc=["Webkit","ms","Moz","O"];Object.keys(Ct).forEach(function(e){Xc.forEach(function(n){n=n+e.charAt(0).toUpperCase()+e.substring(1),Ct[n]=Ct[e]})});function Ps(e,n,t){return n==null||typeof n=="boolean"||n===""?"":t||typeof n!="number"||n===0||Ct.hasOwnProperty(e)&&Ct[e]?(""+n).trim():n+"px"}function zs(e,n){e=e.style;for(var t in n)if(n.hasOwnProperty(t)){var r=t.indexOf("--")===0,l=Ps(t,n[t],r);t==="float"&&(t="cssFloat"),r?e.setProperty(t,l):e[t]=l}}var Jc=V({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ci(e,n){if(n){if(Jc[e]&&(n.children!=null||n.dangerouslySetInnerHTML!=null))throw Error(k(137,e));if(n.dangerouslySetInnerHTML!=null){if(n.children!=null)throw Error(k(60));if(typeof n.dangerouslySetInnerHTML!="object"||!("__html"in n.dangerouslySetInnerHTML))throw Error(k(61))}if(n.style!=null&&typeof n.style!="object")throw Error(k(62))}}function fi(e,n){if(e.indexOf("-")===-1)return typeof n.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var di=null;function tu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var pi=null,Jn=null,qn=null;function bu(e){if(e=nr(e)){if(typeof pi!="function")throw Error(k(280));var n=e.stateNode;n&&(n=fl(n),pi(e.stateNode,e.type,n))}}function Ls(e){Jn?qn?qn.push(e):qn=[e]:Jn=e}function Ts(){if(Jn){var e=Jn,n=qn;if(qn=Jn=null,bu(e),n)for(e=0;e>>=0,e===0?32:31-(af(e)/cf|0)|0}var ar=64,cr=4194304;function Et(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Ar(e,n){var t=e.pendingLanes;if(t===0)return 0;var r=0,l=e.suspendedLanes,i=e.pingedLanes,u=t&268435455;if(u!==0){var s=u&~l;s!==0?r=Et(s):(i&=u,i!==0&&(r=Et(i)))}else u=t&~l,u!==0?r=Et(u):i!==0&&(r=Et(i));if(r===0)return 0;if(n!==0&&n!==r&&!(n&l)&&(l=r&-r,i=n&-n,l>=i||l===16&&(i&4194240)!==0))return n;if(r&4&&(r|=t&16),n=e.entangledLanes,n!==0)for(e=e.entanglements,n&=r;0t;t++)n.push(e);return n}function bt(e,n,t){e.pendingLanes|=n,n!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,n=31-Me(n),e[n]=t}function hf(e,n){var t=e.pendingLanes&~n;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=n,e.mutableReadLanes&=n,e.entangledLanes&=n,n=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Pt),so=" ",ao=!1;function Js(e,n){switch(e){case"keyup":return Vf.indexOf(n.keyCode)!==-1;case"keydown":return n.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function qs(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var An=!1;function Wf(e,n){switch(e){case"compositionend":return qs(n);case"keypress":return n.which!==32?null:(ao=!0,so);case"textInput":return e=n.data,e===so&&ao?null:e;default:return null}}function Qf(e,n){if(An)return e==="compositionend"||!cu&&Js(e,n)?(e=Zs(),_r=ou=tn=null,An=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(n.ctrlKey||n.altKey||n.metaKey)||n.ctrlKey&&n.altKey){if(n.char&&1=n)return{node:t,offset:n-e};e=r}e:{for(;t;){if(t.nextSibling){t=t.nextSibling;break e}t=t.parentNode}t=void 0}t=ho(t)}}function ta(e,n){return e&&n?e===n?!0:e&&e.nodeType===3?!1:n&&n.nodeType===3?ta(e,n.parentNode):"contains"in e?e.contains(n):e.compareDocumentPosition?!!(e.compareDocumentPosition(n)&16):!1:!1}function ra(){for(var e=window,n=Dr();n instanceof e.HTMLIFrameElement;){try{var t=typeof n.contentWindow.location.href=="string"}catch{t=!1}if(t)e=n.contentWindow;else break;n=Dr(e.document)}return n}function fu(e){var n=e&&e.nodeName&&e.nodeName.toLowerCase();return n&&(n==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||n==="textarea"||e.contentEditable==="true")}function ed(e){var n=ra(),t=e.focusedElem,r=e.selectionRange;if(n!==t&&t&&t.ownerDocument&&ta(t.ownerDocument.documentElement,t)){if(r!==null&&fu(t)){if(n=r.start,e=r.end,e===void 0&&(e=n),"selectionStart"in t)t.selectionStart=n,t.selectionEnd=Math.min(e,t.value.length);else if(e=(n=t.ownerDocument||document)&&n.defaultView||window,e.getSelection){e=e.getSelection();var l=t.textContent.length,i=Math.min(r.start,l);r=r.end===void 0?i:Math.min(r.end,l),!e.extend&&i>r&&(l=r,r=i,i=l),l=mo(t,i);var u=mo(t,r);l&&u&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==u.node||e.focusOffset!==u.offset)&&(n=n.createRange(),n.setStart(l.node,l.offset),e.removeAllRanges(),i>r?(e.addRange(n),e.extend(u.node,u.offset)):(n.setEnd(u.node,u.offset),e.addRange(n)))}}for(n=[],e=t;e=e.parentNode;)e.nodeType===1&&n.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof t.focus=="function"&&t.focus(),t=0;t=document.documentMode,Bn=null,xi=null,Lt=null,wi=!1;function vo(e,n,t){var r=t.window===t?t.document:t.nodeType===9?t:t.ownerDocument;wi||Bn==null||Bn!==Dr(r)||(r=Bn,"selectionStart"in r&&fu(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Lt&&Vt(Lt,r)||(Lt=r,r=Hr(xi,"onSelect"),0Wn||(e.current=Ci[Wn],Ci[Wn]=null,Wn--)}function O(e,n){Wn++,Ci[Wn]=e.current,e.current=n}var hn={},ue=vn(hn),pe=vn(!1),zn=hn;function rt(e,n){var t=e.type.contextTypes;if(!t)return hn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===n)return r.__reactInternalMemoizedMaskedChildContext;var l={},i;for(i in t)l[i]=n[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=n,e.__reactInternalMemoizedMaskedChildContext=l),l}function he(e){return e=e.childContextTypes,e!=null}function Qr(){F(pe),F(ue)}function jo(e,n,t){if(ue.current!==hn)throw Error(k(168));O(ue,n),O(pe,t)}function da(e,n,t){var r=e.stateNode;if(n=n.childContextTypes,typeof r.getChildContext!="function")return t;r=r.getChildContext();for(var l in r)if(!(l in n))throw Error(k(108,Yc(e)||"Unknown",l));return V({},t,r)}function Gr(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||hn,zn=ue.current,O(ue,e),O(pe,pe.current),!0}function Eo(e,n,t){var r=e.stateNode;if(!r)throw Error(k(169));t?(e=da(e,n,zn),r.__reactInternalMemoizedMergedChildContext=e,F(pe),F(ue),O(ue,e)):F(pe),O(pe,t)}var Ve=null,dl=!1,Hl=!1;function pa(e){Ve===null?Ve=[e]:Ve.push(e)}function dd(e){dl=!0,pa(e)}function gn(){if(!Hl&&Ve!==null){Hl=!0;var e=0,n=M;try{var t=Ve;for(M=1;e>=u,l-=u,He=1<<32-Me(n)+l|t<_?(Q=C,C=null):Q=C.sibling;var T=h(d,C,p[_],w);if(T===null){C===null&&(C=Q);break}e&&C&&T.alternate===null&&n(d,C),c=i(T,c,_),N===null?j=T:N.sibling=T,N=T,C=Q}if(_===p.length)return t(d,C),U&&wn(d,_),j;if(C===null){for(;__?(Q=C,C=null):Q=C.sibling;var Pe=h(d,C,T.value,w);if(Pe===null){C===null&&(C=Q);break}e&&C&&Pe.alternate===null&&n(d,C),c=i(Pe,c,_),N===null?j=Pe:N.sibling=Pe,N=Pe,C=Q}if(T.done)return t(d,C),U&&wn(d,_),j;if(C===null){for(;!T.done;_++,T=p.next())T=m(d,T.value,w),T!==null&&(c=i(T,c,_),N===null?j=T:N.sibling=T,N=T);return U&&wn(d,_),j}for(C=r(d,C);!T.done;_++,T=p.next())T=y(C,d,_,T.value,w),T!==null&&(e&&T.alternate!==null&&C.delete(T.key===null?_:T.key),c=i(T,c,_),N===null?j=T:N.sibling=T,N=T);return e&&C.forEach(function(dt){return n(d,dt)}),U&&wn(d,_),j}function I(d,c,p,w){if(typeof p=="object"&&p!==null&&p.type===$n&&p.key===null&&(p=p.props.children),typeof p=="object"&&p!==null){switch(p.$$typeof){case ur:e:{for(var j=p.key,N=c;N!==null;){if(N.key===j){if(j=p.type,j===$n){if(N.tag===7){t(d,N.sibling),c=l(N,p.props.children),c.return=d,d=c;break e}}else if(N.elementType===j||typeof j=="object"&&j!==null&&j.$$typeof===qe&&_o(j)===N.type){t(d,N.sibling),c=l(N,p.props),c.ref=xt(d,N,p),c.return=d,d=c;break e}t(d,N);break}else n(d,N);N=N.sibling}p.type===$n?(c=Cn(p.props.children,d.mode,w,p.key),c.return=d,d=c):(w=Or(p.type,p.key,p.props,null,d.mode,w),w.ref=xt(d,c,p),w.return=d,d=w)}return u(d);case Un:e:{for(N=p.key;c!==null;){if(c.key===N)if(c.tag===4&&c.stateNode.containerInfo===p.containerInfo&&c.stateNode.implementation===p.implementation){t(d,c.sibling),c=l(c,p.children||[]),c.return=d,d=c;break e}else{t(d,c);break}else n(d,c);c=c.sibling}c=Jl(p,d.mode,w),c.return=d,d=c}return u(d);case qe:return N=p._init,I(d,c,N(p._payload),w)}if(jt(p))return x(d,c,p,w);if(ht(p))return v(d,c,p,w);gr(d,p)}return typeof p=="string"&&p!==""||typeof p=="number"?(p=""+p,c!==null&&c.tag===6?(t(d,c.sibling),c=l(c,p),c.return=d,d=c):(t(d,c),c=Xl(p,d.mode,w),c.return=d,d=c),u(d)):t(d,c)}return I}var it=ga(!0),ya=ga(!1),Zr=vn(null),Xr=null,Kn=null,mu=null;function vu(){mu=Kn=Xr=null}function gu(e){var n=Zr.current;F(Zr),e._currentValue=n}function zi(e,n,t){for(;e!==null;){var r=e.alternate;if((e.childLanes&n)!==n?(e.childLanes|=n,r!==null&&(r.childLanes|=n)):r!==null&&(r.childLanes&n)!==n&&(r.childLanes|=n),e===t)break;e=e.return}}function et(e,n){Xr=e,mu=Kn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&n&&(de=!0),e.firstContext=null)}function Ce(e){var n=e._currentValue;if(mu!==e)if(e={context:e,memoizedValue:n,next:null},Kn===null){if(Xr===null)throw Error(k(308));Kn=e,Xr.dependencies={lanes:0,firstContext:e}}else Kn=Kn.next=e;return n}var jn=null;function yu(e){jn===null?jn=[e]:jn.push(e)}function xa(e,n,t,r){var l=n.interleaved;return l===null?(t.next=t,yu(n)):(t.next=l.next,l.next=t),n.interleaved=t,Ye(e,r)}function Ye(e,n){e.lanes|=n;var t=e.alternate;for(t!==null&&(t.lanes|=n),t=e,e=e.return;e!==null;)e.childLanes|=n,t=e.alternate,t!==null&&(t.childLanes|=n),t=e,e=e.return;return t.tag===3?t.stateNode:null}var be=!1;function xu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function wa(e,n){e=e.updateQueue,n.updateQueue===e&&(n.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Qe(e,n){return{eventTime:e,lane:n,tag:0,payload:null,callback:null,next:null}}function an(e,n,t){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,R&2){var l=r.pending;return l===null?n.next=n:(n.next=l.next,l.next=n),r.pending=n,Ye(e,t)}return l=r.interleaved,l===null?(n.next=n,yu(r)):(n.next=l.next,l.next=n),r.interleaved=n,Ye(e,t)}function zr(e,n,t){if(n=n.updateQueue,n!==null&&(n=n.shared,(t&4194240)!==0)){var r=n.lanes;r&=e.pendingLanes,t|=r,n.lanes=t,lu(e,t)}}function Po(e,n){var t=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,t===r)){var l=null,i=null;if(t=t.firstBaseUpdate,t!==null){do{var u={eventTime:t.eventTime,lane:t.lane,tag:t.tag,payload:t.payload,callback:t.callback,next:null};i===null?l=i=u:i=i.next=u,t=t.next}while(t!==null);i===null?l=i=n:i=i.next=n}else l=i=n;t={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=t;return}e=t.lastBaseUpdate,e===null?t.firstBaseUpdate=n:e.next=n,t.lastBaseUpdate=n}function Jr(e,n,t,r){var l=e.updateQueue;be=!1;var i=l.firstBaseUpdate,u=l.lastBaseUpdate,s=l.shared.pending;if(s!==null){l.shared.pending=null;var a=s,f=a.next;a.next=null,u===null?i=f:u.next=f,u=a;var g=e.alternate;g!==null&&(g=g.updateQueue,s=g.lastBaseUpdate,s!==u&&(s===null?g.firstBaseUpdate=f:s.next=f,g.lastBaseUpdate=a))}if(i!==null){var m=l.baseState;u=0,g=f=a=null,s=i;do{var h=s.lane,y=s.eventTime;if((r&h)===h){g!==null&&(g=g.next={eventTime:y,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});e:{var x=e,v=s;switch(h=n,y=t,v.tag){case 1:if(x=v.payload,typeof x=="function"){m=x.call(y,m,h);break e}m=x;break e;case 3:x.flags=x.flags&-65537|128;case 0:if(x=v.payload,h=typeof x=="function"?x.call(y,m,h):x,h==null)break e;m=V({},m,h);break e;case 2:be=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,h=l.effects,h===null?l.effects=[s]:h.push(s))}else y={eventTime:y,lane:h,tag:s.tag,payload:s.payload,callback:s.callback,next:null},g===null?(f=g=y,a=m):g=g.next=y,u|=h;if(s=s.next,s===null){if(s=l.shared.pending,s===null)break;h=s,s=h.next,h.next=null,l.lastBaseUpdate=h,l.shared.pending=null}}while(!0);if(g===null&&(a=m),l.baseState=a,l.firstBaseUpdate=f,l.lastBaseUpdate=g,n=l.shared.interleaved,n!==null){l=n;do u|=l.lane,l=l.next;while(l!==n)}else i===null&&(l.shared.lanes=0);Rn|=u,e.lanes=u,e.memoizedState=m}}function zo(e,n,t){if(e=n.effects,n.effects=null,e!==null)for(n=0;nt?t:4,e(!0);var r=Ql.transition;Ql.transition={};try{e(!1),n()}finally{M=t,Ql.transition=r}}function Fa(){return _e().memoizedState}function vd(e,n,t){var r=fn(e);if(t={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null},Ua(e))$a(n,t);else if(t=xa(e,n,t,r),t!==null){var l=se();Ie(t,e,r,l),Aa(t,n,r)}}function gd(e,n,t){var r=fn(e),l={lane:r,action:t,hasEagerState:!1,eagerState:null,next:null};if(Ua(e))$a(n,l);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=n.lastRenderedReducer,i!==null))try{var u=n.lastRenderedState,s=i(u,t);if(l.hasEagerState=!0,l.eagerState=s,Oe(s,u)){var a=n.interleaved;a===null?(l.next=l,yu(n)):(l.next=a.next,a.next=l),n.interleaved=l;return}}catch{}finally{}t=xa(e,n,l,r),t!==null&&(l=se(),Ie(t,e,r,l),Aa(t,n,r))}}function Ua(e){var n=e.alternate;return e===B||n!==null&&n===B}function $a(e,n){Tt=br=!0;var t=e.pending;t===null?n.next=n:(n.next=t.next,t.next=n),e.pending=n}function Aa(e,n,t){if(t&4194240){var r=n.lanes;r&=e.pendingLanes,t|=r,n.lanes=t,lu(e,t)}}var el={readContext:Ce,useCallback:re,useContext:re,useEffect:re,useImperativeHandle:re,useInsertionEffect:re,useLayoutEffect:re,useMemo:re,useReducer:re,useRef:re,useState:re,useDebugValue:re,useDeferredValue:re,useTransition:re,useMutableSource:re,useSyncExternalStore:re,useId:re,unstable_isNewReconciler:!1},yd={readContext:Ce,useCallback:function(e,n){return Fe().memoizedState=[e,n===void 0?null:n],e},useContext:Ce,useEffect:To,useImperativeHandle:function(e,n,t){return t=t!=null?t.concat([e]):null,Tr(4194308,4,Ra.bind(null,n,e),t)},useLayoutEffect:function(e,n){return Tr(4194308,4,e,n)},useInsertionEffect:function(e,n){return Tr(4,2,e,n)},useMemo:function(e,n){var t=Fe();return n=n===void 0?null:n,e=e(),t.memoizedState=[e,n],e},useReducer:function(e,n,t){var r=Fe();return n=t!==void 0?t(n):n,r.memoizedState=r.baseState=n,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:n},r.queue=e,e=e.dispatch=vd.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var n=Fe();return e={current:e},n.memoizedState=e},useState:Lo,useDebugValue:_u,useDeferredValue:function(e){return Fe().memoizedState=e},useTransition:function(){var e=Lo(!1),n=e[0];return e=md.bind(null,e[1]),Fe().memoizedState=e,[n,e]},useMutableSource:function(){},useSyncExternalStore:function(e,n,t){var r=B,l=Fe();if(U){if(t===void 0)throw Error(k(407));t=t()}else{if(t=n(),b===null)throw Error(k(349));Tn&30||Ea(r,n,t)}l.memoizedState=t;var i={value:t,getSnapshot:n};return l.queue=i,To(Ca.bind(null,r,i,e),[e]),r.flags|=2048,Xt(9,Na.bind(null,r,i,t,n),void 0,null),t},useId:function(){var e=Fe(),n=b.identifierPrefix;if(U){var t=We,r=He;t=(r&~(1<<32-Me(r)-1)).toString(32)+t,n=":"+n+"R"+t,t=Yt++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=u.createElement(t,{is:r.is}):(e=u.createElement(t),t==="select"&&(u=e,r.multiple?u.multiple=!0:r.size&&(u.size=r.size))):e=u.createElementNS(e,t),e[Ue]=n,e[Qt]=r,Xa(e,n,!1,!1),n.stateNode=e;e:{switch(u=fi(t,r),t){case"dialog":D("cancel",e),D("close",e),l=r;break;case"iframe":case"object":case"embed":D("load",e),l=r;break;case"video":case"audio":for(l=0;lst&&(n.flags|=128,r=!0,wt(i,!1),n.lanes=4194304)}else{if(!r)if(e=qr(u),e!==null){if(n.flags|=128,r=!0,t=e.updateQueue,t!==null&&(n.updateQueue=t,n.flags|=4),wt(i,!0),i.tail===null&&i.tailMode==="hidden"&&!u.alternate&&!U)return le(n),null}else 2*K()-i.renderingStartTime>st&&t!==1073741824&&(n.flags|=128,r=!0,wt(i,!1),n.lanes=4194304);i.isBackwards?(u.sibling=n.child,n.child=u):(t=i.last,t!==null?t.sibling=u:n.child=u,i.last=u)}return i.tail!==null?(n=i.tail,i.rendering=n,i.tail=n.sibling,i.renderingStartTime=K(),n.sibling=null,t=$.current,O($,r?t&1|2:t&1),n):(le(n),null);case 22:case 23:return Mu(),r=n.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(n.flags|=8192),r&&n.mode&1?ve&1073741824&&(le(n),n.subtreeFlags&6&&(n.flags|=8192)):le(n),null;case 24:return null;case 25:return null}throw Error(k(156,n.tag))}function Cd(e,n){switch(pu(n),n.tag){case 1:return he(n.type)&&Qr(),e=n.flags,e&65536?(n.flags=e&-65537|128,n):null;case 3:return ut(),F(pe),F(ue),Su(),e=n.flags,e&65536&&!(e&128)?(n.flags=e&-65537|128,n):null;case 5:return ku(n),null;case 13:if(F($),e=n.memoizedState,e!==null&&e.dehydrated!==null){if(n.alternate===null)throw Error(k(340));lt()}return e=n.flags,e&65536?(n.flags=e&-65537|128,n):null;case 19:return F($),null;case 4:return ut(),null;case 10:return gu(n.type._context),null;case 22:case 23:return Mu(),null;case 24:return null;default:return null}}var xr=!1,ie=!1,_d=typeof WeakSet=="function"?WeakSet:Set,S=null;function Yn(e,n){var t=e.ref;if(t!==null)if(typeof t=="function")try{t(null)}catch(r){W(e,n,r)}else t.current=null}function Ui(e,n,t){try{t()}catch(r){W(e,n,r)}}var Vo=!1;function Pd(e,n){if(ki=Br,e=ra(),fu(e)){if("selectionStart"in e)var t={start:e.selectionStart,end:e.selectionEnd};else e:{t=(t=e.ownerDocument)&&t.defaultView||window;var r=t.getSelection&&t.getSelection();if(r&&r.rangeCount!==0){t=r.anchorNode;var l=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{t.nodeType,i.nodeType}catch{t=null;break e}var u=0,s=-1,a=-1,f=0,g=0,m=e,h=null;n:for(;;){for(var y;m!==t||l!==0&&m.nodeType!==3||(s=u+l),m!==i||r!==0&&m.nodeType!==3||(a=u+r),m.nodeType===3&&(u+=m.nodeValue.length),(y=m.firstChild)!==null;)h=m,m=y;for(;;){if(m===e)break n;if(h===t&&++f===l&&(s=u),h===i&&++g===r&&(a=u),(y=m.nextSibling)!==null)break;m=h,h=m.parentNode}m=y}t=s===-1||a===-1?null:{start:s,end:a}}else t=null}t=t||{start:0,end:0}}else t=null;for(Si={focusedElem:e,selectionRange:t},Br=!1,S=n;S!==null;)if(n=S,e=n.child,(n.subtreeFlags&1028)!==0&&e!==null)e.return=n,S=e;else for(;S!==null;){n=S;try{var x=n.alternate;if(n.flags&1024)switch(n.tag){case 0:case 11:case 15:break;case 1:if(x!==null){var v=x.memoizedProps,I=x.memoizedState,d=n.stateNode,c=d.getSnapshotBeforeUpdate(n.elementType===n.type?v:Le(n.type,v),I);d.__reactInternalSnapshotBeforeUpdate=c}break;case 3:var p=n.stateNode.containerInfo;p.nodeType===1?p.textContent="":p.nodeType===9&&p.documentElement&&p.removeChild(p.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(k(163))}}catch(w){W(n,n.return,w)}if(e=n.sibling,e!==null){e.return=n.return,S=e;break}S=n.return}return x=Vo,Vo=!1,x}function Rt(e,n,t){var r=n.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var i=l.destroy;l.destroy=void 0,i!==void 0&&Ui(n,t,i)}l=l.next}while(l!==r)}}function ml(e,n){if(n=n.updateQueue,n=n!==null?n.lastEffect:null,n!==null){var t=n=n.next;do{if((t.tag&e)===e){var r=t.create;t.destroy=r()}t=t.next}while(t!==n)}}function $i(e){var n=e.ref;if(n!==null){var t=e.stateNode;switch(e.tag){case 5:e=t;break;default:e=t}typeof n=="function"?n(e):n.current=e}}function ba(e){var n=e.alternate;n!==null&&(e.alternate=null,ba(n)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(n=e.stateNode,n!==null&&(delete n[Ue],delete n[Qt],delete n[Ni],delete n[cd],delete n[fd])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function ec(e){return e.tag===5||e.tag===3||e.tag===4}function Ho(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||ec(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ai(e,n,t){var r=e.tag;if(r===5||r===6)e=e.stateNode,n?t.nodeType===8?t.parentNode.insertBefore(e,n):t.insertBefore(e,n):(t.nodeType===8?(n=t.parentNode,n.insertBefore(e,t)):(n=t,n.appendChild(e)),t=t._reactRootContainer,t!=null||n.onclick!==null||(n.onclick=Wr));else if(r!==4&&(e=e.child,e!==null))for(Ai(e,n,t),e=e.sibling;e!==null;)Ai(e,n,t),e=e.sibling}function Bi(e,n,t){var r=e.tag;if(r===5||r===6)e=e.stateNode,n?t.insertBefore(e,n):t.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Bi(e,n,t),e=e.sibling;e!==null;)Bi(e,n,t),e=e.sibling}var ee=null,Te=!1;function Je(e,n,t){for(t=t.child;t!==null;)nc(e,n,t),t=t.sibling}function nc(e,n,t){if($e&&typeof $e.onCommitFiberUnmount=="function")try{$e.onCommitFiberUnmount(ol,t)}catch{}switch(t.tag){case 5:ie||Yn(t,n);case 6:var r=ee,l=Te;ee=null,Je(e,n,t),ee=r,Te=l,ee!==null&&(Te?(e=ee,t=t.stateNode,e.nodeType===8?e.parentNode.removeChild(t):e.removeChild(t)):ee.removeChild(t.stateNode));break;case 18:ee!==null&&(Te?(e=ee,t=t.stateNode,e.nodeType===8?Vl(e.parentNode,t):e.nodeType===1&&Vl(e,t),At(e)):Vl(ee,t.stateNode));break;case 4:r=ee,l=Te,ee=t.stateNode.containerInfo,Te=!0,Je(e,n,t),ee=r,Te=l;break;case 0:case 11:case 14:case 15:if(!ie&&(r=t.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var i=l,u=i.destroy;i=i.tag,u!==void 0&&(i&2||i&4)&&Ui(t,n,u),l=l.next}while(l!==r)}Je(e,n,t);break;case 1:if(!ie&&(Yn(t,n),r=t.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=t.memoizedProps,r.state=t.memoizedState,r.componentWillUnmount()}catch(s){W(t,n,s)}Je(e,n,t);break;case 21:Je(e,n,t);break;case 22:t.mode&1?(ie=(r=ie)||t.memoizedState!==null,Je(e,n,t),ie=r):Je(e,n,t);break;default:Je(e,n,t)}}function Wo(e){var n=e.updateQueue;if(n!==null){e.updateQueue=null;var t=e.stateNode;t===null&&(t=e.stateNode=new _d),n.forEach(function(r){var l=Fd.bind(null,e,r);t.has(r)||(t.add(r),r.then(l,l))})}}function ze(e,n){var t=n.deletions;if(t!==null)for(var r=0;rl&&(l=u),r&=~i}if(r=l,r=K()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Ld(r/1960))-r,10e?16:e,rn===null)var r=!1;else{if(e=rn,rn=null,rl=0,R&6)throw Error(k(331));var l=R;for(R|=4,S=e.current;S!==null;){var i=S,u=i.child;if(S.flags&16){var s=i.deletions;if(s!==null){for(var a=0;aK()-Tu?Nn(e,0):Lu|=t),me(e,n)}function ac(e,n){n===0&&(e.mode&1?(n=cr,cr<<=1,!(cr&130023424)&&(cr=4194304)):n=1);var t=se();e=Ye(e,n),e!==null&&(bt(e,n,t),me(e,t))}function Dd(e){var n=e.memoizedState,t=0;n!==null&&(t=n.retryLane),ac(e,t)}function Fd(e,n){var t=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(t=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(k(314))}r!==null&&r.delete(n),ac(e,t)}var cc;cc=function(e,n,t){if(e!==null)if(e.memoizedProps!==n.pendingProps||pe.current)de=!0;else{if(!(e.lanes&t)&&!(n.flags&128))return de=!1,Ed(e,n,t);de=!!(e.flags&131072)}else de=!1,U&&n.flags&1048576&&ha(n,Yr,n.index);switch(n.lanes=0,n.tag){case 2:var r=n.type;Rr(e,n),e=n.pendingProps;var l=rt(n,ue.current);et(n,t),l=Eu(null,n,r,e,l,t);var i=Nu();return n.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(n.tag=1,n.memoizedState=null,n.updateQueue=null,he(r)?(i=!0,Gr(n)):i=!1,n.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,xu(n),l.updater=hl,n.stateNode=l,l._reactInternals=n,Ti(n,r,e,t),n=Ii(null,n,r,!0,i,t)):(n.tag=0,U&&i&&du(n),oe(null,n,l,t),n=n.child),n;case 16:r=n.elementType;e:{switch(Rr(e,n),e=n.pendingProps,l=r._init,r=l(r._payload),n.type=r,l=n.tag=$d(r),e=Le(r,e),l){case 0:n=Mi(null,n,r,e,t);break e;case 1:n=$o(null,n,r,e,t);break e;case 11:n=Fo(null,n,r,e,t);break e;case 14:n=Uo(null,n,r,Le(r.type,e),t);break e}throw Error(k(306,r,""))}return n;case 0:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:Le(r,l),Mi(e,n,r,l,t);case 1:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:Le(r,l),$o(e,n,r,l,t);case 3:e:{if(Ka(n),e===null)throw Error(k(387));r=n.pendingProps,i=n.memoizedState,l=i.element,wa(e,n),Jr(n,r,null,t);var u=n.memoizedState;if(r=u.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:u.cache,pendingSuspenseBoundaries:u.pendingSuspenseBoundaries,transitions:u.transitions},n.updateQueue.baseState=i,n.memoizedState=i,n.flags&256){l=ot(Error(k(423)),n),n=Ao(e,n,r,t,l);break e}else if(r!==l){l=ot(Error(k(424)),n),n=Ao(e,n,r,t,l);break e}else for(ge=sn(n.stateNode.containerInfo.firstChild),ye=n,U=!0,Re=null,t=ya(n,null,r,t),n.child=t;t;)t.flags=t.flags&-3|4096,t=t.sibling;else{if(lt(),r===l){n=Ze(e,n,t);break e}oe(e,n,r,t)}n=n.child}return n;case 5:return ka(n),e===null&&Pi(n),r=n.type,l=n.pendingProps,i=e!==null?e.memoizedProps:null,u=l.children,ji(r,l)?u=null:i!==null&&ji(r,i)&&(n.flags|=32),Ga(e,n),oe(e,n,u,t),n.child;case 6:return e===null&&Pi(n),null;case 13:return Ya(e,n,t);case 4:return wu(n,n.stateNode.containerInfo),r=n.pendingProps,e===null?n.child=it(n,null,r,t):oe(e,n,r,t),n.child;case 11:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:Le(r,l),Fo(e,n,r,l,t);case 7:return oe(e,n,n.pendingProps,t),n.child;case 8:return oe(e,n,n.pendingProps.children,t),n.child;case 12:return oe(e,n,n.pendingProps.children,t),n.child;case 10:e:{if(r=n.type._context,l=n.pendingProps,i=n.memoizedProps,u=l.value,O(Zr,r._currentValue),r._currentValue=u,i!==null)if(Oe(i.value,u)){if(i.children===l.children&&!pe.current){n=Ze(e,n,t);break e}}else for(i=n.child,i!==null&&(i.return=n);i!==null;){var s=i.dependencies;if(s!==null){u=i.child;for(var a=s.firstContext;a!==null;){if(a.context===r){if(i.tag===1){a=Qe(-1,t&-t),a.tag=2;var f=i.updateQueue;if(f!==null){f=f.shared;var g=f.pending;g===null?a.next=a:(a.next=g.next,g.next=a),f.pending=a}}i.lanes|=t,a=i.alternate,a!==null&&(a.lanes|=t),zi(i.return,t,n),s.lanes|=t;break}a=a.next}}else if(i.tag===10)u=i.type===n.type?null:i.child;else if(i.tag===18){if(u=i.return,u===null)throw Error(k(341));u.lanes|=t,s=u.alternate,s!==null&&(s.lanes|=t),zi(u,t,n),u=i.sibling}else u=i.child;if(u!==null)u.return=i;else for(u=i;u!==null;){if(u===n){u=null;break}if(i=u.sibling,i!==null){i.return=u.return,u=i;break}u=u.return}i=u}oe(e,n,l.children,t),n=n.child}return n;case 9:return l=n.type,r=n.pendingProps.children,et(n,t),l=Ce(l),r=r(l),n.flags|=1,oe(e,n,r,t),n.child;case 14:return r=n.type,l=Le(r,n.pendingProps),l=Le(r.type,l),Uo(e,n,r,l,t);case 15:return Wa(e,n,n.type,n.pendingProps,t);case 17:return r=n.type,l=n.pendingProps,l=n.elementType===r?l:Le(r,l),Rr(e,n),n.tag=1,he(r)?(e=!0,Gr(n)):e=!1,et(n,t),Ba(n,r,l),Ti(n,r,l,t),Ii(null,n,r,!0,e,t);case 19:return Za(e,n,t);case 22:return Qa(e,n,t)}throw Error(k(156,n.tag))};function fc(e,n){return Us(e,n)}function Ud(e,n,t,r){this.tag=e,this.key=t,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=n,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ee(e,n,t,r){return new Ud(e,n,t,r)}function Ou(e){return e=e.prototype,!(!e||!e.isReactComponent)}function $d(e){if(typeof e=="function")return Ou(e)?1:0;if(e!=null){if(e=e.$$typeof,e===eu)return 11;if(e===nu)return 14}return 2}function dn(e,n){var t=e.alternate;return t===null?(t=Ee(e.tag,n,e.key,e.mode),t.elementType=e.elementType,t.type=e.type,t.stateNode=e.stateNode,t.alternate=e,e.alternate=t):(t.pendingProps=n,t.type=e.type,t.flags=0,t.subtreeFlags=0,t.deletions=null),t.flags=e.flags&14680064,t.childLanes=e.childLanes,t.lanes=e.lanes,t.child=e.child,t.memoizedProps=e.memoizedProps,t.memoizedState=e.memoizedState,t.updateQueue=e.updateQueue,n=e.dependencies,t.dependencies=n===null?null:{lanes:n.lanes,firstContext:n.firstContext},t.sibling=e.sibling,t.index=e.index,t.ref=e.ref,t}function Or(e,n,t,r,l,i){var u=2;if(r=e,typeof e=="function")Ou(e)&&(u=1);else if(typeof e=="string")u=5;else e:switch(e){case $n:return Cn(t.children,l,i,n);case bi:u=8,l|=8;break;case ni:return e=Ee(12,t,n,l|2),e.elementType=ni,e.lanes=i,e;case ti:return e=Ee(13,t,n,l),e.elementType=ti,e.lanes=i,e;case ri:return e=Ee(19,t,n,l),e.elementType=ri,e.lanes=i,e;case ks:return gl(t,l,i,n);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case xs:u=10;break e;case ws:u=9;break e;case eu:u=11;break e;case nu:u=14;break e;case qe:u=16,r=null;break e}throw Error(k(130,e==null?e:typeof e,""))}return n=Ee(u,t,n,l),n.elementType=e,n.type=r,n.lanes=i,n}function Cn(e,n,t,r){return e=Ee(7,e,r,n),e.lanes=t,e}function gl(e,n,t,r){return e=Ee(22,e,r,n),e.elementType=ks,e.lanes=t,e.stateNode={isHidden:!1},e}function Xl(e,n,t){return e=Ee(6,e,null,n),e.lanes=t,e}function Jl(e,n,t){return n=Ee(4,e.children!==null?e.children:[],e.key,n),n.lanes=t,n.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},n}function Ad(e,n,t,r,l){this.tag=n,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Tl(0),this.expirationTimes=Tl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Tl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Du(e,n,t,r,l,i,u,s,a){return e=new Ad(e,n,t,s,a),n===1?(n=1,i===!0&&(n|=8)):n=0,i=Ee(3,null,null,n),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:t,cache:null,transitions:null,pendingSuspenseBoundaries:null},xu(i),e}function Bd(e,n,t){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(mc)}catch(e){console.error(e)}}mc(),ms.exports=we;var Gd=ms.exports,qo=Gd;bl.createRoot=qo.createRoot,bl.hydrateRoot=qo.hydrateRoot;async function Fn(e){const n=await fetch(e);if(!n.ok)throw new Error(`${e} → ${n.status}`);return n.json()}const _n={instances:()=>Fn("/api/instances"),instance:e=>Fn(`/api/instances/${encodeURIComponent(e)}`),forges:(e={})=>{const n=new URLSearchParams;e.role&&n.set("role",e.role),e.status&&n.set("status",e.status);const t=n.toString();return Fn("/api/forges"+(t?"?"+t:""))},forge:e=>Fn(`/api/forges/${encodeURIComponent(e)}`),log:(e,n,t=200)=>Fn(`/api/forges/${encodeURIComponent(e)}/log/${n}?tail=${t}`),ledger:(e={})=>{const n=new URLSearchParams;e.limit&&n.set("limit",String(e.limit)),e.shape&&n.set("shape",e.shape),e.outcome&&n.set("outcome",e.outcome),e.role&&n.set("role",e.role);const t=n.toString();return Fn("/api/ledger"+(t?"?"+t:""))}};function Au(e){if(e==null)return"—";if(e<60)return`${e}m`;const n=Math.floor(e/60),t=e%60;return`${n}h${t?` ${t}m`:""}`}function Bu(e){return e.replace("__","/")}function Pn(e,n=[]){const[t,r]=A.useState(null),[l,i]=A.useState(null),[u,s]=A.useState(!0),[a,f]=A.useState(null),[g,m]=A.useState(0),h=A.useCallback(()=>m(y=>y+1),[]);return A.useEffect(()=>{let y=!1;return s(!0),e().then(x=>{y||(r(x),i(null),f(new Date))}).catch(x=>{y||i(x instanceof Error?x.message:String(x))}).finally(()=>{y||s(!1)}),()=>{y=!0}},[...n,g]),{data:t,error:l,loading:u,loadedAt:a,reload:h}}function Sl(e){return e?`loaded ${e.toLocaleTimeString()}`:""}function Kd(){const{data:e,error:n,loading:t,loadedAt:r,reload:l}=Pn(()=>_n.instances(),[]);return o.jsxs("div",{children:[o.jsxs("div",{className:"section-title",children:[o.jsx("span",{children:"Instances"}),e&&o.jsxs("span",{className:"count",children:["(",e.length," installed)"]}),o.jsx("div",{style:{flex:1}}),o.jsx("span",{className:"refresh-info",children:Sl(r)}),o.jsx("button",{onClick:l,disabled:t,children:"Refresh"})]}),n&&o.jsxs("div",{className:"error",children:["error: ",n]}),!n&&e&&e.length===0&&o.jsxs("div",{className:"empty",children:["No instances installed. Run ",o.jsx("code",{children:"/lmstack:install"})," to add one."]}),o.jsx("div",{className:"inst-list",children:e==null?void 0:e.map(i=>o.jsx(Yd,{inst:i},i.role))})]})}function Yd({inst:e}){var r,l,i,u,s,a,f,g,m,h,y;const n=e.counts.running+e.counts.in_review+e.counts.queued+e.counts.merged+e.counts.failed+e.counts.cleaned+e.counts.stale,t=[!e.sources.hostYaml&&"host.yml",!e.sources.probeJson&&"probe.json",!e.sources.classifyJson&&"classify.json"].filter(Boolean);return o.jsxs("section",{className:"inst",children:[o.jsxs("header",{className:"inst-hdr",children:[o.jsx(Zd,{vendor:((r=e.gpu)==null?void 0:r.vendor)??null}),o.jsxs("div",{className:"inst-hdr-main",children:[o.jsx("h2",{children:e.role}),o.jsxs("div",{className:"inst-sub",children:[(l=e.gpu)!=null&&l.model?o.jsx("span",{children:e.gpu.model}):o.jsx("span",{className:"muted",children:"unknown GPU"}),e.engine.kind&&o.jsx("span",{className:"dot",children:"·"}),e.engine.kind&&o.jsx("span",{children:bo(e.engine.kind)}),e.connection&&o.jsx("span",{className:"dot",children:"·"}),e.connection&&o.jsx("span",{children:e.connection==="local"?"localhost":e.connection})]})]}),o.jsxs("div",{className:"inst-hdr-status",children:[e.verdict&&o.jsx("span",{className:`badge verdict-${e.verdict}`,children:e.verdict}),o.jsxs("a",{href:"#/forges",className:"btn-link",children:["view ",n," forge",n===1?"":"s"," →"]})]})]}),t.length>0&&o.jsxs("div",{className:"inst-hint",children:["Missing on disk: ",t.map(x=>o.jsx("code",{children:x},x)).reduce((x,v,I)=>I===0?[v]:[...x,", ",v],[]),"."," ","Run ",o.jsxs("code",{children:["/lmstack:analyze ",e.connection||""]})," to populate hardware & engine details."]}),o.jsxs("div",{className:"inst-grid",children:[o.jsxs(Sr,{title:"Hardware",children:[o.jsx(H,{k:"GPU",v:(i=e.gpu)==null?void 0:i.model}),o.jsx(H,{k:"VRAM",v:jr((u=e.gpu)==null?void 0:u.vramGib)}),o.jsx(H,{k:"GTT",v:jr((s=e.gpu)==null?void 0:s.gttGib)}),o.jsx(H,{k:"Driver",v:(a=e.gpu)==null?void 0:a.driver}),o.jsx(H,{k:"System RAM",v:jr((f=e.memory)==null?void 0:f.totalGib)})]}),o.jsxs(Sr,{title:"Inference engine",children:[o.jsx(H,{k:"Engine",v:bo(e.engine.kind)}),o.jsx(H,{k:"Role",v:e.engine.host||e.role}),o.jsx(H,{k:"Reason",v:e.engine.reason}),o.jsx(H,{k:"Docker",v:ep(e.docker)}),o.jsx(H,{k:"Runtimes",v:((g=e.docker)==null?void 0:g.runtimes.join(", "))||null}),o.jsx(H,{k:"Vulkan",v:e.vulkan?e.vulkan.present?e.vulkan.device||"yes":"no":null})]}),o.jsxs(Sr,{title:"Operating system",children:[o.jsx(H,{k:"OS",v:(m=e.os)==null?void 0:m.pretty}),o.jsx(H,{k:"Kernel",v:(h=e.os)==null?void 0:h.kernel}),o.jsx(H,{k:"Arch",v:(y=e.os)==null?void 0:y.arch}),o.jsx(H,{k:"Installed",v:e.installedAt})]}),o.jsxs(Sr,{title:"Forge activity",children:[o.jsx(H,{k:"Running",v:e.counts.running}),o.jsx(H,{k:"In review",v:e.counts.in_review}),o.jsx(H,{k:"Queued",v:e.counts.queued}),o.jsx(H,{k:"Merged",v:e.counts.merged}),o.jsx(H,{k:"Cleaned",v:e.counts.cleaned}),o.jsx(H,{k:"Failed",v:e.counts.failed}),e.counts.stale>0&&o.jsx(H,{k:"Stale",v:e.counts.stale})]})]}),e.models.length>0&&o.jsxs("div",{className:"inst-models",children:[o.jsx("h3",{children:"Models"}),o.jsxs("table",{className:"table dense",children:[o.jsx("thead",{children:o.jsxs("tr",{children:[o.jsx("th",{children:"slug"}),o.jsx("th",{children:"hf model"}),o.jsx("th",{children:"context"}),o.jsx("th",{children:"max seqs"}),o.jsx("th",{children:"VRAM est."}),o.jsx("th",{children:"port"}),o.jsx("th",{children:"tier"}),o.jsx("th",{children:"active"})]})}),o.jsx("tbody",{children:e.models.map(x=>o.jsxs("tr",{children:[o.jsx("td",{className:"mono",children:x.slug??"—"}),o.jsx("td",{className:"mono",children:x.hfModel??"—"}),o.jsx("td",{className:"mono",children:bd(x.contextTokens)}),o.jsx("td",{className:"mono",children:x.maxNumSeqs??"—"}),o.jsx("td",{className:"mono",children:jr(x.vramEstimateGib)}),o.jsx("td",{className:"mono",children:x.port??"—"}),o.jsx("td",{className:"mono",children:x.tier??"—"}),o.jsx("td",{children:x.active?o.jsx("span",{className:"badge merged",children:"active"}):o.jsx("span",{className:"badge cleaned",children:"idle"})})]},x.slug??String(Math.random())))})]})]}),(e.arithmetic.length>0||e.warnings.length>0)&&o.jsxs("div",{className:"inst-extra",children:[e.arithmetic.length>0&&o.jsxs("div",{className:"inst-extra-block",children:[o.jsx("h3",{children:"Memory arithmetic"}),o.jsx("pre",{children:e.arithmetic.join(` +`)})]}),e.warnings.length>0&&o.jsxs("div",{className:"inst-extra-block",children:[o.jsx("h3",{children:"Warnings"}),o.jsx("ul",{children:e.warnings.map((x,v)=>o.jsx("li",{children:x},v))})]})]})]})}function Sr({title:e,children:n}){return o.jsxs("div",{className:"inst-sec",children:[o.jsx("h3",{children:e}),o.jsx("dl",{children:n})]})}function H({k:e,v:n}){const t=n==null||n===""||n===void 0;return o.jsxs(o.Fragment,{children:[o.jsx("dt",{children:e}),o.jsx("dd",{className:t?"muted":"",children:t?"—":n})]})}function Zd({vendor:e}){const n=(e||"").toLowerCase();return n==="nvidia"?o.jsxs("div",{className:"vendor vendor-nvidia","aria-label":"NVIDIA",children:[o.jsx(Xd,{}),o.jsx("span",{children:"NVIDIA"})]}):n==="amd"?o.jsxs("div",{className:"vendor vendor-amd","aria-label":"AMD",children:[o.jsx(Jd,{}),o.jsx("span",{children:"AMD"})]}):o.jsxs("div",{className:"vendor vendor-generic","aria-label":"GPU",children:[o.jsx(qd,{}),o.jsx("span",{children:"GPU"})]})}function Xd(){return o.jsxs("svg",{viewBox:"0 0 48 48",fill:"none","aria-hidden":"true",children:[o.jsx("rect",{width:"48",height:"48",rx:"10",fill:"#76b900"}),o.jsx("text",{x:"24",y:"33",textAnchor:"middle",fontFamily:"Inter, Arial, sans-serif",fontWeight:"800",fontSize:"26",fill:"#ffffff",children:"N"})]})}function Jd(){return o.jsxs("svg",{viewBox:"0 0 48 48",fill:"none","aria-hidden":"true",children:[o.jsx("rect",{width:"48",height:"48",rx:"10",fill:"#ed1c24"}),o.jsx("text",{x:"24",y:"33",textAnchor:"middle",fontFamily:"Inter, Arial, sans-serif",fontWeight:"800",fontSize:"26",fill:"#ffffff",children:"A"})]})}function qd(){return o.jsxs("svg",{viewBox:"0 0 48 48",fill:"none","aria-hidden":"true",children:[o.jsx("rect",{width:"48",height:"48",rx:"10",fill:"#656d76"}),o.jsx("text",{x:"24",y:"33",textAnchor:"middle",fontFamily:"Inter, Arial, sans-serif",fontWeight:"800",fontSize:"18",fill:"#ffffff",children:"GPU"})]})}function jr(e){return e==null?null:`${e} GiB`}function bd(e){return e==null?"—":e>=1024?`${(e/1024).toFixed(e%1024===0?0:1)}K`:String(e)}function ep(e){return e?e.present?e.usable?e.version||"usable":`${e.version??"present"} (not usable)`:"not installed":null}function bo(e){return e?{vllm:"vLLM",llamacpp:"llama.cpp"}[e]??e:null}const es={queued:"○ queued",running:"● running","in-review":"◐ in-review",merged:"✓ merged",failed:"✗ failed",cleaned:"· cleaned",stale:"! stale"};function vc({status:e}){const n=e in es?e:"queued";return o.jsx("span",{className:`badge ${n}`,children:es[n]??e})}const np=[{title:"Running",statuses:["running"]},{title:"In review",statuses:["in-review"]},{title:"Queued",statuses:["queued"]},{title:"Completed",statuses:["merged","cleaned"]},{title:"Failed",statuses:["failed"]},{title:"Stale",statuses:["stale"]}];function tp(){var h;const[e,n]=A.useState(""),[t,r]=A.useState(""),{data:l,error:i,loading:u,loadedAt:s,reload:a}=Pn(()=>_n.forges(),[]),f=Pn(()=>_n.instances(),[]),g=A.useMemo(()=>l?l.filter(y=>!(e&&y.role!==e||t&&y.status!==t)):null,[l,e,t]),m=A.useMemo(()=>g?np.map(y=>({title:y.title,forges:g.filter(x=>y.statuses.includes(x.status))})):null,[g]);return o.jsxs("div",{children:[o.jsxs("div",{className:"section-title",children:[o.jsx("span",{children:"Forges"}),g&&o.jsxs("span",{className:"count",children:["(",g.length," shown)"]}),o.jsx("div",{style:{flex:1}}),o.jsx("span",{className:"refresh-info",children:Sl(s)}),o.jsx("button",{onClick:a,disabled:u,children:"Refresh"})]}),o.jsxs("div",{className:"filters",children:[o.jsx("label",{children:"host: "}),o.jsxs("select",{value:e,onChange:y=>n(y.target.value),children:[o.jsx("option",{value:"",children:"all"}),(h=f.data)==null?void 0:h.map(y=>o.jsx("option",{value:y.role,children:y.role},y.role))]}),o.jsx("label",{children:"status: "}),o.jsxs("select",{value:t,onChange:y=>r(y.target.value),children:[o.jsx("option",{value:"",children:"all"}),o.jsx("option",{value:"running",children:"running"}),o.jsx("option",{value:"in-review",children:"in-review"}),o.jsx("option",{value:"queued",children:"queued"}),o.jsx("option",{value:"merged",children:"merged"}),o.jsx("option",{value:"cleaned",children:"cleaned"}),o.jsx("option",{value:"failed",children:"failed"}),o.jsx("option",{value:"stale",children:"stale"})]})]}),i&&o.jsxs("div",{className:"error",children:["error: ",i]}),g&&g.length===0&&!i&&o.jsx("div",{className:"empty",children:"No forges match the current filters."}),m==null?void 0:m.map(y=>y.forges.length>0?o.jsx(rp,{title:y.title,forges:y.forges},y.title):null)]})}function rp({title:e,forges:n}){return o.jsxs("div",{style:{marginTop:16},children:[o.jsxs("div",{className:"section-title",children:[o.jsx("span",{children:e}),o.jsxs("span",{className:"count",children:["(",n.length,")"]})]}),o.jsxs("table",{className:"table",children:[o.jsx("thead",{children:o.jsxs("tr",{children:[o.jsx("th",{children:"status"}),o.jsx("th",{children:"key"}),o.jsx("th",{children:"shape"}),o.jsx("th",{children:"tier"}),o.jsx("th",{children:"host"}),o.jsx("th",{children:"wall"}),o.jsx("th",{children:"judge"}),o.jsx("th",{children:"pr"})]})}),o.jsx("tbody",{children:n.map(t=>o.jsxs("tr",{onClick:()=>{window.location.hash=`#/forge/${encodeURIComponent(t.key)}`},children:[o.jsx("td",{children:o.jsx(vc,{status:t.status})}),o.jsx("td",{className:"key",children:Bu(t.key)}),o.jsx("td",{children:t.shape??"—"}),o.jsx("td",{children:t.tier??"—"}),o.jsx("td",{children:t.role}),o.jsx("td",{className:"mono",children:Au(t.wallMin)}),o.jsx("td",{className:"mono",children:t.judgeRounds||"—"}),o.jsx("td",{className:"mono",children:t.pr??"—"})]},t.key))})]})]})}function lp({forgeKey:e}){const n=Pn(()=>_n.forge(e),[e]),t=Pn(()=>_n.log(e,"exec",200),[e]),r=Pn(()=>_n.log(e,"judge",200),[e]),l=()=>{n.reload(),t.reload(),r.reload()},i=n.loading||t.loading||r.loading;return o.jsxs("div",{children:[o.jsxs("div",{className:"section-title",children:[o.jsx("a",{href:"#/forges",children:"← forges"}),o.jsx("div",{style:{flex:1}}),o.jsx("span",{className:"refresh-info",children:Sl(n.loadedAt)}),o.jsx("button",{onClick:l,disabled:i,children:"Refresh"})]}),n.error&&o.jsxs("div",{className:"error",children:["error: ",n.error]}),n.data&&o.jsx(ip,{data:n.data,execLog:t.data,judgeLog:r.data})]})}function ip({data:e,execLog:n,judgeLog:t}){const{task:r,run:l,ledger:i}=e,u=r.status??"queued",s=r.url,a=r.pr,f=r.tier,g=r.shape;return o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"detail-header",children:[o.jsx("span",{className:"title",children:Bu(e.task.key)}),o.jsx(vc,{status:u}),s&&o.jsx("a",{href:s,target:"_blank",rel:"noreferrer",children:"↗ issue"}),a&&o.jsx("a",{href:a,target:"_blank",rel:"noreferrer",children:"↗ pr"})]}),o.jsxs("div",{className:"detail-meta",children:[o.jsx("span",{className:"k",children:"host"}),o.jsx("span",{className:"v",children:e.role}),o.jsx("span",{className:"k",children:"shape"}),o.jsx("span",{className:"v",children:g??"—"}),o.jsx("span",{className:"k",children:"tier"}),o.jsx("span",{className:"v",children:f??"—"}),o.jsx("span",{className:"k",children:"title"}),o.jsx("span",{className:"v",style:{fontFamily:"inherit"},children:r.title??"—"}),o.jsx("span",{className:"k",children:"started"}),o.jsx("span",{className:"v",children:l.startedAt??"—"}),o.jsx("span",{className:"k",children:"ended"}),o.jsx("span",{className:"v",children:l.endedAt??"—"}),o.jsx("span",{className:"k",children:"tmux session"}),o.jsxs("span",{className:"v",children:["lmstack-",e.slug," ",l.tmuxAlive?"(alive ✓)":"(not running)"]}),o.jsx("span",{className:"k",children:"worktree"}),o.jsxs("span",{className:"v",children:[l.worktreePath??"—"," ",l.worktreePath?l.worktreeExists?"":"(missing)":""]}),o.jsx("span",{className:"k",children:"branch"}),o.jsx("span",{className:"v",children:l.branch??"—"}),i&&o.jsxs(o.Fragment,{children:[o.jsx("span",{className:"k",children:"outcome"}),o.jsxs("span",{className:"v",children:[String(i.outcome??"—")," · wall ",Au(i.wall_min)," · interventions ",String(i.interventions??0)]})]})]}),o.jsxs("div",{className:"panel",children:[o.jsx("h3",{children:"Brief"}),l.brief?o.jsx("pre",{children:l.brief}):o.jsx("div",{className:"empty",children:"no brief.md on disk"})]}),o.jsxs("div",{className:"panel",children:[o.jsxs("h3",{children:["Judge rounds (",l.judgeRounds.length,")"]}),l.judgeRounds.length===0&&o.jsx("div",{className:"empty",children:"(none yet)"}),l.judgeRounds.map(m=>o.jsxs("div",{style:{marginBottom:12},children:[o.jsxs("div",{style:{color:"var(--muted)",fontSize:12,marginBottom:4},children:["round ",m.n]}),o.jsx("pre",{children:m.text})]},m.n))]}),o.jsxs("div",{className:"logs",children:[o.jsx(ns,{title:"lm-exec",log:n}),o.jsx(ns,{title:"lm-judge",log:t})]})]})}function ns({title:e,log:n}){return o.jsxs("div",{className:"log-pane",children:[o.jsxs("h4",{children:[e,n!=null&&n.truncated?" — tail":""]}),!n&&o.jsx("div",{className:"empty",children:"loading…"}),n&&!n.exists&&o.jsxs("div",{className:"empty",children:["no log file at ",n.path]}),n&&n.exists&&n.lines.length===0&&o.jsx("div",{className:"empty",children:"(empty)"}),n&&n.exists&&n.lines.length>0&&o.jsx("pre",{children:n.lines.join(` +`)})]})}function up(){const{data:e,error:n,loading:t,loadedAt:r,reload:l}=Pn(()=>_n.ledger({limit:500}),[]),[i,u]=A.useState(""),[s,a]=A.useState(""),[f,g]=A.useState(""),m=A.useMemo(()=>ql(e==null?void 0:e.map(v=>v.shape).filter(v=>!!v)),[e]),h=A.useMemo(()=>ql(e==null?void 0:e.map(v=>v.outcome).filter(v=>!!v)),[e]),y=A.useMemo(()=>ql(e==null?void 0:e.map(v=>v.host_role).filter(v=>!!v)),[e]),x=A.useMemo(()=>e?e.filter(v=>!(i&&v.shape!==i||s&&v.outcome!==s||f&&v.host_role!==f)):null,[e,i,s,f]);return o.jsxs("div",{children:[o.jsxs("div",{className:"section-title",children:[o.jsx("span",{children:"Ledger"}),x&&o.jsxs("span",{className:"count",children:["(",x.length," of ",(e==null?void 0:e.length)??0," runs)"]}),o.jsx("div",{style:{flex:1}}),o.jsx("span",{className:"refresh-info",children:Sl(r)}),o.jsx("button",{onClick:l,disabled:t,children:"Refresh"})]}),o.jsxs("div",{className:"filters",children:[o.jsx("label",{children:"shape: "}),o.jsxs("select",{value:i,onChange:v=>u(v.target.value),children:[o.jsx("option",{value:"",children:"all"}),m.map(v=>o.jsx("option",{value:v,children:v},v))]}),o.jsx("label",{children:"outcome: "}),o.jsxs("select",{value:s,onChange:v=>a(v.target.value),children:[o.jsx("option",{value:"",children:"all"}),h.map(v=>o.jsx("option",{value:v,children:v},v))]}),o.jsx("label",{children:"role: "}),o.jsxs("select",{value:f,onChange:v=>g(v.target.value),children:[o.jsx("option",{value:"",children:"all"}),y.map(v=>o.jsx("option",{value:v,children:v},v))]})]}),n&&o.jsxs("div",{className:"error",children:["error: ",n]}),x&&x.length===0&&!n&&o.jsx("div",{className:"empty",children:"No ledger entries."}),x&&x.length>0&&o.jsxs("table",{className:"table",children:[o.jsx("thead",{children:o.jsxs("tr",{children:[o.jsx("th",{children:"ended (UTC)"}),o.jsx("th",{children:"key"}),o.jsx("th",{children:"shape"}),o.jsx("th",{children:"tier"}),o.jsx("th",{children:"host"}),o.jsx("th",{children:"outcome"}),o.jsx("th",{children:"wall"}),o.jsx("th",{children:"judge"}),o.jsx("th",{children:"pr"}),o.jsx("th",{children:"int."})]})}),o.jsx("tbody",{children:x.map((v,I)=>o.jsxs("tr",{onClick:()=>{window.location.hash=`#/forge/${encodeURIComponent(v.key)}`},children:[o.jsx("td",{className:"mono",children:op(v.ended??v.ts)}),o.jsx("td",{className:"key",children:Bu(v.key)}),o.jsx("td",{children:v.shape??"—"}),o.jsx("td",{children:v.tier??"—"}),o.jsx("td",{children:v.host_role}),o.jsx("td",{children:v.outcome}),o.jsx("td",{className:"mono",children:Au(v.wall_min)}),o.jsx("td",{className:"mono",children:v.judge_rounds||"—"}),o.jsx("td",{className:"mono",children:v.pr??"—"}),o.jsx("td",{className:"mono",children:v.interventions??0})]},`${v.key}-${v.ts}-${I}`))})]})]})}function ql(e){return e?Array.from(new Set(e)).sort():[]}function op(e){return e?e.replace("T"," ").replace(/\..*Z?$/,"").replace(/Z$/,""):"—"}const sp="https://github.com/ric03uec/lmstack",ap="https://ric03uec.github.io/lmstack/";function ts(){const e=window.location.hash.replace(/^#\/?/,"");return!e||e==="instances"?{name:"instances"}:e==="forges"?{name:"forges"}:e==="ledger"?{name:"ledger"}:e.startsWith("forge/")?{name:"forge",key:decodeURIComponent(e.slice(6))}:{name:"instances"}}function cp(){const[e,n]=A.useState(ts());A.useEffect(()=>{const r=()=>n(ts());return window.addEventListener("hashchange",r),()=>window.removeEventListener("hashchange",r)},[]);const t=r=>e.name===r||r==="forges"&&e.name==="forge";return o.jsxs("div",{className:"app",children:[o.jsxs("header",{className:"header",children:[o.jsxs("a",{className:"brand",href:"#/instances",children:[o.jsx("img",{src:"./lmstack.svg",alt:""}),o.jsx("span",{className:"name",children:"lmstack"}),o.jsx("span",{className:"tagline",children:"put your GPUs to work"})]}),o.jsx("div",{className:"spacer"}),o.jsxs("div",{className:"links",children:[o.jsxs("a",{href:ap,target:"_blank",rel:"noreferrer",title:"Documentation",children:[o.jsx(rs,{})," Docs"]}),o.jsxs("a",{href:sp,target:"_blank",rel:"noreferrer",title:"Source on GitHub",children:[o.jsx(fp,{})," GitHub"]})]})]}),o.jsx("aside",{className:"sidebar",children:o.jsxs("nav",{children:[o.jsxs("a",{href:"#/instances",className:t("instances")?"active":"",children:[o.jsx("span",{className:"icon",children:o.jsx(dp,{})})," Instances"]}),o.jsxs("a",{href:"#/forges",className:t("forges")?"active":"",children:[o.jsx("span",{className:"icon",children:o.jsx(pp,{})})," Forges"]}),o.jsxs("a",{href:"#/ledger",className:t("ledger")?"active":"",children:[o.jsx("span",{className:"icon",children:o.jsx(rs,{})})," Ledger"]})]})}),o.jsxs("main",{className:"main",children:[e.name==="instances"&&o.jsx(Kd,{}),e.name==="forges"&&o.jsx(tp,{}),e.name==="forge"&&o.jsx(lp,{forgeKey:e.key}),e.name==="ledger"&&o.jsx(up,{})]})]})}function fp(){return o.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:o.jsx("path",{d:"M8 0C3.58 0 0 3.58 0 8a8 8 0 0 0 5.47 7.59c.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"})})}function rs(){return o.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:o.jsx("path",{d:"M0 1.75A.75.75 0 0 1 .75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0 1 11.006 1h4.245a.75.75 0 0 1 .75.75v10.5a.75.75 0 0 1-.75.75h-4.507a2.25 2.25 0 0 0-1.591.659l-.622.621a.75.75 0 0 1-1.06 0l-.622-.621A2.25 2.25 0 0 0 5.258 13H.75a.75.75 0 0 1-.75-.75Zm7.251 10.324.004-5.073-.002-2.253A2.25 2.25 0 0 0 5.003 2.5H1.5v9h3.757a3.75 3.75 0 0 1 1.994.574Zm1.504-5.076v5.076a3.75 3.75 0 0 1 1.994-.574H14.5v-9h-3.495a2.25 2.25 0 0 0-2.25 2.248l-.004 2.25Z"})})}function dp(){return o.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:o.jsx("path",{d:"M2 2.75C2 1.784 2.784 1 3.75 1h8.5c.966 0 1.75.784 1.75 1.75v2.5A1.75 1.75 0 0 1 12.25 7h-8.5A1.75 1.75 0 0 1 2 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25Zm-1.75 8c0-.966.784-1.75 1.75-1.75h8.5c.966 0 1.75.784 1.75 1.75v2.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25Zm1.75-.25a.25.25 0 0 0-.25.25v2.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-2.5a.25.25 0 0 0-.25-.25ZM5 4a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-1 8a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"})})}function pp(){return o.jsx("svg",{viewBox:"0 0 16 16",fill:"currentColor","aria-hidden":"true",children:o.jsx("path",{d:"M9.53.22a.75.75 0 0 1 1.06 0l4.19 4.19a.75.75 0 0 1 0 1.06L13.06 7l1.03 1.03a1.75 1.75 0 0 1 0 2.48l-1.55 1.54a1.75 1.75 0 0 1-2.47 0L8 9l-6.42 6.42a.75.75 0 1 1-1.06-1.06L6.94 8 3.85 4.9a.75.75 0 0 1 0-1.06L5.4 2.29a1.75 1.75 0 0 1 2.47 0L9 3.44 9.53.22Zm-3.72 3.13a.25.25 0 0 0-.35 0L4.47 4.35 8.5 8.38l1.35-1.35Z"})})}bl.createRoot(document.getElementById("root")).render(o.jsx(Ic.StrictMode,{children:o.jsx(cp,{})})); diff --git a/ui/dist/assets/index-C39-GzIs.css b/ui/dist/assets/index-C39-GzIs.css new file mode 100644 index 0000000..056adcf --- /dev/null +++ b/ui/dist/assets/index-C39-GzIs.css @@ -0,0 +1 @@ +:root{--bg: #f6f8fa;--panel: #ffffff;--panel-hi: #f0f3f6;--border: #d0d7de;--border-strong: #afb8c1;--fg: #1f2328;--muted: #656d76;--accent: #0969da;--accent-soft: #ddf4ff;--ok: #1a7f37;--warn: #9a6700;--err: #cf222e;--run: #0969da;--review: #9a6700;--queued: #656d76;--sidebar-w: 220px;--header-h: 56px;--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--fg);font-family:var(--font-sans);font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}button{background:var(--panel);color:var(--fg);border:1px solid var(--border-strong);padding:6px 14px;border-radius:6px;cursor:pointer;font:inherit;font-size:14px}button:hover{border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}select,input[type=text]{background:var(--panel);color:var(--fg);border:1px solid var(--border-strong);padding:6px 10px;border-radius:6px;font:inherit;font-size:14px}code,pre{font-family:var(--font-mono)}.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;grid-template-rows:var(--header-h) 1fr;grid-template-areas:"header header" "sidebar main";min-height:100vh}.header{grid-area:header;background:var(--panel);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;padding:0 20px}.header .brand{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600;color:var(--fg)}.header .brand img{width:28px;height:28px;display:block}.header .brand .name{letter-spacing:-.01em}.header .brand .tagline{color:var(--muted);font-size:13.5px;font-weight:400;letter-spacing:0;padding-left:10px;margin-left:4px;border-left:1px solid var(--border)}.header .brand a{color:inherit}.header .spacer{flex:1}.header .links{display:flex;align-items:center;gap:16px}.header .links a{color:var(--muted);font-size:14px;display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px}.header .links a:hover{background:var(--panel-hi);color:var(--fg);text-decoration:none}.header .links svg{width:18px;height:18px}.sidebar{grid-area:sidebar;background:var(--panel);border-right:1px solid var(--border);padding:16px 8px}.sidebar nav{display:flex;flex-direction:column;gap:2px}.sidebar nav a{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:6px;color:var(--fg);font-size:15px;font-weight:500}.sidebar nav a:hover{background:var(--panel-hi);text-decoration:none}.sidebar nav a.active{background:var(--accent-soft);color:var(--accent)}.sidebar nav a .icon{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center}.sidebar nav a .icon svg{width:18px;height:18px}.main{grid-area:main;padding:24px 28px;max-width:1400px}.section-title{display:flex;align-items:center;gap:12px;margin:8px 0 14px;font-weight:600;font-size:20px}.section-title .count{color:var(--muted);font-weight:400;font-size:14px}.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:14px}.card{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:16px 18px;box-shadow:0 1px #1f23280a}.card h3{margin:0 0 8px;font-size:17px}.card .row{display:flex;justify-content:space-between;color:var(--muted);font-size:14px;padding:2px 0}.card .row strong{color:var(--fg);font-weight:500;text-align:right;margin-left:12px}.inst-list{display:flex;flex-direction:column;gap:16px}.inst{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:20px 24px;box-shadow:0 1px #1f23280a}.inst-hdr{display:flex;align-items:center;gap:16px;margin-bottom:14px}.vendor{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:56px}.vendor svg{width:48px;height:48px;display:block}.vendor span{font-size:11px;font-weight:600;color:var(--muted);letter-spacing:.4px}.vendor-nvidia span{color:#4b7f00}.vendor-amd span{color:#b31219}.inst-hdr-main{flex:1;min-width:0}.inst-hdr-main h2{margin:0;font-size:22px;font-weight:600;letter-spacing:-.01em;font-family:var(--font-mono)}.inst-sub{display:flex;align-items:center;gap:6px;color:var(--muted);font-size:14px;margin-top:4px;flex-wrap:wrap}.inst-sub .dot{opacity:.5}.inst-sub .muted{font-style:italic}.inst-hdr-status{display:flex;align-items:center;gap:12px}.btn-link{color:var(--accent);font-size:14px;padding:6px 12px;border:1px solid var(--border-strong);border-radius:6px;background:var(--panel)}.btn-link:hover{border-color:var(--accent);background:var(--accent-soft);text-decoration:none}.badge.verdict-supported{color:var(--ok);border-color:var(--ok);background:#dcffe4}.badge.verdict-unsupported{color:var(--err);border-color:var(--err);background:#ffebe9}.inst-hint{background:#fff8c5;border:1px solid #d4a72c;color:#63410b;padding:10px 14px;border-radius:6px;font-size:14px;margin-bottom:14px}.inst-hint code{background:#0000000f;padding:1px 6px;border-radius:3px;font-size:13px}.inst-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px 32px}.inst-sec h3{margin:0 0 8px;font-size:12px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.inst-sec dl{margin:0;display:grid;grid-template-columns:max-content 1fr;gap:4px 14px;font-size:14px}.inst-sec dt{color:var(--muted)}.inst-sec dd{margin:0;color:var(--fg);font-family:var(--font-mono);font-size:13.5px;overflow-wrap:anywhere}.inst-sec dd.muted{color:var(--muted);font-family:var(--font-sans);font-style:italic}.inst-models{margin-top:20px}.inst-models h3{margin:0 0 8px;font-size:12px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.table.dense th,.table.dense td{padding:6px 10px;font-size:13.5px}.table.dense tbody tr{cursor:default}.table.dense tbody tr:hover{background:transparent}.inst-extra{margin-top:20px;display:grid;grid-template-columns:1fr 1fr;gap:20px}.inst-extra-block h3{margin:0 0 6px;font-size:12px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.inst-extra-block pre{margin:0;padding:10px 12px;background:var(--panel-hi);border:1px solid var(--border);border-radius:6px;font-size:12.5px;white-space:pre-wrap}.inst-extra-block ul{margin:0;padding-left:20px;font-size:13.5px}@media (max-width: 900px){.inst-extra{grid-template-columns:1fr}}.table{width:100%;border-collapse:collapse;font-size:14px;background:var(--panel);border:1px solid var(--border);border-radius:8px;overflow:hidden}.table th,.table td{padding:10px 12px;border-bottom:1px solid var(--border);text-align:left;vertical-align:middle}.table thead th{background:var(--panel-hi);color:var(--muted);font-weight:500;font-size:13px;text-transform:uppercase;letter-spacing:.4px}.table tbody tr{cursor:pointer}.table tbody tr:hover{background:var(--panel-hi)}.table tbody tr:last-child td{border-bottom:0}.table td.key{font-family:var(--font-mono);font-size:13.5px}.table td.mono{font-family:var(--font-mono);color:var(--muted);font-size:13.5px}.badge{display:inline-block;padding:2px 10px;border-radius:12px;font-size:12.5px;font-weight:500;background:var(--panel-hi);border:1px solid var(--border);color:var(--muted);white-space:nowrap}.badge.running{color:var(--run);border-color:var(--run);background:var(--accent-soft)}.badge.in-review{color:var(--review);border-color:var(--review);background:#fff8c5}.badge.queued{color:var(--queued)}.badge.merged,.badge.completed{color:var(--ok);border-color:var(--ok);background:#dcffe4}.badge.failed{color:var(--err);border-color:var(--err);background:#ffebe9}.badge.cleaned{color:var(--muted)}.badge.stale{color:var(--warn);border-color:var(--warn);background:#fff8c5}.filters{display:flex;gap:14px;align-items:center;margin-bottom:14px;flex-wrap:wrap}.filters label{color:var(--muted);font-size:14px}.detail-header{display:flex;align-items:center;gap:14px;margin:4px 0 14px;flex-wrap:wrap}.detail-header .title{font-size:22px;font-weight:600;font-family:var(--font-mono)}.detail-meta{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px 18px;margin-bottom:14px;font-size:14px;display:grid;grid-template-columns:max-content 1fr;gap:6px 16px}.detail-meta .k{color:var(--muted)}.detail-meta .v{font-family:var(--font-mono);font-size:13.5px;word-break:break-all}.panel{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px 18px;margin-bottom:14px}.panel h3{margin:0 0 10px;font-size:13px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.panel pre{margin:0;white-space:pre-wrap;word-break:break-word;font-size:13.5px;color:var(--fg)}.logs{display:grid;grid-template-columns:1fr 1fr;gap:14px}.log-pane{background:#fff;border:1px solid var(--border);border-radius:8px;height:460px;overflow:auto;padding:10px 14px}.log-pane h4{margin:0 0 8px;font-size:12px;color:var(--muted);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.5px}.log-pane pre{margin:0;font-size:13px;color:var(--fg);white-space:pre}.empty{color:var(--muted);font-style:italic;padding:8px 0;font-size:14px}.error{color:var(--err);padding:10px 14px;border:1px solid var(--err);border-radius:6px;background:#ffebe9;margin:12px 0}.refresh-info{color:var(--muted);font-size:13px;margin-right:10px}@media (max-width: 720px){.app{grid-template-columns:1fr;grid-template-areas:"header" "main"}.sidebar{display:none}.main{padding:16px}.logs{grid-template-columns:1fr}} diff --git a/ui/dist/assets/index-DKizVbia.css b/ui/dist/assets/index-DKizVbia.css deleted file mode 100644 index 4159d18..0000000 --- a/ui/dist/assets/index-DKizVbia.css +++ /dev/null @@ -1 +0,0 @@ -:root{--bg: #f6f8fa;--panel: #ffffff;--panel-hi: #f0f3f6;--border: #d0d7de;--border-strong: #afb8c1;--fg: #1f2328;--muted: #656d76;--accent: #0969da;--accent-soft: #ddf4ff;--ok: #1a7f37;--warn: #9a6700;--err: #cf222e;--run: #0969da;--review: #9a6700;--queued: #656d76;--sidebar-w: 220px;--header-h: 56px;--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{background:var(--bg);color:var(--fg);font-family:var(--font-sans);font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{color:var(--accent);text-decoration:none}a:hover{text-decoration:underline}button{background:var(--panel);color:var(--fg);border:1px solid var(--border-strong);padding:6px 14px;border-radius:6px;cursor:pointer;font:inherit;font-size:14px}button:hover{border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}select,input[type=text]{background:var(--panel);color:var(--fg);border:1px solid var(--border-strong);padding:6px 10px;border-radius:6px;font:inherit;font-size:14px}code,pre{font-family:var(--font-mono)}.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;grid-template-rows:var(--header-h) 1fr;grid-template-areas:"header header" "sidebar main";min-height:100vh}.header{grid-area:header;background:var(--panel);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;padding:0 20px}.header .brand{display:flex;align-items:center;gap:10px;font-size:18px;font-weight:600;color:var(--fg)}.header .brand img{width:28px;height:28px;display:block}.header .brand .name{letter-spacing:-.01em}.header .brand .tagline{color:var(--muted);font-size:13.5px;font-weight:400;letter-spacing:0;padding-left:10px;margin-left:4px;border-left:1px solid var(--border)}.header .brand a{color:inherit}.header .spacer{flex:1}.header .links{display:flex;align-items:center;gap:16px}.header .links a{color:var(--muted);font-size:14px;display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border-radius:6px}.header .links a:hover{background:var(--panel-hi);color:var(--fg);text-decoration:none}.header .links svg{width:18px;height:18px}.sidebar{grid-area:sidebar;background:var(--panel);border-right:1px solid var(--border);padding:16px 8px}.sidebar nav{display:flex;flex-direction:column;gap:2px}.sidebar nav a{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:6px;color:var(--fg);font-size:15px;font-weight:500}.sidebar nav a:hover{background:var(--panel-hi);text-decoration:none}.sidebar nav a.active{background:var(--accent-soft);color:var(--accent)}.sidebar nav a .icon{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center}.sidebar nav a .icon svg{width:18px;height:18px}.main{grid-area:main;padding:24px 28px;max-width:1400px}.section-title{display:flex;align-items:center;gap:12px;margin:8px 0 14px;font-weight:600;font-size:20px}.section-title .count{color:var(--muted);font-weight:400;font-size:14px}.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:14px}.card{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:16px 18px;box-shadow:0 1px #1f23280a}.card h3{margin:0 0 8px;font-size:17px}.card .row{display:flex;justify-content:space-between;color:var(--muted);font-size:14px;padding:2px 0}.card .row strong{color:var(--fg);font-weight:500;text-align:right;margin-left:12px}.table{width:100%;border-collapse:collapse;font-size:14px;background:var(--panel);border:1px solid var(--border);border-radius:8px;overflow:hidden}.table th,.table td{padding:10px 12px;border-bottom:1px solid var(--border);text-align:left;vertical-align:middle}.table thead th{background:var(--panel-hi);color:var(--muted);font-weight:500;font-size:13px;text-transform:uppercase;letter-spacing:.4px}.table tbody tr{cursor:pointer}.table tbody tr:hover{background:var(--panel-hi)}.table tbody tr:last-child td{border-bottom:0}.table td.key{font-family:var(--font-mono);font-size:13.5px}.table td.mono{font-family:var(--font-mono);color:var(--muted);font-size:13.5px}.badge{display:inline-block;padding:2px 10px;border-radius:12px;font-size:12.5px;font-weight:500;background:var(--panel-hi);border:1px solid var(--border);color:var(--muted);white-space:nowrap}.badge.running{color:var(--run);border-color:var(--run);background:var(--accent-soft)}.badge.in-review{color:var(--review);border-color:var(--review);background:#fff8c5}.badge.queued{color:var(--queued)}.badge.merged,.badge.completed{color:var(--ok);border-color:var(--ok);background:#dcffe4}.badge.failed{color:var(--err);border-color:var(--err);background:#ffebe9}.badge.cleaned{color:var(--muted)}.badge.stale{color:var(--warn);border-color:var(--warn);background:#fff8c5}.filters{display:flex;gap:14px;align-items:center;margin-bottom:14px;flex-wrap:wrap}.filters label{color:var(--muted);font-size:14px}.detail-header{display:flex;align-items:center;gap:14px;margin:4px 0 14px;flex-wrap:wrap}.detail-header .title{font-size:22px;font-weight:600;font-family:var(--font-mono)}.detail-meta{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px 18px;margin-bottom:14px;font-size:14px;display:grid;grid-template-columns:max-content 1fr;gap:6px 16px}.detail-meta .k{color:var(--muted)}.detail-meta .v{font-family:var(--font-mono);font-size:13.5px;word-break:break-all}.panel{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px 18px;margin-bottom:14px}.panel h3{margin:0 0 10px;font-size:13px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.panel pre{margin:0;white-space:pre-wrap;word-break:break-word;font-size:13.5px;color:var(--fg)}.logs{display:grid;grid-template-columns:1fr 1fr;gap:14px}.log-pane{background:#fff;border:1px solid var(--border);border-radius:8px;height:460px;overflow:auto;padding:10px 14px}.log-pane h4{margin:0 0 8px;font-size:12px;color:var(--muted);font-family:var(--font-mono);text-transform:uppercase;letter-spacing:.5px}.log-pane pre{margin:0;font-size:13px;color:var(--fg);white-space:pre}.empty{color:var(--muted);font-style:italic;padding:8px 0;font-size:14px}.error{color:var(--err);padding:10px 14px;border:1px solid var(--err);border-radius:6px;background:#ffebe9;margin:12px 0}.refresh-info{color:var(--muted);font-size:13px;margin-right:10px}@media (max-width: 720px){.app{grid-template-columns:1fr;grid-template-areas:"header" "main"}.sidebar{display:none}.main{padding:16px}.logs{grid-template-columns:1fr}} diff --git a/ui/dist/index.html b/ui/dist/index.html index 058a319..377e670 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -5,8 +5,8 @@ lmstack — put your GPUs to work - - + +
diff --git a/ui/src/api.ts b/ui/src/api.ts index 3cdc745..fb01ead 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -7,15 +7,36 @@ export type ForgeStatus = | 'cleaned' | 'stale'; +export interface InstanceModel { + slug: string | null; + hfModel?: string | null; + engine?: string | null; + port?: number | null; + contextTokens?: number | null; + maxNumSeqs?: number | null; + vramEstimateGib?: number | null; + tier?: string | null; + quant?: string | null; + active: boolean; +} + export interface Instance { role: string; - host?: string; - engine?: string; - gpu?: string; - models: string[]; - probeAt?: string; - verdict?: string; + connection: string | null; + installedAt: string | null; + verdict: string | null; + engine: { kind: string | null; reason: string | null; host: string | null }; + gpu: { vendor: string | null; model: string | null; vramGib: number | null; gttGib: number | null; driver: string | null } | null; + os: { pretty: string | null; kernel: string | null; arch: string | null } | null; + memory: { totalGib: number } | null; + docker: { present: boolean; usable: boolean; version: string | null; runtimes: string[] } | null; + vulkan: { present: boolean; device: string | null } | null; + arithmetic: string[]; + warnings: string[]; + activeModels: string[]; + models: InstanceModel[]; counts: { running: number; in_review: number; queued: number; merged: number; failed: number; cleaned: number; stale: number }; + sources: { hostYaml: boolean; probeJson: boolean; classifyJson: boolean }; } export interface ForgeSummary { diff --git a/ui/src/routes/Instances.tsx b/ui/src/routes/Instances.tsx index 7a0d586..d74c6d7 100644 --- a/ui/src/routes/Instances.tsx +++ b/ui/src/routes/Instances.tsx @@ -1,4 +1,5 @@ -import { api } from '../api'; +import type { ReactNode } from 'react'; +import { api, type Instance } from '../api'; import { fmtLoaded, useAsync } from '../hooks'; export function Instances() { @@ -16,29 +17,231 @@ export function Instances() { {error &&
error: {error}
} {!error && data && data.length === 0 && ( -
No instances installed. Run /lmstack:install to add one.
+
No instances installed. Run /lmstack:install to add one.
)} -
- {data?.map((inst) => ( -
-

{inst.role}

-
engine{inst.engine ?? '—'}
-
gpu{inst.gpu ?? '—'}
-
models{inst.models.length ? inst.models.join(', ') : '—'}
-
probe{inst.probeAt ?? '—'}
-
verdict{inst.verdict ?? '—'}
-
- forges - - {inst.counts.running} running · {inst.counts.in_review} in-review · {inst.counts.queued} queued · {inst.counts.merged + inst.counts.cleaned} done · {inst.counts.failed} failed - + +
+ {data?.map((inst) => )} +
+
+ ); +} + +function InstanceCard({ inst }: { inst: Instance }) { + const total = inst.counts.running + inst.counts.in_review + inst.counts.queued + + inst.counts.merged + inst.counts.failed + inst.counts.cleaned + inst.counts.stale; + const missing = [ + !inst.sources.hostYaml && 'host.yml', + !inst.sources.probeJson && 'probe.json', + !inst.sources.classifyJson && 'classify.json', + ].filter(Boolean) as string[]; + + return ( +
+
+ +
+

{inst.role}

+
+ {inst.gpu?.model ? {inst.gpu.model} : unknown GPU} + {inst.engine.kind && ·} + {inst.engine.kind && {prettyEngine(inst.engine.kind)}} + {inst.connection && ·} + {inst.connection && {inst.connection === 'local' ? 'localhost' : inst.connection}} +
+
+
+ {inst.verdict && {inst.verdict}} + view {total} forge{total === 1 ? '' : 's'} → +
+
+ + {missing.length > 0 && ( +
+ Missing on disk: {missing.map((m) => {m}).reduce((acc, el, i) => (i === 0 ? [el] : [...acc, ', ', el]), [])}. + {' '}Run /lmstack:analyze {inst.connection || ''} to populate hardware & engine details. +
+ )} + +
+
+ + + + + +
+ +
+ + + + + + +
+ +
+ + + + +
+ +
+ + + + + + + {inst.counts.stale > 0 && } +
+
+ + {inst.models.length > 0 && ( +
+

Models

+ + + + + + + + + + + + + + + {inst.models.map((m) => ( + + + + + + + + + + + ))} + +
slughf modelcontextmax seqsVRAM est.porttieractive
{m.slug ?? '—'}{m.hfModel ?? '—'}{fmtCtx(m.contextTokens)}{m.maxNumSeqs ?? '—'}{fmtGib(m.vramEstimateGib)}{m.port ?? '—'}{m.tier ?? '—'}{m.active ? active : idle}
+
+ )} + + {(inst.arithmetic.length > 0 || inst.warnings.length > 0) && ( +
+ {inst.arithmetic.length > 0 && ( +
+

Memory arithmetic

+
{inst.arithmetic.join('\n')}
-
- view forges → + )} + {inst.warnings.length > 0 && ( +
+

Warnings

+
    {inst.warnings.map((w, i) =>
  • {w}
  • )}
-
- ))} + )} +
+ )} +
+ ); +} + +function Section({ title, children }: { title: string; children: ReactNode }) { + return ( +
+

{title}

+
{children}
+
+ ); +} + +function Row({ k, v }: { k: string; v: ReactNode | number | null | undefined }) { + const empty = v == null || v === '' || v === undefined; + return ( + <> +
{k}
+
{empty ? '—' : v}
+ + ); +} + +function VendorLogo({ vendor }: { vendor: string | null }) { + const v = (vendor || '').toLowerCase(); + if (v === 'nvidia') { + return ( +
+ + NVIDIA +
+ ); + } + if (v === 'amd') { + return ( +
+ + AMD
+ ); + } + return ( +
+ + GPU
); } + +// Simple stylised marks — deliberately not reproducing the trademarked +// wordmarks. A large monogram in the vendor's brand hue plus a plain label. +function NvidiaMark() { + return ( + + ); +} +function AmdMark() { + return ( + + ); +} +function GpuMark() { + return ( + + ); +} + +function fmtGib(g: number | null | undefined): string | null { + if (g == null) return null; + return `${g} GiB`; +} +function fmtCtx(t: number | null | undefined): string { + if (t == null) return '—'; + if (t >= 1024) return `${(t / 1024).toFixed(t % 1024 === 0 ? 0 : 1)}K`; + return String(t); +} +function fmtDocker(d: Instance['docker']): string | null { + if (!d) return null; + if (!d.present) return 'not installed'; + if (!d.usable) return `${d.version ?? 'present'} (not usable)`; + return d.version || 'usable'; +} +function prettyEngine(k: string | null | undefined): string | null { + if (!k) return null; + const m: Record = { vllm: 'vLLM', llamacpp: 'llama.cpp' }; + return m[k] ?? k; +} diff --git a/ui/src/styles.css b/ui/src/styles.css index c9237da..4e4bd4a 100644 --- a/ui/src/styles.css +++ b/ui/src/styles.css @@ -169,6 +169,157 @@ code, pre { font-family: var(--font-mono); } } .card .row strong { color: var(--fg); font-weight: 500; text-align: right; margin-left: 12px; } +/* ─── full-width instance card ─────────────────────────────────────── */ + +.inst-list { display: flex; flex-direction: column; gap: 16px; } +.inst { + background: var(--panel); + border: 1px solid var(--border); + border-radius: 10px; + padding: 20px 24px; + box-shadow: 0 1px 0 rgba(31,35,40,0.04); +} +.inst-hdr { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 14px; +} +.vendor { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + min-width: 56px; +} +.vendor svg { width: 48px; height: 48px; display: block; } +.vendor span { font-size: 11px; font-weight: 600; color: var(--muted); letter-spacing: 0.4px; } +.vendor-nvidia span { color: #4b7f00; } +.vendor-amd span { color: #b31219; } + +.inst-hdr-main { flex: 1; min-width: 0; } +.inst-hdr-main h2 { + margin: 0; + font-size: 22px; + font-weight: 600; + letter-spacing: -0.01em; + font-family: var(--font-mono); +} +.inst-sub { + display: flex; + align-items: center; + gap: 6px; + color: var(--muted); + font-size: 14px; + margin-top: 4px; + flex-wrap: wrap; +} +.inst-sub .dot { opacity: 0.5; } +.inst-sub .muted { font-style: italic; } + +.inst-hdr-status { + display: flex; + align-items: center; + gap: 12px; +} +.btn-link { + color: var(--accent); + font-size: 14px; + padding: 6px 12px; + border: 1px solid var(--border-strong); + border-radius: 6px; + background: var(--panel); +} +.btn-link:hover { border-color: var(--accent); background: var(--accent-soft); text-decoration: none; } + +.badge.verdict-supported { color: var(--ok); border-color: var(--ok); background: #dcffe4; } +.badge.verdict-unsupported { color: var(--err); border-color: var(--err); background: #ffebe9; } + +.inst-hint { + background: #fff8c5; + border: 1px solid #d4a72c; + color: #63410b; + padding: 10px 14px; + border-radius: 6px; + font-size: 14px; + margin-bottom: 14px; +} +.inst-hint code { + background: rgba(0,0,0,0.06); + padding: 1px 6px; + border-radius: 3px; + font-size: 13px; +} + +.inst-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 20px 32px; +} +.inst-sec h3 { + margin: 0 0 8px; + font-size: 12px; + color: var(--muted); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} +.inst-sec dl { + margin: 0; + display: grid; + grid-template-columns: max-content 1fr; + gap: 4px 14px; + font-size: 14px; +} +.inst-sec dt { color: var(--muted); } +.inst-sec dd { + margin: 0; + color: var(--fg); + font-family: var(--font-mono); + font-size: 13.5px; + overflow-wrap: anywhere; +} +.inst-sec dd.muted { color: var(--muted); font-family: var(--font-sans); font-style: italic; } + +.inst-models { margin-top: 20px; } +.inst-models h3 { + margin: 0 0 8px; + font-size: 12px; + color: var(--muted); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} +.table.dense th, .table.dense td { padding: 6px 10px; font-size: 13.5px; } +.table.dense tbody tr { cursor: default; } +.table.dense tbody tr:hover { background: transparent; } + +.inst-extra { + margin-top: 20px; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; +} +.inst-extra-block h3 { + margin: 0 0 6px; + font-size: 12px; + color: var(--muted); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; +} +.inst-extra-block pre { + margin: 0; + padding: 10px 12px; + background: var(--panel-hi); + border: 1px solid var(--border); + border-radius: 6px; + font-size: 12.5px; + white-space: pre-wrap; +} +.inst-extra-block ul { margin: 0; padding-left: 20px; font-size: 13.5px; } +@media (max-width: 900px) { .inst-extra { grid-template-columns: 1fr; } } + .table { width: 100%; border-collapse: collapse; From ae7435e7e87c2696d3069fee8f0a24c1f114c70f Mon Sep 17 00:00:00 2001 From: devashish Date: Tue, 4 Aug 2026 07:33:47 -0700 Subject: [PATCH 3/4] fix(ui): stop rendering vendor badges as a big letter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NVIDIA and AMD marks were literal SVG "N" and "A" characters on brand-hue tiles — the previous comment on that block said "deliberately not reproducing the trademarked wordmarks", which is a fair legal caution but the result read as a placeholder, not a badge. Replace the letters with stylised geometric marks (an eye-shaped lens for NVIDIA, a chevroned "A" for AMD, a card silhouette for the generic case), and add an override path: drop the vendor's official SVG at ui/public/vendor/.svg and VendorMark renders it instead of the built-in mark. The 's onError falls the component back to the SVG if the file is absent, so the common "no override" case still renders and does not console- log a 404 after the first miss. Nothing in the trademarked assets ships with the repo; the vendor/ README points at each vendor's brand kit as the source. --- ui/public/vendor/README.md | 20 +++++++++ ui/src/routes/Instances.tsx | 82 ++++++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 ui/public/vendor/README.md diff --git a/ui/public/vendor/README.md b/ui/public/vendor/README.md new file mode 100644 index 0000000..6b69a5d --- /dev/null +++ b/ui/public/vendor/README.md @@ -0,0 +1,20 @@ +# Vendor marks + +Drop an SVG here named after the probe's `gpu.vendor` string, and the +Instances page will render it in place of the built-in stylised mark: + + nvidia.svg # served at /vendor/nvidia.svg + amd.svg # served at /vendor/amd.svg + +The `` tag falls back to the built-in mark if the file is absent, so +this directory can stay empty. Nothing in the SPA code needs to change when +you add a file — `VendorMark` resolves the URL from the slug at render time. + +## Why this indirection + +The SPA ships stylised marks rather than the official trademarked wordmarks +so a fresh checkout runs without pulling assets from a vendor's site — and +so contributors do not paste screenshots of a trademarked logo into the +repo. If you want the real logo on your own dashboard, get it from the +vendor's brand kit (they are freely downloadable, sometimes with attribution +requirements) and put it here. The file is not committed by default. diff --git a/ui/src/routes/Instances.tsx b/ui/src/routes/Instances.tsx index d74c6d7..9e89829 100644 --- a/ui/src/routes/Instances.tsx +++ b/ui/src/routes/Instances.tsx @@ -1,4 +1,4 @@ -import type { ReactNode } from 'react'; +import { useState, type ReactNode } from 'react'; import { api, type Instance } from '../api'; import { fmtLoaded, useAsync } from '../hooks'; @@ -172,55 +172,81 @@ function Row({ k, v }: { k: string; v: ReactNode | number | null | undefined }) ); } +// Vendor marks: prefer a real logo file at /vendor/.svg (drop the +// official SVG from the vendor's press kit into ui/public/vendor/ and it +// takes over — nothing to change in this file). Fall back to a stylised +// geometric mark when the file is not there, so a fresh checkout still shows +// something the user recognises. +// +// Falling back to a big letter — the previous behaviour, "a big N" and "a big +// A" — read as a placeholder rather than a badge, which is what motivated the +// rewrite. A geometric mark reads as intentional even before the official +// file is added. function VendorLogo({ vendor }: { vendor: string | null }) { const v = (vendor || '').toLowerCase(); - if (v === 'nvidia') { - return ( -
- - NVIDIA -
- ); - } - if (v === 'amd') { - return ( -
- - AMD -
- ); - } + const spec = VENDOR_MARKS[v] || VENDOR_MARKS._generic; return ( -
- - GPU +
+ + {spec.label}
); } -// Simple stylised marks — deliberately not reproducing the trademarked -// wordmarks. A large monogram in the vendor's brand hue plus a plain label. +type MarkSpec = { label: string; color: string; fallback: JSX.Element }; + +const VENDOR_MARKS: Record = { + nvidia: { label: 'NVIDIA', color: '#76B900', fallback: }, + amd: { label: 'AMD', color: '#000000', fallback: }, + _generic: { label: 'GPU', color: '#656D76', fallback: }, +}; + +function VendorMark({ slug, spec }: { slug: string; spec: MarkSpec }) { + const [failed, setFailed] = useState(false); + if (!slug || slug === '_generic' || failed) return spec.fallback; + // The onError fires when the file is missing, so the fallback SVG + // still renders — no 404 in the console for the common "no override" case + // once the error has been caught. + return ( + setFailed(true)} + /> + ); +} + +// Stylised marks, used until ui/public/vendor/.svg is dropped in. Not +// the trademarked wordmarks — an eye-shaped lens for NVIDIA, a chevroned "A" +// on black for AMD, a card silhouette for the generic case. function NvidiaMark() { return ( ); } function AmdMark() { return ( ); } function GpuMark() { return ( ); } From 8afcfcc318371c8dbed3438f0a11a4abeb97bcd7 Mon Sep 17 00:00:00 2001 From: devashish Date: Tue, 4 Aug 2026 07:35:48 -0700 Subject: [PATCH 4/4] feat(ui): ship real NVIDIA and AMD SVGs so the badge is a logo, not a fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stylised marks were only meant to bridge the case where no logo file is present. Ship the actual marks in ui/public/vendor/, so a fresh checkout renders the badge someone recognises without anyone having to download an SVG first. Paths come from simple-icons (CC0), each wrapped in a brand-hue tile — the SVG file carries its own colour, so nothing on the consuming end needs to know about it. The fallback marks in Instances.tsx stay put for any vendor we do not yet have a file for. --- ui/public/vendor/README.md | 23 ++++++++++------------- ui/public/vendor/amd.svg | 4 ++++ ui/public/vendor/nvidia.svg | 4 ++++ 3 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 ui/public/vendor/amd.svg create mode 100644 ui/public/vendor/nvidia.svg diff --git a/ui/public/vendor/README.md b/ui/public/vendor/README.md index 6b69a5d..58ed684 100644 --- a/ui/public/vendor/README.md +++ b/ui/public/vendor/README.md @@ -1,20 +1,17 @@ # Vendor marks -Drop an SVG here named after the probe's `gpu.vendor` string, and the -Instances page will render it in place of the built-in stylised mark: +Ship an SVG here named after the probe's `gpu.vendor` string and the Instances +page renders it in place of the built-in stylised fallback: nvidia.svg # served at /vendor/nvidia.svg amd.svg # served at /vendor/amd.svg -The `` tag falls back to the built-in mark if the file is absent, so -this directory can stay empty. Nothing in the SPA code needs to change when -you add a file — `VendorMark` resolves the URL from the slug at render time. +`nvidia.svg` and `amd.svg` ship in this directory — their paths come from +[simple-icons](https://simpleicons.org/) (CC0), wrapped in a brand-hue tile +so the SVG file is self-contained: no CSS on the consuming end has to know +the vendor's colour. `VendorMark` in `../../src/routes/Instances.tsx` falls +back to a stylised geometric mark if a file is missing, so the SPA still +renders on a checkout with this directory empty. -## Why this indirection - -The SPA ships stylised marks rather than the official trademarked wordmarks -so a fresh checkout runs without pulling assets from a vendor's site — and -so contributors do not paste screenshots of a trademarked logo into the -repo. If you want the real logo on your own dashboard, get it from the -vendor's brand kit (they are freely downloadable, sometimes with attribution -requirements) and put it here. The file is not committed by default. +To swap in a different mark — a company brand asset, a different icon set — +overwrite the SVG here. Nothing in the SPA code needs to change. diff --git a/ui/public/vendor/amd.svg b/ui/public/vendor/amd.svg new file mode 100644 index 0000000..c10d52c --- /dev/null +++ b/ui/public/vendor/amd.svg @@ -0,0 +1,4 @@ + + + + diff --git a/ui/public/vendor/nvidia.svg b/ui/public/vendor/nvidia.svg new file mode 100644 index 0000000..0b09ec3 --- /dev/null +++ b/ui/public/vendor/nvidia.svg @@ -0,0 +1,4 @@ + + + +