Skip to content

feat(coding-agent): agents-view usage columns, section legend, empty-session sort, zebra striping - #2056

Merged
xeophon merged 10 commits into
mainfrom
feat/agents-view-usage-legend-zebra
Sep 5, 2026
Merged

feat(coding-agent): agents-view usage columns, section legend, empty-session sort, zebra striping#2056
xeophon merged 10 commits into
mainfrom
feat/agents-view-usage-legend-zebra

Conversation

@snimu

@snimu snimu commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Fixes RES-1277

Purpose

Make agents-view rows scannable at fleet scale: every session shows the same aligned usage columns (↑in ↓out · $agent · #sub · $total · age) under a bold per-section legend that shares the exact column layout with the rows, and empty sessions stop crowding the top of their section (except the one the view was entered from).

Changes

  1. Usage row format: ↑in ↓out · $agent · #sub · $total · age per row, replacing ↑in ↓out · $agent ($total w/ subagents) · age. #sub is the TOTAL descendant count (resident + passive) from the same unfiltered enumeration that computes the recursive cost (computeRecursiveCosts -> computeRecursiveRollups), shown as an explicit 0. The rollup walk follows agent lineage only: branched/forked sessions (parentSession with the source's rlmDepth) no longer count as descendants or double-book their copied-transcript cost. Empty sessions (no messages) render no usage segment at all but keep the age, aligned to the age column. Empty detection reuses the scan's message-count rule (messageCount === 0); TODO(unify: #2055) marks it for the shared user-content rule.
  2. Section legend + shared layout: every section header (Running (n) / Idle (n) / Inactive (n)) carries the legend right-aligned in the header line, bold like the title — including the search-empty header (dropped when the terminal is too narrow). Legend and rows render through ONE shared column layout per section: column width = max(widest row value in that section, label width), everything right-aligned, so the · separators land in the same terminal column for the legend and every row. Widths are per section (an expensive row widens only its own section); empty sections show the legend at natural label widths.
  3. Empty-session sort: empty sessions sort last within their section, except the session the view was entered from (anchor = backSession/initialSession session id, not the selected row), which keeps its normal recency position.
  4. Viewport fix (review finding, pre-existing on main): the leading ellipsis consumed a viewport line without shifting the content window, so a selection at the very end of the list was sliced out of view.

Zebra striping was implemented, then removed at user request (conflicts visually with the selection highlight); commits f63590b/c67649271 and the review threads preserve the adaptive-contrast approach if it is ever revived (removed in 9b5c4a2).

Screenshot

BEFORE:

image

AFTER:

image

Tests

  • computeRecursiveRollups pins descendant counting through the passive/saved walk (parent keeps count when a child survives only as a catalog row) and pins that branched-session lineage never inflates #sub/$total while a spawned child counts.
  • Formatter pin: shared per-section columns with explicit 0, separator-column equality between legend and every row of a section (fails without the shared layout), and the empty-session age-only cell (merged into the existing usage-cell test); 502 regression regex updated to the new format.
  • Sort pin: entered-from empty session keeps its recency slot; other empty sessions sink below non-empty rows (fails without the anchor exemption).
  • Legend pin: bold legend present on all three section headers; session rows emit no background codes of their own.
  • Viewport pin: selection on the last row stays visible when the leading ellipsis is shown.

LOC

Total src: +212/-36 (net +176); tests: +221/-16 (net +205).

Validation

  • npm run check green per commit (pre-commit hook: biome, tsgo, installer, browser smoke).
  • Targeted local vitest green: agents-view-state, agents-view-mode, agents-view-roster, agents-view-missing-cwd, agents-view-inactive-reply, session-view-search, subagent-summary-line, ipython-cell-diff, theme-adaptive, theme-export, 502-unified-session-view.
  • Sandbox full suite (node:24, --exclude test/daemon-supervisor-process.test.ts): 14 failed files / 82 failed tests, exactly the documented environmental baseline set (extensions-, kernel--skill bridges, tools EACCES-as-root, config, resource-loader, sdk-session-manager, agent-session-recursion, 4428, 4603) — no new failures.

Note

Medium Risk
Changes recursive cost/descendant rollup and parent-child classification (fork vs subagent), which affects displayed totals and hierarchy; UI-only but easy to misread if lineage edge cases remain.

Overview
Agents view session rows now use a shared, right-aligned usage strip (↑in ↓out · $agent · #sub · $total · age) instead of the old parenthetical “w/ subagents” string. buildAgentsViewUsageLayout computes one column width per section so section headers and every row line up; headers show Running|Idle|Inactive (n) plus a bold legend on the same grid (dropped when the terminal is too narrow). Empty sessions (messageCount === 0) show age only in that grid; everyone else gets the full strip with an explicit #sub.

Rollups and tree shape: computeRecursiveCosts becomes computeRecursiveRollups, adding descendantCount for #sub while keeping filter-independent totals. Branched/forked sessions (same **rlmDepth as parent) no longer nest, count as descendants, or inflate $total. anchorSessionId (session you opened agents view from) keeps empty chats in normal sort order; other empty sessions sort to the bottom of their section.

Viewport: when a leading ... ellipsis is shown, the visible slice shifts so a selection on the last row is not clipped off-screen.

Reviewed by Cursor Bugbot for commit 4831d2b. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add aligned usage columns, section legends, and empty-session ordering to agents-view

  • Section headings now show session counts and right-aligned usage legends; usage rows share per-section column positions for input, output, agent-cost, subagent-count, total-cost, and age
  • Recursive cost calculation replaced with recursive rollups returning both total cost and descendant count; branched same-depth sessions are excluded from a parent's descendant lineage
  • Empty sessions (zero messages) sort below non-empty rows within their section, except for the anchor session used to enter the view
  • Empty sessions render only their age field; visible-item slicing accounts for a leading ellipsis so a selected final row stays in the viewport
  • Risk: computeRecursiveCost export removed from index.ts; callers must use computeRecursiveRollups instead

Macroscope summarized 4831d2b.

Optional background token for alternate agents-view rows. Unset or empty
disables striping, so existing custom themes stay valid; built-in themes
get subtle values.
…session sort, zebra rows

- Row details become aligned columns: in/out tokens, own cost, total
  descendant count (explicit 0), recursive total, age. Empty sessions
  (no messages) keep only the age.
- Descendant counts roll up through the same unfiltered enumeration as
  recursive costs (computeRecursiveCosts -> computeRecursiveRollups),
  so passive/saved children are counted for inactive sessions too.
- Every section header shows its row count and a bold right-aligned
  usage legend.
- Empty sessions sort last within their section, except the session the
  view was entered from, which keeps its recency slot.
- Session rows zebra-stripe per top-level block, restarting at each
  section header; selection highlight takes precedence and the stripe
  uses the optional agentsZebraBg theme color.
Comment thread packages/coding-agent/src/modes/agents-view/agents-view-mode.ts
…gents-view legend and rows

Column width = max(widest row value in the section, legend label width);
legend labels and row values are all right-aligned into those columns, so
the ' . ' separators land in the same terminal column for the legend and
every row. Widths are per section, so an expensive row widens only its own
section, and empty sections show the legend at natural label widths.
…e of the real terminal background

A theme stripe darker than the actual terminal background (or too close to
it) rendered as black bands. When the terminal background is known, keep
the configured stripe only if it sits on the contrast side with a minimal
delta; otherwise re-derive a subtle stripe from the terminal background,
like the popup surfaces do.
…ading ellipsis

The prepended ellipsis consumed a viewport line without shifting the
content window, so a selection at the very end of the agents list was
sliced out of view. Pre-existing on main; surfaced by review on #2056.
…ssion lineage

Branch/fork headers point parentSession at the source while keeping the
source's rlmDepth, so the rollup walk counted a branched chat as a
descendant and double-booked its copied-transcript cost. Count a child
only when it is a subagent by runtimeKind (resident) or deeper rlmDepth
(saved).
…alue

Quantization can collapse the configured stripe onto the terminal
background's own palette cell (e.g. #202020 and #1c1c1c both map to
cell 234), so the keep/re-derive decision now uses the rendered
bestAnsiColor value like the selection color path does.
The stripe conflicts visually with the selection highlight. Removes the
zebra rendering, the agentsZebraBg theme token, and the adaptive-stripe
contrast logic with its pins; history and the PR discussion preserve the
adaptive-contrast approach if striping is ever revived. Columns, legend,
sort anchor, and viewport fixes stay.
@snimu

snimu commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Fresh-eyes review follow-ups:

  • #sub counted branch lineage: real — branch/fork headers set parentSession to the source while keeping the source's rlmDepth, so the rollup walk counted a branched chat as a descendant and double-booked its copied-transcript cost. Fixed in 4f3a20d: the walk now rolls up a child only when it is a subagent by runtimeKind (resident) or deeper rlmDepth (saved). Pinned: branched session leaves the source at #sub 0 and its cost out of $total; a spawned child counts as 1.
  • Zebra stripe vs 256-color quantization: was real (fixed in c676492 by judging the rendered bestAnsiColor value), but moot as of 9b5c4a2 — the zebra striping was removed entirely at user request because it conflicts visually with the selection highlight. History preserves the adaptive-contrast approach if striping is ever revived.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 42ee2eb. Configure here.

Comment thread packages/coding-agent/src/modes/agents-view/agents-view-state.ts
…in the agents view

The rollup walk already excluded branch/fork lineage from #sub and $total,
but the tree still nested any saved child with parentSessionPath and the
expander counted it, so a source could show '1 subagent' next to #sub 0.
The nesting decision now shares the rollup's subagent-lineage predicate: a
branched/forked session renders as its own top-level row, matching how the
daemon reports resident forks (runtimeKind top-level).
@snimu
snimu requested a review from xeophon September 5, 2026 18:41
@xeophon
xeophon merged commit 3675112 into main Sep 5, 2026
23 checks passed
@xeophon
xeophon deleted the feat/agents-view-usage-legend-zebra branch September 5, 2026 18:44
snimu added a commit that referenced this pull request Sep 7, 2026
Brings back the #2056 row format that #2087's consolidation replaced:
per-row 'in/out tokens · own cost · descendant count · recursive total ·
age' with one shared column layout per section (column width = max of the
widest section value and the legend label, all right-aligned) and the
bold usage legend right-aligned on every section header. The redesign's
other features stay: the Model column (compact ids) sits between the
session title and the usage cell, Activity still shrinks first at narrow
widths, expandable child sessions, the running-subagents line, and the
actions panel are untouched. Usage cells right-align to the terminal
edge, so age columns line up across sections even when a wide row widens
only its own section. Fixes RES-1317.
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.

2 participants