Release validation: tests green, USB pack, fleet UX and API hardening.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Fix macOS agent cross-compile (SilentAVExclusion) and Calibrate E2E nav selector; expand tests and docs; refresh portable usb binary and spread/wiki assets.
This commit is contained in:
AetherForge
2026-06-06 16:57:39 -07:00
parent 5229854f00
commit 415b5dc6a3
119 changed files with 7005 additions and 3082 deletions

View File

@@ -1,4 +1,4 @@
import { ReactNode, useEffect, useRef, useState } from 'react';
import { ReactNode, memo, useEffect, useMemo, useRef, useState } from 'react';
import { NavLink, useLocation } from 'react-router-dom';
import AmbientBackground from '../Ambient/AmbientBackground';
import SystemStatusBar from '../Visual/SystemStatusBar';
@@ -15,7 +15,7 @@ import { resolvePageWeather } from '../../help/pageWeather';
import { api } from '../../api/client';
import { usePresence } from '../../context/PresenceContext';
import ComradeAvatar from '../Presence/ComradeAvatar';
import type { ServerConfig } from '../../types';
import type { ServerConfig, ServerInfo } from '../../types';
import '../Presence/Presence.css';
import './Layout.css';
import './MobileNav.css';
@@ -145,12 +145,19 @@ function formatHashrate(hs: number): string {
return `${hs.toFixed(0)} H/s`;
}
function FleetReadout() {
const FleetReadout = memo(function FleetReadout() {
const { agents } = useWebSocket();
const online = agents.filter((a) => a.status === 'online').length;
const total = agents.length;
const totalHashrate = agents.reduce((sum, a) => sum + (a.hashrate_15s ?? a.hashrate_15m ?? 0), 0);
const fillPct = total > 0 ? Math.round((online / total) * 100) : 0;
const { online, total, totalHashrate, fillPct } = useMemo(() => {
const on = agents.filter((a) => a.status === 'online').length;
const tot = agents.length;
const hr = agents.reduce((sum, a) => sum + (a.hashrate_15s ?? a.hashrate_15m ?? 0), 0);
return {
online: on,
total: tot,
totalHashrate: hr,
fillPct: tot > 0 ? Math.round((on / tot) * 100) : 0,
};
}, [agents]);
// Tick animation: flash hashrate value whenever it meaningfully changes
const [flash, setFlash] = useState(false);
@@ -191,13 +198,18 @@ function FleetReadout() {
</div>
</div>
);
}
});
function MobileTopStats() {
const MobileTopStats = memo(function MobileTopStats() {
const { agents } = useWebSocket();
const online = agents.filter((a) => a.status === 'online').length;
const total = agents.length;
const hr = agents.reduce((s, a) => s + (a.hashrate_15s ?? a.hashrate_15m ?? 0), 0);
const { online, total, hr } = useMemo(() => {
const on = agents.filter((a) => a.status === 'online').length;
return {
online: on,
total: agents.length,
hr: agents.reduce((s, a) => s + (a.hashrate_15s ?? a.hashrate_15m ?? 0), 0),
};
}, [agents]);
return (
<div className="mobile-top-stats">
<strong>
@@ -206,17 +218,23 @@ function MobileTopStats() {
<span>{hr > 0 ? formatHashrate(hr) : 'IDLE'}</span>
</div>
);
}
});
export default function Layout({ children }: LayoutProps) {
const location = useLocation();
const isMobile = useIsMobileLayout();
const { othersOnline, comrades } = usePresence();
const [serverConfig, setServerConfig] = useState<ServerConfig | null>(null);
const [serverInfo, setServerInfo] = useState<ServerInfo | null>(null);
const [moreOpen, setMoreOpen] = useState(false);
useEffect(() => {
api.getConfig().then(setServerConfig).catch(() => {});
Promise.all([api.getConfig(), api.getServerInfo()])
.then(([cfg, info]) => {
setServerConfig(cfg);
setServerInfo(info);
})
.catch(() => {});
}, []);
useEffect(() => {
@@ -232,7 +250,7 @@ export default function Layout({ children }: LayoutProps) {
};
}, [moreOpen]);
const setupStatus = getSetupStatus(serverConfig);
const setupStatus = getSetupStatus(serverConfig, serverInfo);
const pageWeather = resolvePageWeather(location.pathname);
const moreActive = MOBILE_MORE.some((item) => location.pathname === item.to);
const mobileShortLabel: Record<string, string> = {

View File

@@ -170,6 +170,15 @@ export default function MatrixRain() {
let raf: number;
let lastTime = 0;
let paused = document.visibilityState === 'hidden';
const onVis = () => {
paused = document.visibilityState === 'hidden';
if (!paused && !raf) {
raf = requestAnimationFrame(draw);
}
};
document.addEventListener('visibilitychange', onVis);
const drawWordDrop = (wd: WordDrop, speedMult: number, intense: boolean) => {
const H = canvas.height;
@@ -204,6 +213,10 @@ export default function MatrixRain() {
};
const draw = (ts: number) => {
if (paused) {
raf = 0;
return;
}
raf = requestAnimationFrame(draw);
const intense = forgingRef.current || crucibleRef.current;
const targetFps = intense ? 50 : 24;
@@ -317,6 +330,7 @@ export default function MatrixRain() {
raf = requestAnimationFrame(draw);
return () => {
document.removeEventListener('visibilitychange', onVis);
cancelAnimationFrame(raf);
clearInterval(injectInterval);
clearInterval(wordInterval);