From 351b0576810194d46daab04a1da90a89c01bf4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Thu, 28 May 2026 22:28:20 -0600 Subject: [PATCH 01/33] Add startup state cleanup --- frontend/src/hooks/useStartupStateCleanup.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 frontend/src/hooks/useStartupStateCleanup.ts diff --git a/frontend/src/hooks/useStartupStateCleanup.ts b/frontend/src/hooks/useStartupStateCleanup.ts new file mode 100644 index 0000000..bffdf59 --- /dev/null +++ b/frontend/src/hooks/useStartupStateCleanup.ts @@ -0,0 +1,15 @@ +import { useEffect } from "react"; +import { useAppStore } from "../store/useAppStore"; + +export function useStartupStateCleanup() { + useEffect(() => { + const params = new URLSearchParams(window.location.search); + const requestedState = params.get("state") ?? params.get("mockupState"); + if (requestedState) return; + + const state = useAppStore.getState(); + if (state.mode === "calm" && !state.activeMockupStateId && state.activeCausalPath) { + state.setActiveCausalPath(undefined); + } + }, []); +} From 4fda170b2d3829ba22f806ad533a365779c21a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Thu, 28 May 2026 22:29:01 -0600 Subject: [PATCH 02/33] Add temporal memory expanded overlay --- .../TemporalMemoryExpandedOverlay.tsx | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx diff --git a/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx b/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx new file mode 100644 index 0000000..0f36041 --- /dev/null +++ b/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx @@ -0,0 +1,73 @@ +import { AnimatePresence, motion } from "motion/react"; +import { Clock, FastForward, Play, RotateCcw, Search, X } from "lucide-react"; +import { useAppStore } from "../../store/useAppStore"; + +export function TemporalMemoryExpandedOverlay() { + const memoryPanel = useAppStore((s) => s.panels.find((panel) => panel.id === "memory-ribbon")); + const timeline = useAppStore((s) => s.timeline); + const focusPanel = useAppStore((s) => s.focusPanel); + const setContextPanels = useAppStore((s) => s.setContextPanels); + const setComposerValue = useAppStore((s) => s.setComposerValue); + const expandPanel = useAppStore((s) => s.expandPanel); + const activeMockupStateId = useAppStore((s) => s.activeMockupStateId); + + const open = Boolean(memoryPanel?.expanded); + const events = timeline.slice(-12).reverse(); + + return ( + + {open ? ( + +
+
+ Temporal Memory + Timeline scrub, snapshots, rewind, and event replay +
+ +
+ +
+ + Search memory, timeline, decisions, artifacts... +
+ +
+ + + +
+ +
+ {events.map((event, index) => ( + + ))} +
+
+ ) : null} +
+ ); +} From 98930d70cbd6e0cd9be006f93e8d008691a9301f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Thu, 28 May 2026 22:29:31 -0600 Subject: [PATCH 03/33] Wire startup cleanup and temporal memory expansion --- frontend/src/components/shell/AppShell.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/components/shell/AppShell.tsx b/frontend/src/components/shell/AppShell.tsx index c47c754..6383969 100644 --- a/frontend/src/components/shell/AppShell.tsx +++ b/frontend/src/components/shell/AppShell.tsx @@ -4,6 +4,7 @@ import { useMetricSimulation } from "../../hooks/useMetricSimulation"; import { useKeyboardShortcuts } from "../../hooks/useKeyboardShortcuts"; import { usePersistentStore } from "../../hooks/usePersistentStore"; import { useWorkspaceBootstrap } from "../../hooks/useWorkspaceBootstrap"; +import { useStartupStateCleanup } from "../../hooks/useStartupStateCleanup"; import { usePresetFromUrl } from "../../dev/usePresetFromUrl"; import { StatePresetSwitcher } from "../../dev/StatePresetSwitcher"; import { LivingScene } from "../scene/LivingScene"; @@ -18,6 +19,7 @@ import { StateChoreographyOverlay } from "../overlays/StateChoreographyOverlay"; import { StateWorkbenchOverlay } from "../overlays/StateWorkbenchOverlay"; import { AgentConstellation } from "../overlays/AgentConstellation"; import { TemporalMemoryRibbon } from "../overlays/TemporalMemoryRibbon"; +import { TemporalMemoryExpandedOverlay } from "../overlays/TemporalMemoryExpandedOverlay"; import { LivingCanvas } from "../overlays/LivingCanvas"; import { AmbientAssistantBubble } from "../overlays/AmbientAssistantBubble"; import { ChatDock } from "../chat/ChatDock"; @@ -36,6 +38,7 @@ export function AppShell() { useKeyboardShortcuts(); usePersistentStore(); useWorkspaceBootstrap(); + useStartupStateCleanup(); usePresetFromUrl(); const mode = useAppStore((s) => s.mode); @@ -66,6 +69,7 @@ export function AppShell() { ))} + From 4f1b7121ca9befe1ace7310c9dd606a005e13798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Thu, 28 May 2026 22:31:16 -0600 Subject: [PATCH 04/33] Add temporal memory expansion styles --- frontend/src/styles/temporal.css | 182 +++++++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 frontend/src/styles/temporal.css diff --git a/frontend/src/styles/temporal.css b/frontend/src/styles/temporal.css new file mode 100644 index 0000000..4dbb825 --- /dev/null +++ b/frontend/src/styles/temporal.css @@ -0,0 +1,182 @@ +.temporal-expanded { + position: absolute; + z-index: 56; + left: 50%; + bottom: 180px; + width: min(980px, calc(100vw - 420px)); + max-height: min(520px, calc(100vh - 270px)); + transform: translateX(-50%); + border-radius: 30px; + padding: 16px; + overflow: hidden; + pointer-events: auto; +} + +.temporal-expanded__header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 18px; + padding-bottom: 12px; + border-bottom: 1px solid rgba(142, 227, 255, 0.12); +} + +.temporal-expanded__header strong, +.temporal-expanded__header span { + display: block; +} + +.temporal-expanded__header strong { + display: inline-flex; + align-items: center; + gap: 8px; + color: white; + font-size: 18px; + letter-spacing: -0.03em; +} + +.temporal-expanded__header span { + margin-top: 5px; + color: var(--text-muted); + font-size: 12px; +} + +.temporal-expanded__header button { + width: 34px; + height: 34px; + display: grid; + place-items: center; + border: 1px solid rgba(142, 227, 255, 0.14); + border-radius: 999px; + color: var(--text-secondary); + background: rgba(255, 255, 255, 0.035); + cursor: pointer; +} + +.temporal-expanded__search { + height: 42px; + display: grid; + grid-template-columns: 26px 1fr; + align-items: center; + gap: 8px; + margin: 14px 0; + border: 1px solid rgba(142, 227, 255, 0.12); + border-radius: 999px; + color: var(--cyan); + background: rgba(255, 255, 255, 0.035); + padding: 0 12px; +} + +.temporal-expanded__search span { + color: rgba(214, 231, 248, 0.5); + font-size: 12px; +} + +.temporal-expanded__scrub { + display: flex; + gap: 8px; + margin-bottom: 14px; +} + +.temporal-expanded__scrub button { + height: 32px; + display: inline-flex; + align-items: center; + gap: 7px; + border: 1px solid rgba(142, 227, 255, 0.12); + border-radius: 999px; + color: var(--text-secondary); + background: rgba(255, 255, 255, 0.035); + padding: 0 11px; + cursor: pointer; + font-size: 12px; +} + +.temporal-expanded__track { + max-height: 330px; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; + overflow: auto; + padding-right: 4px; +} + +.temporal-expanded__event { + min-height: 88px; + display: grid; + gap: 4px; + border: 1px solid rgba(142, 227, 255, 0.1); + border-radius: 20px; + color: var(--text-secondary); + background: + radial-gradient(circle at 0% 0%, rgba(47, 252, 255, 0.08), transparent 34%), + rgba(255, 255, 255, 0.025); + padding: 12px; + cursor: pointer; + text-align: left; +} + +.temporal-expanded__event:hover { + border-color: rgba(47, 252, 255, 0.28); + background: + radial-gradient(circle at 0% 0%, rgba(47, 252, 255, 0.14), transparent 34%), + rgba(47, 252, 255, 0.045); +} + +.temporal-expanded__event i, +.temporal-expanded__event em { + color: var(--text-muted); + font-size: 10px; + font-style: normal; +} + +.temporal-expanded__event strong { + color: white; + font-size: 12px; +} + +.temporal-expanded__event span { + color: var(--text-secondary); + font-size: 11px; + line-height: 1.4; +} + +.temporal-expanded__event--warning { + border-color: rgba(255, 191, 72, 0.22); + background: + radial-gradient(circle at 0% 0%, rgba(255, 191, 72, 0.12), transparent 34%), + rgba(255, 255, 255, 0.025); +} + +.temporal-expanded__event--critical { + border-color: rgba(255, 59, 95, 0.28); + background: + radial-gradient(circle at 0% 0%, rgba(255, 59, 95, 0.13), transparent 34%), + rgba(255, 255, 255, 0.025); +} + +.temporal-expanded__event--success { + border-color: rgba(56, 255, 179, 0.24); + background: + radial-gradient(circle at 0% 0%, rgba(56, 255, 179, 0.11), transparent 34%), + rgba(255, 255, 255, 0.025); +} + +.temporal-expanded--state-22 { + border-color: rgba(255, 191, 72, 0.36); + background: + radial-gradient(circle at 50% 0%, rgba(255, 191, 72, 0.12), transparent 38%), + radial-gradient(circle at 12% 80%, rgba(47, 252, 255, 0.08), transparent 32%), + rgba(7, 13, 31, 0.72); +} + +@media (max-width: 1180px) { + .temporal-expanded { + left: calc(50% + 36px); + width: calc(100vw - 170px); + } + + .temporal-expanded__track { + grid-template-columns: 1fr; + } +} From c0872850c585733e81ea37c2d08352df501c94eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Thu, 28 May 2026 22:31:37 -0600 Subject: [PATCH 05/33] Import temporal overlay styles --- frontend/src/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5178941..adc5174 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -11,6 +11,7 @@ import "./styles/motion.css"; import "./styles/command-palette.css"; import "./styles/drawers.css"; import "./styles/canvas.css"; +import "./styles/temporal.css"; import "./styles/animations.css"; import "./styles/responsive.css"; import "./styles/visual-atlas.css"; From b344dab0bbed9ebff7e28f16d9dd62e688a2e0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:27:58 -0600 Subject: [PATCH 06/33] Add product surface overlay router --- .../overlays/ProductSurfaceOverlay.tsx | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 frontend/src/components/overlays/ProductSurfaceOverlay.tsx diff --git a/frontend/src/components/overlays/ProductSurfaceOverlay.tsx b/frontend/src/components/overlays/ProductSurfaceOverlay.tsx new file mode 100644 index 0000000..807294e --- /dev/null +++ b/frontend/src/components/overlays/ProductSurfaceOverlay.tsx @@ -0,0 +1,33 @@ +import { AnimatePresence } from "motion/react"; +import { useAppStore } from "../../store/useAppStore"; +import { SettingsDrawer } from "../surfaces/SettingsDrawer"; +import { NotificationsDrawer } from "../surfaces/NotificationsDrawer"; +import { ArtifactInspectorDrawer } from "../surfaces/ArtifactInspectorDrawer"; +import { ProductModalStack } from "../surfaces/ProductModalStack"; + +const productDrawers = new Set(["settings", "notifications", "artifact-inspector"]); +const productModals = new Set(["add-widget", "context-picker", "model-selector", "export", "approval", "shortcuts", "compare", "stop-confirm"]); + +export function isProductSurfaceDrawer(drawer?: string) { + return Boolean(drawer && productDrawers.has(drawer)); +} + +export function isProductSurfaceModal(modal?: string) { + return Boolean(modal && productModals.has(modal)); +} + +export function ProductSurfaceOverlay() { + const activeDrawer = useAppStore((s) => s.activeDrawer); + const activeModal = useAppStore((s) => s.activeModal); + + return ( + <> + + {activeDrawer === "settings" ? : null} + {activeDrawer === "notifications" ? : null} + {activeDrawer === "artifact-inspector" ? : null} + + {isProductSurfaceModal(activeModal) ? : null} + + ); +} From e10ff1a0478d5b864a790d0ac15ae8dc613c9117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:31:10 -0600 Subject: [PATCH 07/33] Add reusable product surface shell --- .../src/components/surfaces/SurfaceShell.tsx | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 frontend/src/components/surfaces/SurfaceShell.tsx diff --git a/frontend/src/components/surfaces/SurfaceShell.tsx b/frontend/src/components/surfaces/SurfaceShell.tsx new file mode 100644 index 0000000..c276413 --- /dev/null +++ b/frontend/src/components/surfaces/SurfaceShell.tsx @@ -0,0 +1,85 @@ +import type { ReactNode } from "react"; +import { motion } from "motion/react"; +import { X } from "lucide-react"; +import { useAppStore } from "../../store/useAppStore"; +import type { ModalId } from "../../types/app"; + +export function ProductDrawerShell({ + title, + subtitle, + icon, + children, +}: { + title: string; + subtitle: string; + icon: ReactNode; + children: ReactNode; +}) { + const setDrawerOpen = useAppStore((s) => s.setDrawerOpen); + + return ( + +
+ {icon} +
+ {title} + {subtitle} +
+ +
+
{children}
+
+ ); +} + +export function ProductModalShell({ + modalId, + title, + subtitle, + icon, + children, +}: { + modalId: ModalId; + title: string; + subtitle: string; + icon: ReactNode; + children: ReactNode; +}) { + const setModalOpen = useAppStore((s) => s.setModalOpen); + + return ( + +
+ {icon} +
+ {title} + {subtitle} +
+ +
+
{children}
+
+ ); +} From 2ee64077aefb6e58e5a16b206c79be5b6b9b8a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:33:30 -0600 Subject: [PATCH 08/33] Add settings product drawer --- .../components/surfaces/SettingsDrawer.tsx | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 frontend/src/components/surfaces/SettingsDrawer.tsx diff --git a/frontend/src/components/surfaces/SettingsDrawer.tsx b/frontend/src/components/surfaces/SettingsDrawer.tsx new file mode 100644 index 0000000..47d88af --- /dev/null +++ b/frontend/src/components/surfaces/SettingsDrawer.tsx @@ -0,0 +1,42 @@ +import { Cpu, Settings, SlidersHorizontal } from "lucide-react"; +import { useAppStore } from "../../store/useAppStore"; +import { ProductDrawerShell } from "./SurfaceShell"; + +export function SettingsDrawer() { + const mode = useAppStore((s) => s.mode); + const composer = useAppStore((s) => s.composer); + const performanceOverlayOpen = useAppStore((s) => s.performanceOverlayOpen); + const setPerformanceOverlayOpen = useAppStore((s) => s.setPerformanceOverlayOpen); + const layoutEditMode = useAppStore((s) => s.layoutEditMode); + const setLayoutEditMode = useAppStore((s) => s.setLayoutEditMode); + + const rows = [ + ["System mode", mode], + ["Selected model", composer.selectedModel], + ["Run mode", composer.selectedMode], + ["Tools", composer.selectedTools.join(" / ")], + ]; + + return ( + }> +
+ {rows.map(([label, value]) => ( +
+ {label} + {value} +
+ ))} +
+
+ + +
+
+ ); +} From 1143ab0843b3c05a0fb19e318d0bff1c7d9669c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:33:57 -0600 Subject: [PATCH 09/33] Add notifications product drawer --- .../surfaces/NotificationsDrawer.tsx | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 frontend/src/components/surfaces/NotificationsDrawer.tsx diff --git a/frontend/src/components/surfaces/NotificationsDrawer.tsx b/frontend/src/components/surfaces/NotificationsDrawer.tsx new file mode 100644 index 0000000..81b4a3f --- /dev/null +++ b/frontend/src/components/surfaces/NotificationsDrawer.tsx @@ -0,0 +1,25 @@ +import { Bell } from "lucide-react"; +import { useAppStore } from "../../store/useAppStore"; +import { ProductDrawerShell } from "./SurfaceShell"; + +export function NotificationsDrawer() { + const eventToasts = useAppStore((s) => s.eventToasts); + const timeline = useAppStore((s) => s.timeline); + const items = eventToasts.length + ? eventToasts.map((toast) => ({ id: toast.id, title: toast.title, description: toast.description, severity: toast.severity, label: "toast" })) + : timeline.slice(-8).reverse().map((event) => ({ id: event.id, title: event.title, description: event.description, severity: event.severity, label: event.type })); + + return ( + }> +
+ {items.map((item) => ( +
+ {item.label} + {item.title} + {item.description ? {item.description} : null} +
+ ))} +
+
+ ); +} From e4ef4237373e424ff2b3ce36126b37ac4b906345 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:35:59 -0600 Subject: [PATCH 10/33] Add artifact inspector product drawer --- .../surfaces/ArtifactInspectorDrawer.tsx | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 frontend/src/components/surfaces/ArtifactInspectorDrawer.tsx diff --git a/frontend/src/components/surfaces/ArtifactInspectorDrawer.tsx b/frontend/src/components/surfaces/ArtifactInspectorDrawer.tsx new file mode 100644 index 0000000..8905338 --- /dev/null +++ b/frontend/src/components/surfaces/ArtifactInspectorDrawer.tsx @@ -0,0 +1,55 @@ +import { Download, FileText, Layers } from "lucide-react"; +import { useAppStore } from "../../store/useAppStore"; +import type { PanelId } from "../../types/app"; +import { ProductDrawerShell } from "./SurfaceShell"; + +function panelLabel(id: PanelId) { + const labels: Record = { + "system-health": "System Health", + "project-nexus": "Project Nexus", + "realtime-insights": "Real-Time Insights", + "model-performance": "Model Performance", + "data-stream": "Data Stream", + "pipeline-orchestrator": "Pipeline", + "activity-feed": "Activity", + "smart-suggestions": "Suggestions", + causality: "Causality", + "memory-ribbon": "Temporal Memory", + }; + return labels[id] ?? id; +} + +export function ArtifactInspectorDrawer() { + const artifacts = useAppStore((s) => s.artifacts); + const activeArtifactId = useAppStore((s) => s.activeArtifactId); + const setWorkspaceView = useAppStore((s) => s.setWorkspaceView); + const setActiveArtifact = useAppStore((s) => s.setActiveArtifact); + const artifact = artifacts.find((item) => item.id === activeArtifactId) ?? artifacts[artifacts.length - 1]; + + return ( + }> + {artifact ? ( + <> +
+ {artifact.kind} + {artifact.title} + {artifact.content.slice(0, 360)} +
+
+ {artifact.relatedPanelIds.map((panelId) => ( + + ))} +
+
+ + +
+ + ) : ( +
No artifact yet. Run a generate command to create a canvas object.
+ )} +
+ ); +} From 300dd8095c82d0215aab46d8fe581f9ad8629aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:38:02 -0600 Subject: [PATCH 11/33] Add real product modal stack --- .../components/surfaces/ProductModalStack.tsx | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 frontend/src/components/surfaces/ProductModalStack.tsx diff --git a/frontend/src/components/surfaces/ProductModalStack.tsx b/frontend/src/components/surfaces/ProductModalStack.tsx new file mode 100644 index 0000000..eb22821 --- /dev/null +++ b/frontend/src/components/surfaces/ProductModalStack.tsx @@ -0,0 +1,196 @@ +import { + Boxes, + ClipboardCheck, + Cpu, + Download, + GitCompare, + Keyboard, + Plus, + ShieldAlert, + Sparkles, + Square, + X, +} from "lucide-react"; +import { useAppStore } from "../../store/useAppStore"; +import type { ModalId, PanelId } from "../../types/app"; +import { ProductModalShell } from "./SurfaceShell"; + +function panelLabel(id: PanelId) { + const labels: Record = { + "system-health": "System Health", + "project-nexus": "Project Nexus", + "realtime-insights": "Real-Time Insights", + "model-performance": "Model Performance", + "data-stream": "Data Stream", + "pipeline-orchestrator": "Pipeline", + "activity-feed": "Activity", + "smart-suggestions": "Suggestions", + causality: "Causality", + "memory-ribbon": "Temporal Memory", + }; + return labels[id] ?? id; +} + +function AddWidgetModal() { + const setComposerValue = useAppStore((s) => s.setComposerValue); + const setModalOpen = useAppStore((s) => s.setModalOpen); + const templates = ["Latency causes", "Model drift", "Pipeline stage timing", "Cost pressure", "Agent work queue"]; + + return ( + }> +
+ {templates.map((template) => ( + + ))} +
+
+ ); +} + +function ContextPickerModal() { + const panels = useAppStore((s) => s.panels); + const contextPanelIds = useAppStore((s) => s.composer.contextPanelIds); + const setContextPanels = useAppStore((s) => s.setContextPanels); + const focusPanel = useAppStore((s) => s.focusPanel); + + function toggle(panelId: PanelId) { + const next = contextPanelIds.includes(panelId) + ? contextPanelIds.filter((id) => id !== panelId) + : [...contextPanelIds, panelId].slice(0, 6); + setContextPanels(next); + } + + return ( + }> +
+ {panels.map((panel) => ( + + ))} +
+
+ ); +} + +function ModelSelectorModal() { + const composer = useAppStore((s) => s.composer); + const setSelectedModel = useAppStore((s) => s.setSelectedModel); + const setSelectedMode = useAppStore((s) => s.setSelectedMode); + const models = ["GPT-5.5", "Local DeepSeek", "Qwen Coder", "Fast Router"]; + const modes: Array = ["fast", "deep", "creative", "code", "agent"]; + + return ( + }> +
Models
+
+ {models.map((model) => )} +
+
Modes
+
+ {modes.map((mode) => )} +
+
+ ); +} + +function ExportModal() { + const artifacts = useAppStore((s) => s.artifacts); + const timeline = useAppStore((s) => s.timeline); + + return ( + }> +
+
Artifacts{artifacts.length}
+
Timeline events{timeline.length}
+
FormatReport bundle
+
+
+
+ ); +} + +function ApprovalModal() { + const metrics = useAppStore((s) => s.metrics); + const setModalOpen = useAppStore((s) => s.setModalOpen); + const setDrawerOpen = useAppStore((s) => s.setDrawerOpen); + + return ( + }> +
+
Latency{Math.round(metrics.latencyMs)}ms
+
Pipeline{Math.round(metrics.pipelineSuccess)}%
+
Risk{metrics.latencyMs > 110 ? "high" : "medium"}
+
+
+ +
+
+ ); +} + +function ShortcutsModal() { + const shortcuts = [ + ["Cmd/Ctrl + K", "Command palette"], + ["Cmd/Ctrl + L", "Focus composer"], + ["Cmd/Ctrl + Enter", "Run command"], + ["Escape", "Close overlays / collapse panels"], + ]; + return ( + }> +
+ {shortcuts.map(([key, label]) =>
{key}{label}
)} +
+
+ ); +} + +function CompareModal() { + const artifacts = useAppStore((s) => s.artifacts); + const first = artifacts[0]; + const second = artifacts[1] ?? artifacts[0]; + + return ( + }> +
+ {[first, second].map((artifact, index) => ( +
+ Branch {index + 1} + {artifact?.title ?? "No branch"} + {artifact?.content.slice(0, 300) ?? "Generate an artifact to compare branches."} +
+ ))} +
+
+ ); +} + +function StopConfirmModal() { + const cancelActiveTasks = useAppStore((s) => s.cancelActiveTasks); + const setModalOpen = useAppStore((s) => s.setModalOpen); + const tasks = useAppStore((s) => s.tasks.filter((task) => ["queued", "planning", "running", "waiting"].includes(task.status))); + + return ( + }> +
Active tasks{tasks.length}Stopping cancels running work while preserving timeline, artifacts, and context.
+
+
+ ); +} + +export function ProductModalStack({ modalId }: { modalId: ModalId }) { + if (modalId === "add-widget") return ; + if (modalId === "context-picker") return ; + if (modalId === "model-selector") return ; + if (modalId === "export") return ; + if (modalId === "approval") return ; + if (modalId === "shortcuts") return ; + if (modalId === "compare") return ; + if (modalId === "stop-confirm") return ; + return null; +} From 492a731122958dbac43ce16e65dbd10ebf0411c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:42:46 -0600 Subject: [PATCH 12/33] Route dedicated product surfaces before fallback workbench --- .../overlays/StateWorkbenchOverlay.tsx | 29 ++++--------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/overlays/StateWorkbenchOverlay.tsx b/frontend/src/components/overlays/StateWorkbenchOverlay.tsx index e31d800..4884524 100644 --- a/frontend/src/components/overlays/StateWorkbenchOverlay.tsx +++ b/frontend/src/components/overlays/StateWorkbenchOverlay.tsx @@ -2,34 +2,16 @@ import { AnimatePresence, motion } from "motion/react"; import { X } from "lucide-react"; import { getMockupStateSpec } from "../../engine/mockupStateBank"; import { useAppStore } from "../../store/useAppStore"; +import { ProductSurfaceOverlay, isProductSurfaceDrawer, isProductSurfaceModal } from "./ProductSurfaceOverlay"; const drawerTitles: Record = { - settings: "Settings", - notifications: "Notifications", - "artifact-inspector": "Artifact Inspector", performance: "Performance Overlay", }; -const modalTitles: Record = { - "add-widget": "Add Widget", - "context-picker": "Context Picker", - "model-selector": "Model Selector", - export: "Export Workspace", - approval: "Deployment Approval", - shortcuts: "Keyboard Shortcuts", - compare: "Artifact Branch Compare", - "stop-confirm": "Stop Active Run?", -}; +const modalTitles: Record = {}; function linesForSurface(label: string) { - if (label.includes("Settings")) return ["Motion intensity", "Memory scope", "Backend: mock / remote", "Visual priority tuning"]; - if (label.includes("Notifications")) return ["Critical latency", "Tool result returned", "Artifact created", "Agent task completed"]; - if (label.includes("Artifact")) return ["Deployment Report", "Primary branch", "Related panels: pipeline, model, causality", "Export ready"]; - if (label.includes("Context")) return ["System Health", "Project Nexus", "Causal Insights", "Temporal Memory"]; - if (label.includes("Model")) return ["GPT-5.5 frontier", "Deep mode", "Latency budget: medium", "Tool policy: approved"]; - if (label.includes("Approval")) return ["Canary 5%", "Risk: medium", "Rollback gate: ready", "Human approval required"]; - if (label.includes("Shortcuts")) return ["Cmd/Ctrl+K command palette", "Cmd/Ctrl+L composer focus", "Cmd/Ctrl+Enter run", "Escape closes overlays"]; - if (label.includes("Compare")) return ["Branch A: concise", "Branch B: evidence-rich", "Branch C: deployment-safe", "Recommended: Branch B"]; + if (label.includes("Performance")) return ["FPS", "Memory", "Render cost", "Stream health"]; return ["Workspace snapshot", "Timeline range", "Artifacts and memory", "Ready"]; } @@ -41,11 +23,12 @@ export function StateWorkbenchOverlay() { const setModalOpen = useAppStore((s) => s.setModalOpen); const mockup = getMockupStateSpec(activeMockupStateId); - const drawerTitle = activeDrawer ? drawerTitles[activeDrawer] : undefined; - const modalTitle = activeModal ? modalTitles[activeModal] : undefined; + const drawerTitle = activeDrawer && !isProductSurfaceDrawer(activeDrawer) ? drawerTitles[activeDrawer] : undefined; + const modalTitle = activeModal && !isProductSurfaceModal(activeModal) ? modalTitles[activeModal] : undefined; return ( <> + {drawerTitle ? ( Date: Fri, 29 May 2026 05:43:53 -0600 Subject: [PATCH 13/33] Add basic product surface styles --- frontend/src/styles/product-surfaces.css | 1 + 1 file changed, 1 insertion(+) create mode 100644 frontend/src/styles/product-surfaces.css diff --git a/frontend/src/styles/product-surfaces.css b/frontend/src/styles/product-surfaces.css new file mode 100644 index 0000000..147ad34 --- /dev/null +++ b/frontend/src/styles/product-surfaces.css @@ -0,0 +1 @@ +.product-surface-drawer{position:absolute;z-index:74;top:72px;right:24px;bottom:116px;width:min(520px,calc(100vw - 310px));border-radius:30px;overflow:hidden;pointer-events:auto}.product-surface-modal{position:absolute;z-index:86;left:50%;top:50%;width:min(760px,calc(100vw - 140px));max-height:min(680px,calc(100vh - 140px));transform:translate(-50%,-50%);border-radius:30px;overflow:hidden;pointer-events:auto}.product-surface__header{min-height:72px;display:grid;grid-template-columns:42px 1fr 36px;align-items:center;gap:12px;padding:14px 18px;border-bottom:1px solid rgba(142,227,255,.12)}.product-surface__icon{width:40px;height:40px;display:grid;place-items:center;border-radius:16px;color:var(--cyan);background:rgba(47,252,255,.08);border:1px solid rgba(47,252,255,.12)}.product-surface__header strong,.product-surface__header em{display:block}.product-surface__header strong{color:white;font-size:16px}.product-surface__header em{margin-top:4px;color:var(--text-muted);font-size:12px;font-style:normal}.product-surface__header button{width:34px;height:34px;display:grid;place-items:center;border:1px solid rgba(142,227,255,.14);border-radius:999px;color:var(--text-secondary);background:rgba(255,255,255,.035);cursor:pointer}.product-surface__body{max-height:calc(100% - 72px);overflow:auto;padding:14px}.surface-stat-grid,.surface-card-list--grid,.surface-compare-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.surface-card-list,.surface-action-list{display:grid;gap:10px}.surface-action-list{margin-top:14px}.surface-stat-grid article,.surface-hero-card,.surface-card,.surface-template-card,.surface-compare-grid article{border:1px solid rgba(142,227,255,.1);border-radius:20px;background:rgba(255,255,255,.025);padding:12px}.surface-stat-grid em,.surface-hero-card em,.surface-card i,.surface-compare-grid em,.surface-section-title{display:block;color:var(--text-muted);font-size:10px;font-style:normal;text-transform:uppercase;letter-spacing:.06em}.surface-stat-grid strong,.surface-hero-card strong,.surface-card strong,.surface-template-card strong,.surface-compare-grid strong{display:block;margin-top:4px;color:white;font-size:13px}.surface-hero-card span,.surface-card span,.surface-template-card span,.surface-compare-grid span{display:block;margin-top:7px;color:var(--text-secondary);font-size:12px;line-height:1.45}.surface-action-list button,.surface-chip-row button,.surface-pill-grid button{min-height:34px;display:inline-flex;align-items:center;gap:8px;border:1px solid rgba(142,227,255,.12);border-radius:999px;color:var(--text-secondary);background:rgba(255,255,255,.035);padding:0 12px;cursor:pointer;font-size:12px}.surface-action-list button:hover,.surface-chip-row button:hover,.surface-pill-grid button:hover,.surface-pill-grid button.is-active,.surface-template-card.is-active{color:white;border-color:rgba(47,252,255,.32);background:rgba(47,252,255,.08)}.surface-template-card{min-height:110px;display:grid;gap:5px;color:var(--text-secondary);cursor:pointer;text-align:left}.surface-template-card svg{color:var(--cyan)}.surface-card--warning{border-color:rgba(255,191,72,.24)}.surface-card--critical{border-color:rgba(255,59,95,.28)}.surface-card--success{border-color:rgba(56,255,179,.24)}.surface-chip-row,.surface-pill-grid{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}.surface-section-title{margin:12px 0 8px}.surface-empty{border:1px solid rgba(142,227,255,.08);border-radius:20px;color:var(--text-muted);background:rgba(255,255,255,.025);padding:18px;text-align:center;font-size:12px}@media(max-width:1040px){.product-surface-drawer{left:90px;right:12px;width:auto}.product-surface-modal{width:calc(100vw - 120px)}.surface-card-list--grid,.surface-stat-grid,.surface-compare-grid{grid-template-columns:1fr}} \ No newline at end of file From 975ff726b4fb3adcf06467aed47e8928ec0078d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:47:30 -0600 Subject: [PATCH 14/33] Import product surface styles --- frontend/src/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index adc5174..bb8b1e7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -12,6 +12,7 @@ import "./styles/command-palette.css"; import "./styles/drawers.css"; import "./styles/canvas.css"; import "./styles/temporal.css"; +import "./styles/product-surfaces.css"; import "./styles/animations.css"; import "./styles/responsive.css"; import "./styles/visual-atlas.css"; From 27cdad23410b5c198228e922c0b1e46a7dc84f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 05:53:43 -0600 Subject: [PATCH 15/33] Fix temporal memory overlay TypeScript namespace issue --- .../src/components/overlays/TemporalMemoryExpandedOverlay.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx b/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx index 0f36041..f96f0ca 100644 --- a/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx +++ b/frontend/src/components/overlays/TemporalMemoryExpandedOverlay.tsx @@ -47,7 +47,7 @@ export function TemporalMemoryExpandedOverlay() {
- {events.map((event, index) => ( + {events.map((event) => ( - - - From 73416e3bfb53135e97ae0cb9bf362580f58fabdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 09:03:29 -0600 Subject: [PATCH 23/33] Wire left rail to real product surfaces --- frontend/src/components/shell/LeftRail.tsx | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/shell/LeftRail.tsx b/frontend/src/components/shell/LeftRail.tsx index ef3f488..d20a299 100644 --- a/frontend/src/components/shell/LeftRail.tsx +++ b/frontend/src/components/shell/LeftRail.tsx @@ -10,6 +10,7 @@ import { Home, LayoutDashboard, PackageCheck, + Settings, ShieldCheck, Sparkles, } from "lucide-react"; @@ -19,28 +20,35 @@ const navItems = [ { label: "Home", icon: Home, action: "dashboard" }, { label: "Projects", icon: Folder, action: "dashboard" }, { label: "Datasets", icon: Database, action: "dashboard" }, - { label: "Models", icon: Box, action: "dashboard" }, + { label: "Models", icon: Box, action: "model-selector" }, { label: "Pipelines", icon: GitBranch, action: "dashboard" }, - { label: "Deployments", icon: PackageCheck, action: "canvas" }, + { label: "Deployments", icon: PackageCheck, action: "approval" }, { label: "Monitoring", icon: ShieldCheck, action: "dashboard" }, { label: "Agents", icon: Bot, action: "agent-queue" }, { label: "Memory", icon: Database, action: "memory" }, - { label: "Alerts", icon: Bell, action: "dashboard", badge: 3 }, - { label: "Reports", icon: FileText, action: "canvas" }, + { label: "Alerts", icon: Bell, action: "notifications", badge: 3 }, + { label: "Reports", icon: FileText, action: "artifact-inspector" }, + { label: "Settings", icon: Settings, action: "settings" }, ] as const; export function LeftRail() { const setWorkspaceView = useAppStore((s) => s.setWorkspaceView); const setDrawerOpen = useAppStore((s) => s.setDrawerOpen); + const setModalOpen = useAppStore((s) => s.setModalOpen); const workspaceView = useAppStore((s) => s.workspaceView); const runAction = (action: (typeof navItems)[number]["action"]) => { - if (action === "agent-queue" || action === "memory") { - setDrawerOpen(action); + if (action === "dashboard" || action === "canvas") { + setWorkspaceView(action); return; } - setWorkspaceView(action); + if (["agent-queue", "memory", "notifications", "artifact-inspector", "settings"].includes(action)) { + setDrawerOpen(action as never); + return; + } + + setModalOpen(action as never); }; return ( From 2b73e48fcd214938c0468074832d93605c9bee98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 09:11:39 -0600 Subject: [PATCH 24/33] Include temporal memory anchor in frontend proof CI --- .github/workflows/frontend-proof.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend-proof.yml b/.github/workflows/frontend-proof.yml index 9126617..4a42f91 100644 --- a/.github/workflows/frontend-proof.yml +++ b/.github/workflows/frontend-proof.yml @@ -35,11 +35,11 @@ jobs: - name: Capture anchor visual states working-directory: frontend - run: npm run proof:visual -- --states=01,06,26,37,61 --label=ci-anchors + run: npm run proof:visual -- --states=01,06,22,26,37,61 --label=ci-anchors - name: Produce non-strict pixel receipt working-directory: frontend - run: npm run proof:pixel -- --states=01,06,26,37,61 + run: npm run proof:pixel -- --states=01,06,22,26,37,61 - name: Summarize proof working-directory: frontend From deb5eb338d120467f7117343b8366e76cbe0c63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 09:30:16 -0600 Subject: [PATCH 25/33] Keep StateWorkbenchOverlay as fallback only --- frontend/src/components/overlays/StateWorkbenchOverlay.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/overlays/StateWorkbenchOverlay.tsx b/frontend/src/components/overlays/StateWorkbenchOverlay.tsx index 4884524..1ba2371 100644 --- a/frontend/src/components/overlays/StateWorkbenchOverlay.tsx +++ b/frontend/src/components/overlays/StateWorkbenchOverlay.tsx @@ -2,7 +2,7 @@ import { AnimatePresence, motion } from "motion/react"; import { X } from "lucide-react"; import { getMockupStateSpec } from "../../engine/mockupStateBank"; import { useAppStore } from "../../store/useAppStore"; -import { ProductSurfaceOverlay, isProductSurfaceDrawer, isProductSurfaceModal } from "./ProductSurfaceOverlay"; +import { isProductSurfaceDrawer, isProductSurfaceModal } from "./ProductSurfaceOverlay"; const drawerTitles: Record = { performance: "Performance Overlay", @@ -28,7 +28,6 @@ export function StateWorkbenchOverlay() { return ( <> - {drawerTitle ? ( Date: Fri, 29 May 2026 09:32:37 -0600 Subject: [PATCH 26/33] Render product surfaces separately from fallback workbench --- frontend/src/components/shell/AppShell.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/components/shell/AppShell.tsx b/frontend/src/components/shell/AppShell.tsx index 6383969..368f1e8 100644 --- a/frontend/src/components/shell/AppShell.tsx +++ b/frontend/src/components/shell/AppShell.tsx @@ -17,6 +17,7 @@ import { FocusHalo } from "../overlays/FocusHalo"; import { FlowFieldOverlay } from "../overlays/FlowFieldOverlay"; import { StateChoreographyOverlay } from "../overlays/StateChoreographyOverlay"; import { StateWorkbenchOverlay } from "../overlays/StateWorkbenchOverlay"; +import { ProductSurfaceOverlay } from "../overlays/ProductSurfaceOverlay"; import { AgentConstellation } from "../overlays/AgentConstellation"; import { TemporalMemoryRibbon } from "../overlays/TemporalMemoryRibbon"; import { TemporalMemoryExpandedOverlay } from "../overlays/TemporalMemoryExpandedOverlay"; @@ -76,6 +77,7 @@ export function AppShell() { + From ff7279cc87b2311f64311f04c1a9c6ae7f50e9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 09:44:10 -0600 Subject: [PATCH 27/33] Document AE See-Suite MCP setup --- docs/ae-see-suite/MCP_SETUP.md | 87 ++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 docs/ae-see-suite/MCP_SETUP.md diff --git a/docs/ae-see-suite/MCP_SETUP.md b/docs/ae-see-suite/MCP_SETUP.md new file mode 100644 index 0000000..d394b51 --- /dev/null +++ b/docs/ae-see-suite/MCP_SETUP.md @@ -0,0 +1,87 @@ +# AE See-Suite MCP Setup + +This repo now includes a dedicated AE See-Suite MCP lane for build/proof control of the living dashboard. + +## Server + +```bash +node ./scripts/ae-see-suite-mcp-server.mjs +``` + +The server registers a focused AE See-Suite tool pack. It does not replace the broader OrangeBOX MCP server; it gives Claude Code/Codex a smaller surface specifically for the living dashboard work. + +## Tools + +- `ae_see_suite_help` +- `ae_see_suite_build_frontend` +- `ae_see_suite_proof_anchors` +- `ae_see_suite_proof_72` +- `ae_see_suite_state_open_command` + +## Product law encoded in MCP + +- One AppShell. +- Many semantic states. +- Do not build 72 pages. +- Do not use mockup images as UI. +- Use the 72-state atlas as proof/QA, not production logic. + +## Anchor state proof target + +The canonical anchor states are: + +- `01` Calm Overview +- `06` Alert / Critical Latency +- `22` Temporal Memory Expanded +- `26` Command Palette +- `37` Agent Queue +- `61` Living Canvas + +Run anchor proof through MCP with: + +```txt +ae_see_suite_proof_anchors +``` + +Equivalent shell path: + +```bash +npm run build:web +npm run frontend:proof:visual -- --states=01,06,22,26,37,61 --label=anchor-pass +npm run frontend:proof:pixel -- --states=01,06,22,26,37,61 +``` + +Run the full atlas proof with: + +```txt +ae_see_suite_proof_72 +``` + +Equivalent shell path: + +```bash +npm run build:web +npm run frontend:proof:visual:72 +``` + +## Example Claude Desktop / MCP config shape + +Use the local repo path that exists on the machine running the MCP client. + +```json +{ + "mcpServers": { + "ae-see-suite": { + "command": "node", + "args": ["C:/AtomEons/orangebox-delta/scripts/ae-see-suite-mcp-server.mjs"], + "env": { + "ORANGEBOX_URL": "http://127.0.0.1:8787" + } + } + } +} +``` + +## Operating note + +The MCP tools call the existing OrangeBOX receipted executor for builds/proofs. The OrangeBOX service must be running at `ORANGEBOX_URL` for build/proof tools to execute. The state URL helper does not require execution; it returns direct browser URLs and acceptance checks. From b4219d4f3c177cc610125f964e98e7cd95b04a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Fri, 29 May 2026 10:15:33 -0600 Subject: [PATCH 28/33] Add AE See-Suite MCP syntax workflow --- .github/workflows/ae-see-suite-mcp.yml | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/ae-see-suite-mcp.yml diff --git a/.github/workflows/ae-see-suite-mcp.yml b/.github/workflows/ae-see-suite-mcp.yml new file mode 100644 index 0000000..bd4d308 --- /dev/null +++ b/.github/workflows/ae-see-suite-mcp.yml @@ -0,0 +1,31 @@ +name: AE See-Suite MCP + +on: + pull_request: + paths: + - "scripts/ae-see-suite-mcp-*.mjs" + - ".github/workflows/ae-see-suite-mcp.yml" + push: + branches: [main] + paths: + - "scripts/ae-see-suite-mcp-*.mjs" + - ".github/workflows/ae-see-suite-mcp.yml" + +jobs: + ae-see-suite-mcp-check: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Syntax check AE See-Suite MCP tools + run: node --check ./scripts/ae-see-suite-mcp-tools.mjs + + - name: Syntax check AE See-Suite MCP server + run: node --check ./scripts/ae-see-suite-mcp-server.mjs From 391b8f1d38ffbe6b3e733546ee74c8d185f0e144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Sat, 30 May 2026 00:14:09 -0600 Subject: [PATCH 29/33] Make calm boot causality-free in store baseline --- frontend/src/store/useAppStore.ts | 335 ++++++++++-------------------- 1 file changed, 107 insertions(+), 228 deletions(-) diff --git a/frontend/src/store/useAppStore.ts b/frontend/src/store/useAppStore.ts index db9b074..64c9f7f 100644 --- a/frontend/src/store/useAppStore.ts +++ b/frontend/src/store/useAppStore.ts @@ -120,7 +120,7 @@ export const useAppStore = create((set, get) => ({ focusPanelId: undefined, panels: seedPanels, agents: seedAgents, - activeCausalPath: createLatencyCausalPath(), + activeCausalPath: undefined, timeline: persisted?.timeline ?? seedTimeline, messages: persisted?.messages ?? seedMessages, tasks: [], @@ -145,10 +145,9 @@ export const useAppStore = create((set, get) => ({ pendingApprovals: [], eventToasts: [], performanceOverlayOpen: false, - chatDockExpanded: false, + chatDockExpanded: true, layoutEditMode: false, activeMockupStateId: undefined, - setWorkspaceId: (workspaceId) => set({ workspaceId }), setMode: (mode) => set({ mode }), setWorkspaceView: (workspaceView) => set({ workspaceView }), @@ -161,8 +160,8 @@ export const useAppStore = create((set, get) => ({ panels: state.panels.map((panel) => ({ ...panel, dimmed: false, highlighted: false })), }; } - const focusedPanel = state.panels.find((panel) => panel.id === panelId); - const related = new Set(focusedPanel ? [focusedPanel.id, ...focusedPanel.connectedTo] : [panelId]); + const focused = state.panels.find((panel) => panel.id === panelId); + const related = new Set(focused ? [focused.id, ...focused.connectedTo] : [panelId]); return { focusPanelId: panelId, panels: state.panels.map((panel) => ({ @@ -170,10 +169,7 @@ export const useAppStore = create((set, get) => ({ dimmed: !related.has(panel.id), highlighted: related.has(panel.id) && panel.id !== panelId, })), - composer: { - ...state.composer, - contextPanelIds: Array.from(related).slice(0, 4), - }, + composer: { ...state.composer, contextPanelIds: Array.from(related).slice(0, 4) }, }; }), clearFocus: () => @@ -183,271 +179,154 @@ export const useAppStore = create((set, get) => ({ })), expandPanel: (panelId, expanded) => set((state) => ({ - panels: state.panels.map((panel) => ({ ...panel, expanded: panel.id === panelId ? expanded : false })), + panels: state.panels.map((panel) => (panel.id === panelId ? { ...panel, expanded } : panel)), focusPanelId: expanded ? panelId : state.focusPanelId, })), - collapseAllPanels: () => - set((state) => ({ - panels: state.panels.map((panel) => ({ ...panel, expanded: false })), - })), - setPanelSeverity: (panelId, severity) => - set((state) => ({ - panels: state.panels.map((panel) => (panel.id === panelId ? { ...panel, severity } : panel)), - })), - setComposerValue: (value) => - set((state) => ({ - composer: { ...state.composer, value, slashMenuOpen: value.startsWith("/") }, - mode: state.composer.isFocused ? "listening" : state.mode, - })), - setComposerFocus: (isFocused) => - set((state) => ({ - composer: { ...state.composer, isFocused }, - mode: isFocused && state.mode === "calm" ? "listening" : !isFocused && state.mode === "listening" ? "calm" : state.mode, - })), + collapseAllPanels: () => set((state) => ({ panels: state.panels.map((panel) => ({ ...panel, expanded: false })) })), + setPanelSeverity: (panelId, severity) => set((state) => ({ panels: state.panels.map((panel) => (panel.id === panelId ? { ...panel, severity } : panel)) })), + setComposerValue: (value) => set((state) => ({ composer: { ...state.composer, value, slashMenuOpen: value.startsWith("/") } })), + setComposerFocus: (isFocused) => set((state) => ({ composer: { ...state.composer, isFocused }, mode: isFocused ? "listening" : state.mode })), setSelectedMode: (selectedMode) => set((state) => ({ composer: { ...state.composer, selectedMode } })), setSelectedModel: (selectedModel) => set((state) => ({ composer: { ...state.composer, selectedModel } })), toggleTool: (tool) => - set((state) => { - const selectedTools = state.composer.selectedTools.includes(tool) - ? state.composer.selectedTools.filter((item) => item !== tool) - : [...state.composer.selectedTools, tool]; - return { composer: { ...state.composer, selectedTools } }; - }), + set((state) => ({ + composer: { + ...state.composer, + selectedTools: state.composer.selectedTools.includes(tool) + ? state.composer.selectedTools.filter((item) => item !== tool) + : [...state.composer.selectedTools, tool], + }, + })), setContextPanels: (contextPanelIds) => set((state) => ({ composer: { ...state.composer, contextPanelIds } })), setSlashMenuOpen: (slashMenuOpen) => set((state) => ({ composer: { ...state.composer, slashMenuOpen } })), setPlanPreview: (planPreview) => set((state) => ({ composer: { ...state.composer, planPreview } })), - addMessage: (message) => set((state) => ({ messages: [...state.messages, message] })), - updateMessage: (id, patch) => - set((state) => ({ - messages: state.messages.map((message) => (message.id === id ? { ...message, ...patch } : message)), - })), + addMessage: (message) => set((state) => ({ messages: [...state.messages, message].slice(-100) })), + updateMessage: (id, patch) => set((state) => ({ messages: state.messages.map((message) => (message.id === id ? { ...message, ...patch } : message)) })), addTimelineEvent: (event) => set((state) => ({ timeline: [...state.timeline, event].slice(-120) })), - addTask: (task) => set((state) => ({ tasks: [...state.tasks, task].slice(-40) })), - updateTask: (id, patch) => + addTask: (task) => set((state) => ({ tasks: [...state.tasks, task].slice(-80) })), + updateTask: (id, patch) => set((state) => ({ tasks: state.tasks.map((task) => (task.id === id ? { ...task, ...patch } : task)) })), + completeTask: (id) => set((state) => ({ - tasks: state.tasks.map((task) => (task.id === id ? { ...task, ...patch } : task)), + tasks: state.tasks.map((task) => (task.id === id ? { ...task, status: "complete", progress: 100, completedAt: Date.now() } : task)), + agents: state.agents.map((agent) => (agent.taskId === id ? { ...agent, state: "complete", taskId: undefined, energy: 0.68 } : agent)), })), - completeTask: (id) => - set((state) => { - const completedTask = state.tasks.find((task) => task.id === id); - return { - tasks: state.tasks.map((task) => - task.id === id ? { ...task, status: "complete", progress: 100, completedAt: Date.now() } : task, - ), - agents: completedTask - ? state.agents.map((agent) => - agent.id === completedTask.assignedAgentId ? { ...agent, state: "complete", taskId: undefined, energy: 0.68 } : agent, - ) - : state.agents, - }; - }), cancelActiveTasks: () => set((state) => ({ - mode: state.activeCausalPath ? "alert" : "calm", - energy: state.activeCausalPath ? 0.82 : 0.55, + mode: "calm", + energy: 0.55, tasks: state.tasks.map((task) => ["queued", "planning", "running", "waiting"].includes(task.status) - ? { ...task, status: "cancelled", progress: Math.min(task.progress, 99), completedAt: Date.now() } + ? { ...task, status: "cancelled", completedAt: Date.now() } : task, ), - agents: state.agents.map((agent) => ({ - ...agent, - state: agent.state === "working" || agent.state === "thinking" || agent.state === "blocked" ? "idle" : agent.state, - taskId: undefined, - energy: Math.max(0.42, agent.energy * 0.7), - })), + agents: state.agents.map((agent) => ({ ...agent, state: agent.state === "blocked" ? "blocked" : "idle", taskId: undefined, energy: 0.48 })), })), - updateAgent: (id, patch) => - set((state) => ({ agents: state.agents.map((agent) => (agent.id === id ? { ...agent, ...patch } : agent)) })), + updateAgent: (id, patch) => set((state) => ({ agents: state.agents.map((agent) => (agent.id === id ? { ...agent, ...patch } : agent)) })), setActiveCausalPath: (activeCausalPath) => set({ activeCausalPath, mode: activeCausalPath ? "alert" : "calm" }), triggerLatencyScenario: () => set((state) => { - const activeCausalPath = createLatencyCausalPath(); - const activeIds: PanelId[] = ["realtime-insights", "data-stream", "model-performance", "system-health", "activity-feed", "causality"]; + const path = createLatencyCausalPath(); return { - activeCausalPath, mode: "alert", energy: 1, - composer: { ...state.composer, contextPanelIds: activeIds.slice(0, 4) }, + activeCausalPath: path, panels: state.panels.map((panel) => { - if (panel.id === "realtime-insights") return { ...panel, dimmed: false, severity: "warning" }; - if (panel.id === "system-health") return { ...panel, dimmed: false, severity: "critical" }; - if (panel.id === "data-stream") return { ...panel, dimmed: false, severity: "warning" }; - return { ...panel, dimmed: !activeIds.includes(panel.id), highlighted: activeIds.includes(panel.id) }; - }), - agents: state.agents.map((agent) => { - if (agent.id === "watcher") return { ...agent, state: "working", energy: 1, connectedPanel: "realtime-insights" }; - if (agent.id === "analyst") return { ...agent, state: "thinking", energy: 0.92, connectedPanel: "causality" }; - return { ...agent, energy: Math.max(0.42, agent.energy * 0.76) }; + if (["realtime-insights", "data-stream", "system-health"].includes(panel.id)) return { ...panel, severity: "warning", dimmed: false }; + if (panel.id === "causality") return { ...panel, severity: "critical", dimmed: false }; + return { ...panel, dimmed: !["model-performance", "activity-feed", "smart-suggestions"].includes(panel.id) }; }), + agents: state.agents.map((agent) => + agent.id === "watcher" || agent.id === "analyst" ? { ...agent, state: "working", energy: 1, connectedPanel: "causality" } : { ...agent, energy: 0.48 }, + ), timeline: [ ...state.timeline, - createTimelineEvent({ - title: "Latency anomaly activated", - description: "Causal path generated across gateway, model, resource, and user impact signals.", - type: "alert", - severity: "warning", - relatedPanelIds: activeIds, - }), - ], - eventToasts: [ - ...state.eventToasts.slice(-4), - { id: createId("toast"), title: "Causal path generated", description: activeCausalPath.title, severity: "warning", createdAt: Date.now() }, - ], + createTimelineEvent({ title: "Latency anomaly traced", description: path.title, type: "alert", severity: "warning", relatedPanelIds: ["causality", "data-stream", "system-health"] }), + ].slice(-120), }; }), clearCausality: () => set((state) => ({ - activeCausalPath: undefined, mode: "calm", energy: 0.55, + activeCausalPath: undefined, panels: state.panels.map((panel) => ({ ...panel, dimmed: false, highlighted: false, severity: undefined })), - agents: state.agents.map((agent) => ({ - ...agent, - state: agent.id === "watcher" || agent.id === "analyst" ? "watching" : "idle", - energy: 0.55, - taskId: undefined, - })), + agents: state.agents.map((agent) => ({ ...agent, state: agent.id === "watcher" ? "watching" : "idle", taskId: undefined, energy: 0.55 })), })), tickMetrics: () => set((state) => { - const alertActive = state.mode === "alert"; - const thinkingActive = ["thinking", "analyzing", "generating"].includes(state.mode); - const metrics: SystemMetrics = { - cpu: jitterMetric(state.metrics.cpu + (alertActive ? 1.2 : thinkingActive ? 0.5 : 0), alertActive ? 6 : 3, 12, 98), - memory: jitterMetric(state.metrics.memory + (thinkingActive ? 0.4 : 0), 3, 20, 96), - gpu: jitterMetric(state.metrics.gpu + (state.mode === "generating" ? 1 : 0), 5, 10, 98), - network: jitterMetric(state.metrics.network + (alertActive ? 1.4 : 0), 6, 18, 99), - latencyMs: jitterMetric(state.metrics.latencyMs + (alertActive ? 8 : -1.5), alertActive ? 28 : 8, 24, alertActive ? 220 : 120), - throughputTbs: jitterMetric(state.metrics.throughputTbs, 0.16, 1.2, 3.8), - eventsPerSecondM: jitterMetric(state.metrics.eventsPerSecondM, 0.24, 0.8, 3.4), - modelAccuracy: jitterMetric(state.metrics.modelAccuracy, 0.18, 88, 98), - precision: jitterMetric(state.metrics.precision, 0.22, 86, 98), - recall: jitterMetric(state.metrics.recall, 0.22, 86, 98), - f1: jitterMetric(state.metrics.f1, 0.18, 86, 98), - activeStreams: Math.round(jitterMetric(state.metrics.activeStreams, 3, 14, 42)), - pipelineSuccess: jitterMetric(state.metrics.pipelineSuccess - (alertActive ? 0.12 : 0), 0.25, 92, 99.8), + const metrics = { + ...state.metrics, + cpu: jitterMetric(state.metrics.cpu + (state.mode === "alert" ? 1.2 : 0), 5, 12, 98), + memory: jitterMetric(state.metrics.memory, 3, 20, 96), + gpu: jitterMetric(state.metrics.gpu + (state.mode === "generating" ? 1.3 : 0), 5, 10, 99), + network: jitterMetric(state.metrics.network + (state.mode === "alert" ? 1.8 : 0), 5, 18, 99), + latencyMs: Math.round(jitterMetric(state.metrics.latencyMs + (state.mode === "alert" ? 3.8 : -0.6), state.mode === "alert" ? 18 : 5, 28, state.mode === "alert" ? 260 : 90)), }; - return { metrics, metricHistory: [...state.metricHistory.slice(-48), { timestamp: Date.now(), system: metrics }] }; - }), - ingestMetricSnapshot: (incoming) => - set((state) => { - const metrics = { ...state.metrics, ...incoming }; - return { metrics, metricHistory: [...state.metricHistory.slice(-48), { timestamp: Date.now(), system: metrics }] }; + return { metrics, metricHistory: [...state.metricHistory.slice(-40), { timestamp: Date.now(), system: metrics }] }; }), + ingestMetricSnapshot: (incoming) => set((state) => { + const metrics = { ...state.metrics, ...incoming }; + return { metrics, metricHistory: [...state.metricHistory.slice(-40), { timestamp: Date.now(), system: metrics }] }; + }), setDrawerOpen: (activeDrawer) => set({ activeDrawer }), setModalOpen: (activeModal) => set({ activeModal }), - setCommandPaletteOpen: (commandPaletteOpen) => - set({ commandPaletteOpen, commandPaletteQuery: commandPaletteOpen ? get().commandPaletteQuery : "" }), + setCommandPaletteOpen: (commandPaletteOpen) => set({ commandPaletteOpen, commandPaletteQuery: commandPaletteOpen ? get().commandPaletteQuery : "" }), setCommandPaletteQuery: (commandPaletteQuery) => set({ commandPaletteQuery }), - addPendingApproval: (approval) => - set((state) => ({ - pendingApprovals: [...state.pendingApprovals.filter((item) => item.id !== approval.id), approval], - activeDrawer: "tool-approval", - })), - resolveApproval: (id, status) => - set((state) => ({ - pendingApprovals: state.pendingApprovals.map((approval) => (approval.id === id ? { ...approval, status } : approval)), - })), - addEventToast: (toast) => - set((state) => ({ eventToasts: [...state.eventToasts.slice(-4), { ...toast, id: createId("toast"), createdAt: Date.now() }] })), + addPendingApproval: (approval) => set((state) => ({ pendingApprovals: [...state.pendingApprovals.filter((item) => item.id !== approval.id), approval], activeDrawer: "tool-approval" })), + resolveApproval: (id, status) => set((state) => ({ pendingApprovals: state.pendingApprovals.map((approval) => (approval.id === id ? { ...approval, status } : approval)) })), + addEventToast: (toast) => set((state) => ({ eventToasts: [...state.eventToasts.slice(-4), { ...toast, id: createId("toast"), createdAt: Date.now() }] })), dismissEventToast: (id) => set((state) => ({ eventToasts: state.eventToasts.filter((toast) => toast.id !== id) })), setPerformanceOverlayOpen: (performanceOverlayOpen) => set({ performanceOverlayOpen }), setChatDockExpanded: (chatDockExpanded) => set({ chatDockExpanded }), - setLayoutEditMode: (layoutEditMode) => set({ layoutEditMode, mode: layoutEditMode ? "reviewing" : get().mode }), + setLayoutEditMode: (layoutEditMode) => set({ layoutEditMode }), setActiveMockupState: (activeMockupStateId) => set({ activeMockupStateId }), - resetToBaseline: () => - set(() => { - const metrics = baselineMetrics(); - return { - mode: "calm", - workspaceView: "dashboard", - energy: 0.78, - focusPanelId: undefined, - panels: baselinePanels(), - agents: baselineAgents(), - activeCausalPath: undefined, - timeline: baselineTimeline(), - messages: baselineMessages(), - tasks: [], - metrics, - metricHistory: [{ timestamp: Date.now(), system: metrics }], - composer: { - value: "", - isFocused: false, - selectedModel: "GPT-5.5", - selectedMode: "deep", - selectedTools: defaultSelectedTools, - contextPanelIds: ["project-nexus", "system-health"], - slashMenuOpen: false, - planPreview: undefined, - }, - artifacts: [], - activeArtifactId: undefined, - activeDrawer: undefined, - activeModal: undefined, - commandPaletteOpen: false, - commandPaletteQuery: "", - pendingApprovals: [], - eventToasts: [], - performanceOverlayOpen: false, - chatDockExpanded: false, - layoutEditMode: false, - activeMockupStateId: undefined, - }; - }), - resetToDemoBaseline: () => - set(() => { - const metrics = baselineMetrics(); - return { - workspaceView: "dashboard", - mode: "calm", - energy: 0.78, - focusPanelId: undefined, - panels: demoPanels(), - agents: baselineAgents(), - activeCausalPath: createLatencyCausalPath(), - tasks: [], - timeline: baselineTimeline(), - messages: baselineMessages(), - metrics, - metricHistory: [{ timestamp: Date.now(), system: metrics }], - composer: { - value: "", - isFocused: false, - selectedModel: "GPT-5.5", - selectedMode: "deep", - selectedTools: defaultSelectedTools, - contextPanelIds: ["project-nexus", "system-health"], - slashMenuOpen: false, - planPreview: undefined, - }, - artifacts: [], - activeArtifactId: undefined, - activeDrawer: undefined, - activeModal: undefined, - commandPaletteOpen: false, - commandPaletteQuery: "", - pendingApprovals: [], - eventToasts: [], - performanceOverlayOpen: false, - chatDockExpanded: false, - layoutEditMode: false, - activeMockupStateId: undefined, - }; - }), - addArtifact: (artifact) => - set((state) => ({ - artifacts: [ - ...state.artifacts.filter((item) => item.id !== artifact.id), - { ...artifact, createdAt: artifact.createdAt ?? Date.now(), updatedAt: artifact.updatedAt ?? Date.now() }, - ], - activeArtifactId: artifact.id, - workspaceView: "canvas", - })), - updateArtifact: (id, patch) => - set((state) => ({ - artifacts: state.artifacts.map((artifact) => (artifact.id === id ? { ...artifact, ...patch, updatedAt: Date.now() } : artifact)), - })), + resetToBaseline: () => set({ + mode: "calm", + workspaceView: "dashboard", + energy: 0.55, + focusPanelId: undefined, + panels: baselinePanels(), + agents: baselineAgents(), + activeCausalPath: undefined, + tasks: [], + metrics: baselineMetrics(), + metricHistory: [{ timestamp: Date.now(), system: baselineMetrics() }], + activeDrawer: undefined, + activeModal: undefined, + commandPaletteOpen: false, + commandPaletteQuery: "", + pendingApprovals: [], + eventToasts: [], + performanceOverlayOpen: false, + layoutEditMode: false, + activeMockupStateId: undefined, + }), + resetToDemoBaseline: () => set({ + mode: "calm", + workspaceView: "dashboard", + energy: 0.72, + panels: demoPanels(), + agents: baselineAgents(), + timeline: baselineTimeline(), + messages: baselineMessages(), + tasks: [], + metrics: baselineMetrics(), + metricHistory: [{ timestamp: Date.now(), system: baselineMetrics() }], + activeCausalPath: undefined, + activeDrawer: undefined, + activeModal: undefined, + commandPaletteOpen: false, + commandPaletteQuery: "", + pendingApprovals: [], + eventToasts: [], + performanceOverlayOpen: false, + layoutEditMode: false, + }), + addArtifact: (artifact) => set((state) => ({ + artifacts: [...state.artifacts.filter((item) => item.id !== artifact.id), artifact], + activeArtifactId: artifact.id, + workspaceView: "canvas", + })), + updateArtifact: (id, patch) => set((state) => ({ artifacts: state.artifacts.map((artifact) => (artifact.id === id ? { ...artifact, ...patch, updatedAt: Date.now() } : artifact)) })), setActiveArtifact: (activeArtifactId) => set({ activeArtifactId, workspaceView: activeArtifactId ? "canvas" : "dashboard" }), })); From 58400a90834a1562c23c92f3c20aaf878b97a6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Sat, 30 May 2026 00:24:30 -0600 Subject: [PATCH 30/33] Capture frontend build logs for green debugging --- .github/workflows/frontend-proof.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/frontend-proof.yml b/.github/workflows/frontend-proof.yml index 4a42f91..d0e219b 100644 --- a/.github/workflows/frontend-proof.yml +++ b/.github/workflows/frontend-proof.yml @@ -28,7 +28,14 @@ jobs: run: npm install - name: Build frontend - run: npm run build -w @ae-see-suite/web + shell: bash + run: | + mkdir -p frontend/proof/logs + set +e + npm run build -w @ae-see-suite/web 2>&1 | tee frontend/proof/logs/build-web.log + status=${PIPESTATUS[0]} + set -e + exit "$status" - name: Install Playwright Chromium run: npx playwright install chromium --with-deps From 1562f9140e83e8b6227b96bf2536c11c0c7ed84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=86?= Date: Sat, 30 May 2026 00:25:24 -0600 Subject: [PATCH 31/33] Capture Project Green frontend build logs --- .github/workflows/project-green.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/project-green.yml b/.github/workflows/project-green.yml index 4607bd2..08d34f4 100644 --- a/.github/workflows/project-green.yml +++ b/.github/workflows/project-green.yml @@ -9,6 +9,8 @@ jobs: syntax-and-build: runs-on: ubuntu-latest timeout-minutes: 25 + env: + DATABASE_URL: postgresql://ae:ae@localhost:5432/ae_see_suite steps: - name: Checkout uses: actions/checkout@v4 @@ -30,8 +32,26 @@ jobs: - name: Build API workspace run: npm run build -w @ae-see-suite/api + - name: Test API workspace + run: npm run test -w @ae-see-suite/api + - name: Build frontend workspace - run: npm run build -w @ae-see-suite/web + shell: bash + run: | + mkdir -p frontend/proof/logs + set +e + npm run build -w @ae-see-suite/web 2>&1 | tee frontend/proof/logs/project-green-build-web.log + status=${PIPESTATUS[0]} + set -e + exit "$status" - name: AtomSmasher runtime syntax run: node --check ./scripts/v4/atomsmasher-runtime.mjs && node --check ./scripts/v4/atomsmasher-api-routes.mjs + + - name: Upload green logs + uses: actions/upload-artifact@v4 + if: always() + with: + name: project-green-logs + path: frontend/proof/logs/ + if-no-files-found: warn From 2deca1abfb788e128e54aa4bb180116a364e2ded Mon Sep 17 00:00:00 2001 From: AtomEons <275631985+AtomEons@users.noreply.github.com> Date: Sat, 30 May 2026 12:08:49 -0600 Subject: [PATCH 32/33] Fix left rail action type mismatch --- frontend/src/components/shell/LeftRail.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/shell/LeftRail.tsx b/frontend/src/components/shell/LeftRail.tsx index d20a299..aa9b847 100644 --- a/frontend/src/components/shell/LeftRail.tsx +++ b/frontend/src/components/shell/LeftRail.tsx @@ -38,7 +38,7 @@ export function LeftRail() { const workspaceView = useAppStore((s) => s.workspaceView); const runAction = (action: (typeof navItems)[number]["action"]) => { - if (action === "dashboard" || action === "canvas") { + if (action === "dashboard") { setWorkspaceView(action); return; } @@ -65,8 +65,7 @@ export function LeftRail() { {navItems.map((item) => { const Icon = item.icon; const active = - (item.action === "dashboard" && workspaceView === "dashboard" && item.label === "Home") || - (item.action === "canvas" && workspaceView === "canvas" && item.label === "Deployments"); + item.action === "dashboard" && workspaceView === "dashboard" && item.label === "Home"; return (