chore: snapshot working tree - pty_exited notifications + in-flight inference WIP

feat(booterm): structured pty_exited WS notifications. Plan-validated, impl-validated, code-reviewed green (contracts build clean, contracts test 29/29, booterm + web typecheck clean).

wip: in-progress inference/provider refactor (agents.ts, provider.ts, new llama-providers.ts, removed llama-args-validator), plus arena, dispatcher, compaction, schema changes.

openspec: pty-exit-notifications complete; x-agent-flags planned (not yet implemented).
This commit is contained in:
2026-06-14 12:48:47 +00:00
parent 0ed506f1da
commit b18de2a331
204 changed files with 25344 additions and 867 deletions

View File

@@ -0,0 +1,107 @@
import { useEffect, useRef } from 'react';
import * as echarts from 'echarts/core';
import { GaugeChart } from 'echarts/charts';
import { CanvasRenderer } from 'echarts/renderers';
import type { EChartsType } from 'echarts/core';
import { buildEChartsTheme } from './buildEChartsTheme';
echarts.use([GaugeChart, CanvasRenderer]);
interface VramGaugeProps {
used: number; // MB
total: number; // MB
size?: number;
}
export function VramGauge({ used, total, size = 120 }: VramGaugeProps) {
const containerRef = useRef<HTMLDivElement>(null);
const chartRef = useRef<EChartsType | null>(null);
useEffect(() => {
if (!containerRef.current) return;
if (!chartRef.current) {
const theme = buildEChartsTheme();
chartRef.current = echarts.init(containerRef.current, theme);
}
const chart = chartRef.current;
const root = getComputedStyle(document.documentElement);
const get = (prop: string) => root.getPropertyValue(prop).trim();
const pct = total > 0 ? Math.round((used / total) * 100) : 0;
// Derive gauge progress color from CSS custom properties
// Green -> Amber -> Red as utilization increases
let color = get('--glow-green');
if (pct > 80) color = get('--glow-red');
else if (pct > 60) color = get('--glow-amber');
chart.setOption({
backgroundColor: 'transparent',
series: [
{
type: 'gauge',
startAngle: 220,
endAngle: -40,
min: 0,
max: total,
radius: '90%',
center: ['50%', '55%'],
pointer: { show: false },
progress: {
show: true,
overlap: false,
roundCap: true,
clip: false,
itemStyle: { color },
width: 8,
},
axisLine: {
lineStyle: {
width: 8,
color: [[1, get('--border')]],
},
},
axisTick: { show: false },
splitLine: { show: false },
axisLabel: { show: false },
title: {
show: true,
offsetCenter: ['0%', '-10%'],
fontSize: 11,
color: get('--muted-foreground'),
fontFamily: 'Inter',
},
detail: {
show: true,
offsetCenter: ['0%', '10%'],
fontSize: 18,
fontWeight: 'bold',
color: get('--foreground'),
fontFamily: 'Orbitron',
formatter: () => `${used} / ${total} MB`,
},
data: [{ value: used, name: 'VRAM' }],
},
],
});
const observer = new ResizeObserver(() => chart.resize());
observer.observe(containerRef.current);
return () => {
observer.disconnect();
chart.dispose();
chartRef.current = null;
};
}, [used, total]);
return (
<div
ref={containerRef}
className="flex items-center justify-center"
style={{ width: size, height: size }}
/>
);
}