Feat/phase 2 agent focus - #107
Conversation
The Factorio zoom-in: click a stage card on the factory floor and the
dashboard transitions to a full-screen Agent Focus Mode showing:
- Live terminal output (polled every 2s via single /focus endpoint)
- Token usage stats (input, output, cache read/write)
- Context % with color-coded fill bar (green/amber/red)
- Git diff of agent's worktree changes (syntax highlighted)
- Workflow progress (step X/Y)
- Prompt input bar to send instructions to the agent
- "Agent not running — Start Agent" CTA when agent is stopped
Backend: single GET /v1/agents/{ws}/{agent}/focus endpoint combines
terminal capture, usage scanning, diff resolution, and context %
extraction in one response. Eliminates polling race conditions.
Design: follows DESIGN.md tokens throughout. Smart auto-scroll on
terminal (stays put if user scrolled up). Mobile layout with swipeable
tabs (<768px). Keyboard: Escape returns to factory floor.
Also fixes dispatch panel json.status bug (was checking json.status
instead of json.ok).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The default 30s grace period was too short — the implementer agent was being marked idle before it had time to read the codebase and start writing code, causing premature "no commit" failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Make stage cards keyboard-activatable (Enter/Space keydown handler) - Prevent overlapping focus polls from racing (focusPolling guard flag) - Check /up response status before marking as successful - Escape statRow values via escapeHtml to prevent innerHTML injection - Replace deprecated word-break: break-word with overflow-wrap: anywhere - Clamp lines query param to [1, 10000] before pane capture - Validate agent exists in workspace config before building focus data Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pre-populate agent name, status, and session from appState.agents on click instead of waiting for the first /focus poll. Reduces perceived latency from ~2s to near-instant. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
scan_workspace_usage() does expensive filesystem I/O (~11s on large projects). Move it to a separate slow poll (?usage=1, every 30s) so the main focus endpoint (terminal + diff + context) responds in ~35ms for instant terminal updates. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README: dashboard section updated from "Planned" to "Built" with Agent Focus Mode details, roadmap checkboxes updated - CHANGELOG: added Unreleased section with Phase 2 features - DESIGN.md: added Agent Focus Mode design specifications - Cargo.toml: bumped version to 0.6.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Documents the repeatable workflow from failed run to root cause: run inspection → step timeline → agent check → log analysis. Covers provider, policy, and tool failure patterns with concrete CLI examples. Links dashboard Focus Mode for visual debugging. Closes #79 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis pull request introduces Agent Focus Mode, a full-screen drill-down UI feature for the dashboard that displays live terminal output, token usage metrics, Git diffs, and context health percentages for individual agents. It includes a new consolidated API endpoint Changes
Sequence DiagramsequenceDiagram
participant Browser as Browser Client
participant Server as Dashboard Server
participant Tmux as Tmux Session
participant Git as Git Repository
participant Usage as Usage Tracker
Browser->>Browser: User clicks agent card
Browser->>Browser: Enter focus mode (hide factory, show focus view)
par Terminal & Diff Poll (2s interval)
loop Poll terminal
Browser->>Server: GET /v1/agents/{ws}/{agent}/focus?lines=100
Server->>Tmux: Capture pane output
Server->>Git: Read git diff HEAD
Server->>Server: Extract context %
Server-->>Browser: {terminal, diff, context}
Browser->>Browser: Render terminal (auto-scroll), diff
end
and Usage Stats Poll (30s interval)
loop Poll usage
Browser->>Server: GET /v1/agents/{ws}/{agent}/focus?usage=1
Server->>Usage: Query aggregated stats
Server-->>Browser: {tokens, cache_io}
Browser->>Browser: Update usage/stats display
end
end
Browser->>Server: User presses Escape
Browser->>Browser: Exit focus mode (stop polls, restore factory view)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
README.md (1)
502-512:⚠️ Potential issue | 🟡 MinorDuplicate roadmap entry for web dashboard.
Lines 502 and 512 both contain
[x] Web dashboard (factory floor + Agent Focus Mode). One of these entries should be removed.📝 Remove duplicate entry
Remove line 512:
- [x] SDLC automation framework (issue → implement → test → PR → review → merge) - [x] Published on crates.io (`cargo install tutti`) - [ ] Agent-to-agent message bus - [ ] Phrase registry (community prompts/skills) - [ ] Arrangement sharing (community team configs) -- [x] Web dashboard (factory floor + Agent Focus Mode)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 502 - 512, Remove the duplicate checklist entry "Web dashboard (factory floor + Agent Focus Mode)" — keep a single instance and delete the second occurrence so the README checklist contains only one "[x] Web dashboard (factory floor + Agent Focus Mode)" entry.
🧹 Nitpick comments (2)
dashboard/index.html (1)
50-50: Considerrole="region"instead ofrole="main"to avoid duplicate landmarks.When focus-view becomes visible, both it (
role="main") and<main id="factory">would be present as main landmarks, which can confuse screen reader navigation. Since the factory main is hidden when focus-view is shown, this may be acceptable, but usingrole="region"with anaria-labelwould be semantically cleaner.♿ Optional accessibility refinement
- <div id="focus-view" role="main" style="display:none"> + <div id="focus-view" role="region" aria-label="Agent focus view" style="display:none">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dashboard/index.html` at line 50, Change the landmark role on the focus view to avoid duplicate main landmarks: update the element with id "focus-view" to use role="region" (instead of role="main") and add an appropriate aria-label (e.g., aria-label="Focus view" or context-specific label) so screen readers can identify it; ensure the existing <main id="factory"> remains role="main" and that visibility toggling still controls which landmark is exposed.src/cli/serve.rs (1)
1115-1136: Add timeouts to git diff commands to prevent hanging requests.The
git diff HEADandgit diff HEAD --statcommands (lines 1115 and 1123) have no timeout. Since this endpoint is polled every 2 seconds by the dashboard, a hung git command would compound quickly. On large repositories or with network-attached storage, these operations can block indefinitely.The
wait-timeoutcrate (already in dependencies) can wrap the command execution. The pattern is established insrc/automation/mod.rsat line 2474 usingspawn()withwait_timeout()to handle timeouts gracefully.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/cli/serve.rs` around lines 1115 - 1136, The git diff and git diff --stat invocations must be converted to spawn + wait_timeout (like the pattern in automation::mod.rs) to avoid hanging: replace the .output() calls for the two std::process::Command::new("git").args([...]).current_dir(&worktree_path).output() chains with spawn(), call wait_timeout(Duration::from_secs(5)) (or another short timeout), capture stdout on success, and on timeout kill the process and treat the result as empty string (and log/warn); keep the subsequent parse_diff_stat(&stat) usage unchanged so (diff, fc, ins, del) semantics remain the same and ensure errors map to String::new()/0s instead of blocking.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dashboard/app.js`:
- Around line 637-640: The focus-mode entry code sets inline styles to hide
`#detail-drawer`, `#dispatch-panel`, and `#timeline` (e.g.,
document.getElementById("detail-drawer").style.display = "none") but never
clears them, so later toggles (selectAgent()/selectRun() using the .open class)
don't make the drawer visible; update the focus-mode exit/close path to restore
these elements by removing the inline display (set .style.display = "" or call
.removeProperty('display')) or explicitly set the correct display value so the
.open class can take effect; apply the same fix to the other occurrence that
mirrors lines 672-675.
- Around line 726-731: The header always shows "working" because renderFocusView
only checks data.running; change logic to prefer a specific runtime state field
(e.g., data.state or data.status) when present and fall back to data.running.
Update renderFocusView to read a canonical state (e.g., const state = data.state
|| data.status || (data.running ? "working" : "stopped")), map known values
("idle","blocked","auth-failed","running"/"working") to user-facing labels and
CSS classes, then set $focusStatus.textContent and $focusStatus.className from
that mapped state (leave the stopped fallback when neither state nor running
indicate active).
- Around line 626-629: The sendFocusPrompt function is vulnerable to re-entry
(Enter can trigger it while a request is in-flight); add a re-entry guard:
introduce or reuse a boolean flag (e.g., focusPolling or a new focusSending) and
at the start of sendFocusPrompt return immediately if the flag is true, set the
flag true before initiating the async POST to /v1/actions/send and clear it in a
finally block after the request completes or errors; apply the same pattern to
the analogous function referenced around lines 840-874 to prevent duplicate
non-idempotent submissions.
- Around line 699-723: The error branch and pollFocusUsage() only guard by agent
name, causing cross-workspace leaks; update both the fetch().catch handler (the
earlier reconnect catch that sets focusPolling = false and updates
$focusTerminal) and the early-return in pollFocusUsage() to verify both
workspace and agent match appState.focusAgent (compare fa.workspace and fa.agent
to appState.focusAgent.workspace and .agent) before updating UI so stale
responses for the same agent name from a different workspace are ignored.
- Around line 803-818: The progress pane is showing the first running run
globally; narrow it to the focused agent by only considering runs where
run.status === "running" AND run.steps[run.stepIndex] (or the active step) has
an agent that matches the current focus (e.g. appState.focusedAgent or
focusedAgent). Update the loop over appState.runs to skip runs whose active
step.agent !== appState.focusedAgent (and if workspace collisions are possible,
ensure the step stored at run.steps[idx] includes evt.workspace when created and
compare that too). Keep using statRow("workflow", run.workflowName),
statRow("step", ...), and statRow("started", ...) for the matched run and fall
back to the "No active run." message if none match.
---
Outside diff comments:
In `@README.md`:
- Around line 502-512: Remove the duplicate checklist entry "Web dashboard
(factory floor + Agent Focus Mode)" — keep a single instance and delete the
second occurrence so the README checklist contains only one "[x] Web dashboard
(factory floor + Agent Focus Mode)" entry.
---
Nitpick comments:
In `@dashboard/index.html`:
- Line 50: Change the landmark role on the focus view to avoid duplicate main
landmarks: update the element with id "focus-view" to use role="region" (instead
of role="main") and add an appropriate aria-label (e.g., aria-label="Focus view"
or context-specific label) so screen readers can identify it; ensure the
existing <main id="factory"> remains role="main" and that visibility toggling
still controls which landmark is exposed.
In `@src/cli/serve.rs`:
- Around line 1115-1136: The git diff and git diff --stat invocations must be
converted to spawn + wait_timeout (like the pattern in automation::mod.rs) to
avoid hanging: replace the .output() calls for the two
std::process::Command::new("git").args([...]).current_dir(&worktree_path).output()
chains with spawn(), call wait_timeout(Duration::from_secs(5)) (or another short
timeout), capture stdout on success, and on timeout kill the process and treat
the result as empty string (and log/warn); keep the subsequent
parse_diff_stat(&stat) usage unchanged so (diff, fc, ins, del) semantics remain
the same and ensure errors map to String::new()/0s instead of blocking.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 8c1a6747-b355-48cc-b759-d96911ddbbdb
📒 Files selected for processing (12)
CHANGELOG.mdCargo.tomlDESIGN.mdREADME.mddashboard/app.jsdashboard/index.htmldashboard/style.cssdashboard/test.htmldocs/OPERATOR_DEBUGGING.mdsrc/cli/serve.rssrc/cli/snapshot.rstutti.toml
Keep Phase 2a agent focus features (query param, agent validation, keyboard accessibility, focus polling guard, XSS escaping). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Versioning (required)
Cargo.tomlversionCHANGELOG.mdSemVer choice
Version selected:
v__________Validation
cargo test -qRelease
vX.Y.Z)Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores