Skip to content

vscode: codelens-driven review comments in the unified diff editor — per-builder queue with batched submit to PTY (follow-up to #789) #1037

@amrmelsayed

Description

@amrmelsayed

Composes with #1049 (contextual bottom panel umbrella). This issue ships the persistence layer + the codelens / inline-thread input surface for review comments. The bottom-panel surface where the queue is displayed and acted on is owned by #1049, which structures the panel as a contextual surface that morphs by active editor. The two view shapes for the queue (per-builder scoped in Code Review mode + cross-builder roll-up in Attention mode) live as two modes under #1049; this issue powers both. See "Where this fits in the contextual panel" below.

Follow-up to #789. #789 ships the inject-on-click codelens behavior in the unified diff editor (> Send to builder PTY injects path/file.ts:L42-L58 into the builder's prompt buffer, user types feedback inline, submits with Enter). This issue layers a structured review-comment mode on top: instead of typing in the PTY, the user composes a comment in an inline comment thread mounted at the line/hunk, the comment goes into a per-builder queue, and a Submit review action packages all queued comments and forwards them to the builder PTY as a single batched message. The PTY-injection model from #789 stays — this is a complementary surface, not a replacement.

Why this is a separate surface, not an extension of #789

The PTY-injection model is frictionless — click, the reference is there, you keep typing as you would have anyway. It works well for one-off reactions ("revert this", "rename to X").

The structured-comment model is sustained — there's a discrete "I am writing a review comment" moment that ends with submit. It works well for sentence-or-paragraph feedback over multiple hunks during a single review session, especially when you want to think about the whole diff before submitting.

Both coexist on the diff editor: the codelens shows exactly one entry per file/hunk header at a time — either the comment entry or the inject entry, controlled by an editor-level toggle (comment is the default). The right-click context menu on file/hunk headers always exposes both actions regardless of the codelens mode, so the non-default flow is always one menu away without flipping the editor mode.

The two surfaces never merge state. #789 clicks fire-and-forget into the PTY — they never enter the queue and never appear in the panel view below. #1037 clicks always enter the queue and are only "spent" via Submit Review. The user's mental model: "if I see it in the panel, I haven't submitted it yet; if I sent it via #789, it's already in the PTY history."

Behavior change for #789's existing flow. Today (post-#789 / pre-#1037), the > Send to builder PTY codelens is the only codelens on the diff and is shown unconditionally. After #1037 lands with codev.diffCodelensMode defaulting to "comment", the inject codelens is hidden by default — users who prefer the frictionless inject either toggle the diff editor to forward mode once (the preference persists per workspace) or use the right-click context menu which always exposes both actions. Cmd/Ctrl+K B (the existing #789 keyboard shortcut) continues to inject regardless of the codelens mode.

Proposed mechanic

  1. Codelens entry on each file / hunk header: exactly one entry, matching the current diff codelens mode — > Comment for builder in comment mode (default), > Send to builder PTY in forward mode. An editor title-bar toggle button on the unified diff editor flips between the two modes; the choice persists per workspace as codev.diffCodelensMode: "comment" | "forward".
  2. Right-click context menu on file/hunk headers always exposes both Codev: Comment for builder and Codev: Send to builder PTY regardless of the codelens mode.
  3. Comment-mode click (codelens or context menu) mounts an inline comment thread at the line using VSCode's comments API (vscode.comments.createCommentController + CommentThread). Forward-mode click (codelens or context menu) injects the reference into the active builder's PTY per vscode: inject file/hunk reference into builder PTY from the unified-diff editor (codelens) #789's existing behavior.
  4. User types in the thread input (VSCode's native input, supports markdown, multi-line, paragraph-length feedback).
  5. Submit on the thread adds the comment to a per-builder pending-comments queue.
  6. Submit review action (palette command + status-bar button + per-builder action in the panel view) packages all pending comments for the active builder into a single batched message and writes it to the builder PTY's prompt buffer. The user reviews the packaged message and presses Enter to send.
  7. Queue clears after successful submit. Pending comments persist across VSCode restarts via worktree-local file (see persistence below).

Persistence: per-builder queue, worktree-local file

Each builder's pending review comments live in .builders/<id>/.codev/pending-comments.json. Schema (plan-gate may adjust):

{
  "version": 1,
  "builderId": "pir-859",
  "comments": [
    {
      "id": "uuid",
      "createdAt": "2026-06-13T10:00:00Z",
      "file": "packages/vscode/src/views/builders.ts",
      "lineRange": { "start": 42, "end": 58 },
      "diffContext": "...optional anchor for verification on apply...",
      "body": "the early return here is wrong because Y; suggest Z"
    }
  ]
}

The file:

  • Sits inside the builder's worktree directory (matches the existing per-builder state pattern alongside codev/state/<id>_thread.md)
  • Goes into .gitignore so it doesn't ship with the branch (it's local review state, not committed work)
  • Cleans up automatically when afx cleanup removes the worktree
  • Survives VSCode reloads, machine restarts, opening the project in another window

Where this fits in the contextual panel (#1049)

Under #1049 the bottom panel is one contextual tab that morphs by active editor; this issue powers the queue's display in two of #1049's four modes:

  • Code Review mode (active when the user has the unified diff editor open for a builder) — the panel shows THAT builder's pending-comments queue scoped to just one builder. Per-comment actions (Edit / Delete) and a Submit Review button for this builder. Source: .builders/<builder-id>/.codev/pending-comments.json.
  • Attention mode (fallback when no specific context matches) — the panel shows the cross-builder roll-up of all pending queues. Builder roots → comment children, same tree shape this issue previously described as a standalone tab. Per-builder Submit Review and Discard All actions; per-comment Edit and Delete actions. Source: every .builders/*/.codev/pending-comments.json file aggregated.

The panel skeleton, mode resolver, header, pin behavior, and the switch between modes are owned by #1049. This issue owns:

  1. The codelens / inline-thread input surface (composing comments).
  2. The persistence (.builders/<builder-id>/.codev/pending-comments.json per builder).
  3. The submit action (batched flush to the builder's PTY via vscode: inject file/hunk reference into builder PTY from the unified-diff editor (codelens) #789's existing infrastructure).
  4. The data each mode renders (sub-tree of the panel content).

The standalone tab description that previously lived here is dropped — #1049 supersedes it.

Empty states per mode:

Cross-window — multiple VSCode windows on the same machine all read the same .builders/<id>/.codev/pending-comments.json. File-watcher-based sync gives each window a consistent view at OS-event latency. An in-process bus is cheaper but only syncs within one VSCode process. Plan-gate decision #7 below picks.

Plan-gate decisions to lock

These are the design calls that affect the v1 shape — the plan should pick each before coding starts.

  1. Codelens surface (locked: single-mode + editor toggle + always-on context menu). The diff editor's codelens shows exactly one entry per file/hunk header — > Comment for builder in comment mode (default), > Send to builder PTY in forward mode. An editor title-bar toggle button on the unified diff editor flips between modes; the choice persists as codev.diffCodelensMode (default "comment"). The right-click context menu on file/hunk headers always shows BOTH actions regardless of mode. Remaining sub-decisions for the plan to lock: title-bar button shape (single icon with tooltip-displayed mode, or two icons toggling), icon choices for each mode, and whether to also surface the toggle as a setting in the Codev sidebar or rely solely on the per-editor title-bar button + workspace setting.
  2. Submit format: when packaging queued comments into the single PTY message, what's the wire format? Options:
    • One message with per-comment markdown sections (### packages/foo.ts:L42-L58\n\n<body>\n\n### ...)
    • Multiple PTY writes, one per comment, separated by a blank line (the builder receives them as a sequence)
    • A JSON envelope that the builder unpacks (requires builder-side parsing logic)
  3. Edit / delete of queued comments: can the user edit a queued comment before submit? Delete one? Re-order them? Plan-gate picks. Cheapest: read-only queue, "submit or delete all" is the only action. Most flexible: per-comment edit/delete/reorder UI in the thread. Likely lean: per-comment edit + delete, no reorder.
  4. Behavior when the builder has no active terminal at submit time: fall through to the existing terminal-manager open-terminal flow (matches vscode: inject file/hunk reference into builder PTY from the unified-diff editor (codelens) #789's behavior), or fail with a status-bar message, or queue the submit until a terminal opens?
  5. Multi-comment threads (replies): VSCode's comments API supports replies within a thread. For v1, do replies on a queued comment turn into edits, or do they accumulate as separate queued comments under the same hunk? Probably "edits" for v1 simplicity; replies-as-separate is a follow-up.
  6. Comment thread persistence across reloads: VSCode's CommentController is recreated on extension reactivation. After a reload, do queued comments re-mount as visible threads on the diff (requires diff editor to be re-opened on the same builder) or stay invisible until the user opens the diff again? Lean: re-mount when the diff is re-opened for that builder.
  7. Sync mechanism between the inline threads, the status-bar counter, and the panel view: file watcher on .builders/*/.codev/pending-comments.json (cross-window safe, but OS-event latency and edge cases on Windows / network filesystems), or an in-process event bus from the queue write path (cheap, but only syncs within one VSCode process — multi-window users see stale state until next refresh). Plan-gate picks; if file-watcher is chosen, decide debounce window.

Acceptance criteria

Out of scope

Suggested protocol

PIR. The implementation is non-trivial (vscode.comments API integration, persistence layer, per-builder queue management, status-bar integration, bottom-panel tree view, three-way sync between inline threads / status-bar / panel), and the seven plan-gate decisions above are real design surface that benefits from a locked plan before coding. The dev-approval gate is load-bearing because the multi-builder queue-isolation behavior and the three-way sync are best verified by running the worktree against two real builders and walking through the interaction by hand.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/vscodeArea: VS Code extension

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions