// app.jsx — Correx TUI shell: layout, live state, keybind engine, theme + tweaks. const { useState, useEffect, useRef, useCallback } = React; const D = window.CORREX; const { applyTheme, THEMES, ACCENTS } = window.CORREX_THEMES; const DIR_ORDER = ["boxed", "soft", "bare"]; const ACC_ORDER = ["cyan", "amber", "green", "magenta", "neutral"]; const SPIN = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "direction": "boxed", "accent": "cyan", "fontSize": 13, "motion": true, "scanlines": false }/*EDITMODE-END*/; function Panel({ n, title, right, active, className, footer, bodyRef, children }) { return (
{n && {n}} {title} {right && {right}}
{children}
{footer}
); } function App() { const [t, setTweak] = useTweaks(TWEAK_DEFAULTS); const rootRef = useRef(null); const evRef = useRef(null); const [overlay, setOverlay] = useState(null); // 'cmd'|'events'|'context'|'graph'|'models'|'tools'|'approval'|null const [focusPanel, setFocusPanel] = useState("conv"); // 'conv'|'events' const [sessionState, setSessionState] = useState("awaiting_approval"); const [activeModel, setActiveModel] = useState(D.SESSION.model); const [tools, setTools] = useState(D.TOOLS); const [autoApprove, setAutoApprove] = useState(false); const [approvalResolved, setApprovalResolved] = useState(false); const [msgs, setMsgs] = useState(D.CONVERSATION); const [events, setEvents] = useState(D.EVENTS); const [stages, setStages] = useState(D.STAGES); const [toast, setToast] = useState(null); const [streamTarget, setStreamTarget] = useState(D.CONVERSATION.length - 1); const [streamLen, setStreamLen] = useState(0); const [frame, setFrame] = useState(0); const [draft, setDraft] = useState(""); const [promptFocus, setPromptFocus] = useState(false); const promptRef = useRef(null); const convRef = useRef(null); // theme application useEffect(() => { if (rootRef.current) applyTheme(rootRef.current, t.direction, t.accent); }, [t.direction, t.accent]); // spinner / clock frames useEffect(() => { if (!t.motion) return; const id = setInterval(() => setFrame((f) => f + 1), 110); return () => clearInterval(id); }, [t.motion]); // streaming reveal useEffect(() => { if (streamTarget == null) return; const full = (msgs[streamTarget] || {}).text || ""; if (streamLen >= full.length) return; if (!t.motion) { setStreamLen(full.length); return; } const id = setTimeout(() => setStreamLen((n) => Math.min(n + 3, full.length)), 16); return () => clearTimeout(id); }, [streamTarget, streamLen, msgs, t.motion]); // autoscroll event panel useEffect(() => { if (evRef.current) evRef.current.scrollTop = evRef.current.scrollHeight; }, [events]); // autoscroll conversation useEffect(() => { if (convRef.current) convRef.current.scrollTop = convRef.current.scrollHeight; }, [msgs, streamLen]); const flash = (m) => { setToast(m); setTimeout(() => setToast(null), 2600); }; const pushEvent = (e) => setEvents((arr) => [...arr, { id: "x" + arr.length + Math.random().toString(36).slice(2, 5), ...e }]); const addMsg = (m) => { setMsgs((arr) => { const ni = arr.length; setStreamTarget(ni); setStreamLen(0); return [...arr, m]; }); }; const appendMsg = (m) => setMsgs((arr) => [...arr, m]); // user steering input → routes back through Correx const hm = () => new Date().toTimeString().slice(0, 5); const replyFor = (q) => { const s = q.toLowerCase(); if (/test|spec|cover/.test(s)) return "Queued — I'll add SegmentStoreTest with an append→read round-trip and a dedup assertion (identical bytes ⇒ one object). Runs at the validation gate."; if (/perf|bench|fast|speed|throughput/.test(s)) return "Noted. I'll add a JMH harness for append throughput; the mmap read path stays zero-copy so reads aren't affected by compression."; if (/revert|undo|stop|cancel|rollback/.test(s)) return "Holding edits. Nothing destructive ran — the gated gradle resolve was the only external op. Awaiting your next instruction."; if (/compress|zstd|gzip|lz4|codec/.test(s)) return "Compression is pluggable behind a SegmentCodec — zstd for cold, raw for hot. I can swap lz4 for lower CPU at a worse ratio; say the word."; if (/index|offset|seek|lookup/.test(s)) return "SegmentIndex maps logical offset ranges → CAS keys with a binary search over segment bounds; O(log n) seeks. I'll memo the hot range."; return "Understood — folding that into the implementation plan. I'll surface a revised ImplementationArtifact at the validation gate for review."; }; const send = () => { const text = draft.trim(); if (!text) return; setDraft(""); setStreamTarget(null); appendMsg({ role: "user", t: hm(), text }); const at = (ms, fn) => seqRef.current.push(setTimeout(fn, ms)); at(320, () => pushEvent({ t: hm() + ":02", cat: "Context", type: "steer.captured", text: "router → agent context (L1)" })); at(760, () => addMsg({ role: "kernel", kind: "route", text: "Steering synthesized → injected at L1 · agent context updated" })); at(1500, () => addMsg({ role: "assistant", t: hm(), text: replyFor(text) })); }; // resolve approval → drive the live sequence const seqRef = useRef([]); const clearSeq = () => { seqRef.current.forEach(clearTimeout); seqRef.current = []; }; useEffect(() => () => clearSeq(), []); const resolveApproval = useCallback((kind, note) => { setOverlay(null); setApprovalResolved(true); setSessionState("active"); setEvents((arr) => arr.map((e) => e.pending ? { ...e, pending: false } : e)); const at = (ms, fn) => seqRef.current.push(setTimeout(fn, ms)); if (kind === "reject") { flash("Rejected — agent re-plans without the network tool"); pushEvent({ t: "14:12:31", cat: "Approval", type: "approval.rejected", text: "operator rejected T3 gate" }); at(700, () => pushEvent({ t: "14:12:33", cat: "Inference", type: "infer.start", text: "re-planning · no-network constraint" })); at(1600, () => addMsg({ role: "assistant", t: "14:12", text: "Understood — dropping zstd. I'll compress cold segments with the JDK Deflater instead: no new dependency, no network. Slightly worse ratio, zero supply-chain surface." })); at(3400, () => pushEvent({ t: "14:12:48", cat: "Domain", type: "artifact.emitted", text: "ImplementationArtifact ✓ (deflater path)" })); at(4200, () => transition()); return; } // approve / auto / steer const auto = kind === "auto"; if (auto) setAutoApprove(true); flash(kind === "steer" ? "Steered + approved — note injected into agent context" : auto ? "Auto-approve enabled for session" : "Approved"); pushEvent({ t: "14:12:14", cat: "Approval", type: kind === "steer" ? "approval.steered" : "approval.approved", text: note ? "“" + note + "”" : "operator approved" + (auto ? " · auto-session ON" : "") }); at(500, () => pushEvent({ t: "14:12:15", cat: "Tool", type: "shell.exec", text: "gradle resolving zstd-jni …", running: true })); at(2100, () => setEvents((arr) => arr.map((e) => e.running ? { id: e.id, t: "14:12:19", cat: "Tool", type: "shell.exec", text: "gradle resolve OK (4.1s) · +1 dep" } : e))); at(2600, () => addMsg({ role: "assistant", t: "14:12", text: (note ? "Locking the version as asked. " : "") + "Resolved zstd-jni 1.5.6-3. Cold segments now zstd-compress on write; hot segments stay raw for mmap. Emitting the implementation artifact." })); at(4600, () => pushEvent({ t: "14:12:34", cat: "Domain", type: "artifact.emitted", text: "ImplementationArtifact ✓ valid" })); at(5400, () => transition()); }, []); const transition = () => { pushEvent({ t: "14:12:36", cat: "Lifecycle", type: "stage.transition", text: "implementation → validation" }); setStages((arr) => arr.map((s) => s.id === "implementation" ? { ...s, status: "done", note: "artifact accepted" } : s.id === "validation" ? { ...s, status: "active", enter: "14:12", note: "schema + semantic checks" } : s)); pushEvent({ t: "14:12:36", cat: "Lifecycle", type: "stage.enter", text: "validation (role=reviewer)" }); }; // auto-open the approval gate once (modal interrupt demonstration) const raised = useRef(false); useEffect(() => { if (raised.current) return; raised.current = true; const id = setTimeout(() => { if (!approvalResolved) setOverlay("approval"); }, 1100); return () => clearTimeout(id); }, []); // ── keybind engine ── const cycle = (key, order) => setTweak(key, order[(order.indexOf(t[key]) + 1) % order.length]); const setDirection = (dir) => setTweak({ direction: dir, accent: THEMES[dir].defaultAccent }); const cycleDir = () => setDirection(DIR_ORDER[(DIR_ORDER.indexOf(t.direction) + 1) % DIR_ORDER.length]); const open = (id) => { if (id === "appearance") { cycleDir(); return; } if (id === "approval") { if (approvalResolved) { flash("No pending approvals"); return; } setOverlay("approval"); return; } setOverlay(id); }; useEffect(() => { const onKey = (e) => { const typing = /^(INPUT|TEXTAREA)$/.test(document.activeElement && document.activeElement.tagName); // approval modal chords if (overlay === "approval") { if (typing) return; if (e.key === "a") { resolveApproval("approve"); e.preventDefault(); } else if (e.key === "A") { resolveApproval("auto"); e.preventDefault(); } else if (e.key === "r") { resolveApproval("reject"); e.preventDefault(); } else if (e.key === "Escape") setOverlay(null); return; } if (e.key === "Escape") { if (overlay) { setOverlay(null); e.preventDefault(); } return; } if (typing) return; if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") { setOverlay("cmd"); e.preventDefault(); return; } if (overlay === "cmd") return; // palette owns keys if (overlay) return; // other overlays: only esc (above) switch (e.key) { case "p": case ":": case "/": setOverlay("cmd"); e.preventDefault(); break; case "e": open("events"); break; case "c": open("context"); break; case "g": open("graph"); break; case "m": open("models"); break; case "t": open("tools"); break; case "i": promptRef.current && promptRef.current.focus(); e.preventDefault(); break; case "a": open("approval"); break; case "F2": cycleDir(); e.preventDefault(); break; case "F3": cycle("accent", ACC_ORDER); e.preventDefault(); break; case "Tab": setFocusPanel((p) => p === "conv" ? "events" : "conv"); e.preventDefault(); break; default: break; } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [overlay, approvalResolved, t.direction, t.accent, resolveApproval]); // ── footer hints (contextual) ── const hints = (() => { if (overlay === "approval") return [["a", "approve"], ["A", "auto-session"], ["s", "steer"], ["r", "reject"], ["esc", "later"]]; if (overlay === "cmd") return [["↑↓", "move"], ["↵", "run"], ["esc", "close"]]; if (overlay) return [["↑↓", "navigate"], ["↵", "select"], ["esc", "back"]]; if (promptFocus) return [["↵", "send to correx"], ["esc", "blur"]]; return [["i", "message"], ["p", "commands"], ["a", "approval"], ["e", "events"], ["c", "context"], ["g", "graph"], ["m", "models"], ["t", "tools"], ["F2", "skin"]]; })(); const tokPct = Math.min(100, Math.round((D.CONTEXT_PACK.used / D.CONTEXT_PACK.budget) * 100) + (approvalResolved ? 4 : 0)); const spin = SPIN[frame % SPIN.length]; return (
{t.scanlines &&
} {/* top status line */}
correx · session {D.SESSION.name} · {D.SESSION.branch} · {activeModel} ({D.MODELS.find((m) => m.id === activeModel).provider}) {autoApprove && auto-approve} ctx
{tokPct}%
{sessionState === "awaiting_approval" ? "⏸ awaiting approval" : "▸ active"}
{/* main split */}
promptRef.current && promptRef.current.focus()}> {promptFocus ? "❯" : "›"} setPromptFocus(true)} onBlur={() => setPromptFocus(false)} onChange={(e) => setDraft(e.target.value)} onKeyDown={(e) => { e.stopPropagation(); if (e.key === "Enter") send(); else if (e.key === "Escape") promptRef.current.blur(); }} /> {!promptFocus && !draft && i focus · send}
}> {msgs.map((m, i) => { const streaming = i === streamTarget; const text = streaming ? m.text.slice(0, streamLen) : m.text; const who = m.role === "user" ? "you" : m.role === "kernel" ? "correx" : "agent"; return (
{who}{m.t} {text}{streaming && streamLen < m.text.length && }{streaming && streamLen >= m.text.length && sessionState === "awaiting_approval" && }
); })} {spin} paused : {spin} live}>
{events.map((e) => (
setOverlay("events")}> {e.t} {e.cat} {e.running && {spin} }{e.type} {e.text}{e.pending && a}
))}
{/* footer keybind bar */}
{hints.map(([k, l], i) => ( { const map = { p: () => setOverlay("cmd"), a: () => open("approval"), e: () => open("events"), c: () => open("context"), g: () => open("graph"), m: () => open("models"), t: () => open("tools"), i: () => promptRef.current && promptRef.current.focus(), F2: () => cycleDir() }; map[k] && map[k](); }}> {k}{l} ))} {THEMES[t.direction].label} · {t.accent}
{toast &&
{toast}
} {/* overlays */} {overlay === "cmd" && { setOverlay(null); setTimeout(() => open(id), 0); }} onClose={() => setOverlay(null)} />} {overlay === "approval" && resolveApproval(auto ? "auto" : "approve")} onReject={() => resolveApproval("reject")} onSteer={(n) => resolveApproval("steer", n)} onClose={() => setOverlay(null)} />} {overlay === "events" && setOverlay(null)} />} {overlay === "context" && setOverlay(null)} />} {overlay === "graph" && setOverlay(null)} />} {overlay === "models" && { setActiveModel(id); setOverlay(null); flash("Switched → " + id + " · re-synthesizing Context Pack"); pushEvent({ t: "14:12", cat: "Context", type: "pack.resynth", text: "for " + id }); }} onClose={() => setOverlay(null)} />} {overlay === "tools" && setTools((arr) => arr.map((x) => x.id === id ? { ...x, enabled: !x.enabled } : x))} onClose={() => setOverlay(null)} />} {/* tweaks */} setDirection(v)} /> { const map = { "#56c8d8": "cyan", "#e8b765": "amber", "#8fd96a": "green", "#c98fd9": "magenta", "#b9c0c9": "neutral" }; setTweak("accent", map[hex] || "cyan"); }} /> setTweak("fontSize", v)} /> setTweak("motion", v)} /> setTweak("scanlines", v)} />
); } ReactDOM.createRoot(document.getElementById("root")).render();