feat(vscode): builder diffs, terminal image paste, backlog & Builders-tree UX#771
Merged
Conversation
PIR's protocol.json declares verify.models [gemini, codex] (CMAP-2), but the shipped DEFAULT_CONFIG porch.consultation.models [gemini, codex, claude] always wins over a protocol's verify.models: loadConfig seeds every config from DEFAULT_CONFIG before merging, so config.porch.consultation.models is never undefined and the resolver's '=== undefined -> protocol fallback' branch is unreachable. Every PIR run is therefore 3-way, silently contradicting the protocol's own CMAP-2 prose and its '## Consultation Footprint' invariant. This change does NOT fix that resolver/config precedence bug (a system-wide change, deliberately out of scope here). It only aligns PIR's docs + prompts with the behavior that actually ships: - CMAP-2 / 'CMAP' wording -> 3-way consultation (Gemini, Codex, Claude) in protocol.json, protocol.md, builder-prompt.md, prompts/implement.md, prompts/review.md, consult-types/pr-review.md - review.md architect-notification snippet now also captures and reports the claude verdict alongside gemini/codex - removed the misleading 'leave porch.consultation.models unset to keep CMAP-2' paragraph — that mitigation never worked given the above verify.models is left [gemini, codex] (inert due to the precedence bug); not changed to 3 models here to avoid widening scope into the config-resolver territory left untouched on purpose. Applied to both codev-skeleton/ (shipped to consumers) and codev/ (this repo's instance) so the two stay in lockstep. No behavioral/code change.
Adds a codev.viewDiff command + right-click action that opens a builder worktree's delta vs the default branch in the Multi Diff Editor. The previously-removed review-diff.ts failed because it resolved base content through git:-scheme URIs, which VSCode's built-in Git extension can't serve for a worktree hidden in the host repo's .gitignore'd .builders/ dir. This backs the base side with our own read-only codev-diff: TextDocumentContentProvider (running git -C <worktree> directly), so resolution no longer depends on Git-extension worktree discovery. The right side is a plain file: URI; base content is keyed by the immutable merge-base SHA. Handles A/M/D/R/C and binary files. Coexists with Open Worktree in New Window. Pure parsing/URI logic is factored out and unit-tested (16 tests in view-diff.test.ts).
Codev terminals are Pseudoterminal-backed, so VSCode's image-paste bridge never fires — an image-only clipboard is dropped before the extension sees it (text-only handleInput). This was the last terminal feature gap vs the web dashboard. Cmd/Ctrl+V in a focused Codev terminal now reads the clipboard image per-OS, POSTs it to Tower's workspace-scoped paste-image endpoint, and injects the returned path into the PTY. Every non-image path (no image, clipboard tool missing, read error, Tower down, non-Codev terminal) delegates to VSCode's built-in workbench.action.terminal.paste, so text / bracketed paste cannot regress by construction. - core: TowerClient.pasteImage(workspacePath, bytes, mime) — posts to /workspace/<enc>/api/paste-image (the handler is workspace-scoped; a global /api/paste-image has no route). Direct fetch (request<T>() forces application/json); ArrayBuffer body for cross-lib BodyInit. - clipboard-image.ts: macOS osascript (no brew dep), Linux wl-paste / xclip (Wayland vs X11 via WAYLAND_DISPLAY), Windows PowerShell; ENOENT->tool-missing, clean+empty->no-image; injectable for tests. - terminal-adapter: writeNotice() renderer-only status line. - terminal-manager: getActiveManagedPty()/isCodevTerminalActive(). - extension: codev.pasteImage command + onDidChangeActiveTerminal -> codev.terminalFocused context key (scopes the Cmd+V rebind so it never shadows paste outside a focused Codev terminal). - failure notice surfaces the reason ([Image upload failed: <reason>]). - 9 unit tests for the clipboard-image seam (30 passing total).
Each builder row in the Builders tree is now expandable to a second-level list of its changed files vs the default branch; clicking a file opens its 2-way diff (codev-diff base <-> worktree file). The existing multi-file View Diff command is unchanged. view-diff.ts is refactored to share its engine: the inline git sequence becomes exported getBuilderChanges(); a diffUrisForChange() seam wraps the URI builders. Both the command and the tree use them — no behavior change to the command. BuilderDiffCache (15s TTL, keyed by builder id) guards against running git on every overview/SSE tick: VSCode re-queries an expanded node's children on each refresh, so the TTL caps git to ~1 spawn / 15s per expanded builder; collapsed builders never call getChildren. Adds BuilderFileTreeItem (status-colored diff icons, row-click -> codev.openBuilderFileDiff) and placeholder rows for no-worktree / git-error / no-changes. 50 unit tests pass (+4 diffUrisForChange).
Replace the diff-* codicons with VSCode's native Source Control look: the file-type icon (from resourceUri) plus a colored one-letter status badge and tinted label, via a FileDecorationProvider — the same API the built-in Git decorator uses (it can't see the gitignored .builders/ worktrees, so we supply our own). BuilderDiffCache now also owns a global fsPath->status registry with per-builder path tracking and an onDidChangeDecorations(Uri[]) event, so decorations refresh in lockstep with the file list under the same 15s TTL. One shared cache instance is injected into both BuildersProvider and BuilderFileDecorationProvider from extension.ts. Letter/color mapping mirrors the Git extension (A/M/D/R/C/T/U) and uses gitDecoration.* theme tokens so the user's theme drives exact colors. 50 unit tests still pass; type-check + lint clean.
Replace the 'play' icon (reads as a press-to-start button) with 'circle-filled' in green — the running-process/live-status idiom — so an active builder looks like it's working, not awaiting a click. Blocked rows keep the amber bell. Distinct from Backlog's issues/account icons.
The extension Backlog listed every issue Tower puts in data.backlog, including ones that already have an active builder — clicking one would spawn a second builder for the same issue. The web dashboard already hides these (BacklogList.tsx: items.filter(i => !i.hasBuilder)); the extension ignored the server-computed OverviewBacklogItem.hasBuilder. Add a single-sourced spawnableBacklog(items) => items.filter(!hasBuilder) in views/backlog.ts, applied in BacklogProvider.getChildren() before the existing assignee (mine/rest) ordering, and reused for the 'Backlog (N)' title count in extension.ts so the count can't desync from the visible rows (the count is computed at a separate call site). View-layer only — no core/types/Tower change; hasBuilder already ships in the overview payload. Filter behaviour now matches the web dashboard exactly (the extension keeps its own assignee-first ordering + count badge). 4 unit tests for spawnableBacklog (54 passing total).
Expanding one builder auto-collapses the others so a reviewer can't have diffs from unrelated worktrees open at once. On a builder expand, run the built-in collapseAll then reveal(expand:true) on that builder; guarded by an openBuilderId idempotency check (reveal re-fires the expand event regardless of timing) plus a reconciling debounce. Builder rows now set a stable TreeItem.id = builderId — also fixes a latent bug where label churn (wait-time/phase) regenerated the id every overview poll and reset the user's expansion. getParent() added (reveal requirement). Behavior is gated on a persisted setting codev.buildersAutoCollapse (default true), toggled from a Builders header button whose icon/tooltip reflect state (fold = on, unfold = off), the Command Palette, or Settings. 54 unit tests green; type-check + lint clean.
Rebinding Cmd+V to the image-paste command corrupted normal multi-line text paste in Codev terminals: every paste took an async detour (readClipboardImage spawns a subprocess) then re-dispatched workbench.action.terminal.paste, which races VSCode's atomic paste handling for a Pseudoterminal (the [Pasted text #N] chip interleaved with raw characters). Codev terminals are Pseudoterminal-backed, so VSCode's native text paste is correct on its own — the regression was self-inflicted by intercepting Cmd+V. Move image paste to a dedicated shortcut and stop touching Cmd+V: - keybinding: codev.pasteImage -> Cmd+Alt+V (mac) / Ctrl+Alt+V (Win/ Linux), consistent with the Cmd/Ctrl+Alt+<letter> Codev family; Ctrl+Shift+V deliberately avoided (native terminal-paste chord on Win/Linux). Cmd+V is no longer bound by the extension at all. - paste-image.ts: image-only. Removed builtinPaste() and every workbench.action.terminal.paste re-dispatch (the race source). No image / tool missing / read error / Tower down -> a toast; text paste is never our concern now. Text paste is now 100% native VSCode Pseudoterminal paste (incl. bracketed multi-line) by construction. Image upload + path injection unchanged (web-parity). 54 tests passing.
…ycle Covers every extension-facing change on the branch: per-builder changed-files (expandable rows + SCM-style decorations), Codev: View Diff, accordion mode for the Builders tree, live-status dot for active builders, image paste via Cmd+Alt+V, and the Backlog hiding builder-active issues. Written in the existing developer-facing voice. PIR protocol-docs reconciliation is intentionally excluded (not an extension change). Internal parallel-development provenance is omitted — the changelog documents user-facing effects, not process.
waleedkadous
approved these changes
May 19, 2026
waleedkadous
added a commit
that referenced
this pull request
May 19, 2026
Bugfix release fixing the multi-architect routing regression (#774) that broke sibling-architect affinity end-to-end since v3.0.5: detectCurrentBuilderId opened the empty worktree-local state.db via the singleton getDb(), causing the canonical builder ID lookup to miss and the sender ID to drop the 'builder-' prefix. Downstream lookupBuilderSpawningArchitect then bypassed the affinity branch and routed every builder->architect message to main, regardless of which sibling spawned the builder. The fix in detectCurrentBuilderId opens the workspace's state.db readonly directly, mirroring the per-workspace-handle pattern in state.ts:380. End-to-end verified before tagging: ob-refine-spawned builder's message landed on ob-refine's terminal, not main's. Also includes Amr's VSCode extension round (#771): per-builder file trees, View Diff command, accordion mode for the Builders tree, image paste into Codev terminals, Backlog dedup for issues with active builders.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integration branch aggregating several independently-developed feature commits for the VS Code extension, plus one protocol-docs reconcile. Reviewed best per-commit (do not squash — keep the individual commits).
VS Code extension
gitDecoration.*), since the built-in Git decorator can't see the gitignored.builders/worktrees. 15s git throttle per expanded builder. (55912a40,7b06bf0d)codev-diff:provider (git -C <worktree>). Handles A/M/D/R/C + binary. (3b253ecc)codev.buildersAutoCollapsesetting (default on) + title-bar toggle. Stable row ids fix expansion resetting each overview poll. (4c5fbda2)playicon; blocked keeps the amber bell. (50aac68f)Cmd+Alt+V/Ctrl+Alt+Vin a focused Codev terminal uploads a clipboard image to Tower and injects the saved path (web-/built-in-terminal parity). Codev terminals arePseudoterminal-backed so VSCode's image bridge never fires; this reimplements it (per-OS clipboard read). Initially bound to Cmd+V (822385d5); that corrupted native multi-line text paste, so it was moved to a dedicated chord and Cmd+V left fully native (0d37fae5).hasBuilderis machine-local. (78165263)[Unreleased]documents the above in the user-facing voice. (3a1d9e30)Preview
Protocol docs (out-of-theme, included on the branch)
docs(pir): reconcile PIR protocol/prompts with the 3-way consultation that actually ships (theDEFAULT_CONFIGprecedence makes PIR run 3-way despite its CMAP-2 prose). Docs-only; the resolver/config bug is deliberately left out of scope. (78c50e28)Verification
tsc+ eslint + esbuild clean; 54 unit tests passing (clipboard-image, backlog, view-diff seams, etc.).Closes #736