Skip to content
This repository was archived by the owner on Jun 8, 2026. It is now read-only.

Commit 1225e46

Browse files
authored
Merge pull request #275 from closedloop-ai/fea-1550-sqlite-pglite-migration
FEA-1550: Cut Agent Dashboard over to PGlite
2 parents 4d5a674 + 39c121c commit 1225e46

267 files changed

Lines changed: 14060 additions & 56339 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,15 @@ This rule does NOT apply to internal contracts that ship as a single unit with t
4545
- **[mistake]**: Never fabricate history in changelogs, commit messages, or comments. Do not claim code "replaces" or "fixes" a prior implementation unless that implementation verifiably exists in the codebase or git history. (context: changelog|hallucination|fabrication)
4646
- **[mistake]**: Before adding a fallback or recovery path, verify the triggering condition can actually occur. Dead fallbacks that read from files never written or variables never set create false confidence in error handling. (context: dead-code|fallback|unreachable)
4747

48-
### Agent Monitor & Sidecar Security
49-
- **[mistake]**: Treat localhost sidecar routes and iframe messages as privileged surfaces. Mutating routes need origin/trusted-action guards, explicit target origins, and regression coverage. (context: agent-monitor|sidecar|security)
48+
### Agent Monitor Security
49+
- **[mistake]**: Treat localhost Agent Monitor hook/listener routes and renderer IPC as privileged surfaces. Mutating routes need explicit local-only binding, trusted-action guards where applicable, and regression coverage. (context: agent-monitor|listener|ipc|security)
5050

5151
### Process Spawning & Secrets
5252
- **[mistake]**: Keep large or sensitive data out of spawned argv/env. Use stdin or files for prompts, quote shell args, set approved cwd, and pass minimal child environments. (context: spawn|argv|env|secrets)
5353

5454
### Boundary Validation
5555
- **[mistake]**: Runtime-validate gateway, IPC, and persisted payloads before path or file use. TypeScript casts and preload promise types do not protect missing or null fields. (context: validation|ipc|gateway)
5656

57-
### Generated Agent Monitor Runtime
58-
- **[pattern]**: When generated sidecar overlays, snippets, or patch inputs change, update stamp/materialization inputs and verify generated output so stale assets or bypassed patches cannot ship. (context: agent-monitor|generated|build)
59-
6057
### State & Lifecycle
6158
- **[mistake]**: Setting toggles must update persisted state and in-memory side effects together. Avoid one-way restart guards, stale tray state, or stale cloud presence. (context: settings|lifecycle|state)
6259

apps/desktop/CLAUDE.md

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,12 @@ The Diagnostics tab shows the current in-memory gateway log plus a bounded previ
138138

139139
## Agent Monitor
140140

