Skip to content

Feat/entire review multi agent#1018

Draft
peyton-alt wants to merge 21 commits intofeat/entire-reviewfrom
feat/entire-review-multi-agent
Draft

Feat/entire review multi agent#1018
peyton-alt wants to merge 21 commits intofeat/entire-reviewfrom
feat/entire-review-multi-agent

Conversation

@peyton-alt
Copy link
Copy Markdown
Contributor

@peyton-alt peyton-alt commented Apr 24, 2026

Summary

Adds a multi-agent mode to entire review. When multiple eligible agents support headless execution, the CLI multi-selects agents, prompts for optional per-run context, runs N reviews in parallel with a Bubble Tea status table, and (optionally) synthesizes a unified cross-agent verdict at the end.

Closes Phase 2 of the entire review redesign (items 1–4) on top of PR #993 / #1009. Phase 1 (install-aware skill picker) shipped separately.

Phase 2 — what landed

1. Pick the review agent

  • Spawn-time picker when 2+ agents are configured (81c4c1192).
  • Per-run prompt textarea after agent selection so users can scope a single run without editing settings (434a6ae96).

2. Parallel headless spawn + status table

  • New agent.HeadlessLauncher capability interface; per-agent implementations for claude-code, codex, gemini-cli (b53d82f1e).
  • Binary lookup deferred to Cmd.Start so construction is infallible and unit tests verify argv/stdin contracts without the agent binaries on PATH (880bae867).
  • Codex / gemini headless invocation + Ctrl+C cancellation cascade with a 5s SIGKILL watchdog (8e82e407a).
  • multiReviewOrchestrator runs N agents in parallel under a shared cancellation context, owns the pending-review marker lifecycle, and dumps per-agent results once the TUI exits (b0036d737).
  • reviewTUIModel (Bubble Tea) renders a live status table with spinner, per-row duration, token count, and a faint preview line (701bf3948).
  • Codex exec-mode noise filter strips session chrome (banners, hook firings, exec ... blocks, timestamped errors) before the per-agent dump so findings aren't buried (d0f05d1bd).

3. Ctrl+O drill-in + aggregated dumps

  • Press Ctrl+O during a run to drill into any agent's live buffer; ←/→ to switch agents, Esc to return (21920e4f5). Drill-in uses the alt-screen so the table doesn't tear underneath (b2466e5c0).
  • After all agents finish, the orchestrator emits one ─────── <agent> review ─────── block per agent containing the filtered narrative.

4. AI-synthesized cross-agent verdict

  • New opt-in (y/N) prompt after the per-agent dumps. Reuses resolveCheckpointSummaryProvider (the same picker entire explain uses) to resolve a configured summary agent and asks it to produce a unified verdict with sections for common findings, unique findings, disagreements, and priority order (840239d32).
  • Skipped silently when stdin isn't a TTY, when the run was cancelled, or when fewer than two agents produced usable output. Provider failures degrade to a one-line "synthesis unavailable" notice — the user can still commit the underlying reviews.

Other improvements

  • Per-agent marker entries. Multi-agent markers carry a per-agent map of {Skills, Prompt} so each adopting hook records the skills/prompt that that agent actually ran. Single-agent markers keep the legacy top-level fields. Fixes the Bugbot HIGH where multi-agent reviews previously persisted with empty ReviewSkills/ReviewPrompt (52546abf3).
  • Scope clause in the prompt. Without guidance, agents picked their own review surface (codex defaulted to origin/main...HEAD, claude defaulted to working-tree-only). The composed prompt now appends a clause that pins agents to "commits unique to this branch vs the closest ancestor branch," with detectScopeBaseRef finding that ancestor by tip-timestamp (falling back to main) (b9ed9c074). Commits-only — uncommitted bytecode and editor temp files were polluting findings.
  • Skill-discovery dedupe. Same plugin cached under multiple versions no longer produces duplicate /foo:bar entries in the picker (92d7a98e7).
  • TUI cancellation correctness. In-TUI Ctrl+C now routes through the same path as out-of-TUI SIGINT — sets the cancelled flag, arms the SIGKILL watchdog, returns Cancelled=true (26ebe72e1).
  • TUI rendering correctness. Per-row run-start timestamps so late-starting agents don't show inflated durations (1744d5402); rune-safe preview truncation so multi-byte UTF-8 doesn't get split mid-rune (68f5a3707).
  • Cobra usage silenced on multi-agent picker cancel and dispatch errors so the error message stays scannable (a42912e89).

