Skip to content

feat(cli-mode): make CLI/tmux agent 'working right now' legible in web UI (animated, is_running-driven)#44

Merged
miguelrisero merged 4 commits into
mainfrom
chief/bc-cli-working-indicator
Jul 23, 2026
Merged

feat(cli-mode): make CLI/tmux agent 'working right now' legible in web UI (animated, is_running-driven)#44
miguelrisero merged 4 commits into
mainfrom
chief/bc-cli-working-indicator

Conversation

@miguelrisero

Copy link
Copy Markdown
Owner

Problem

In web ("UIX"/CLI) mode, when a CLI/tmux-driven claude agent is actively working, the UI didn't make it legible — the in-view indicator was a static, mislabeled CircleIcon dot reading "CLI session active". It read like a passive presence LED, not "the agent is working right now". (Owner: "you don't know when the agent is doing/processing. that's not good.")

Approach — reuse the existing live signal, animate the render

The live signal already exists end-to-end and needed no backend/schema change: the cli_activity poller sets state='running' when the tmux claude pane emits output within a 5s window (ACTIVE_WINDOW_SECS, crates/local-deployment/src/cli_activity.rs) → SQL is_running (crates/db/src/models/workspace.rs) → the frontend already computes cliSessionActive = isRunning && !isExecutorRunning (WorkspacesLayout.tsx), which flips false ~5s after output stops. This PR only fixes the rendering inside that already-correct gate.

What changed (frontend-only, additive)

  1. Sidebar overlay badge (ConversationListContainer.tsx): static CircleIcon → animated <RunningDots/> (the app's canonical "running" animation, same component the sidebar WorkspaceSummary uses), copy → new conversation.cliAgentWorking ("Agent working…"). The {cliSessionActive && …} gate is unchanged, so it animates only while producing output and vanishes within ~5s of silence.
  2. CliMainPane mirror (CliMainPane.tsx + both WorkspacesLayout.tsx call sites): new cliRunning={cliSessionActive} prop drives a compact header chip — a spinning CircleNotchIcon + cliMode.working ("Working…") when running, a quiet dot + cliMode.idle ("Idle") otherwise. Gated on sessionsReady && !executorRunning so it never hides the live terminal nor contradicts the executor full-screen notice. Label is icon-only on mobile.
  3. i18n: added conversation.cliAgentWorking, cliMode.working, cliMode.idle and removed the now-superseded conversation.cliSessionActive across all 7 locales (en/es/fr/ja/ko/zh-Hans/zh-Hant).

The one correctness point

The animation is driven by the live is_running flip (off ~5s after output stops), not by "a CLI session exists" — an always-pulsing indicator would be as useless as the old static dot. The {cliSessionActive && …} gate and cliRunning={cliSessionActive} derivation preserve this. Proven live (see below): both the ON and the OFF transition.

Deliberate design calls

  • CircleNotch (not RunningDots) on the main pane: matches the file's existing executor-notice spinner and the brief's "extend the CircleNotch spinner" — each pane keeps its established language.
  • RunningDots reused verbatim as the canonical running animation; a motion-reduce:animate-none guard was added to it (it was previously missing across all ~6 of its usages) so reduced-motion users are respected — meaning is also carried by the role="status" text label.
  • Main-pane chip is visual-only (aria-hidden): the canonical announced status is the sidebar <Badge role="status"> (announces once, unmounts on idle — no chatter); the chip is a redundant visual mirror, so marking it aria-hidden avoids screen-reader chatter on every flip and an empty live-region on mobile. (From the review gauntlet.)

STRETCH — not done (intentional)

The optional "derive an actively-emitting boolean from patch-arrival cadence in the stream hooks" was skipped: it's more than a small addition (new state/timers + plumbing in useJsonPatchWsStream/useSessionNativeFeed), so per the brief it's left to the design doc rather than gold-plated here.

Verification

Static (all green): tsc (web-core/ui/local-web/remote-web) · eslint (max-warnings 0) · check-i18n.sh (dup-keys + cross-locale parity + literal-strings) · unused-i18n-key checker · vitest (224 passed) · CI-exact cargo clippy --workspace --all-targets --exclude vibe-kanban-tauri -- -D warnings · cargo test --workspace.

Caveat: frontend *.test.ts are excluded from the CI tsconfig; vitest was run manually via npx.

Live e2e on a scratch dev stack (decisive — both transitions proven on-screen): drove a real CLI/tmux claude agent and captured, for both surfaces:

  • Sidebar badge — "••• Agent working…" (animated RunningDots) while claude produced output → badge gone once idle (the separate "Unassigned CLI" badge correctly persisted, confirming the working badge tracks is_running, not session-existence).
  • CliMainPane chip — "◐ Working…" (spinner) while working → "● Idle" within ~5s of output stopping.

Review gauntlet (proportional to a ~79-line additive change)

  • CodeRabbit CLI unusable on this fork → replaced by a lane-owned read-only Codex sweep (gpt-5.6-sol).
  • Deep-review: 2 independent finders (correctness/React/imports + a11y/mobile/reduced-motion/conventions). No blockers; correctness invariant held; the a11y findings above were applied.
  • Council (frontend-systems + mobile/touch-UX personas): realized via the model-diverse review trio (Codex + 2 Claude finders spanning those angles) rather than the standalone multi-engine skill — disproportionate after 3 reviews on this diff.
  • /simplify: covered by the review consensus (dead min-w-0 removed; CircleNotch-vs-RunningDots is a deliberate keep).

Risk: LOW (additive UI, no schema, no dispatch paths). Opened as DRAFT for boss verification. Note: shares ConversationListContainer.tsx region-wise and the 7 common.json files with concurrent Lane M — kept to distinct i18n keys; rebase onto M then re-verify before flipping to ready.

@miguelrisero
miguelrisero marked this pull request as ready for review July 23, 2026 12:47
@miguelrisero
miguelrisero merged commit f02232e into main Jul 23, 2026
7 checks passed
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