// Shared dashboard state — the one piece of cross-domain state in the // dashboard SPA: the live agent roster. // // The roster is read by nearly every tab (the container tree, the // capabilities + tool-group matrices, the schedule target-chips, the // container-load poll, the selection bar, and the operator inbox), so // it lives here as a single source of truth that each domain module // imports rather than threading through call signatures. Everything // else in the dashboard is domain-local and lives with its own module. // // `containersState` is keyed by `ContainerView.name` so a lifecycle // form's POST → 200 → matching SSE event can flip a single row without // a full snapshot refetch. Mutated in place (`set` / `delete` / `clear`) // by the container apply-handlers; consumers read it by reference, so // the imported binding always reflects the latest roster. export const containersState = new Map(); // Replace the whole roster from a fresh `/api/state` snapshot. Called by // the entry's `refreshState` on cold load and after async-form submits; // live single-row updates go through the container apply-handlers. export function syncContainersFromSnapshot(s) { containersState.clear(); for (const c of s.containers || []) containersState.set(c.name, c); } // Derived question state — the other genuinely cross-domain store. Owned by // the Y3R C4LL questions domain (`call.js`: cold-loaded from /api/state, then // mutated live by `question_added` / `question_resolved` events), but also // read by the SW4RM container rows, which render per-agent asker/target // question-count badges off `questionsState.pending`. It lives here for the // same reason as `containersState`: a single source of truth both domains // import by reference rather than threading through call signatures. export const QUESTION_HISTORY_LIMIT = 20; export const questionsState = { pending: [], history: [] };