-
Notifications
You must be signed in to change notification settings - Fork 0
Add local Fleet web dashboard #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
47a6bfd
19953bf
c1131d2
6915642
ae12ed3
ebaa876
008bc64
07bd6e2
2d72d87
13dad5d
7d3c2ba
bfa02aa
78dd65b
f1e9e71
5f0f5ea
83a7fc3
4413921
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| --- | ||
| module: web | ||
| version: 1 | ||
| status: active | ||
| files: | ||
| - src/web.ts | ||
| - src/fleet-adapters.ts | ||
| - src/fleet-brand.ts | ||
| db_tables: [] | ||
| depends_on: | ||
| - catalog | ||
| --- | ||
|
|
||
| # Web | ||
|
|
||
| ## Purpose | ||
|
|
||
| Serve a local, read-only Fleet dashboard backed directly by Let's federated | ||
| index cards. The dashboard makes agent activity inspectable without becoming a | ||
| workflow engine or a remote-control surface. | ||
|
|
||
| ## Public API | ||
|
|
||
| | Export | Description | | ||
| |--------|-------------| | ||
| | `buildFleetSnapshot` | Build a bounded, metadata-only Fleet snapshot from Let catalog APIs. | | ||
| | `fleetStateForSessions` | Classify observed heartbeats as Recent activity or History. | | ||
| | `fleetHtml` | Render the privacy-bounded local Fleet page. | | ||
| | `startFleetWeb` | Start the local-only web server and return its URL and stop handle. | | ||
| | `FleetFreshness` | One of live, recent, stale, or unknown activity states. | | ||
| | `FleetSession` | Sanitized provider, session label, and bounded freshness metadata. | | ||
| | `FleetState` | Recent activity or History repository activity classification. | | ||
| | `FleetWorktree` | Sanitized worktree and branch metadata belonging to a repository. | | ||
| | `FleetRepository` | Repository-first collection of worktrees and secondary session evidence. | | ||
| | `LiveAgent` | Whitelisted local CLI agent with an internal current working directory. | | ||
| | `WorkingAgent` | Sanitized live agent record matched to a repo/worktree or marked unassigned. | | ||
| | `FleetAgentActivity` | Safe agent-focused status derived from a local process or session metadata. | | ||
| | `FleetGitEvidence` | Local Git dirty, ahead/behind, and active Spec Sync change evidence. | | ||
| | `gitEvidence` | Read local Git evidence for a resolved agent worktree. | | ||
| | `selectAgentWorkContext` | Prefer a bounded child verifier worktree over its agent parent process context. | | ||
| | `redactLocalDetail` | Redact known token, credential, and environment-value patterns before local display. | | ||
| | `fleetContextLabels` | Build explicit project, worktree, and branch labels for agent supervision. | | ||
| | `retainFleetOpenKeys` | Keep open panel keys only while their backing Fleet cards remain available. | | ||
| | `mergeFleetOpenKeys` | Merge visible panel state without discarding an open panel in the other view. | | ||
| | `fleetLiveChangeAnnouncement` | Describe material agent visibility or status changes for accessible live updates. | | ||
| | `parseLocalAgentProcessLines` | Parse only whitelisted agent CLI processes and resolve their cwd internally. | | ||
| | `FleetSnapshot` | Sanitized rows, bounded session metadata, refresh interval, and policy. | | ||
| | `FLEET_SESSION_ADAPTERS` | Let-native presentation adapters for Claude, Codex, Grok, Gemini, and Antigravity session cards. | | ||
| | `fleetAdapterFor` | Resolve the local Fleet presentation adapter for an indexed session card. | | ||
| | `fleetSessionDetail` | Extract bounded, redacted display text from an already-indexed local session file. | | ||
| | `FleetProvider` | Supported Fleet session-provider name. | | ||
| | `FleetSessionDetail` | Bounded local prompt and output detail plus an internal-only path for resolving sanitized project context. | | ||
| | `FleetSessionAdapter` | Host-card matching contract for Fleet's presentation adapters. | | ||
| | `CORVID_TOKENS_CSS` | Local serving copy of the CorvidLabs design-system token stylesheet. | | ||
| | `CORVID_THEME_JS` | Local serving copy of the standard CorvidLabs theme controller. | | ||
|
|
||
| ## Invariants | ||
|
|
||
| 1. `let web` binds only to `127.0.0.1` and defaults to port `8731`. | ||
| 2. Fleet data is derived from Let catalog APIs, not parsed terminal output. | ||
| 3. Responses never include raw secrets, browser shell endpoints, or agent-control actions. The localhost supervisor may include redacted session text, commands, and project context for active-agent supervision. | ||
| 4. Repository cards group worktrees first; sessions remain secondary evidence. | ||
| 5. Working now comes only from a local process probe with exact agent CLI executable allowlist and cwd resolution. Session timestamps never prove a process is running. | ||
| 6. Unmapped live processes are surfaced as Unassigned running agent and agent type only; their current working directories never leave the process probe. | ||
| 7. Worktrees, sessions, instructions, and skills are capped before rendering. | ||
| 8. Session-only records are bounded and include metadata only. | ||
| 9. The normal CLI exits after ordinary commands, but remains alive while `web` | ||
| owns the local server. | ||
| 10. The agent view distinguishes a process-backed `Working now` status from recent or historical session metadata; no session record is represented as a running process. | ||
| 11. The process probe may inspect a bounded descendant tree internally to classify an allowlisted operation label; the localhost supervisor may show its redacted command and resolved project context, but never exposes process IDs. | ||
| 12. The localhost supervisor may expose redacted command, prompt/update, and recent output only after applying `redactLocalDetail`; unavailable detail is labeled instead of inferred. | ||
| 13. Agent context shows project, worktree, and branch independently when Let can resolve them; raw local paths never leave the server. | ||
| 14. Fleet maps host session cards through explicit presentation adapters; it does not scan host paths independently of Let's catalog. | ||
| 15. Gemini must be shown through its Gemini or Antigravity adapter when indexed, otherwise Fleet shows an explicit unavailable state. | ||
| 16. A 20-second refresh preserves the selected view, open Fleet panels, scroll position, and focused control where the backing card remains available; removed cards may no longer retain state. | ||
| 17. Material agent visibility or status changes are announced through a polite live region without moving focus. | ||
|
|
||
| ## Behavioral Examples | ||
|
|
||
| ``` | ||
| Given multiple host worktrees and path-only sessions | ||
| When let web starts | ||
| Then the browser receives sanitized Fleet rows without transcript contents | ||
| ``` | ||
|
|
||
| ``` | ||
| Given `let web --port 8732` | ||
| When the server starts | ||
| Then the URL is http://127.0.0.1:8732 and no non-local interface is bound | ||
| ``` | ||
|
|
||
| ## Error Cases | ||
|
|
||
| | Error | When | Behavior | | ||
| |-------|------|----------| | ||
| | invalid port | `--port` is not an integer from 1 to 65535 | Return a validation envelope. | | ||
| | unavailable port | local port already bound | Let reports Bun's startup failure; no fallback external binding. | | ||
|
|
||
| ## Dependencies | ||
|
|
||
| - `./catalog/context-builder` - trusted scan context. | ||
| - `./catalog/find` - structured federated index cards. | ||
|
|
||
| ## Change Log | ||
|
|
||
| | Version | Date | Changes | | ||
| |---------|------|---------| | ||
| | 1 | 2026-08-01 | Initial local read-only Fleet dashboard. | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,48 @@ import { geminiHome, projectGeminiDir } from "../paths.ts"; | |
| import { instructionId, pathCardId } from "./ids.ts"; | ||
| import type { IndexCard } from "./types.ts"; | ||
|
|
||
| export function antigravitySessionCards( | ||
| brainRoot: string, | ||
| limit: number, | ||
| ): IndexCard[] { | ||
| if (!isDirectory(brainRoot)) { | ||
| return []; | ||
| } | ||
| try { | ||
| return readdirSync(brainRoot) | ||
| .slice(0, limit) | ||
| .flatMap((sessionId) => { | ||
| const transcript = join( | ||
| brainRoot, | ||
| sessionId, | ||
| ".system_generated", | ||
| "logs", | ||
| "transcript_full.jsonl", | ||
| ); | ||
| if (!pathExists(transcript)) { | ||
|
Comment on lines
+28
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If an Antigravity session directory or its transcript is a symlink outside AGENTS.md reference: AGENTS.md:L11-L11 Useful? React with 👍 / 👎. |
||
| return []; | ||
| } | ||
| return [ | ||
| { | ||
| id: pathCardId("sessions", transcript), | ||
| kind: "sessions" as const, | ||
| host: "gemini" as const, | ||
| name: `Antigravity session ${sessionId.slice(0, 8)}`, | ||
| path: transcript, | ||
| scope: "user" as const, | ||
| mtime_ms: mtimeMs(transcript), | ||
| meta: { | ||
| source: "antigravity-cli", | ||
| detail_available: true, | ||
| }, | ||
| }, | ||
| ]; | ||
| }); | ||
| } catch { | ||
| return []; | ||
| } | ||
| } | ||
|
|
||
| function readProjectsMap(): Map<string, string> { | ||
| // path -> short name | ||
| const map = new Map<string, string>(); | ||
|
|
@@ -198,6 +240,12 @@ export function findGeminiSessions(ctx: ScanContext): IndexCard[] { | |
| }, | ||
| }); | ||
| } | ||
| cards.push( | ||
| ...antigravitySessionCards( | ||
| join(home, "antigravity-cli", "brain"), | ||
| ctx.policy.maxEntriesPerRoot, | ||
| ), | ||
| ); | ||
| } | ||
|
|
||
| return cards; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a populated Codex history, this adds another nested directory enumeration beneath the existing year, month, and day loops, allowing a large multiplicative scan on every session query and exceeding the repository's shallow-root ScanPolicy invariant. Index a bounded shallow card or use a purpose-built fixed lookup rather than recursively composing
listChildPaths.AGENTS.md reference: AGENTS.md:L11-L11
Useful? React with 👍 / 👎.