Skip to content

feat: add @clens/web dashboard + monorepo restructure + security/stan…#1

Open
silouone wants to merge 38 commits into
mainfrom
clens-oss-refactor
Open

feat: add @clens/web dashboard + monorepo restructure + security/stan…#1
silouone wants to merge 38 commits into
mainfrom
clens-oss-refactor

Conversation

@silouone

Copy link
Copy Markdown
Owner

…dards fixes

Monorepo:

  • Move CLI to packages/cli/, add packages/web/ for SolidJS dashboard
  • Add tsconfig.base.json, workspace package configs

Web dashboard (@clens/web):

  • SolidJS + Hono server with SSE live updates, LRU cache, file watchers
  • Session list, session detail, agent view, conversation panel, diff panel
  • Virtual scroll, bidirectional linking, keyboard nav, dark theme
  • 72 tests across API, integration, and gate suites

Security fix:

  • Add validateSessionId() middleware to /api/commands/sessions/:sessionId/*
    to prevent path traversal (was only on /api/sessions/ routes)

Standards cleanup (12 violations):

  • Remove non-null assertion (SessionHeader cost()!)
  • Replace for/while loops with reduce/recursion (AgentView, events, cache)
  • Eliminate let module state → const object properties (ring buffer)
  • Replace .push()/.length=0 mutations with immutable patterns (events, live, DiffPanel)
  • Add runtime type guards before as-casts on API responses (stores, events)
  • Remove no-op ternary in ConversationPanel

Dev workflow fixes:

  • Skip auth in development mode (localhost-only, no token needed)
  • Fix Vite proxy port mismatch (3700 → 3117)
  • Add findProjectDir() to resolve git root, not cwd (fixes 8 vs 122 sessions)
  • Allow all localhost origins in dev CORS

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

silouone and others added 30 commits March 8, 2026 10:31
…dards fixes

Monorepo:
- Move CLI to packages/cli/, add packages/web/ for SolidJS dashboard
- Add tsconfig.base.json, workspace package configs

Web dashboard (@clens/web):
- SolidJS + Hono server with SSE live updates, LRU cache, file watchers
- Session list, session detail, agent view, conversation panel, diff panel
- Virtual scroll, bidirectional linking, keyboard nav, dark theme
- 72 tests across API, integration, and gate suites

Security fix:
- Add validateSessionId() middleware to /api/commands/sessions/:sessionId/*
  to prevent path traversal (was only on /api/sessions/ routes)

Standards cleanup (12 violations):
- Remove non-null assertion (SessionHeader cost()!)
- Replace for/while loops with reduce/recursion (AgentView, events, cache)
- Eliminate let module state → const object properties (ring buffer)
- Replace .push()/.length=0 mutations with immutable patterns (events, live, DiffPanel)
- Add runtime type guards before as-casts on API responses (stores, events)
- Remove no-op ternary in ConversationPanel

Dev workflow fixes:
- Skip auth in development mode (localhost-only, no token needed)
- Fix Vite proxy port mismatch (3700 → 3117)
- Add findProjectDir() to resolve git root, not cwd (fixes 8 vs 122 sessions)
- Allow all localhost origins in dev CORS

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace listSessions() + enrichSessionSummaries() (reads ALL file content
for 122 sessions, ~60MB) with listSessionsLightweight() that reads only
first+last JSONL lines per file for metadata. Session detail is fetched
lazily on navigation.

Also replace existsSync-via-listSessions for session existence checks
with direct existsSync on the session file.

Result: session list loads in ~94ms vs stalling indefinitely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Settings page with 5 sections: Appearance, Display, Capture & Cost, Server Info, Data Management
- All 13 controls have real behavior (font size, timestamps, page sizes, sidebar width, auto-distill, capture, pricing, theme, reset)
- New app header with sticky nav: clickable logo, Sessions/Work Units menu items, gear icon, theme toggle
- Server config API (GET/PUT /api/config) with validation
- Client preferences store (localStorage) with reactive signals
- Keyboard shortcut (,) for settings via SPA navigate bridge
- New UI components: Toggle switch, SettingRow, SettingsSection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Header: thicker padding, bigger logo, separator, nav items with more spacing
- Moved Live SSE indicator, global KPI stats (Total/Today/Events/Avg), and refresh button to header
- Removed duplicate Sessions/Work Units toggle from SessionList page
- Made viewMode derived from URL params (header nav drives it)
- SessionList now starts clean with filters + session table

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

- Removed refresh button from global header (not global context)
- Added refresh button back to SessionList filters row (refreshes both sessions + work units)
- Pushed nav items (Sessions/Work Units/Live) to the right side of header
- Added vertical separator between nav and action icons (theme/gear/help)
- KPIs stay in header center area, nav pushed right with ml-auto
- Fixed missing SessionSummary import in SessionDetail.tsx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds --global flag to list, what, and web commands, enabling unified views
across all registered projects. Projects auto-register on clens init via
~/.clens/projects.json registry. Web server supports multi-project mode
with per-project live watchers, session-to-project resolution map, and
project filtering in the client UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pricing, cost wiring

- B1: /api/sessions event_count now exact (cached newline scan) instead of estimated
- B2: duration_ms = wall-clock span in CLI list + web list + detail display agree
- B3: active duration computed from wall span (idle gaps no longer subtracted twice)
- B7: live hydration paginates events (single limit=10000 request 400'd silently)
- B8: pricing table covers fable-5/opus-4.5+/haiku-4.5; longest-prefix match; real context windows
- B9: cost_estimate mirrored top-level in distill output; UI falls back to stats.cost_estimate
- B13: index.css stray é in --clens-surface + token lint gate test
- B14: work-unit end times use wall span (both feeds)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7 builder clusters (status/staleness semantics, analytics truth, distill count
doubling, raw-text rendering, list/file panels, live auto-distill guard, hook
project-root) + orchestrator follow-ups: SessionList status filter regression
(All|Complete|Active|Idle), date-filter consumer (B22), narrative/user-prompt
verbatim rendering (B16 second half), pricing/context table alignment,
StalenessData validation, lightweight analytics population scan, FP refactors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- file-map: anchored bash path extraction (no more garbage paths), failed ops
  counted as errors not successes, repo-root path normalization
- distill extractors: task-list completed/deleted status (P0), backtracks
  agent partitioning, decisions/plan-drift/user-messages fixes
- agent attribution: tool calls attributed by data.agent_id (ghost zeroing),
  pricing tier threaded through agent/merge cost paths
- web server: assets cache headers, registry nested projects, distill command
  analytics refresh
- web client state: stale-fetch guards, debounce max-wait, live status overlay
  (active/idle aligned with B6), live duration from server timestamps
- INSTRUMENT token foundation: IBM Plex self-hosted fonts, full --clens-* token
  system both modes, tailwind config

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on, feature-flag sentinel, ghost sessions, torn-last-line, global analytics fallback, child-session live filter, tier_stale surface

Closes every confirmed P0/P1 finding. Suite: 1953 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… web-review)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…deps removed

18/18 web-review stories pass. 1953 tests green. Final report in specs/revive/.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… baseline

Planning artifacts: GOAL, ORCHESTRATION runbook, SHARED-CONTEXT, 24 audit reports,
feedback-aggregate (127 items), requirements (72 EARS), implementation-plan, build-tasks.json.
Branch baseline for gated build waves. typecheck+tests GREEN at this commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- OSS-1 canonical npm name -> clens (unscoped, verified available); cascaded rename across web imports+tests
- OSS-2 publish.yml publishes only packages/cli (--access public) + tag==version guard
- OSS-3 manifest -> 0.3.0 + CHANGELOG Unreleased/compare links; plugin.json -> 0.3.0
- OSS-4 SECURITY.md; OSS-7 issue/PR templates; OSS-8 CODE_OF_CONDUCT.md
- OSS-5 drop tracked Gemini asset; DEP-1 untrack deliberation/; DEP-6 untrack .verify.json (gitignored)
- DEP-4 drop @types/bun; DEP-5 fix misleading deprecated tag; TEST-1 root lint fan-out; TEST-12 CI PR trigger
- NUM-23 hook.ts rejects .clens-segment roots (stops capture recursion) + regression test

Deferred: OSS-6 stale-branch deletion; NUM-23 nested .clens real-data dir (needs Silou).
Gate: typecheck GREEN; tests 1822 pass / 0 fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… /assets/ gitignore

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- NUM-1 de-dup global session list by session_id (keep max-event owner) — deflates inflated SESSIONS/EVENTS/TOTAL TIME (global-read.ts, sessions.ts)
- NUM-2 read-time cost re-pricing from tokens x current rate (stats.ts, read.ts, types/distill.ts) + cost-basis test
- CLI-1 clean safety: bare 'clens clean' no longer mass-deletes; --all explicit lever; confirm/--yes gate (clean.ts, cli.ts, shared.ts)
- CLI-2 'clens web' prod packaging (web.ts, build.ts, app.ts, index.ts, package.json)
- DIST-7 atomic analytics-summary write
- regression fixes: repriceAgent guards undefined children (legacy distills); assets cache-header gate tracks distDir rename

Gate: typecheck GREEN; tests 1828 CLI + 267 web pass / 0 fail. (Wave-1 workflow stalled post-write on a hung builder; killed it, work intact.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- NUM-7 analytics-summary reconciles vs distilled/ on read (closes 317<320 coverage gap)
- NUM-12 freeze live duration counter once session idle
- NUM-14 normalize bare model aliases (opus/sonnet/haiku/fable) before pricing prefix-match
- NUM-22 torn-final-line no longer +1 miscounts staleness raw_event_count
- DIST-2 batch analytics-summary write (O(N) not O(N^2)); DIST-3 --deep gates git enrichment
- plus DIST-4 schema-version freshness, cost honesty, CLI papercuts, publish-pipeline tasks (17 total)

Gate: typecheck GREEN; tests 1833 CLI + 269 web pass / 0 fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- NUM-3 header 'Total time'->'Span' (wall) + distinct '~Active' chip (idle-trimmed, analyzed-only, honest tooltip); count 'Active'->'Live'
- NUM-4 lone-SessionEnd files render EMPTY/'—', never 'DONE 0s'
- NUM-5 estimated cost shows '~' in both >=$0.01 and <$0.01 branches
- NUM-6 modelDisplayName humanizer ('Claude Fable 5'/'Claude Opus 4.8', strips [1M]); NOTE: Fable 5 is a REAL model, not a codename — pricing kept
- NUM-8 Insights '· N pending' coverage; NUM-15 cost drilldown populated from cost_estimate; NUM-16 charts gated on hasCost (ChartEmpty)

Gate: typecheck GREEN; tests 1833 CLI + 269 web pass / 0 fail. (12/13 done; NUM-6 partial by false-premise, functionally complete.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- FE-3 single signal-green per mode (brand ramp via --clens-brand color-mix; kills two-greens dark bug)
- FE-5 unified microcaps H1 across pages (session-detail title stays mono = data); FE-6 square hairline LED toggle (no shadow/pill)
- FE-7 sessions table min-w-[1040px] (NAME never clipped); FE-8 KPI band wraps not clips; FE-13 mobile detail drawer usable width; FE-18 tab bar no 375px clip
- FE-17 explicit 3-tier breakpoint contract; FE-28 consolidated filter store (foundation for W5)
- NUM-11 Span/Active vocabulary standardized incl. CLI list 'Duration'->'Span' (test updated)

Gate: typecheck GREEN; tests green (1 CLI test updated for intentional Span rename). 19/19 done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
silouone and others added 8 commits June 27, 2026 05:58
- FE-9 consolidated filter surface: 1 primary row + Filters popover + active-filter chips (4 stacked rows gone)
- FE-10 clear-all restores FILTER_DEFAULTS; FE-11 always-visible hidden-subagents chip; FE-12 split conflated agents facet -> hideSubagents + composition
- FE-4 single muted categorical chart palette (kills MODEL_PALETTE rainbow + duplicate-green decision chart bug)
- FE-24 neutral hairline hover (border.strong) not generic green; FE-25 'Has feature' label; FE-27 drop dead 'incomplete' alias; FE-34 KPI cells as filter shortcuts
- IA/live: Work Units stays hidden + fetch guarded, /work-units no dead-end, short-id/team routes, analytics dropdown, KPI no 0-flash, SSE reconnect

Gate: typecheck GREEN; tests 1833 CLI + 269 web pass / 0 fail. 19/19 done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- CFG-1/2/4 extractSessionConfig: permission_mode + effort (typed closed-sets) + MCP servers (from mcp__ tool names, deduped/counted); wired into distill (index.ts:266) -> DistilledSession.session_config
- CFG-3 settings.json snapshot at SessionStart (output_style/statusline/plugins/defaultMode/hooks; scope union; never on hot path, never throws)
- CFG-5 (partial) CLAUDE.md-in-effect from InstructionsLoaded + inferred fallback capability
- CFG-6 web 'Config / Environment' panel (INSTRUMENT: model+1M chip, effort, permission LED, MCP); CFG-7 CLI 'what'/report config surface + WhatJson.config

Gate: typecheck GREEN; tests pass / 0 fail. 5/6 done (CFG-5 partial: live-binary verify + fallback wiring deferred).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- FE-1 cut Work Units end-to-end: ~2,500-3,000 LOC, 13 files deleted (distill/session/web routes, WorkUnit* components, WorkUnitDetail page, feature-flags, work-unit libs, 3 test files) + SHOW_WORK_UNITS flag, nav, filters, stores; cascade-removed related-sessions (read _work_units.json). On-disk _work_units.json left as gitignored data.
- DEP-2 removed --otel export vaporware (flag, help, Flags type, OTLP)
- DEP-3 deleted orphan SessionSnapshot.tsx + dead uninitCommand
- DIST-1 removed per-distill rebuildWorkUnitIndex (was O(N^2) per batch)

Gate: typecheck GREEN; tests 1793 CLI + 261 web pass / 0 fail (counts down: removed-feature tests). No dangling refs in real source. 4/4 done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- TEST-2 clean.test.ts (11 tests, 100% cov): pins clean-safety (bare errors/no-op, --all needs --yes, --force, [y/N] confirm, targeted)
- TEST-4 pricing.test.ts (14): per-tier rates + opus 4->4-5 longest-prefix boundary + bare-alias normalization
- TEST-6 design-tokens gate: locked INSTRUMENT palette pins + banned shadow/rounded-full idioms
- TEST-7 api-fetch-auth source gate (FE-35 lock); TEST-11 tier_stale match/mismatch pins
- TEST-3/8 (D5): dropped dead/broken vitest+@solidjs/testing-library; web-review is the UI gate; test:api = bun test test/

Gate: typecheck GREEN; tests green. Deferred follow-ups: TEST-10 (freeze dates in analytics tests — builder API-stalled mid-edit, reverted to keep green), DOCS-3 (demo gif/screenshots — needs running app/web-qa).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- DOCS-1 README Web Dashboard section (clens web, token security, Config/Environment panel, cost honesty) [assets pending screenshots]
- DOCS-4 extractor count -> '20+' (drop stale 23/agent-lifetimes); DOCS-5 CLI Reference matches cli.ts (web/name/config/init --global, clean safety, drop --otel)
- DOCS-6 CI-status badge (drop stale '1151 tests'); DOCS-7 30-second quickstart lead
- DOCS-2 CONTRIBUTING rewritten for the Bun monorepo (packages/*, web-review gate, no Work Units)
- DOCS-8 LICENSE holder/year; FE-36 Usage/Insights separation decision record
- TEST-5 CI runs test:cli + test:web as explicit steps

Gate: typecheck GREEN; tests 1818 CLI + 276 web / 0 fail. 8/9 done (DOCS-1 assets pending web-qa screenshots). Noted: 'bun run lint' matches 0 files (biome scope) — morning follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… done)

6 INSTRUMENT-themed PNGs (sessions dark/light, detail, insights, usage, mobile-375) in .github/assets/.
README hero -> dashboard-sessions.png, detail -> dashboard-detail.png (were dead gif/session-detail refs).
NOTE: animated hero gif still a nice-to-have follow-up; static hero ships now.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- LAND-8 single dependency-free static landing/index.html (INSTRUMENT tokens, hero, trust strip, 3 value props, problem framing, 3 feature blocks, privacy, get-started, Free $0/Individual $12/Team $24 pricing, FAQ, footer); ALL links functional, responsive-verified 360-1280px, no-flash theme
- LAND-4 self-contained landing/assets/ (credibility-gated dashboard PNGs)
- LAND-7 free-tier-shape decision record (D2 open); LAND-9 purged unverified Astro-acquisition claim + gray/blue design mandate from site report

Gate: typecheck GREEN; tests pass / 0 fail (landing/ is outside bun workspaces). 4/4 done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- LAND-1 INSTRUMENT tokens verified ported verbatim (5 locked hexes, square/hairline/no-shadow); LAND-3 honesty-safe copy verified (cost 'estimated', 20+ extractors, no Quality Score, no Fable)
- LAND-6 pricing: Free $0 (MIT, capture-only hard wall) / Individual $12-mo / Team $24-seat-mo, open-core explainer in pricing-note + FAQ; all CTAs live
- LAND-2 canonical name 'clens' in install cmd + honest 'publish pending' caveat (end-to-end install unverifiable without publish creds)

Gate: typecheck GREEN; tests pass / 0 fail. 4/4 done (LAND-2 partial: blocked on npm publish creds). Landing page is launch-ready pending deploy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@silouone silouone self-assigned this Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant