feat(vscode): idle-waiting builders, sidebar polish, and PIR default-branch fix (#777 Layer 2)#779
Merged
Merged
Conversation
Promote the existing Unreleased entries (image paste via Cmd+Alt+V, per-builder changed-files with SCM-style decorations, Codev: View Diff, accordion mode for the Builders tree, live-status dot for active builders, Backlog hiding builder-active issues) to a versioned section so the published CHANGELOG carries a clean per-version history. package.json already declares 3.0.7; no version bump needed. Dropped the empty Unreleased scaffold so a dangling header doesn't ship in the production changelog.
Previously `vscode:publish` ran `vsce publish` only — easy to silently skip Open VSX by using the wrong entry point and drift the two registries apart. The dual-registry shell script that packages once and uploads to both lived at the repo root as a separate entry point. Wire `vscode:publish[:pre]` to invoke the shell script directly so the npm command is the single canonical publish path, and move the script inside the package to drop the `../../` traversal. - Move `scripts/publish-vscode.sh` -> `packages/vscode/scripts/publish.sh` (rename preserves history + executable bit; `-vscode` suffix dropped as redundant inside the package). cwd resolution simplified to `$SCRIPT_DIR/..` — direct invocation still works from any cwd. - `packages/vscode/package.json`: `vscode:publish` / `vscode:publish:pre` now run `sh scripts/publish.sh [--pre-release]`. - Final log line echoes both listing URLs (VS Code Marketplace + Open VSX) — the Open VSX URL was missing from the publish log before. No external doc references the old script path (verified via `git grep`).
When a builder is blocked at a human-approval gate the Codev sidebar icon now carries a numeric bubble with the count — the same 'needs me' signal the status-bar bell already surfaces, now visible even with the sidebar collapsed. Tooltip explains the number. VSCode has no container-level badge API; per-view TreeView.badge is the only way to paint the activity-bar icon, and badges bubble up from a container's views to the icon when the sidebar is hidden. Badging buildersView is the natural carrier for the blocked signal and avoids inflating an aggregate sum across multiple views. - updateActivityBadge() reads data.builders.filter(b => b.blocked) (same predicate as updateStatusBarCounts) and sets the badge only when connected to Tower and the count is > 0; otherwise clears it. - Wired into the existing overviewCache.onDidChange reconcile loop so it stays live without new event plumbing. - Seeded once after createTreeView so a cached overview shows the badge immediately, not on the next refresh tick. Per-view titles (Builders (N) / Pull Requests (N) / Backlog (N) / Recently Closed (N)) unchanged — different semantics: titles show current activity, badge shows action required. 54 tests passing.
Single-click on a builder row now opens its terminal *and* expands
the row's changed-file list — single-click does what most users
expected. Chevron click still toggles expansion; right-click is
unchanged.
New codev.openBuilderRow wrapper command runs the existing
openBuilderByRoleOrId, then calls buildersView.reveal(item,
{expand:true, focus:false}). The reveal-driven expand fires
onDidExpandElement, so the accordion handler picks it up and collapses
peers when codev.buildersAutoCollapse is on; the existing openBuilderId
idempotency guard keeps the re-fired event a no-op. focus:false keeps
the terminal focused, not the tree.
codev.openBuilderById is untouched, so other callers (terminal links,
etc.) still open the terminal without expanding the row.
Adds an @-mention icon on each backlog row. Clicking it opens (or focuses) the architect terminal and types '#<issueId> ' into its prompt without submitting, so the user can add their own context (e.g. 'use PIR for this') before hitting Enter. New TerminalManager.injectArchitectText(text) calls Terminal.sendText with addNewLine=false on the 'architect' entry — that flows through the Pseudoterminal's handleInput exactly like a user keystroke. The codev.referenceIssueInArchitect command awaits codev.openArchitectTerminal first so the architect is guaranteed available, then injects. The button is a view/item/context inline@1 entry on backlog-item rows, mirroring the same idiom as the green-check Approve button on blocked builders. Row-click behavior is unchanged: still opens the markdown preview via codev.viewBacklogIssue. The new button is a separate affordance.
Two surgical changes to the layout diagram: - Drop the leading '#' from example issue refs in the right column ([#42] [#43] -> [42] [43], Builder #42 -> Builder 42). The Marketplace's README renderer autolinks any '#NN' pattern to repository.url's issues endpoint (even inside fenced code blocks), so 'Builder #42' in the diagram became a clickable link to issue #42 in the published version. Bare numbers don't match the '#\d+' autolink, so the diagram now stays plain. Backslash-escape doesn't work — the '\' renders literally inside a fenced code block. - Add a bottom-panel row to reflect 3.0.6's 'dev-server terminals live in the bottom panel' decision. The diagram previously only showed the editor groups, so a reader couldn't tell where dev servers go.
A builder that hasn't emitted PTY output for > 5 minutes while still
being able to make progress (not blocked at a gate, not complete or
verified) is flagged as idle-waiting — a proxy for "agent paused at a
clarifying question", distinct from both running and blocked.
Pipeline:
shellper tracks lastDataAt per PTY byte → sends it in every WELCOME
(new optional protocol field) → Tower's ShellperClient hydrates on
connect and bumps per DATA frame → PtySession.attachShellper hydrates
Spec 467's existing lastDataAt from the client's value (covering
Tower-restart cold start, where the in-memory ShellperClient is fresh
but the detached shellper process still knows the genuine last-byte
moment) → /api/overview enrichment maps the runtime terminal registry
back to the discovery list via the newly-stamped roleId → ISO string
on OverviewBuilder.lastDataAt → isIdleWaiting returns true once
Date.now() − lastDataAt > 5min.
roleId is computed once per builder at discovery (worktreeNameToRoleId
in discoverBuilders) and stamped on BuilderOverview so the bridge
between filesystem-discovered builders and the runtime terminal
registry is a single field lookup. The enrichment loop matches the
shape of the established pattern in /api/state's builder list
(tower-routes.ts:1572): iterate entry.builders, look up the session
via TerminalManager, do the work. No per-request regex on the
worktree basename.
WELCOME-side hydration is the crux of correctness across Tower
restarts: the shellper process survives, but Tower's ShellperClient
does not. Reading the shellper's own tracker on WELCOME eliminates
what would otherwise be a 5-minute warm-up window after each restart,
once shellpers themselves have been spawned with the new code.
idleMs is unchanged — it measures cumulative gate-wait time (sum
over gates of approvedAt − requestedAt), which is orthogonal to PTY
silence and stays 0 for the case this surfaces.
The threshold and predicate live in @cluesmith/codev-core/builder-
helpers so the VSCode extension and the web dashboard cannot drift.
The types package stays wire-contract-only.
Surfaces:
- Builders tree: 3-bucket order (blocked → idle → active),
comment-discussion icon, "waiting on input [Xm silent]" label,
contextValue awaiting-builder-<protocol> with existing menu
rules extended to match it alongside builder-/blocked-builder-.
- Status bar gains an "N waiting" segment when > 0.
- Activity-bar badge counts blocked + idle with composed tooltip.
- Dashboard BuilderCard: "Waiting on input" + --waiting class.
13 new test cases cover the predicate's threshold edges (>, not >=),
blocked / completed / verified exclusions, null-lastDataAt fallback,
and the 3-bucket orderForDisplay invariants including blocked-takes-
precedence-over-idle and blockedSince-ascending sort within the
blocked bucket.
…se sites Followup to the idle-waiting feature commit. views/builders.ts no longer re-exports `isIdleWaiting` — extension.ts and the unit test file import it directly from @cluesmith/codev-core/builder-helpers, the canonical home. The re-export was a convenience kept after the centralisation to avoid touching call sites; with two consumers it was indirection without benefit. Side effect: removes the only export that wasn't view-local from views/builders.ts. The module now cleanly contains only the tree provider, the row helpers (orderForDisplay, timeSince), and the view's local types.
IssueContentProvider was missing the onDidChange hook that lets a TextDocumentContentProvider invalidate a cached document — so even when viewBacklogIssue re-fetched and overwrote the content map on re-click, VSCode reused its cached TextDocument and the markdown preview stayed frozen at the first view's content until the tab was closed or the window reloaded. Two changes, single file (plus a one-line caller update): - Add EventEmitter<Uri> on the provider, expose as onDidChange, and fire from set(). set() also dedups (no fire when the new markdown matches the cached value), so identical refetches don't churn the preview. - Subscribe to OverviewCache.onDidChange in activateIssueView so open previews refresh on the existing sidebar-poll + SSE heartbeat — no custom timer. A leading-edge 30s throttle absorbs SSE bursts during builder activity. The content map's keys ARE the 'what's open' set, bounded exactly by visibility: onDidCloseTextDocument drops entries when the preview tab closes (VSCode unloads the codev-issue: TextDocument). No magic cap, no LRU bookkeeping. Net behavior: re-click refreshes immediately; passive updates land within the next overview tick (default ~60s, ~30s minimum); identical refetches are silent; closed previews stop being polled.
PIR's builder/reviewer prompts hardcoded `main` as the integration
branch in five literal git commands and one review question, plus two
conventions. On repos whose integration branch isn't `main` (e.g. `dev`,
`ci`, `master`), agents either errored (no `main` branch) or produced
diffs/rebases against an irrelevant branch — polluting planning and
review reasoning.
Replace each hard-fail literal command with the in-tree resolver pattern
already used by `packages/vscode/src/commands/view-diff.ts:262-271`:
$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null \
| sed 's|^origin/||' || echo main)
Reads the actual default branch from `origin/HEAD` (set on every
properly-cloned remote); falls back to `main` only when `origin/HEAD`
is unset. Behaviour-preserving on `main`-default repos, correct on the
non-`main` ones the bug surfaced on.
Sites updated (in both `codev/protocols/pir/` and the
`codev-skeleton/protocols/pir/` template that ships via `codev init`):
- builder-prompt.md:85 (resumption diff for dev-approval)
- prompts/implement.md (resumption-feedback diff, files-summary stat,
push-prohibition wording)
- prompts/review.md (files-changed stat, push-prohibition wording,
rebase-on-conflict block)
- consult-types/pr-review.md (PR-review "up to date with default
branch?" question)
Conventions ("Don't push to main") reworded to "Don't push to the
default branch" — semantically identical, no fossilised name.
This fixes only PIR's Layer 2 sites for codev#777. Layer 1
(consult/index.ts:989, 1297), Layer 2 in the other protocols
(BUGFIX, SPIR, ASPIR, AIR, MAINTAIN), Layer 3 test infrastructure,
and the optional porch-side prompt substitution mechanism are tracked
on the same issue and are out of scope here.
PIR is the first protocol to adopt this resolver pattern in markdown
prompts; future Layer 2 work on the other protocols should follow the
same shape for consistency.
waleedkadous
approved these changes
May 20, 2026
Contributor
waleedkadous
left a comment
There was a problem hiding this comment.
Some super nice features!!
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.
A grab-bag of VSCode-extension polish around the Builders view, plus a PIR-protocol fix that addresses Layer 2 (PIR slice) of #777.
What's new in the extension
Preview
Fixed
consult --type {spec,plan,impl} resolves artifact from invoking workspace (not the builder's branch); impl-review diff base hardcoded to main #777 Layer 2 (PIR slice). PIR builder/reviewer prompts no longer hardcode `main` as the integration branch. The eight PIR-specific sites (builder-prompt.md, prompts/implement.md, prompts/review.md, consult-types/pr-review.md — plus the matching `codev-skeleton/protocols/pir/` copies) now resolve the default branch dynamically via the in-tree resolver pattern from `view-diff.ts:262-271`:
```
$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||' || echo main)
```
Behaviour-preserving on `main`-default repos; correct on `dev`/`ci`/`master`-default ones (which is exactly where consult --type {spec,plan,impl} resolves artifact from invoking workspace (not the builder's branch); impl-review diff base hardcoded to main #777 surfaced). Layer 1 (the consult harness CLI), Layer 2 of the other protocols, Layer 3 (test infrastructure), and the optional porch-side prompt substitution mechanism remain tracked on consult --type {spec,plan,impl} resolves artifact from invoking workspace (not the builder's branch); impl-review diff base hardcoded to main #777.
Internal / chore
Verification
Branch notes
Branch was renamed from `feat/vscode-updates-2` mid-development as the scope grew to include PIR work.
Closes the PIR slice of #777; remaining layers tracked there.