Final sweep: Crucible fixes, Path Tracer polish, forge progress, tests green.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Align dashboard subtitle default and UpsertAgent tests with fleet label behavior; WebSocket coalesce and PathForge hardening; Crucible expanded ops and visual DV fixes; Vitest 610/610 and full test-suite pass; trim PROBLEMS.md to open items only.
This commit is contained in:
AetherForge
2026-06-06 18:07:47 -07:00
parent e65753ce49
commit 6372b07e6c
40 changed files with 1495 additions and 794 deletions

View File

@@ -11,6 +11,7 @@ import { primaryGroupForAgent } from '../help/fleetGroups';
import { useFleetGroups } from '../hooks/useFleetGroups';
import { useMatrixRain } from '../context/MatrixRainContext';
import { parseFullSysCheckMessage, type FullSysCheckReport } from '../types/syscheck';
import type { WSCommandResult } from '../types/ws';
import { sanitizeScreenshotBase64 } from '../help/screenshotDownload';
import FullSysCheckPanel from '../components/Fleet/FullSysCheckPanel';
import CrucibleExpandedOps from '../components/Fleet/CrucibleExpandedOps';
@@ -306,7 +307,7 @@ const TERM_RENDER_CAP = 400;
// ── Component ──────────────────────────────────────────────────────────────
export default function CruciblePage() {
const { agents, commandResults } = useWebSocket();
const { agents, commandResults, latestMessage } = useWebSocket();
const { setCrucibleFocus } = useMatrixRain();
// Selection
@@ -322,6 +323,7 @@ export default function CruciblePage() {
const termEndRef = useRef<HTMLDivElement>(null);
const cmdRef = useRef<HTMLInputElement>(null);
const lastSeqRef = useRef(0);
const lastLatestCmdRef = useRef<typeof latestMessage>(null);
// Command history
const [cmdHistory, setCmdHistory] = useState<string[]>([]);
@@ -435,12 +437,18 @@ export default function CruciblePage() {
useEffect(() => {
if (!commandResults || commandResults.length === 0) return;
const newEntries = commandResults.filter((r) => r._seq > lastSeqRef.current);
const newEntries = commandResults.filter(
(r) => typeof r._seq === 'number' && r._seq > lastSeqRef.current,
);
if (newEntries.length === 0) return;
lastSeqRef.current = newEntries[newEntries.length - 1]._seq;
const lines: TermLine[] = [];
let maxSeq = lastSeqRef.current;
for (const r of newEntries) {
if (typeof r._seq === 'number') {
maxSeq = Math.max(maxSeq, r._seq);
}
const aid = r.agent_id;
if (!aid) continue;
@@ -517,6 +525,10 @@ export default function CruciblePage() {
});
} else {
const msgLines = msg.split('\n').filter(Boolean);
if (msgLines.length === 0) {
const label = r.action ? `[${r.action}]` : '[result]';
msgLines.push(r.success ? `${label} OK` : `${label} FAILED`);
}
for (const line of msgLines) {
lines.push({
id: mkId(), agentId: aid, agentName: name,
@@ -525,12 +537,64 @@ export default function CruciblePage() {
}
}
}
lastSeqRef.current = maxSeq;
if (lines.length > 0) {
setTermLines((prev) => [...prev, ...lines].slice(-2000));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [commandResults]);
// Backup path: if commandResults batching ever misses an entry, latestMessage
// still carries command_result (WS_LATEST_MESSAGE_TYPES includes it).
useEffect(() => {
if (!latestMessage || latestMessage.type !== 'command_result') return;
if (latestMessage === lastLatestCmdRef.current) return;
lastLatestCmdRef.current = latestMessage;
let r = latestMessage.payload as WSCommandResult | string;
if (typeof r === 'string') {
try {
r = JSON.parse(r) as WSCommandResult;
} catch {
return;
}
}
const aid = r.agent_id;
if (!aid) return;
// commandResults effect owns entries already queued in the provider buffer
if (
commandResults?.some(
(c) => c.agent_id === aid && c.action === r.action && c.message === r.message,
)
) {
return;
}
const msg = r.message ?? '';
const agent = agents.find((a) => a.id === aid);
const name = agent?.name ?? aid.slice(0, 8);
const targeted = selectedIds.size === 0 || selectedIds.has(aid);
const msgLines = msg.split('\n').filter(Boolean);
if (msgLines.length === 0) {
const label = r.action ? `[${r.action}]` : '[result]';
msgLines.push(r.success ? `${label} OK` : `${label} FAILED`);
}
const lines: TermLine[] = msgLines.map((line) => ({
id: mkId(),
agentId: aid,
agentName: name,
isCmd: false,
text: line,
ts: new Date(),
success: r.success,
targeted,
}));
setTermLines((prev) => [...prev, ...lines].slice(-2000));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [latestMessage, commandResults]);
// ── Selection helpers ──────────────────────────────────────────────────
const toggle = (id: string) =>