diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5620ede1..2860e501 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,5 +45,14 @@ jobs: - name: Typecheck run: pnpm typecheck + - name: Assert design-system boundary + run: pnpm -C apps/desktop assert:design-system-boundary + + - name: Assert design-system flag-off boot + run: pnpm -C apps/desktop test:boot:design-system-off + + - name: Measure Agent Dashboard storage + run: pnpm -C apps/desktop measure:agent-dashboard-storage + - name: Run tests run: pnpm test diff --git a/.gitignore b/.gitignore index 8a8728f3..01660e56 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,9 @@ apps/desktop/.generated/ apps/desktop/test-results/ apps/desktop/playwright-report/ +# Desktop-local workflow/debug artifacts +apps/desktop/.closedloop-ai/ + # UI Numbers Audit generated reports (FEA-1415 / PLN-738) # These embed a timestamp; regenerate locally via `pnpm --filter desktop audit:report` # or `node apps/desktop/test-e2e/agent-monitor/inventory/scan-tiles.mjs`. diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 2873a25b..1328fc49 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -13,11 +13,9 @@ development/build, and the desktop build generates a runtime tree under - **Pinned commit:** `840c518d7fa69231de049e41b893938228b67e40` - **Imported via:** pnpm dependencies `agent-dashboard` and `agent-dashboard-client` -- **Usage:** Bundled and run as a local `127.0.0.1` sidecar process by the - desktop app (the embedded "Claude Dashboard" tab). The desktop build applies - three local host patches while generating - `apps/desktop/.generated/agent-monitor/`: loopback-only bind, explicit - `CCAM_AUTO_INSTALL_HOOKS` gating, and a hook uninstall script. +- **Usage:** Bundled and run as the default local `127.0.0.1` legacy sidecar + dashboard. The desktop build applies local host patches while generating + `apps/desktop/.generated/agent-monitor/`. - **License:** MIT — © 2026 Son Nguyen. Bundled runtime dependencies remain pure JS. The generated sidecar runtime uses @@ -57,9 +55,8 @@ SOFTWARE. - **Used as:** documentation/algorithm reference for the OpenAI **Codex** CLI rollout JSONL format — the cumulative→session token semantics and the `turn_context.model` attribution rule (`docs/codex.md`). No CodexBar source - is bundled. Our own Codex ingestion modules - (`apps/desktop/scripts/agent-monitor-codex/codex-*.js`, copied into the - generated runtime tree at build time) were merely informed by it. + is bundled. Our own first-party Codex ingestion modules + (`apps/desktop/src/main/collectors/codex/`) were merely informed by it. - **License:** MIT — © 2026 Peter Steinberger. ``` diff --git a/apps/desktop/CLAUDE.md b/apps/desktop/CLAUDE.md index d3693041..b08711c1 100644 --- a/apps/desktop/CLAUDE.md +++ b/apps/desktop/CLAUDE.md @@ -136,108 +136,94 @@ Typical log locations: The Diagnostics tab shows the current in-memory gateway log plus a bounded previous-session tail read from `main.log` at startup. First-run or unreadable log files must not block boot; return an empty previous-session tail and continue. -## Agent Monitor Sidecar - -The desktop app bundles the MIT-licensed `Claude-Code-Agent-Monitor` -(`agent-dashboard` + `agent-dashboard-client`, pinned in -`apps/desktop/package.json`) and runs a generated runtime tree as a managed -localhost **sidecar** for local Claude Code session/agent observability. It is -the single embedded observability tool. It powers the **Dashboard** and the -agent nav items (Sessions, Kanban, Activity Feed, etc.) in the desktop left -sidebar. The feature is gated by the persisted `agentMonitorEnabled` desktop -setting, which **defaults ON**; when disabled, the agent nav items are hidden -and only the Gateway section remains. - -- **Process model:** `src/main/agent-monitor-sidecar.ts` spawns the generated - `server/index.js` from `apps/desktop/.generated/agent-monitor/` (packaged: - unpacked `extraResources/agent-monitor`) using the Electron binary as Node - (`ELECTRON_RUN_AS_NODE=1`, `process.execPath`) — a packaged app ships no - standalone `node`. Started fire-and-forget from `boot()` **only when - `agentMonitorEnabled` is true**, and still before the gateway-start try-block - so a gateway-start failure never prevents it from running and a sidecar - failure never blocks or fails app boot. +## Agent Monitor + +> **Status (FEA-1504):** Agent Monitor has three boot modes. The default user +> experience is the legacy sidecar-backed dashboard (`agentMonitorEnabled=true`, +> `agentDashboardDesignSystemEnabled=false`): pnpm-managed upstream packages are +> materialized into `.generated/agent-monitor`, shipped unpacked, and rendered in +> the legacy iframe shell. The in-process design-system dashboard is a Labs +> opt-in only. When `agentDashboardDesignSystemEnabled` is not the literal +> boolean `true`, the main process must not load `src/main/database/`, +> `src/main/collectors/`, `AgentHookListener`, `desktop:db:*`, or the `app://` +> design renderer path. + +The desktop app provides local Claude Code (and opt-in Codex) session/agent +observability. It powers the **Dashboard** and the agent nav items (Sessions, +Activity, Analytics, Workflows, Kanban) in the desktop left sidebar. The feature +is gated by the persisted `agentMonitorEnabled` desktop setting, which +**defaults ON**; when disabled, the agent nav items are hidden and only the +Gateway section remains. + +- **Legacy sidecar (default):** `src/main/agent-monitor-sidecar.ts` launches the + generated Claude-Code-Agent-Monitor runtime tree. `build:agent-monitor` + materializes the tree from pnpm-managed upstream packages; package/stage logic + must keep `.generated/agent-monitor` available for default users. +- **Design-system runtime (Labs opt-in):** `src/main/agent-dashboard-design-system-runtime.ts` + is the only module allowed to import `src/main/database/`, + `src/main/collectors/`, `AgentHookListener`, or register `desktop:db:*`. It is + reached only through `await import()` after boot mode resolves to + `design-system`. +- **Disabled mode:** `agentMonitorEnabled=false` starts no sidecar, no + design-system runtime, no dashboard-derived sync source, and no + dashboard-derived cost source. +- **Hook listener:** in design-system mode, `src/main/agent-monitor-listener.ts` + binds `127.0.0.1:4820` in the main process and accepts the hook payload + (`POST /api/hooks/event`, `GET /api/health`). Each event is gated by the + FEA-1407 sandbox check, harness-stamped from `__provider`, and applied by the + lifecycle state machine. +- **Collection layer (`src/main/collectors/`):** design-system mode uses + `CollectorManager` for best-effort boot bulk import and live file watchers for + all five agent CLIs, writing through the first-party `importSession` into the + same in-process DB. - **Fixed port (differs from the gateway):** `127.0.0.1:4820` - (`AGENT_MONITOR_PORT` in `src/shared/contracts.ts`), passed via - `DASHBOARD_PORT`. It MUST be fixed — Claude Code hooks bake a port at install - time and the hook handler POSTs to `127.0.0.1:${CLAUDE_DASHBOARD_PORT||4820}`, - so 4820 (upstream's default) means hooks need zero per-hook env. 4820 is - outside `PORT_PROBE_ORDER`, so it never collides with the gateway. -- **Durable DB:** `DASHBOARD_DB_PATH` is set to - `app.getPath("userData")/agent-monitor/dashboard.db` (the packaged app dir is - read-only). Uses Node's built-in `node:sqlite`; the generated `server/db.js` - is patched to prefer `./compat-sqlite`, and staged packaging removes the - hoisted `better-sqlite3` module as a belt-and-suspenders guard. -- **UI:** embedded in the main window (`src/renderer/index.html`) as a plain - `