// overlays.jsx — Correx overlays: command palette, approval gate, and inspectors. const { useState, useEffect, useRef, useMemo } = React; /* ── generic overlay shell ── */ function Overlay({ tag, title, esc = "esc", center, width, onClose, children }) { return (
{ if (e.target === e.currentTarget) onClose(); }}>
e.stopPropagation()}>
{tag} {title} {esc} to close
{children}
); } /* ── command palette ── */ function CommandPalette({ commands, onRun, onClose }) { const [q, setQ] = useState(""); const [i, setI] = useState(0); const inp = useRef(null); useEffect(() => { inp.current && inp.current.focus(); }, []); const score = (c) => { const s = (c.label + " " + c.hint).toLowerCase(), t = q.toLowerCase().trim(); if (!t) return 1; if (s.includes(t)) return 2; let qi = 0; for (const ch of s) if (ch === t[qi]) qi++; return qi === t.length ? 1 : 0; }; const list = useMemo(() => commands.map((c) => [c, score(c)]).filter(([, s]) => s > 0) .sort((a, b) => b[1] - a[1]).map(([c]) => c), [q]); useEffect(() => { setI(0); }, [q]); const key = (e) => { if (e.key === "ArrowDown") { setI((x) => Math.min(x + 1, list.length - 1)); e.preventDefault(); } else if (e.key === "ArrowUp") { setI((x) => Math.max(x - 1, 0)); e.preventDefault(); } else if (e.key === "Enter") { list[i] && onRun(list[i].id); e.preventDefault(); } else if (e.key === "Escape") { onClose(); } e.stopPropagation(); }; return (
{ if (e.target === e.currentTarget) onClose(); }}>
e.stopPropagation()}>
setQ(e.target.value)} onKeyDown={key} />
{list.length === 0 &&
no matches
} {list.map((c, n) => (
setI(n)} onClick={() => onRun(c.id)}> {c.key} {c.label} {c.hint}
))}
); } /* ── approval gate (modal interrupt) ── */ function ApprovalModal({ data, onApprove, onReject, onSteer, onClose }) { const [steer, setSteer] = useState(""); const sref = useRef(null); return (
e.stopPropagation()}>
e.stopPropagation()}>
{data.tier}
Approval required · {data.tierLabel}
{data.intent}
execution paused
$ {data.command}
{data.detail}
tool
{data.tool} {data.tier}
reversible
{data.reversible ? "yes" : "no"}
policy
{data.policy}
semantic risk scan
{data.risks.map((r, n) =>
{r}
)}
setSteer(e.target.value)} onKeyDown={(e) => { e.stopPropagation(); if (e.key === "Enter" && steer.trim()) onSteer(steer.trim()); if (e.key === "Escape") sref.current.blur(); }} />
); } /* ── event stream inspector ── */ function EventInspector({ events, onClose }) { const cats = ["All", "Lifecycle", "Context", "Inference", "Tool", "Domain", "Approval"]; const [cat, setCat] = useState("All"); const [sel, setSel] = useState(events[events.length - 1]); const list = events.filter((e) => cat === "All" || e.cat === cat); const payload = { id: sel.id, type: sel.type, category: sel.cat, ts: "2026-05-29T" + sel.t, session_id: window.CORREX.SESSION.id, correlation_id: "cor-7f2a", causation_id: sel.id === "e49" ? "e48" : null, payload: { detail: sel.text }, }; return (
{cats.map((c) => setCat(c)}>{c})}
{list.map((e) => (
setSel(e)}> {e.t} {e.cat} {e.type} {e.text}
))}
{JSON.stringify(payload, null, 2)}
); } /* ── context pack inspector ── */ function ContextPackInspector({ pack, onClose }) { const pct = Math.round((pack.used / pack.budget) * 100); return (
{pack.used.toLocaleString()} / {pack.budget.toLocaleString()} tok
{pct}%
{pack.layers.map((l) => (
{l.id} {l.name}
{l.mode}
{l.items.join(" · ")} {l.tok}t
))}
excluded by synthesis
{pack.dropped.map((d, n) =>
− {d}
)}
); } /* ── stage / transition graph ── */ function StageGraph({ stages, transitions, onClose }) { const glyph = { done: "✔", active: "▸", pending: "·" }; return (
{stages.map((s, n) => (
{glyph[s.status]} {s.id} role:{s.role} {s.status === "active" && running · {s.enter}} {s.note}
{n < stages.length - 1 &&
}
))}
transition rules
no hardcoded graph — rules eval per artifact
{transitions.map((t, n) => (
when {t.when}
→ goto {t.goto}
))}
); } /* ── model registry / provider switch ── */ function ModelRegistry({ models, active, onSwitch, onClose }) { return (
models are stateless engines — switching re-synthesizes the Context Pack for the new window.
{models.map((m) => (
m.id !== active && onSwitch(m.id)}>
{m.id} {m.provider} {m.id === active && active} {m.status}
{m.caps.join(" · ")} — ctx {m.ctx.toLocaleString()} · t={m.temp} · {m.gpu}
sessions {m.parallel}{m.id !== active &&
switch →
}
))}
); } /* ── tool palette ── */ function ToolPalette({ tools, onToggle, onClose }) { return (
config-driven · capability-scoped. tier sets the approval gate; disabled tools are invisible to the agent.
{tools.map((t) => (
onToggle(t.id)}> {t.tier} {t.id} — {t.desc} {t.mode} {t.enabled ? "enabled" : "disabled"}
))}
); } Object.assign(window, { Overlay, CommandPalette, ApprovalModal, EventInspector, ContextPackInspector, StageGraph, ModelRegistry, ToolPalette });