Test plan

  • mise run check — fmt + lint + unit + integration + canary
  • Manual smoke: entire-dev review in a multi-branch repo with both claude-code and codex configured; verified scope clause limits review to commits unique to current branch and synthesis prompt fires only when at least two agents succeed.
  • Manual smoke: Ctrl+O drill-in switches between agents and returns cleanly via Esc.
  • Manual smoke: Ctrl+C during a run produces "(cancelled)" rows, marker is cleaned up.
  • CI green on the latest commit (test, test-core, test-integration a/b/c, test-canary, lint, license-check, binary-size).

Review-feedback addressed

All 12 PR comments from Cursor Bugbot + Copilot triaged; 11 fixed across the commits above, 1 (for i, task := range tasks capture) is a false positive on Go 1.22+ (project is on 1.26.2).

🤖 Generated with Claude Code

peyton-alt and others added 5 commits April 23, 2026 12:10
Four fixes from end-to-end smoke testing of the multi-agent review flow:

- codex and gemini both require the prompt piped via stdin, not as a
  positional arg. Mirror each agent's existing GenerateText invocation:
  codex exec --skip-git-repo-check -, gemini -p " ", with
  cmd.Stdin = strings.NewReader(prompt). Do NOT mirror the isolation
  (TempDir + StripGitEnv) — review MUST fire the agent's hooks to drive
  pending-review marker adoption. Relax the HeadlessLauncher contract
  doc: Stdin MAY be set when the prompt must be piped; Stdout/Stderr
  remain unwired for the caller.

- bubbletea's raw-mode terminal captures Ctrl+C as the byte 0x03 and
  converts to tea.KeyMsg{KeyCtrlC} — the OS never sends SIGINT, so the
  orchestrator's signal.Notify goroutine never wakes. tea.WithoutSignalHandler
  lets us own signal handling but isn't enough on its own. Wire the TUI
  model with an onCancel func field; the constructor takes cancelRun
  from the orchestrator; the KeyCtrlC handler calls it on first press,
  which cancels runCtx and propagates SIGKILL to subprocesses via
  exec.CommandContext.

- Reorder the status-classification switch in runSingleAgentTask.
  ctx-cancelled + signal-killed delivers an *exec.ExitError with exit
  code -1, so errors.As(&exitErr) matched first and classified as
  Failed. Check ctx.Err() first so cancelled runs are reported as
  AgentRunCancelled with 0 succeeded / 0 failed / N cancelled in the
  summary.

- Skip the FinalOutput dump for cancelled agents. The buffered partial
  stdout (often 100+ lines of codex hook/tool-call noise) is rarely
  useful and the user explicitly asked to stop. Show "(cancelled)" on
  the header line and move on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 6b2243c45a68
Copilot AI review requested due to automatic review settings April 24, 2026 02:07
Comment thread cmd/entire/cli/review_multi.go
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces multi-agent support for entire review, including a parallel orchestrator with a Bubble Tea TUI status table and new headless-launch capabilities for supported agents, plus marker adoption changes to allow multiple agents to tag the same pending review.

Changes:

  • Add multi-agent orchestration (multiReviewOrchestrator) that runs multiple agents in parallel, writes a shared pending-review marker, and prints a combined result summary.
  • Add a Bubble Tea TUI (reviewTUIModel) to render per-agent status/progress and previews when output is a TTY.
  • Introduce agent.HeadlessLauncher and implement headless launch for Claude Code, Codex, and Gemini CLI; update review dispatching + tests.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
