feat: Mission Control tab — live visualization of agent activity (Gource-inspired)#85
feat: Mission Control tab — live visualization of agent activity (Gource-inspired)#85sujayjayjay wants to merge 1 commit intomainfrom
Conversation
Implement the Mission Control dashboard for real-time visualization of parallel agent activity, inspired by Gource. The feature includes three panels: 1. Agent Map (left): D3 force-directed visualization showing agents as orbiting nodes around a central "main" node, with files they touch as leaf nodes that pulse on modification. 2. Branch Timeline (center): Horizontal swimlanes per agent showing commits as nodes, with visual indication of how far each branch has diverged from main. 3. Activity Feed (right): Real-time scrolling feed of agent actions via SSE, showing commits, file changes, and PR events as they happen. Technical implementation: - GitActivityPoller service polls git log on worktrees every 10 seconds - New /api/activity SSE endpoint streams events to clients - D3-force for physics simulation, Canvas for rendering - Event buffering to handle rapid-fire git activity Closes #81 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 6 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| for (const link of linksRef.current) { | ||
| const source = link.source as Node; | ||
| const target = link.target as Node; | ||
| if (!source.x || !source.y || !target.x || !target.y) continue; |
There was a problem hiding this comment.
Falsy coordinate check skips nodes at x=0 or y=0
High Severity
The checks !source.x || !source.y and !node.x || !node.y use falsy evaluation, which treats 0 as false. D3's phyllotaxis initialization sets the first node (the "main" node) to y = radius * sin(0) = 0, so the central main node is invisible during early simulation ticks. Any node passing through coordinate 0 during simulation will also flicker out. These checks need to test for undefined/null rather than falsiness.
Additional Locations (1)
| es.close(); | ||
| // Reconnect after 3 seconds | ||
| setTimeout(connectToSSE, 3000); | ||
| }; |
There was a problem hiding this comment.
SSE reconnection timeout leaks after component unmount
Medium Severity
The setTimeout(connectToSSE, 3000) in onerror is never cancelled on unmount. If the component unmounts while a reconnect timeout is pending, it fires after cleanup runs, creating an orphaned EventSource that is never closed. That orphaned connection can error again, scheduling another timeout — creating an unbounded loop of leaked connections.
Triggered by project rule: BugBot Configuration
| hash = hash & hash; | ||
| } | ||
| return colors[Math.abs(hash) % colors.length]; | ||
| } |
There was a problem hiding this comment.
Duplicated getSessionColor utility across three components
Low Severity
getSessionColor is identically copy-pasted in AgentMap.tsx, ActivityFeed.tsx, and BranchTimeline.tsx. If the color palette or hash logic needs to change, all three copies must be updated in sync. This belongs in a shared utility, which the activity/index.ts barrel file could easily re-export.
Additional Locations (2)
| export function clearActivityCache(sessionId: string): void { | ||
| activityCache.delete(sessionId); | ||
| seenCommits.delete(sessionId); | ||
| } |
There was a problem hiding this comment.
Unused exported functions in git-activity.ts
Low Severity
getCachedActivity, getAllCachedActivity, and clearActivityCache are exported but never imported or called anywhere in the codebase. Since clearActivityCache is the only way to prune the module-level seenCommits and activityCache maps, these caches also grow without bound.
| }, | ||
| ]), | ||
| ), | ||
| }; |
There was a problem hiding this comment.
State update replaces sessions and gitActivity with incomplete data
High Severity
The state_update event omits branch from session objects and commits from gitActivity entries, but the client replaces sessions wholesale and shallow-merges gitActivity by key. After the first polling cycle (~10 seconds), all sessions lose their branch property and all gitActivity entries lose their commits array. This causes the BranchTimeline to show no branch names and no commit nodes, and affects AgentMap graph construction — effectively breaking the visualization shortly after load.
Additional Locations (1)
| No recent commits | ||
| </span> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
Conflicting flex and relative positioning for commit nodes
Medium Severity
Commit dots are placed inside a flex justify-between container while each item also has position: relative with a left percentage. These two positioning strategies compound: flexbox distributes items evenly, then left shifts each item further from its flex position by a percentage of the container width. For anything beyond the first commit, nodes are pushed progressively further right, with the last commit rendered at roughly double the container width (completely off-screen).


Summary
Adds a Mission Control tab to the dashboard that makes parallel agent activity feel alive — the viral moment where someone screen-records 8 agents autonomously building a codebase in real time.
Technical implementation
GitActivityPollerservice pollsgit logon each worktree every 10 seconds/api/activitySSE endpoint streams events to connected clientsScreenshots
The Mission Control dashboard can be accessed via the "mission control" link in the main dashboard header.
Test plan
pnpm typecheck- passespnpm lint- no new errorspnpm build- passesCloses #81
🤖 Generated with Claude Code