diff --git a/README.md b/README.md index a09a461..4643621 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,15 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![CLI](https://img.shields.io/badge/CLI-agent--comms-cb3837)](scripts/agent-comms.mjs) +[![Agent Comms operator dashboard demo](docs/assets/agent-comms-demo-dashboard.png)](https://agent-comms.github.io/agent-comms-demo/) + Async communication infrastructure for coding and operations agents that share a human operator. Created by [Shay Palachy Affek](http://www.shaypalachy.com/). +Live public demo: + The project is intentionally product-neutral. It provides the open-source core for: diff --git a/docs/assets/agent-comms-demo-dashboard.png b/docs/assets/agent-comms-demo-dashboard.png new file mode 100644 index 0000000..2fe66d5 Binary files /dev/null and b/docs/assets/agent-comms-demo-dashboard.png differ diff --git a/package.json b/package.json index 1d8cc7e..4b7645b 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "scripts": { "dev": "vite --host 127.0.0.1", "build": "tsc -b && vite build", + "build:demo": "VITE_AGENT_COMMS_DEMO=1 VITE_BASE=/agent-comms-demo/ npm run build", "preview": "vite preview --host 127.0.0.1", "test": "vitest run", "check": "tsc -b" diff --git a/src/App.tsx b/src/App.tsx index 88a9622..57ead47 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -52,7 +52,9 @@ const emptyState: AgentCommsState = { todos: [], }; -const useDemoData = import.meta.env.DEV && new URLSearchParams(window.location.search).get("demo") === "1"; +const useDemoData = + import.meta.env.VITE_AGENT_COMMS_DEMO === "1" || + (import.meta.env.DEV && new URLSearchParams(window.location.search).get("demo") === "1"); const themePreferenceKey = "agent-comms-theme-mode"; const nightModeTheme: Record = { @@ -1508,6 +1510,9 @@ export function App() { const operatorRequest = useCallback( async (path: string, options: RequestInit = {}) => { + if (useDemoData) { + throw new Error("Demo mode uses public sample data and does not write to an operator API."); + } const controller = new AbortController(); const timeout = window.setTimeout(() => controller.abort(), 8000); const headers: Record = { @@ -1685,10 +1690,12 @@ export function App() { }, [liveSessions, operatorRequest, operatorToken]); useEffect(() => { + if (useDemoData) return; void refreshOperatorData(); }, [refreshOperatorData]); useEffect(() => { + if (useDemoData) return; const timer = window.setInterval(() => { void refreshOperatorData(); }, 1000); @@ -1696,6 +1703,10 @@ export function App() { }, [refreshOperatorData]); useEffect(() => { + if (useDemoData) { + document.title = defaultBranding.appName; + return; + } let cancelled = false; void loadDeploymentBranding().then((nextBranding) => { if (cancelled) return; diff --git a/src/styles.css b/src/styles.css index d7b4548..e7d74a2 100644 --- a/src/styles.css +++ b/src/styles.css @@ -47,6 +47,7 @@ button { display: grid; grid-template-columns: 280px minmax(0, 1fr); min-height: 100vh; + color: var(--color-text); background: var(--color-bg); } diff --git a/vite.config.ts b/vite.config.ts index 081c8d9..c5780b8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,5 +2,6 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; export default defineConfig({ + base: process.env.VITE_BASE ?? "/", plugins: [react()], });