141-
> **Status (FEA-1504):** Agent Monitor has three boot modes. The default user
142-
> experience is the legacy sidecar-backed dashboard (`agentMonitorEnabled=true`,
143-
> `agentDashboardDesignSystemEnabled=false`): pnpm-managed upstream packages are
144-
> materialized into `.generated/agent-monitor`, shipped unpacked, and rendered in
145-
> the legacy iframe shell. The in-process design-system dashboard is a Labs
146-
> opt-in only. When `agentDashboardDesignSystemEnabled` is not the literal
147-
> boolean `true`, the main process must not load `src/main/database/`,
148-
> `src/main/collectors/`, `AgentHookListener`, `desktop:db:*`, or the `app://`
149-
> design renderer path.
141+
> **Status (FEA-1550):** Agent Monitor is an in-process, PGlite-backed desktop
142+
> feature. The legacy generated runtime tree, embedded web shell, and
143+
> `agentDashboardDesignSystemEnabled` boot split have been removed. When
144+
> `agentMonitorEnabled=false`, the main process must not start collectors,
145+
> `AgentHookListener`, the `desktop:db:*` IPC handlers, cloud session sync, or
146+
> dashboard-derived cost reads.
150147
151148
The desktop app provides local Claude Code (and opt-in Codex) session/agent
152149
observability. It powers the **Dashboard** and the agent nav items (Sessions,
@@ -155,23 +152,20 @@ is gated by the persisted `agentMonitorEnabled` desktop setting, which
155152
**defaults ON**; when disabled, the agent nav items are hidden and only the
156153
Gateway section remains.
157154

158-
- **Legacy sidecar (default):** `src/main/agent-monitor-sidecar.ts` launches the
159-
generated Claude-Code-Agent-Monitor runtime tree. `build:agent-monitor`
160-
materializes the tree from pnpm-managed upstream packages; package/stage logic
161-
must keep `.generated/agent-monitor` available for default users.
162-
- **Design-system runtime (Labs opt-in):** `src/main/agent-dashboard-design-system-runtime.ts`
155+
- **Runtime:** `src/main/agent-dashboard-design-system-runtime.ts`
163156
is the only module allowed to import `src/main/database/`,
164157
`src/main/collectors/`, `AgentHookListener`, or register `desktop:db:*`. It is
165-
reached only through `await import()` after boot mode resolves to
166-
`design-system`.
167-
- **Disabled mode:** `agentMonitorEnabled=false` starts no sidecar, no
168-
design-system runtime, no dashboard-derived sync source, and no
169-
dashboard-derived cost source.
158+
reached only through `await import()` after the Agent Monitor setting is
159+
enabled.
160+
- **Disabled mode:** `agentMonitorEnabled=false` starts no design-system
161+
runtime, no dashboard-derived sync source, and no dashboard-derived cost
162+
source.
170163
- **Hook listener:** in design-system mode, `src/main/agent-monitor-listener.ts`
171164
binds `127.0.0.1:4820` in the main process and accepts the hook payload
172-
(`POST /api/hooks/event`, `GET /api/health`). Each event is gated by the
173-
FEA-1407 sandbox check, harness-stamped from `__provider`, and applied by the
174-
lifecycle state machine.
165+
(`POST /api/hooks/event`, `GET /api/health`). Each event is
166+
harness-stamped from `__provider` and applied by the lifecycle state machine.
167+
Local import is ungated — all hook events are written to the local DB
168+
regardless of the sandbox directory (FEA-1550).
175169
- **Collection layer (`src/main/collectors/`):** design-system mode uses
176170
`CollectorManager` for best-effort boot bulk import and live file watchers for
177171
all five agent CLIs, writing through the first-party `importSession` into the
@@ -182,12 +176,12 @@ Gateway section remains.
182176
`~/.claude/settings.json` at install time, so 4820 means hooks need zero
183177
per-hook env. 4820 is outside `PORT_PROBE_ORDER`, so it never collides with
184178
the gateway. (FEA-1500 tracks migrating this transport later.)
185-
- **Durable DB:** `app.getPath("userData")/agent-dashboard.sqlite` (schema in
186-
`src/main/database/schema.ts`), Node's built-in `node:sqlite`. Persisted
187-
collector caches live under `<userData>/agent-monitor/`.
188-
- **UI:** a first-party React app in the main window (`src/renderer/`) — NO
189-
iframe. The left sidebar drives the **Dashboard** + agent nav items; live
190-
updates arrive via the `desktop:db:changed` IPC push after each write.
179+
- **Durable DB:** `app.getPath("userData")/agent-dashboard.pgdata` (PGlite,
180+
schema in `src/main/database/pglite.ts`). Persisted collector caches live
181+
under `<userData>/agent-dashboard-ingest/`.
182+
- **UI:** a first-party React app in the main window (`src/renderer/`). The
183+
left sidebar drives the **Dashboard** + agent nav items; live updates arrive
184+
via the `desktop:db:changed` IPC push after each write.
191185
- **Hooks are explicit opt-in (consent-bearing).** The user enables/disables
192186
tracking via the toggle → `src/main/agent-monitor-hooks.ts` writes/removes the
193187
hook entries in `~/.claude/settings.json` (and, opt-in, `~/.codex/hooks.json`).
@@ -206,10 +200,12 @@ Gateway section remains.
206200
tree.
207201
- **Security model (by design):** the collectors + listener read the agent-CLI
208202
home dirs (`~/.claude`, `~/.codex`, …) **directly**, outside the gateway
209-
`isPathAllowed` sandbox, but every captured session is dropped unless its
210-
`cwd` is inside the FEA-1407 sandbox base directory (fail-closed). The listener
211-
is bound to `127.0.0.1` only; no cloud egress from collectors. Hooks only
212-
mutate global Claude/Codex config on explicit user opt-in and are reversible.
203+
`isPathAllowed` sandbox. Local import and hook capture are ungated — all
204+
sessions are written to the local PGlite DB regardless of working directory
205+
(FEA-1550). Cloud sync sends all local sessions without sandbox filtering;
206+
payloads are sanitized before upload. The listener is bound to `127.0.0.1`
207+
only; no cloud egress from collectors. Hooks only mutate global Claude/Codex
208+
config on explicit user opt-in and are reversible.
213209
- **Multi-harness support (5 agent tools):** ingests sessions from **Claude
214210
Code** (hooks live + file historical), **OpenAI Codex** (rollout JSONL under
215211
`~/.codex/sessions/`), **Cursor** (agent transcripts under `~/.cursor/projects/`),

apps/desktop/electron-builder.yml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,6 @@ extraResources:
1414
to: trayIconTemplate.png
1515
- from: resources/trayIconTemplate@2x.png
1616
to: trayIconTemplate@2x.png
17-
# Generated Claude-Code-Agent-Monitor runtime tree, shipped unpacked
18-
# (outside the asar) so the spawned Node server, the built client, and the
19-
# hook scripts resolve as real files. Built by scripts/build-agent-monitor.mjs
20-
# before packaging (chained into `build`). `client/dist/**/*` (NOT
21-
# `client/**/*`) — the server resolves ../client/dist relative to server/, so
22-
# the server/ <-> client/dist/ layout must be preserved.
23-
- from: .generated/agent-monitor
24-
to: agent-monitor
25-
filter:
26-
- server/**/*
27-
- client/dist/**/*
28-
- scripts/**/*
29-
- package.json
30-
- LICENSE
3117
# First-party agent-monitor hook handlers (FEA-1503), shipped unpacked outside
3218
# the asar so they resolve as real files. agent-monitor-hooks.ts copies them
3319
# into userData at install time; the installed hook command runs them via the

apps/desktop/package.json

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
{
22
"name": "desktop",
3-
"version": "0.15.117",
3+
"version": "0.16.0",
44
"description": "ClosedLoop Desktop",
55
"author": "ClosedLoop AI <support@closedloop.ai>",
66
"private": true,
77
"type": "module",
88
"main": "dist/main/index.js",
99
"scripts": {
1010
"dev": "pnpm build && ELECTRON_BIN=$(bash scripts/patch-electron-plist.sh | tail -1) && \"$ELECTRON_BIN\" .",
11-
"start": "pnpm build:agent-monitor && ELECTRON_BIN=$(bash scripts/patch-electron-plist.sh | tail -1) && \"$ELECTRON_BIN\" .",
11+
"start": "ELECTRON_BIN=$(bash scripts/patch-electron-plist.sh | tail -1) && \"$ELECTRON_BIN\" .",
1212
"clean:dist": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
1313
"clean:package": "node -e \"require('fs').rmSync('dist-dmg',{recursive:true,force:true})\"",
1414
"prebuild": "node -e \"const{execSync:e}=require('child_process'),{writeFileSync:w}=require('fs');const h=e('git rev-parse HEAD').toString().trim();w('src/shared/build-info.ts','// AUTO-GENERATED — do not edit\\nexport const BUILD_COMMIT_HASH = \\\"'+h+'\\\";\\n');\"",
15-
"build": "pnpm clean:dist && pnpm prebuild && tsc -p tsconfig.json && pnpm build:renderer && pnpm build:agent-monitor",
15+
"build": "pnpm clean:dist && pnpm prebuild && tsc -p tsconfig.json && pnpm build:renderer",
1616
"build:renderer": "vite build --config vite.renderer.config.ts",
17-
"build:agent-monitor": "node scripts/build-agent-monitor.mjs",
1817
"dashboard:reset": "node scripts/reset-dashboard-db.mjs",
19-
"dashboard:reset-packs": "node scripts/reset-dashboard-db.mjs --packs-only",
2018
"stage:package": "node scripts/stage-packaging-app.mjs",
2119
"typecheck": "tsc -p tsconfig.json --noEmit && pnpm typecheck:renderer",
2220
"typecheck:renderer": "tsc -p tsconfig.renderer.json --noEmit",
@@ -25,28 +23,15 @@
2523
"test:boot:design-system-off": "node --import tsx scripts/assert-design-system-boot-off.mjs",
2624
"measure:agent-dashboard-storage": "node scripts/measure-agent-dashboard-storage.mjs",
2725
"verify:electron-binary": "node scripts/ensure-electron-binary.mjs",
28-
"test": "tsx --test --test-concurrency=1 test/*.test.ts && node --test \"scripts/agent-monitor-packs/__tests__/*.test.js\" \"scripts/agent-monitor-pull-requests/__tests__/*.test.js\"",
29-
"pretest:contract": "pnpm build:agent-monitor",
30-
"test:contract": "node --test \"test-e2e/agent-monitor/specs/api-contract/*.test.mjs\"",
31-
"pretest:e2e": "pnpm build:agent-monitor",
32-
"test:e2e": "playwright test --config test-e2e/agent-monitor/playwright.config.ts",
33-
"pretest:audit": "pnpm build:agent-monitor && pnpm audit:scan && pnpm audit:classify",
34-
"audit:scan": "node test-e2e/agent-monitor/inventory/scan-tiles.mjs",
35-
"audit:classify": "node test-e2e/agent-monitor/inventory/coverage-classifier.mjs",
36-
"audit:coverage": "bash scripts/check-audit-coverage.sh",
37-
"test:audit": "node --test \"test-e2e/agent-monitor/specs/audit/*.test.mjs\"",
38-
"pretest:audit:ui": "pnpm build:agent-monitor",
39-
"test:audit:ui": "playwright test --config test-e2e/agent-monitor/playwright.audit.config.ts",
40-
"preaudit:report": "pnpm build:agent-monitor",
41-
"audit:report": "node test-e2e/agent-monitor/inventory/run-report.mjs",
26+
"test": "tsx --test --test-concurrency=1 test/*.test.ts",
4227
"package": "pnpm clean:package && pnpm build && pnpm stage:package && node scripts/run-electron-builder.mjs",
4328
"release": "pnpm clean:package && pnpm build && pnpm stage:package && node scripts/run-electron-builder.mjs --publish always"
4429
},
4530
"dependencies": {
4631
"@closedloop-ai/design-system": "0.1.1-dev.26892521643.1",
4732
"@closedloop-ai/loops-api": ">=0.3.1",
33+
"@electric-sql/pglite": "^0.4.6",
4834
"@pydantic/genai-prices": "0.0.62",
49-
"agent-dashboard": "github:hoangsonww/Claude-Code-Agent-Monitor#840c518d7fa69231de049e41b893938228b67e40",
5035
"busboy": "^1.6.0",
5136
"electron-log": "^5.4.3",
5237
"electron-store": "^8.2.0",
@@ -72,7 +57,6 @@
7257
"@typescript-eslint/eslint-plugin": "^8.57.1",
7358
"@typescript-eslint/parser": "^8.57.1",
7459
"@vitejs/plugin-react": "^5.1.3",
75-
"agent-dashboard-client": "github:hoangsonww/Claude-Code-Agent-Monitor#840c518d7fa69231de049e41b893938228b67e40&path:/client",
7660
"autoprefixer": "10.4.20",
7761
"electron": "^35.0.2",
7862
"electron-builder": "^26.8.1",

0 commit comments

Comments
 (0)