go.mod / go.sum Add Bubble Tea TUI test dependency (teatest) and related indirect deps.
cmd/entire/cli/review.go Add multi-agent dispatch path, MultiAgentTask/result types, and multi-agent marker adoption logic.
cmd/entire/cli/review_multi.go New parallel orchestrator that runs multiple headless agents and optionally drives the TUI.
cmd/entire/cli/review_tui.go New Bubble Tea model rendering a multi-agent status table with previews and cancellation handling.
cmd/entire/cli/review_multi_test.go Add orchestrator tests using a fake headless agent.
cmd/entire/cli/review_tui_test.go Add Bubble Tea model tests using teatest.
cmd/entire/cli/review_test.go Add tests pinning picker/dispatch behavior via dependency injection.
cmd/entire/cli/lifecycle_test.go Add tests for multi-agent marker adoption behavior.
cmd/entire/cli/agent/agent.go Add HeadlessLauncher interface contract.
cmd/entire/cli/agent/claudecode/headless.go (+test) Add Claude Code headless launch command builder and tests.
cmd/entire/cli/agent/codex/headless.go (+test) Add Codex headless launch command builder and tests.
cmd/entire/cli/agent/geminicli/headless.go (+test) Add Gemini CLI headless launch command builder and tests.

Comment thread cmd/entire/cli/review_multi.go
Comment thread cmd/entire/cli/review.go Outdated
Comment thread cmd/entire/cli/review.go
Comment thread cmd/entire/cli/review_multi.go Outdated
Comment thread cmd/entire/cli/review_tui.go Outdated
Comment thread cmd/entire/cli/review_tui.go Outdated
Comment thread cmd/entire/cli/agent/claudecode/headless_test.go
Comment thread cmd/entire/cli/agent/codex/headless_test.go
Comment thread cmd/entire/cli/agent/geminicli/headless_test.go
Comment thread cmd/entire/cli/review_multi_test.go Outdated
peyton-alt and others added 14 commits April 24, 2026 12:07
Entire-Checkpoint: 932e1f838aa4
… multiple versions

Claude Code's plugin cache layout is <marketplace>/<plugin>/<version>/,
and a single plugin can appear under multiple version directories (e.g.
after an update leaves the old content-hash version alongside the new
one). The walker emitted one entry per version, so the picker showed
`/pr-review-toolkit:review-pr` twice on disks where pr-review-toolkit
was cached as both `cf62a6c02dc0` and `unknown`.

Collapse by invocation Name after the walk — first-seen wins, ordering
otherwise preserved. Regression test asserts a single entry when two
version directories carry the same review command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: ccdce9099840
Pressing Ctrl+O inside the dashboard now opens a full-screen scrollable
view of a single agent's live stdout. Arrow keys scroll the buffer
(up/down) and cycle between agents (left/right); Esc returns to the
dashboard. Ctrl+C is ignored in detail mode so scrolling can't
accidentally kill the run — user has to Esc back to cancel.

