feat: initial public release (MAESTRO)

This commit is contained in:
oss-sync
2026-06-03 05:08:00 +00:00
commit f5c7666f6b
823 changed files with 184150 additions and 0 deletions
@@ -0,0 +1,131 @@
import { useNodeStatus, type NodeStatus } from '../../hooks/useNodeStatus';
import { useNodeAnimationState } from '../../hooks/useNodeAnimationState';
import { useActivePet } from '../../hooks/useActivePet';
import { usePetFrameAnalysis } from '../../hooks/usePetFrameAnalysis';
import { PetSprite } from '../pets/PetSprite';
/**
* Side Info Panel widget that surfaces the BackendStatusRegistry feed:
* for every direct worker and every proxy backend, one row with Pet
* sprite, status icon, slots, model, throughput.
*
* Polling cadence matches the server-side registry tick (5s) so the
* client cache stays roughly aligned with the cache the server is
* already maintaining — see hooks/useNodeStatus for the rationale.
*/
export function NodeStatusWidget() {
const { nodes, isLoading, isError, isUnavailable } = useNodeStatus();
if (isLoading) return <div className="text-xs text-slate-500 p-3">...</div>;
if (isUnavailable) {
return (
<div className="text-xs text-slate-500 p-3">
node-status registry <br />
config.yaml provider.workers
</div>
);
}
if (isError) return <div className="text-xs text-red-600 p-3"></div>;
if (nodes.length === 0) {
return (
<div className="text-xs text-slate-500 p-3">
<br />
config.yaml provider.workers
</div>
);
}
return (
<div className="flex flex-col gap-1 p-2 overflow-auto h-full">
{nodes.map((n) => (
<NodeRow key={`${n.workerId}|${n.nodeId}`} node={n} />
))}
</div>
);
}
function statusEmoji(node: NodeStatus): { icon: string; label: string; color: string } {
if (!node.online) return { icon: '⚫', label: 'offline', color: 'text-slate-500' };
if (node.totalSlots > 0 && node.busySlots >= node.totalSlots) {
return { icon: '🔴', label: 'full', color: 'text-rose-600' };
}
if (node.busySlots > 0) return { icon: '🟡', label: 'busy', color: 'text-amber-600' };
return { icon: '🟢', label: 'idle', color: 'text-emerald-600' };
}
function usePrefersReducedMotion(): boolean {
if (typeof window === 'undefined' || !window.matchMedia) return false;
return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}
function NodeRow({ node }: { node: NodeStatus }) {
// The Pet selection logic in useActivePet already prefers
// workerPets[backendId] over workerPets[workerId]; passing nodeId as
// the "backend" argument hands the resolver the most specific key.
const { data: pet } = useActivePet(node.workerId, node.nodeId);
const framesPerRow = usePetFrameAnalysis(
pet?.spriteUrl ?? null,
pet?.gridCols ?? null,
pet?.gridRows ?? null,
);
const systemReducedMotion = usePrefersReducedMotion();
const petReducedMotion = (pet?.settings as { reducedMotion?: boolean } | undefined)?.reducedMotion ?? false;
const reducedMotion = petReducedMotion || systemReducedMotion;
const { icon, label, color } = statusEmoji(node);
// Phase C: derive the animation state through useNodeAnimationState so
// both this widget and the ChatPetOverlay see the same idle/running
// decision against the registry feed. The hook reads the shared
// useNodeStatus query (React Query dedups), so N rows here don't
// multiply polling traffic.
const petState = useNodeAnimationState(node.nodeId);
const showPet = pet?.pet && pet.imageUrl;
return (
<div className="flex items-center gap-2 px-2 py-1.5 rounded-md hover:bg-surface-2">
<div className="w-8 h-8 flex-shrink-0 flex items-center justify-center">
{showPet ? (
<PetSprite
name={pet.pet!.name}
imageUrl={pet.imageUrl}
frameWidth={pet.frameWidth}
frameHeight={pet.frameHeight}
gridCols={pet.gridCols}
gridRows={pet.gridRows}
framesPerRow={framesPerRow}
state={petState}
size={32}
reducedMotion={reducedMotion}
/>
) : (
<span className={`text-base ${color}`} aria-label={label}>{icon}</span>
)}
</div>
<div className="flex-1 min-w-0">
<div className="text-xs font-medium text-slate-800 truncate flex items-center gap-1.5">
{node.nodeId}
{node.source === 'proxy' && (
<span className="text-[9px] uppercase tracking-wide text-slate-400">via {node.workerId}</span>
)}
</div>
<div className="text-[10px] text-slate-500 font-mono truncate">
{node.loadedModel ?? '-'}
{node.lastProbeError && (
<span className="text-rose-500 ml-1" title={node.lastProbeError}>(probe error)</span>
)}
</div>
</div>
<div className="flex flex-col items-end text-[11px] font-mono leading-tight">
<div className="flex items-center gap-1">
<span className={color}>{icon}</span>
{node.totalSlots > 0
? <span className="text-slate-600">{node.busySlots}/{node.totalSlots}</span>
: <span className="text-slate-400">-</span>}
</div>
<span className="text-slate-400">
{node.throughputTps != null ? `${node.throughputTps.toFixed(0)} tok/s` : ' '}
</span>
</div>
</div>
);
}