You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Codev sidebar's Backlog needs an embedded text input that filters the rows live as the user types. The user wants the input to feel like a first-class part of the Backlog section — visually indistinguishable from VSCode's own SCM "CHANGES" pattern where the input sits inside the section, with items rendered directly below it in the same scrollable area.
#891 explored two lighter approaches and rejected both after visual review in the running worktree:
Shared search webview above Backlog + Builders — felt disconnected (two separate sections with their own headers).
Per-view search webview directly above each TreeView — also felt disconnected; the unavoidable section divider between the search webview and the TreeView below made them read as two peer widgets, not "one thing".
Option i: name: " " stealth-merge of the per-view webview — VSCode still reserves the section header bar (~22px) regardless of name, leaving a residual empty strip above the input. User verdict: "not good at all".
The fundamental constraint: VSCode's view contribution model makes every contributes.views entry a peer section with its own header and divider. You cannot place a webview's content inside another view's section. The only way to render [input → items] as a single visually-unified section is to make the entire section a webview — i.e., replace the Backlog TreeView with a WebviewView.
#891's in-flight branch (builder/pir-891) has the prep work — see "Carry forward" below.
Scope (Path B — full webview Backlog)
Convert
codev.backlog becomes a WebviewView (was: TreeView).
The webview renders:
Search input as the first element inside the section (matching VSCode's SCM CHANGES pattern)
Backlog rows rendered as HTML below the input, in the same scrollable area
All visually unified — one Backlog section, search input as its first child, items underneath
The BacklogProvider TreeView class is removed (or repurposed as a pure data projector — issue numbers + titles + areas → render model — with the webview doing all DOM work).
Visual fidelity (REQUIRED)
Theme integration via VSCode CSS variables. At minimum:
Codicons for row icons (load via `@vscode/codicons` package — matches what the TreeView renders today: `issues` / `account` icons).
Hover, focus, selection states matching native list styling pixel-for-pixel.
Live theme switching (dark/light) propagates without reload.
Behavioral parity (REQUIRED — do NOT drop)
Keyboard navigation: ↑ / ↓ / Home / End / PgUp / PgDn move selection through rows.
Enter on a selected row fires the row's primary click action (today: `codev.viewBacklogIssue`).
Right-click context menu — replicate today's Backlog row actions. Five actions:
Reference Issue in Architect (inline button on the row today)
View Issue
Spawn Builder
Open Issue in Browser
Copy Issue Number
Implementation: HTML/JS custom context menu (VSCode webviews can't contribute to `view/item/context`). Visually close to native.
ARIA roles for accessibility (`role='list'` / `role='listitem'`, or `role='treegrid'` if grouping by area is retained).
Group-by-area behavior preserved (alphabetical specific areas, then Uncategorized last). The `@cluesmith/codev-core/area-grouping` projection (`groupByArea`, `formatAreaForDisplay`) is shared with other views — reuse it for the render model.
Mine-first sort preserved within each group (current user's assigned items sort to top with the `account` codicon).
Group expand/collapse persistence — current behavior stores per-area expansion in `workspaceState` under `codev.backlogGroupExpansion`. New webview should preserve this (post-message to the extension on toggle, read back on reload).
`labels[]` (full label name list, including `area/*`)
`assignees[]`
`author`
Performance (REQUIRED)
Backlog can have hundreds of issues. Use virtual scrolling — only render visible rows + a small buffer. Don't render 500 DOM nodes upfront.
Either:
Add `lit-virtualizer` as a dependency (small, well-maintained), OR
Implement simple manual windowing (~80 LOC: track scrollTop, compute visible range, render that range, pad above/below with sentinel divs)
The previous design preference was zero new dependencies. Manual windowing is the path-of-least-resistance.
Validate performance with a 500-row fixture before signaling ready.
Carry forward from #891's branch (`builder/pir-891`)
The in-flight #891 branch has prep work that should land with this PR:
Wire-format change (commit `5538edfa`): `labels: string[]` added to `OverviewBacklogItem` and `OverviewBuilder` in `packages/types/src/api.ts` and populated in `packages/codev/src/agent-farm/servers/overview.ts`. The new webview's filter scope needs this.
Labels-iteration defensive guard (commit `527c8f59`): `Array.isArray(labels) ? labels : []` pattern guards against stale-Tower wire payloads. The new webview's row-render path that iterates `item.labels` must apply the same guard.
The `BacklogSearchViewProvider` separate webview — its filter logic ports into the new combined webview, but the standalone view goes away.
The `SearchState` class — filter state becomes local to the new webview component (transient `useState`-style; the extension host doesn't need to know).
The `codev.toggleBacklogSearch` command — replaced by clicking the input or using the title-bar focus shortcut.
The `codev.backlogSearch` view contribution in package.json.
The labels-iteration guard pattern (apply at the new iteration site).
The placeholder copy `"Search backlog..."`.
#891 itself should be closed without merge (the per-view-webview implementation it shipped is being replaced by this issue). The architect decides whether to rebase #891's prep commits onto this issue's branch or cherry-pick them fresh.
Search across other Codev views (Pull Requests, Recently Closed, Team) — separate concern.
Search history / saved searches / multi-criteria advanced search — over-engineering for v1.
Persisting the filter query across sessions — filter is transient; cleared on workspace reload.
Match modes (case-sensitive / whole-word / regex) — plain substring only for v1. Can add later without changing public surface.
Acceptance criteria
Backlog renders as a single unified section: search input first, items below, in the same scrollable area.
Search filters items live as the user types (debounced ~150ms).
All today's Backlog row actions still work: View Issue (click), Reference Issue in Architect (inline button), Spawn Builder (right-click), Open in Browser (right-click), Copy Issue Number (right-click).
Keyboard navigation works: ↑/↓ at minimum; Home/End/PgUp/PgDn ideally; Enter fires View Issue.
Performance acceptable with 500+ rows (smooth scroll, no jank, virtual rendering).
Theme variables in use; switching dark/light updates colors live.
Group-by-area preserved with expand/collapse persistence in `workspaceState`.
Mine-first sort preserved within groups.
No regression: Builders view is unchanged (no search section, no buildersSearch view, no toggle icon).
Labels-iteration defensively guarded (`Array.isArray(...) ? ... : []`) at every iteration site.
Tests pass (DOM logic should be unit-testable via jsdom or vitest's happy-dom).
Suggested protocol
This is a UX-heavy webview rewrite — visual verification in the running extension is the only way to know it's right. The architect's earlier estimate was ~30-40 hours of careful CSS+JS work.
PIR (Plan → Implement → Review) gives the human reviewer the `dev-approval` gate where they can run the worktree and visually confirm. That gate is the right surface for "does this actually look and feel native?". The previous attempt (#891) iterated multiple times at this gate, which is what the gate is for.
SPIR if the architect prefers a fuller spec/plan/review ceremony with consult at every phase. The webview component design (virtual scrolling algorithm, context-menu structure, message protocol) might warrant a spec.
Architect decides; this issue is the WHAT, not the HOW.
PIR #891 dev-approval review on 2026-05-28: tried three lighter approaches (shared webview, per-view webviews, `name: " "` stealth-merge) and visually verified all three felt disconnected. Full WebviewView is the only path to genuine visual unification with VSCode's view contribution model.
Problem
The Codev sidebar's Backlog needs an embedded text input that filters the rows live as the user types. The user wants the input to feel like a first-class part of the Backlog section — visually indistinguishable from VSCode's own SCM "CHANGES" pattern where the input sits inside the section, with items rendered directly below it in the same scrollable area.
Why not the per-view-webview approach (#891)
#891 explored two lighter approaches and rejected both after visual review in the running worktree:
name: " "stealth-merge of the per-view webview — VSCode still reserves the section header bar (~22px) regardless ofname, leaving a residual empty strip above the input. User verdict: "not good at all".The fundamental constraint: VSCode's view contribution model makes every
contributes.viewsentry a peer section with its own header and divider. You cannot place a webview's content inside another view's section. The only way to render[input → items]as a single visually-unified section is to make the entire section a webview — i.e., replace the Backlog TreeView with a WebviewView.#891's in-flight branch (
builder/pir-891) has the prep work — see "Carry forward" below.Scope (Path B — full webview Backlog)
Convert
codev.backlogbecomes aWebviewView(was:TreeView).BacklogProviderTreeView class is removed (or repurposed as a pure data projector — issue numbers + titles + areas → render model — with the webview doing all DOM work).Visual fidelity (REQUIRED)
Behavioral parity (REQUIRED — do NOT drop)
Keyboard navigation: ↑ / ↓ / Home / End / PgUp / PgDn move selection through rows.
Enter on a selected row fires the row's primary click action (today: `codev.viewBacklogIssue`).
Right-click context menu — replicate today's Backlog row actions. Five actions:
Implementation: HTML/JS custom context menu (VSCode webviews can't contribute to `view/item/context`). Visually close to native.
ARIA roles for accessibility (`role='list'` / `role='listitem'`, or `role='treegrid'` if grouping by area is retained).
Group-by-area behavior preserved (alphabetical specific areas, then Uncategorized last). The `@cluesmith/codev-core/area-grouping` projection (`groupByArea`, `formatAreaForDisplay`) is shared with other views — reuse it for the render model.
Mine-first sort preserved within each group (current user's assigned items sort to top with the `account` codicon).
Group expand/collapse persistence — current behavior stores per-area expansion in `workspaceState` under `codev.backlogGroupExpansion`. New webview should preserve this (post-message to the extension on toggle, read back on reload).
Filter scope (per the #891 design discussion)
Case-insensitive substring match across:
Performance (REQUIRED)
Carry forward from #891's branch (`builder/pir-891`)
The in-flight #891 branch has prep work that should land with this PR:
What to drop from the #891 branch:
What to keep from the #891 branch:
#891 itself should be closed without merge (the per-view-webview implementation it shipped is being replaced by this issue). The architect decides whether to rebase #891's prep commits onto this issue's branch or cherry-pick them fresh.
Out of scope
Acceptance criteria
Suggested protocol
This is a UX-heavy webview rewrite — visual verification in the running extension is the only way to know it's right. The architect's earlier estimate was ~30-40 hours of careful CSS+JS work.
PIR (Plan → Implement → Review) gives the human reviewer the `dev-approval` gate where they can run the worktree and visually confirm. That gate is the right surface for "does this actually look and feel native?". The previous attempt (#891) iterated multiple times at this gate, which is what the gate is for.
SPIR if the architect prefers a fuller spec/plan/review ceremony with consult at every phase. The webview component design (virtual scrolling algorithm, context-menu structure, message protocol) might warrant a spec.
Architect decides; this issue is the WHAT, not the HOW.
Related
Discovered while
PIR #891 dev-approval review on 2026-05-28: tried three lighter approaches (shared webview, per-view webviews, `name: " "` stealth-merge) and visually verified all three felt disconnected. Full WebviewView is the only path to genuine visual unification with VSCode's view contribution model.