Implementation: one agentBuffer (mutex + bytes.Buffer) per task, shared
by the orchestrator's tee writer and the TUI model. Snapshot() copies
the current contents on every repaint so the live output updates while
the user is drilled in. reviewTUIModel gains detailMode/idx/scroll
fields plus termHeight (tracked from WindowSizeMsg) to size the
viewport. View() dispatches to a separate detailView() when detailMode
is on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: e2c15aa5c481
Smoke test surfaced stale header lines accumulating in terminal
scrollback when watching a codex run drill-in live: the buffer grew
mid-view, bubbletea's inline repaint couldn't erase properly, and each
frame with a different line count left ghost rows. Also codex emits
private-mode CSI sequences (e.g. cursor-hide \x1b[?25l) that the
previous regex missed, so those control bytes were passing through into
the rendered view and shifting the cursor.

Three fixes bundled:

- Enter/exit alt-screen via tea.EnterAltScreen / tea.ExitAltScreen on
  Ctrl+O and Esc. Detail view gets its own screen buffer, dashboard
  stays on primary. No more drill-in history in scrollback.
- Pad the detail render to a fixed line count (viewport height) so
  every frame returns the same size — stable frame diff even in alt-
  screen.
- Truncate each line to termWidth so codex's wide shell output can't
  wrap and throw off line counts; extend the ANSI-strip regex to catch
  ? and ; in CSI parameters (covers cursor-hide/show).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 7ee78eef2d67
Codex exec-mode emits session chrome (banners, hook firings, `exec ...`
tool-call blocks, timestamped error logs) interleaved with the actual
narrative response. Surfacing all of that in the multi-agent results
dump buried the findings under noise. Per-agent output filters now
strip codex chrome and slice the final assistant turn out of the
cleaned buffer; claude-code and gemini-cli pass through unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 7759a6fcad0d
Without scope guidance, agents picked their own review surface and
disagreed: codex defaulted to `origin/main...HEAD` (which pulls in
commits inherited from sibling branches), claude defaulted to
working-tree-only. The result was inconsistent reviews of different
content on the same invocation.

The composed prompt now carries an explicit scope clause that pins
agents to "commits unique to this branch vs the closest ancestor
branch." A new detectScopeBaseRef helper finds the nearest non-self
ancestor branch (preferring the most recently authored tip), falling
back to the repo's default base. The clause is commits-only —
uncommitted bytecode and editor temp files were polluting findings,
so users who want uncommitted work reviewed should commit first or
say so in the per-run prompt textarea.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: d1a03a7c0b67
LaunchHeadlessCmd implementations called exec.LookPath up front,
which made unit tests for argv shape and stdin wiring fail in CI
runners that don't have claude/codex/gemini on PATH. Move the
lookup to *exec.Cmd.Start by passing the bare binary name to
exec.CommandContext — missing-binary errors still surface when
the orchestrator runs the command (already classified as
AgentRunFailed there), but construction is now infallible.

Adds a regression test per agent that scrubs PATH and confirms
LaunchHeadlessCmd no longer errors at construction. Updates the
HeadlessLauncher interface contract to document the deferred
lookup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 548670d392c1
The multi-agent orchestrator wrote PendingReviewMarker without Skills
or Prompt, but the adopting hook unconditionally copied those fields
into session state. Multi-agent review sessions therefore persisted
with empty ReviewSkills and ReviewPrompt, losing the "what was
actually reviewed" trail in checkpoint metadata.

Add an AgentEntries map keyed by agent name to PendingReviewMarker.
The orchestrator populates one entry per task with that agent's own
skills and composed prompt, and adoption looks up the entry matching
the adopting agent. Top-level Skills/Prompt remain the single-agent
path and the legacy fallback for markers without entries.

Reported by Cursor Bugbot on PR #1018 (HIGH severity).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 96f09baae112
The multi-agent picker's cancel branch and the dispatchMultiAgent
error-return branch both let errors propagate without setting
cmd.SilenceUsage, so cobra dumped a full usage block on top of the
actual error message. The single-agent picker already does the right
thing — match that pattern here so user-cancelled and runtime-failure
paths both produce a concise, scannable error.

Reported by Copilot on PR #1018.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 17a53d070bf6
In raw mode, bubbletea captures Ctrl+C as tea.KeyCtrlC and dispatches
it to the model — the orchestrator's signal.Notify goroutine never
sees a SIGINT. The previous wiring passed cancelRun directly as the
model's onCancel, which canceled runCtx but skipped two side effects
the sigCh path performs:

- Setting the cancelled atomic flag, so callers (and the result
  classifier) saw Cancelled=false on in-TUI cancels.
- Arming the 5s SIGKILL watchdog, so any subprocess that ignored
  SIGTERM hung forever instead of being force-killed.

Wrap onCancel in a sync.Once-guarded helper that flips both. Out-of-
TUI cancels (Ctrl+C without a TTY, or external SIGTERM) still reach
the original sigCh goroutine and behave the same.

Reported by Copilot on PR #1018.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2d7b15c20084
The tickMsg handler computed duration as now - m.startTime, where
startTime is when the TUI itself launched. Agents that entered
AgentRunRunning later (e.g., second agent when launches are
serialized for any reason) showed inflated time-since-TUI durations
on every tick instead of time-since-their-own-start.

Stamp runStart on the queued→running transition and tick from there.
The on-completion duration in agentStateMsg is unchanged because the
orchestrator already measures from its own startTime per task.

Reported by Copilot on PR #1018.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 7be800b1f909
stripped[:maxLine-1] sliced by bytes, which could split a multi-byte
UTF-8 rune mid-sequence and produce invalid output for non-ASCII
agent narrative (em-dashes, CJK, accented Latin). Switch to
stringutil.TruncateRunes which already exists for exactly this case
elsewhere in the package.

Reported by Copilot on PR #1018.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2f9f57be100f
- Remove unused cancelMsg type and its Update branch in review_tui.go.
  The type was documented as "orchestrator posts when SIGTERM begins"
  but had no senders — cancellation already routes through onCancel
  and the cancelling banner is set there. Dead code.

- Fix curly-quote typo in shellQuote's docstring (review_multi_test.go).
  The conventional shell escape for embedding a single quote inside
  single quotes is '\'' — the comment had a curly quote U+201D
  instead of the literal sequence.

Both reported by Copilot on PR #1018.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 45de134f4744
Two small fixes that surfaced after the previous PR-feedback batch:

- review_tui_test.go: TestTUIModel_TickUsesPerRowRunStart used
  short-form type assertions (updated.(reviewTUIModel)) which
  errcheck flags. Wrap them in a t.Helper-tagged asReviewTUIModel
  helper that fails the test loudly if Update returns the wrong
  concrete type — same observable behavior, lint-clean.

- review_multi_test.go: the previous attempt to fix the curly-quote
  typo in shellQuote's docstring kept getting normalized back to a
  curly quote by editor/formatter passes. Reword in plain prose so
  there are no ambiguous escape characters to round-trip through.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 8905eba75ebd
@peyton-alt
Copy link
Copy Markdown
Contributor Author

@BugBot review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

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 3 potential issues.

Fix All in Cursor

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

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit db7a12d. Configure here.

Comment thread cmd/entire/cli/review_tui.go Outdated
// Truncate wide lines so they can't wrap and throw off bubbletea's
// frame-line count. Scroll with ↑/↓ if you need to see the tail.
if len(line) > maxLineWidth {
line = line[:maxLineWidth-1] + "…"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Detail view truncates lines by bytes, not runes

Medium Severity

The detailView method truncates lines using byte-level slicing (line[:maxLineWidth-1]), which can split multi-byte UTF-8 characters and produce invalid output. The same file's truncatePreview function correctly uses stringutil.TruncateRunes for rune-safe truncation, and there's even a dedicated test (TestTruncatePreview_RuneSafe) asserting this concern. The detail view missed the same fix.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit db7a12d. Configure here.

if strings.HasPrefix(line, "exec") {
inExec = true
continue
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Overly broad prefix match filters valid narrative content

Medium Severity

filterCodexOutput uses strings.HasPrefix(line, "exec") to detect codex tool-call blocks, but this matches any line starting with "exec" — including legitimate narrative content like "Executing tests revealed…" or "Excellent exception handling…". Matched lines enter the inExec state, silently discarding all subsequent lines until a blank line. The codex format uses a bare exec on its own line; a stricter check like line == "exec" or strings.TrimSpace(line) == "exec" would avoid false positives.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit db7a12d. Configure here.

Comment thread cmd/entire/cli/review.go
base = runContext
} else {
base = base + "\n\nFor this review: " + runContext
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Skills template causes triple newline before run context

Low Severity

When composeReviewPrompt builds from skills, the template produces a trailing \n (from the last fmt.Fprintf(&sb, " %d. %s\n", ...)). Appending run context via base + "\n\nFor this review: " then creates a triple newline (\n\n\n) between skills and context. The custom-prompt path produces only a double newline (\n\n). This formatting inconsistency results in an extra blank line in the skills-based prompt.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit db7a12d. Configure here.

peyton-alt and others added 2 commits April 27, 2026 17:56
Closes Phase 2 item 4 (AI-synthesized cross-agent verdict). After the
per-agent dumps and the "N agents done" line, prompt the user to opt
into a single synthesis pass that resolves the configured summary
provider (claude/codex/gemini, same picker `entire explain` uses) and
asks it to produce a unified verdict across the per-agent reviews.

Default is no — synthesis is one extra LLM call, so it shouldn't fire
unless the user explicitly asks. Skipped silently when stdin isn't a
TTY (CI, piped output) or fewer than two agents produced usable
output. Provider failures degrade gracefully to a one-line "synthesis
unavailable" notice rather than blocking the user from committing.

Refactor dumpMultiAgentResults into dumpPerAgentReviews +
dumpRunCounts + dumpRunFooter so the synthesis step can land between
the run counts and the commit hint without further nesting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c5108ac4e23a
Three Bugbot findings on the latest commits, all real:

- review_tui.go detailView truncates rendered lines by bytes — same
  UTF-8-split risk as truncatePreview but I missed the sibling spot
  when fixing the first one. Switch to stringutil.TruncateRunes.
- review_multi.go filterCodexOutput uses strings.HasPrefix(line,
  "exec") to detect tool-call blocks. Anchor on either bare `^exec$`
  or the `exec <cmd> in /<cwd>` shape codex actually emits, so
  legitimate narrative like "executed by the runner" or "execution
  succeeded" is no longer eaten.
- review.go composeReviewPrompt produced a triple-newline gap when
  appending run context to a skills-template base — the template's
  trailing \n stacked with the joiner's "\n\n". Trim before joining.

Also refresh the CLAUDE.md `entire review` section to cover what's
shipped on this branch: multi-agent picker, per-run prompt textarea,
AgentEntries on the marker, scope clause + closest-ancestor base
detection, and the cross-agent verdict synthesis prompt. The settings
schema example was also stale — corrected to the current
ReviewConfig{Skills, Prompt} shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: a207b0bc3f5b
peyton-alt added a commit that referenced this pull request May 5, 2026
review/prompt.go's ComposeReviewPrompt assembles the agent prompt from
Skills + AlwaysPrompt + PerRunPrompt + scope clause. Empty sections
are skipped (no triple-newline gaps — regression class from PR #1018
commit 13415f5). The scope clause pins agents to 'commits unique
to this branch vs <closest-ancestor>' to prevent the divergent-default
problem where codex used origin/main...HEAD and claude used
working-tree-only on the same invocation (fixed in #1018 commit
b9ed9c0, structurally enforced here).

review/scope.go's detectScopeBaseRef finds the closest non-self
ancestor branch by tip timestamp, with fallback chain origin/HEAD →
origin/main → origin/master → main → master. ComputeScopeStats and
formatScopeBanner produce the 'Reviewing feat/X vs main: 3 commits,
7 files changed, 2 uncommitted' output that CU6 will print before
agent launch.

Consolidates CU3's placeholder composePrompt and duplicated
appendReviewEnv into shared helpers in review/. Each agent reviewer
(claudecode, codex, geminicli) now calls review.ComposeReviewPrompt
and review.AppendReviewEnv directly. Per-agent local copies removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
peyton-alt added a commit that referenced this pull request May 5, 2026
CU9 introduces TUISink, a Sink implementation that renders a per-agent
status dashboard during multi-agent review runs. Composed alongside
DumpSink in TTY mode; non-TTY multi-agent runs continue to use DumpSink
alone.

  - review/tui_sink.go: TUISink wraps a Bubble Tea program. AgentEvent
    translates each Event into a tea.Msg and sends it via Program.Send.
    RunFinished signals the model to render a final dashboard frame and
    waits for the user to dismiss with any key.
  - review/tui_model.go: reviewTUIModel handles agentEventMsg / tickMsg
    / WindowSizeMsg / KeyMsg. Per-row run-start timestamps stamped on
    first event from each agent (regression-prevented: PR #1018 used a
    single TUI-start timestamp that inflated late-starting agents'
    durations). Single cancel function: KeyCtrlC and out-of-TUI SIGINT
    both call the same context.CancelFunc, gated by sync.Once.
  - review/tui_detail.go: alt-screen drill-in. Ctrl+O enters; left/right
    cycles agents; up/down scrolls; Esc returns. detailView pads to
    termHeight so every frame returns the same line count (avoids ghost
    rows in the alt-screen frame diff). ANSI/CSI sequences stripped per
    line. Rune-safe truncation via stringutil.TruncateRunes.

Wires dispatch in cmd.go's runMultiAgentPath: TTY mode composes
[TUISink, DumpSink] (TUI for live dashboard, DumpSink for post-run
narrative); non-TTY composes [DumpSink] alone. tea.WithoutSignalHandler
keeps SIGINT routing on the cobra root's existing handler so the
single-cancel contract holds even when the TUI captures KeyCtrlC.

Anti-features explicitly NOT recreated:
- sync.Once-guarded onCancel + parallel signal.Notify goroutine: replaced
  by a single shared context.CancelFunc gated by one sync.Once on the model
- cancelMsg dead-code type: omitted entirely
- byte-slice truncation: stringutil.TruncateRunes throughout
- single TUI-start timestamp: per-row runStart stamped on first event
- missing alt-screen on drill-in: tea.EnterAltScreen on Ctrl+O
- variable-line-count detail render: detailView pads to termHeight

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
peyton-alt added a commit that referenced this pull request May 5, 2026
CU9 introduces TUISink, a Sink implementation that renders a per-agent
status dashboard during multi-agent review runs. Composed alongside
DumpSink in TTY mode; non-TTY multi-agent runs continue to use DumpSink
alone.

  - review/tui_sink.go: TUISink wraps a Bubble Tea program. AgentEvent
    translates each Event into a tea.Msg and sends it via Program.Send.
    RunFinished signals the model to render a final dashboard frame and
    waits for the user to dismiss with any key.
  - review/tui_model.go: reviewTUIModel handles agentEventMsg / tickMsg
    / WindowSizeMsg / KeyMsg. Per-row run-start timestamps stamped on
    first event from each agent (regression-prevented: PR #1018 used a
    single TUI-start timestamp that inflated late-starting agents'
    durations). Single cancel function: KeyCtrlC and out-of-TUI SIGINT
    both call the same context.CancelFunc, gated by sync.Once.
  - review/tui_detail.go: alt-screen drill-in. Ctrl+O enters; left/right
    cycles agents; up/down scrolls; Esc returns. detailView pads to
    termHeight so every frame returns the same line count (avoids ghost
    rows in the alt-screen frame diff). ANSI/CSI sequences stripped per
    line. Rune-safe truncation via stringutil.TruncateRunes.

Wires dispatch in cmd.go's runMultiAgentPath: TTY mode composes
[TUISink, DumpSink] (TUI for live dashboard, DumpSink for post-run
narrative); non-TTY composes [DumpSink] alone. tea.WithoutSignalHandler
keeps SIGINT routing on the cobra root's existing handler so the
single-cancel contract holds even when the TUI captures KeyCtrlC.

Anti-features explicitly NOT recreated:
- sync.Once-guarded onCancel + parallel signal.Notify goroutine: replaced
  by a single shared context.CancelFunc gated by one sync.Once on the model
- cancelMsg dead-code type: omitted entirely
- byte-slice truncation: stringutil.TruncateRunes throughout
- single TUI-start timestamp: per-row runStart stamped on first event
- missing alt-screen on drill-in: tea.EnterAltScreen on Ctrl+O
- variable-line-count detail render: detailView pads to termHeight

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants