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

FEA-1504: Gate embedded agent dashboard - #264

Merged
mikeangstadt merged 35 commits into
mainfrom
feat/in-process-agent-database
Jun 5, 2026
Merged

mikeangstadt merged 35 commits into
mainfrom
feat/in-process-agent-database

Conversation

@mikeangstadt

@mikeangstadt mikeangstadt commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Finalizes the embedded agent dashboard work for PR #264 by keeping the legacy monitor as the default boot path and gating the new design-system dashboard runtime, storage, and IPC behind the explicit Labs flag.

Changes

  • Adds the embedded agent monitor build/package path, parser/importer modules for multiple harnesses, pack/plan/pull-request surfaces, and audit/contract coverage fixtures.
  • Splits legacy and design-system preload/runtime wiring so the new renderer and storage are loaded only when the design-system agent dashboard flag is enabled.
  • Adds guardrails for flag-off boot, design-system boundary checks, storage measurement, audit coverage, and serialized desktop test execution for shared fixture state.

Testing

  • pnpm -r prebuild
  • pnpm -C apps/desktop lint
  • pnpm typecheck
  • pnpm -C apps/desktop assert:design-system-boundary
  • pnpm -C apps/desktop test:boot:design-system-off
  • pnpm -C apps/desktop measure:agent-dashboard-storage
  • pnpm test
  • pnpm -C apps/desktop build

Review State

  • Final workflow review passed.
  • Targeted guardrail-validation and security-abuse rechecks passed after remediation.
  • PR is open and non-draft.

Collaborated & Orchestrated by ClosedLoop.AI | GitHub

@mikeangstadt
mikeangstadt requested a review from a team June 1, 2026 13:10

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 573c54d50a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/package.json Outdated
Comment thread apps/desktop/src/renderer/App.tsx
Comment thread apps/desktop/src/main/app.ts Outdated
@mikeangstadt
mikeangstadt force-pushed the feat/in-process-agent-database branch 3 times, most recently from c3d3370 to c6d86c5 Compare June 1, 2026 13:37
Comment thread apps/desktop/vendor/design-system/package.json Outdated
Comment thread apps/desktop/vendor/design-system/styles/globals.css Outdated
Comment thread apps/desktop/src/renderer/App.tsx Outdated
Comment thread apps/desktop/src/renderer/App.tsx Outdated
Comment thread apps/desktop/src/main/app.ts Outdated
Comment thread apps/desktop/src/main/app.ts Outdated
Comment thread apps/desktop/src/main/database/hooks-ingestion.ts Outdated
Comment thread apps/desktop/src/main/database/agents.ts Outdated
Comment thread apps/desktop/src/main/database/schema.ts Outdated
Comment thread apps/desktop/src/renderer/components/dashboard/DashboardPage.tsx Outdated
Comment thread apps/desktop/src/renderer/components/dashboard/DashboardPage.tsx Outdated
Comment thread apps/desktop/src/renderer/components/approvals/ApprovalsPanel.tsx
Comment thread apps/desktop/src/renderer/components/settings/SettingsPanel.tsx Outdated

@thadeusb thadeusb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things make me want to talk before this lands instead of just patching. The renderer only builds on your machine: the vendored design-system points every export at a dist/ that .gitignore excludes, and globals.css pulls in two tailwind modules that aren't in package.json, so a clean clone or CI can't produce a bundle. And the description says strangler-fig with a legacy iframe fallback, but the code dropped legacy.html and hid the sidecar dashboard behind 'coming soon' stubs, so it's a hard cutover, not parallel operation. Lots of fixable bugs underneath too, but I want the build and the migration strategy settled first.

@mikeangstadt
mikeangstadt force-pushed the feat/in-process-agent-database branch 2 times, most recently from 2a3bb7d to d7c538b Compare June 1, 2026 13:46
…React renderer

- Replace agent-dashboard sidecar (external process) with in-process node:sqlite database
- Create functional repository layer matching symphony-alpha patterns (sessions, agents, events, dashboard stores)
- Add Vite + React 19 renderer with DesignSystemProvider shell and DS components
- Add hook ingestion endpoint (POST /api/hooks/event) writing directly to local SQLite
- Extend preload bridge with typed db IPC channels (db.getSessions, db.getAgents, db.getEvents, db.getDashboardSummary)
- Update window.ts to load Vite-built renderer (dev server in dev, file in prod)
- Vendor @closedloop-ai/design-system as file: dep with subpath component exports
- Preserve legacy HTML renderer as legacy.html for strangler-fig migration via iframe
- Add DashboardPage using DS Card/Badge/Button components with real-time summary queries

Testing: pnpm build:renderer (Vite) and npx tsc (main process) both compile clean; all DB-layer errors resolved; pre-existing tsc errors (node-pty, ws, react) unchanged.
Risks: Sidecar not yet disabled — this adds parallel in-process DB alongside existing agent-monitor; legacy HTML still works via iframe fallback.
@mikeangstadt
mikeangstadt force-pushed the feat/in-process-agent-database branch from d7c538b to a6427ce Compare June 1, 2026 14:22
mikeangstadt and others added 7 commits June 1, 2026 14:50
- Fix build ordering: renderer builds after clean:dist, not before
- Fix vendor DS: gitignore negation for dist/, add tw-animate-css dep
- Fix runtimeStatus.healthy → gatewayHealthy in App.tsx
- Wire agentDatabase.close() into shutdown sequence
- Gate all db:* IPC handlers behind agentMonitorEnabled
- Add zod validation to hooks-ingestion payload
- Fix agent updateStmt to include metadata; fix session update guard
- Add PRAGMA user_version migration system for schema versioning
- Remove unpopulated Token Usage card from dashboard
- Add 3s polling to DashboardPage and ApprovalsPanel
- Add error handling to approval actions
- Replace window.prompt with inline input in SettingsPanel
- Restore Labs settings tab with feature flag toggles
- Force light mode via DesignSystemProvider
- Add lucide-react icons to MetricCard and WorkflowStatTile
- Rebuild AnalyticsView with DS components (ActivityHeatmap, DonutChart,
  RankedBar, SegmentedBar, LineChart)
- Rebuild WorkflowsView with DS composites (OrchestrationDag, SankeyGraph,
  AgentCollaborationNetwork, WorkflowStatTile, effectiveness table)
- Enhance DashboardPage with tool usage RankedBar + agent types table
- Enhance SessionsView with search, status filter, polling
- Enhance ActivityFeedView with search, type filter, expandable detail
- Add analytics + workflow database queries (tool usage, daily events,
  status distributions, orchestration DAG, tool flow transitions)
- Code-split pages with React.lazy() — initial load 49KB vs 1.6MB
- Add useQueryCache hook with TTL for shared cross-component caching
- Rename Dashboard → "My Tasks", Workflows → "Agents" in nav

Testing: typecheck passes, build produces chunked output
Risks: vendor/design-system/dist/ adds ~1074 files to git

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Hoist all analytics + workflow SQL into prepared statements at init
  time instead of re-preparing on every poll (major perf fix)
- Nav order: My Tasks, Sessions, Activity Feed, Analytics, Agents
- Rename: Dashboard → Sessions, Kanban Board → My Tasks,
  Workflows → Agents
- Remove duplicate Sessions nav item (Dashboard now serves that role)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add schema migration v2: indexes on events.tool_name and
  events(session_id, rowid) for tool queries
- Rewrite tool transitions from correlated subquery to LEAD() window
  function, scoped to last 7 days (was 5.2s full scan → sub-second)
- Scope tool usage query to last 30 days, daily events to last 365 days
- Increase cache TTL for analytics/workflows to 10s/15s poll
  (heavy queries don't need 3s freshness)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix schema migration v2: rowid is a pseudo-column that can't be
  indexed — use (session_id, created_at) instead
- Add rollupOptions.output.manualChunks to split vendor bundle:
  vendor-charts (recharts/d3), vendor-icons (lucide-react),
  vendor-radix, vendor-ds
- Bump chunkSizeWarningLimit to 1000 (vendor chunks cache once)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Schema migration v3: add indexes on events(event_type),
  events(created_at, tool_name), agents(status), agents(type),
  agents(parent_agent_id)
- events-by-type: 1.1s → 0.15s with event_type index
- Dashboard: split getSummary (49ms, 5s poll) from getAnalytics
  (4s+, 60s poll) so initial load is instant
- Fix tool usage query column order for index coverage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…y Feed into Sessions

- New AgentsPage with Analytics/Orchestration tabs replaces separate
  Analytics and Workflows nav items
- Sessions page (dashboard) now has Sessions/Activity Feed tabs
- Nav: My Tasks, Sessions, Agents, then Gateway section
- Removes activity-feed, analytics, workflows as separate NavIds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 0 of the in-process agent monitor replacement (PR #264): make the
integration branch current and compilable before any feature work.

- Merge origin/main (175 commits) into feat/in-process-agent-database,
  bringing in FEA-1431 genai-prices pricing, FEA-1434 billing_mode, and
  the FEA-1435/1436 cost-reconciliation subsystem.
- Resolve conflicts:
  - app.ts: keep both 264's in-process SQLite wiring (openAgentDatabase,
    desktop:db:* IPC handlers) and main's reconciliation subsystem
    imports/wiring; drop the broken HarnessImportService import, field,
    constructor, start(), and stop() — harness-parsers/ never existed on
    the branch and was the tsc build break.
  - preload.ts: union both sides — 264's db.* bridge plus main's flags /
    ingest-progress / managed-key-hint methods.
  - package.json: bump version to 0.15.105 (above main's 0.15.104); keep
    both @playwright/test (main) and @tailwindcss/* (264).
  - index.html: keep 264's clean Vite entry (drop the monolithic shell).
  - pnpm-lock.yaml: regenerated via pnpm install against the merged
    package.json (re-links vendored @closedloop-ai/design-system).
- model_pricing is now absent from the entire desktop src (main's
  FEA-1431 removed it); the new-DB read path (src/main/database) never
  referenced it. The Phase 1 relay repoint stays out of scope.

Testing:
- just desktop-typecheck passes (tsc --noEmit, exit 0, zero errors)
- git merge-base --is-ancestor origin/main HEAD holds after this commit
- grep confirms zero model_pricing references in apps/desktop/src

Risks:
- Sidecar + iframe runtime still present (cutover is Phase 1); two SQLite
  DBs coexist by design until then. No external contract changed.
- Scope limited to Phase 0; no write path, relay repoint, or feature work
  in this commit.
thadeusb and others added 17 commits June 2, 2026 16:27
…on (Phase 1 S5)

Cut the agent-monitor runtime from the vendor sidecar to the in-process
listener and repoint every consumer of the old vendor dashboard.db — all in one
change so :4820 is never double-bound.

- Atomic cutover (app.ts): stop instantiating/starting AgentMonitorSidecar;
  construct the hook lifecycle (createLifecycle over the shared connection,
  billing_mode stamping, webContents 'desktop:db:changed' live-update emit) and
  AgentHookListener instead. startAgentCapture() (boot + enable path) runs the
  boot migration, starts the listener, self-heals hooks, and starts the relay.
  Shutdown stops the listener before closing the shared DB. The listener's
  onBindError preserves the degraded-tray UX on EADDRINUSE. Sandbox changes need
  no restart (the listener reads the sandbox live).
- Relay repoint (agent-session-sync-service.ts): new getConnection option — the
  relay reads the shared in-process connection (no per-cycle open/close, no
  existsSync no-op) and the token query drops the +baseline_* arithmetic (the
  v4 plain columns are already effective). Tests keep the path-based fallback.
- Cost-reconciliation repoint (plan-challenge blocker): reconciliation-worker
  loadMeteredUsageRows drops +baseline_* and reads the shared connection via
  app.ts loadUsageRows; removed the now-dead loadMeteredUsageRowsFromDisk. This
  was the second live vendor-DB consumer the cutover would have silently broken.
- Boot migration (agent-monitor-db-migration.ts): one-time idempotent import of
  the vendor dashboard.db (sessions/agents/events, baseline->effective tokens,
  billing_mode) into the in-process DB, then rename dashboard.db ->
  dashboard.db.migrated (downgrade-safe, not deleted).
- IPC: get-agent-monitor-url -> listener; ingest-progress -> null; reprocess ->
  honest unavailable (no destructive clear; filesystem import returns in Phase 2).
- Migrated the relay + reconciliation test fixtures to the v4 schema (effective
  in plain columns) and retargeted the 4 agent-monitor-wiring-static assertions
  to the listener-based invariants. Updated apps/desktop/CLAUDE.md to describe
  the in-process runtime (sidecar source dormant until Phase 3E).

Testing: just desktop-lint, just desktop-typecheck, full suite (2131 pass / 0
fail / 14 pre-existing skips) incl. new agent-monitor-db-migration tests
(import+rename, idempotency, absent, and cost-recon reads the real v4 schema
with no 'no such column' baseline error).

Risks: relay/recon now depend on the shared connection — covered by the
repointed fixtures + the real-v4-schema reconciliation test. The vendor sidecar
source remains in the tree (dormant) until the Phase 3E teardown.
…ning)

From the adversarial code + database review of the Phase 1 diff:
- HIGH: the boot migration aborted entirely on a single orphaned vendor agent
  row. INSERT OR IGNORE does NOT swallow a FK-constraint failure (it throws), so
  one agent whose session was pruned rolled back the whole import and re-failed
  on every boot (dashboard.db never renamed). copyAgents now explicitly skips
  agents whose session_id is absent from the imported sessions, matching its
  comment. Added a regression test seeding an orphaned vendor agent.
- MEDIUM: moved BEGIN IMMEDIATE inside processEvent's try so a stale open
  transaction (from a prior ROLLBACK that itself failed) is rolled back and the
  next event recovers, instead of escaping processEvent's "never throws" contract.
- LOW: runMigrations wraps each migration DDL + user_version bump in one
  transaction so a crash mid-migration rolls back both (clean re-run); the v4
  CREATE TABLE token_usage is now IF NOT EXISTS as belt-and-suspenders.
- LOW: shutdown stops the cost-reconciliation timers before closing the shared
  DB connection (close the connection last); fixed a stale dashboard.db comment.

Testing: just desktop-lint, just desktop-typecheck; full suite 2132 pass / 0
fail / 14 pre-existing skips (incl. the new orphaned-agent migration regression).
…n anchors

Per repo CLAUDE.md D6, the in-code legacy-migration anchors now cite the
ClosedLoop cleanup tickets that track their removal.
…echeck)

Targeted fixes for review comments that remained valid against the
current FEA-1497 code (most other comments were already resolved by the
in-process rewrite). Each fix is scoped and behavior-preserving.

- lifecycle: guard hook session_id at runtime (typeof string, non-empty)
  before it becomes a SQLite primary-key binding. It arrives as `unknown`
  through the zod envelope, so a non-string would be stringified to
  "[object Object]" and stored as a junk PK. (thread: thadeusb)
- db IPC: add shared coerceDbId() guard and apply it to every
  desktop:db:* handler that takes a renderer-supplied id/sessionId/
  agentId. IPC is a runtime boundary; TS annotations are erased, so a
  malformed value could otherwise reach node:sqlite bindings. Invalid
  args now return the same empty result as the disabled path. Adds
  db-ipc-validation unit tests. (thread: shafty023)
- renderer typecheck: add tsconfig.renderer.json and a typecheck:renderer
  script chained into `typecheck` so the .tsx renderer is type-checked in
  CI (previously only src/**/*.ts was, src/renderer excluded). Surfaced
  and fixed a real latent bug: 7 component files imported
  ../../main/database/types (resolves to the nonexistent renderer/main)
  instead of ../../../main/database/types — masked because they are
  erased `import type`s. Declared @types/react / @types/react-dom (used
  transitively but never as a direct dep). Renderer now type-checks
  clean with full strict. (thread: shafty023)
- packaging: re-chain build:agent-monitor into the package/release
  scripts. `build` no longer generates .generated/agent-monitor but
  stage-packaging hard-requires it and the runtime still loads the
  generated hook-handler scripts, so `pnpm package` failed on a clean
  checkout (not covered by CI). (thread: shafty023)
- packaging: exclude the file:vendor/design-system dep from the staged
  prod dependencies. Staging runs `pnpm install --prod` before copying
  app files, so the relative vendor path can't resolve; the renderer is
  already bundled into dist/renderer by Vite, so it isn't a runtime
  module. (thread: shafty023)
- vendor DS: fix the root export/main/module fields to point at files
  that exist — import/module/default -> dist/index.mjs (ESM),
  require/main -> dist/index.js (CJS). They previously pointed import at
  the CJS index.js and require/main at a nonexistent index.cjs.
  (thread: shafty023)
- window: gate the dev-server load (http://localhost:5173) behind an
  explicit CL_RENDERER_DEV_SERVER=1 opt-in, defaulting every build to the
  app:// renderer. The privileged preload would otherwise attach to
  whatever local process binds :5173 first. No current recipe starts a
  Vite dev server, so this also removes a pointless failed loadURL on the
  common dev path. (thread: shafty023)
- bump desktop version 0.15.108 -> 0.15.109

Testing: pnpm lint, pnpm typecheck (main + new renderer project),
pnpm build:renderer, and pnpm test (2032 pass / 0 fail) all green
locally. Staging script syntax-checked.

Risks: Packaging changes (build:agent-monitor re-chain, staged-dep
filter) are not exercised by CI; validated by code inspection and script
syntax check, full electron-builder package not run locally. Renderer
typecheck is now CI-gating — verified clean before wiring in.
- replace vendored desktop design-system with the published GitHub Packages release\n- update renderer session drill-down to follow the published SessionTable contract\n- refresh desktop lockfile and packaging flow for registry-based installs\n\nTesting:\n- pnpm -C apps/desktop typecheck\n- pnpm -C apps/desktop build:renderer\n- pnpm -C apps/desktop dev\n\nRisks:\n- desktop still pins an explicit design-system prerelease until a stable package version exists\n- session detail deep links now depend on hash-based navigation staying aligned with the dashboard tab
- replace the renderer bootstrap import of DesignSystemProvider with next-themes ThemeProvider\n- avoid the published design-system root bundle that still references a missing global React binding\n\nTesting:\n- pnpm -C apps/desktop typecheck\n- pnpm -C apps/desktop build:renderer\n- just desktop-dev\n\nRisks:\n- desktop no longer mounts the design-system root toaster wrapper until the published package root entry is fixed upstream
- force desktop renderer imports onto the design-system ESM files\n- inject missing React imports into broken published design-system modules during bundling\n\nTesting:\n- pnpm -C apps/desktop typecheck\n- pnpm -C apps/desktop build:renderer\n- just desktop-dev\n\nRisks:\n- this is a consumer-side compatibility patch for a malformed published package and should be removed once the design-system publish is corrected upstream
- Add a first-party in-process collection layer (src/main/collectors/):
  boot-time bulk import + live file watchers for all five agent CLIs
  (Claude, Codex, Cursor, Copilot, OpenCode), writing through a new
  idempotent importSession into the in-process node:sqlite DB. Ports the
  per-tool parsers/home modules from CommonJS to first-party TypeScript.
- Add a first-party Claude file collector (historical import + watch over
  ~/.claude/projects). Its live watcher is gated off when hooks are
  installed (hooks own live Claude capture; avoids double-counting turns).
- Own the hook handlers: ship resources/hooks/{hook-handler,codex-hook-
  handler}.js via electron-builder extraResources; agent-monitor-path now
  resolves resources/hooks. No build-agent-monitor, no generated tree.
- Gate all collection by agentMonitorEnabled and the FEA-1407 sandbox
  (fail-closed, per session); wire CollectorManager into app.ts boot,
  the enable/disable toggle, and shutdown (before agentDatabase.close()).
  Restart the collectors on a hooks toggle so the Claude-watch gating is
  re-evaluated rather than frozen at boot.
- Remove the third-party Claude-Code-Agent-Monitor entirely (absorbs
  FEA-1501): delete all scripts/agent-monitor-*, build-agent-monitor.mjs,
  the dormant sidecar, the iframe embed, the dashboard.db migration
  adapter, the agent-monitor e2e/audit suites, the vendor deps + lockfile
  entries, and the package/stage/electron-builder wiring. Rewrite the
  CLAUDE.md "Agent Monitor" section and THIRD_PARTY_NOTICES.
- Bump desktop version 0.15.109 -> 0.15.110.

Testing:
- just desktop-lint, desktop-typecheck (main + renderer), desktop-test:
  all green (1935 tests, 0 fail, 0 skipped).
- Real `pnpm build` (tsc emit + Vite renderer) succeeds.
- New tests (collectors-{parsers,import,hook-handler}): idempotent
  re-import adds no duplicate rows, fail-closed sandbox gating, both hook
  handlers' POST envelope, and ported-parser fixtures.
- Manually verified locally: the dashboard populates from existing
  sessions on a fresh DB.

Risks:
- The full electron-builder DMG (`pnpm package`) was not run locally
  (needs macOS + signing; not part of PR CI, only release.yml). The
  packaging config was updated and review-verified, but a clean-machine
  DMG smoke test remains the real proof for the asar-external node:sqlite
  path.
- Dropping the dashboard.db migration adapter (FEA-1501) means existing
  internal vendor-DB users re-derive history from on-disk transcripts on
  next launch; sessions whose transcripts were deleted are lost
  (acceptable pre-launch).
- The :4820 HTTP hook transport is intentionally preserved (FEA-1500) so
  hook commands already baked into ~/.claude/settings.json keep working.
…pp token

The Tests (and Release) workflows install deps with this repo's GITHUB_TOKEN,
which lacks read access to @closedloop-ai/design-system — it's published to
GitHub Packages from another org repo, so pnpm install fails with
ERR_PNPM_FETCH_403. Mint an org-scoped GitHub App token (the CLOSEDLOOP_APP_*
app already used by compatibility-smoke for cross-repo access) with
packages:read and use it for pnpm install only; the release publish step keeps
the repo GITHUB_TOKEN for contents:write.

This is a pre-existing branch CI failure (red on the prior commit too), not
specific to this PR's code.
The @closedloop-ai/design-system + loops-api GitHub Packages now grant
closedloop-electron read access (package Manage Actions access), so the stock
GITHUB_TOKEN can fetch them. Revert the org-scoped app-token install step in
test.yml + release.yml back to GITHUB_TOKEN.
@mikeangstadt

Copy link
Copy Markdown
Contributor Author

UI Regression Review

Critical Issues

1. Deep subpath imports from @closedloop-ai/design-system may fail at build/runtime
SettingsPanel.tsx:2-3 imports from @closedloop-ai/design-system/components/ui/button and @closedloop-ai/design-system/components/ui/card; DashboardPage.tsx:1 imports from @closedloop-ai/design-system/components/ui/primitives/metric-card. These require the published npm package's package.json exports field to expose these subpaths. If the DS package has strict exports (as most modern packages do), these will resolve to undefined or fail at build time.

Action: Verify @closedloop-ai/design-system@>=0.1.1-0 actually exposes these subpaths. Run pnpm build:renderer in a clean install to confirm.

2. Fragile MetricCard style overrides target DS internal DOM slots
DashboardPage.tsx:7-8SUMMARY_CARD_CLASS_NAME uses [data-slot=card-title] and [data-slot=card-description] selectors. These target internal Radix slot attributes that are not a public API. A DS minor bump could silently break all four metric cards.

Action: Either upstream MetricCard to accept titleClassName/descriptionClassName props, or lock the DS version to an exact semver.

High Issues

3. CSS custom properties may render invisible UI
The renderer uses var(--sidebar), var(--sidebar-foreground), var(--sidebar-accent), var(--warning), var(--warning-foreground), var(--input), var(--success). These are non-standard shadcn-style variables. If DesignSystemProvider doesn't define all of them, sidebar sections, warning text, and input fields will be invisible.

Action: Verify the DS theme includes all referenced CSS vars, or add fallback definitions in globals.css.

4. DS version range is too broad
package.json: ">=0.1.1-0" allows ANY version >= 0.1.1-0, combined with the minimumReleaseAgeExclude exemption in pnpm-workspace.yaml. A DS prerelease with breaking internal structure gets pulled in immediately.

Action: Pin to "0.1.1-dev.0" until the subpath exports and slot selectors are upstreamed as a public contract.

Medium Issues

5. Topbar missing labels for several nav tabs
Topbar.tsx:8-16NAV_LABELS map is missing entries for activity, analytics, workflows, sessions. The fallback shows raw navId strings like "activity" instead of "Activity".

6. postcss.renderer.config.mjs is dead config
Vite won't auto-discover a file named postcss.renderer.config.mjs (it looks for postcss.config.mjs). Remove the file and @tailwindcss/postcss/postcss from devDependencies if only the @tailwindcss/vite plugin is intended.

Low / Cosmetic

  1. @tailwindcss/typography in devDependencies — unused in any renderer component (no prose classes). Remove if not needed.

  2. PR description references "legacy.html iframe fallback" but this fallback doesn't exist. The old HTML was fully replaced. Update the PR description.

Verdict

@mikeangstadt

Copy link
Copy Markdown
Contributor Author

UI Regression Review — All Items Addressed

#1: DS subpath exports ✅ Verified

Installed @closedloop-ai/design-system@0.1.1-dev.26892521643.1 exposes all required subpaths: ./components/ui/button, ./components/ui/card, and ./components/ui/primitives/metric-card. Build confirmed (2542 modules).

#2: MetricCard slot selectors 🔒 Mitigated by version pin

[data-slot=card-title] and [data-slot=card-description] are stable DS Card component attributes (not private Radix internals). Pinning the DS version (#4) prevents silent breakage.

#3: CSS custom properties ✅ Verified

All referenced vars (--sidebar, --sidebar-foreground, --sidebar-accent, --warning, --warning-foreground, --input, --success, etc.) are defined in @closedloop-ai/design-system/styles/globals.css (imported in main.tsx:5).

#4: DS version pinned ✅

package.json: ">=0.1.1-0""0.1.1-dev.26892521643.1" (exact version matching lockfile).

#5: Topbar labels ✅ Added

Missing activity, analytics, workflows entries added to NAV_LABELS.

#6: Dead postcss config ✅ Removed

postcss.renderer.config.mjs deleted. Vite uses @tailwindcss/vite plugin — no PostCSS pipeline needed. Unused @tailwindcss/postcss and postcss devDependencies removed.

#7: @tailwindcss/typography 🔒 Required by DS globals.css

Kept as devDependency — the DS packages globals.css uses @plugin "@tailwindcss/typography", so it must be resolvable at build time.

#8: PR description ✅ Updated

Removed stale legacy.html iframe and vendored DS references.

@mikeangstadt mikeangstadt left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing prior review feedback

@shafty023: "remove clone of design system" ✅ Done

The vendored vendor/design-system/ was removed in commit a876313 (FEA-1503). The branch now consumes @closedloop-ai/design-system as a published npm dependency from GitHub Package Registry. The stale .gitignore negation (!apps/desktop/vendor/design-system/dist/) has also been cleaned up.

@thadeusb: Build concerns ✅ Resolved

  • Vendored DS dist/ gitignored: Vendored DS is gone; the published npm package includes its dist.
  • globals.css pulls in tailwind modules not in package.json: The DS globals.css @plugin "@tailwindcss/typography" is now resolvable — @tailwindcss/typography is in devDependencies. The @tailwindcss/vite plugin handles the Tailwind pipeline; the dead PostCSS config and its deps (@tailwindcss/postcss, postcss) have been removed.
  • Strangler-fig / legacy.html: PR description updated to reflect that this is a direct replacement, not parallel operation.

Additional fixes in this batch

  • DS version pinned to 0.1.1-dev.26892521643.1 (was ">=0.1.1-0" which could pull breaking prereleases)
  • Added missing Topbar labels for activity, analytics, workflows
  • Build verified: pnpm build passes (2542 modules, 2.57s)

shafty023 added 2 commits June 4, 2026 11:28
… type decoupling, tests)

- Add API key set/clear controls and an auto update status/apply banner to
  the React Settings UI, consuming existing but previously unused IPC
  (getApiKeyStatus/setApiKey/clearApiKey, desktop:update-status/-available,
  applyUpdate). Onboarding wizard, command-key management, and sandbox/origins
  editors remain deferred to a later phase.
- Decouple renderer-facing DB response types into
  src/shared/agent-db-contract.ts so the renderer no longer imports from
  src/main/database/types; raw rows map to the shared DTOs at the existing
  repository toRow() boundary.
- Add React renderer tests (UpdateBanner reducers plus active source guards)
  replacing the stale skipped renderer-logs guard; keep one accurately labeled
  skip for the still deferred diagnostics and command-signing UI.
- Pin @closedloop-ai/design-system to the locked prerelease and bump desktop
  version to 0.15.111.

Testing:
- just desktop-lint: clean
- just desktop-typecheck: clean (main and renderer)
- just desktop-test: 1949 pass / 0 fail
- pnpm build:renderer: success (2545 modules)

Risks:
- Settings parity ports only the quick win controls; heavier setup/recovery
  controls stay deferred.
- Type move is internal only (IPC ships as one unit with the app); no
  persisted-contract migration needed.
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

Compatibility Smoke Test Results ⚠️

Status: skipped
Electron SHA: 0372f26695a77a2a52f58f0bde1d537eb43cdbf4
Symphony Alpha SHA (last-known-good): 24741ed9be45cc761195d7a7b6613bd30cdfce84
Note: Skipped because the stage GitHub App credentials are not configured for this workflow run.

View Actions run

@shafty023

Copy link
Copy Markdown
Contributor

Thanks for the thorough pass, this is genuinely helpful. One important update before the item by item notes: since this review was written, the vendored design-system clone was removed (commit a876313). @closedloop-ai/design-system is now consumed as a real GitHub Packages dependency, resolved through the package exports map and the lockfile, which makes several of the build and runtime concerns below moot.

B1 (deep subpath imports): not an issue. The published package exports map exposes every subpath we import (./components/ui/button, ./components/ui/card, ./components/ui/primitives/metric-card, ./components/ui/composites/session-table, ./styles/globals.css, and the rest), so vite build resolves them with no extra alias. Confirmed by a clean pnpm build:renderer (2545 modules, exit 0).

B2 (data-slot overrides): not an issue. data-slot="card-title" and data-slot="card-description" are emitted by the design-system's own Card component, not by a Radix internal. They are the intended shadcn style styling hooks, and MetricCard renders CardTitle / CardDescription, so the selectors target a stable, public surface.

B3 (CSS custom properties): not an issue. All referenced variables (--sidebar, --sidebar-foreground, --sidebar-accent, --warning, --warning-foreground, --input, --success, and the rest) are defined in the design-system styles/globals.css, which the renderer imports in src/renderer/main.tsx. Our local globals.css intentionally only sets font variables and defers the theme tokens to the design-system.

B7 (@tailwindcss/typography unused): keeping it. There are no prose classes in our renderer, but the dependency is load bearing: the design-system globals.css we import declares @plugin "@tailwindcss/typography" (and @import "tw-animate-css"), so both packages must resolve at build time. Removing @tailwindcss/typography would break pnpm build:renderer.

B8 (legacy.html iframe fallback): no code issue. There is no legacy.html in the tree and no iframe in the renderer; index.html is a plain React mount point. That line in the PR description is stale and worth a quick edit, but there is nothing to change in the code.

B5 (missing Topbar labels): fixed in b4ba906. NAV_LABELS was missing activity, analytics, and workflows, so those breadcrumbs fell back to the raw nav id. The three labels (and removal of the dead agents key) landed in that commit.

B6 (dead postcss config): fixed in b4ba906. postcss.renderer.config.mjs was unreferenced and the renderer build uses the @tailwindcss/vite plugin, so the file was dead. It was deleted there, along with the now-unused @tailwindcss/postcss, autoprefixer, and postcss devDeps.

B4 (version range too broad): fixed in b4ba906. @closedloop-ai/design-system is now pinned to the exact locked prerelease (0.1.1-dev.26892521643.1) instead of the open >=0.1.1-0 range.

Separately, the three remaining open review threads (Settings setup/recovery controls, renderer DB type coupling, and the skipped renderer guards) are addressed in commit f40b4d1 on top of this. Thanks again for catching B4, B5, and B6.

@shafty023
shafty023 self-requested a review June 4, 2026 21:46
Keep the legacy monitor as the default boot path, put the design-system dashboard runtime and storage behind the explicit Labs flag, and package the embedded agent dashboard assets and tests.

Validation: pnpm -r prebuild; pnpm -C apps/desktop lint; pnpm typecheck; pnpm -C apps/desktop assert:design-system-boundary; pnpm -C apps/desktop test:boot:design-system-off; pnpm -C apps/desktop measure:agent-dashboard-storage; pnpm test; pnpm -C apps/desktop build.
@shafty023 shafty023 changed the title FEA: Replace agent-monitor sidecar with in-process SQLite database + React renderer FEA-1504: Gate embedded agent dashboard Jun 4, 2026
@mikeangstadt
mikeangstadt merged commit 4e7eb9e into main Jun 5, 2026
5 checks passed
@mikeangstadt
mikeangstadt deleted the feat/in-process-agent-database branch June 5, 2026 03:34
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants