review button highlight
This commit is contained in:
+1
-1
@@ -385,7 +385,7 @@ Every new snapshot of a task gets a review: a separate agent session on the vend
|
||||
- **Forwarding.** When a submitted review has findings, byre sends them to the task's live agent as a `byre` message (`forwardFindings` and `findingsMessage` in `internal/agents/review.go`): each finding's severity, title, location and detail, under a preamble asking the agent to check each one against the code and its brief, act on those that hold up, and say in its final message which it acted on and which it left and why. It goes through `Manager.Message`, so it is queued like any message while the agent is mid-turn. A task with no live agent session gets nothing, and the log says `review findings not forwarded`. Forwarding doesn't set any finding's state; **fix** and **ignore** stay available.
|
||||
- **Screenshots.** Reviewer sessions also get the Playwright MCP server (`playwrightMCP` in `internal/agents/review.go`: `npx @playwright/mcp` at a pinned version, headless Chrome, isolated profile, absolute file paths), passed to Claude as a `stdio` entry in `--mcp-config` and to Codex as `mcp_servers` in the thread's `config`. Its automatically named files go to `worktrees/<project-id>/review-<review-id>-media`, removed with the checkout. Each `images` entry is `{path, caption}`, the path absolute or relative to the checkout; at `submit_review` byre reads every one, refuses the whole submission (nothing recorded) for a missing file or one that isn't one of `store.ImageTypes` within `store.MaxBlobBytes`, then stores each as a blob and replaces its `path` with `blob`, since the files are deleted with the checkout. They run without the Stop-hook bounce, mid-turn delivery, end-of-turn commit, snapshots or turn summaries, and their `user.message` events carry no `head`. When the reviewer's turn ends byre completes its session, kills its process and removes the worktree; a review still `running` then fails with why (no submission, with the final message; an error; an interrupt). A process that exits mid-turn fails the review the same way. `StopReview` (`POST /api/reviews/{reviewId}/stop`, the Stop button on a running review's card) ends the reviewer the same way and fails the review ("the reviewer was stopped"), and `Watch` calls it for a reviewer whose process the health check finds `stuck` (no stream event for `StuckAfter`), which is how a reviewer whose connection died while the machine slept gets cleared. Merging or discarding the task fails its running reviews ("the task was closed") and ends their reviewers. On startup, a running reviewer resumes like any session, and a running review whose reviewer isn't `running` fails.
|
||||
- **Events.** `review.started`, `review.finished` (state `done`, `failed` or `skipped`; a skipped review emits only `review.finished`) and `review.finding` (a finding's state set, with the user as actor) carry the whole review, with the task's ids and no `agent_session_id`. A reviewer's own events carry its session id and the task's ids: the transcript skips every event of a session whose `session.created` has `role` `reviewer`, and draws each `review.finished` as a note with its outcome; the lead's `read_transcript` leaves the reviewer's events out and shows each `review.finished` with its summary and findings (`reviewLine`). `GET /api/tasks/{taskId}/sessions` and everything that looks for the task's agent (`ListSessions`) see only implementer sessions.
|
||||
- **UI.** The **Reviews** tab (`mac/Sources/Byre/Reviews.swift`) shows one review at a time, picked by snapshot (see "Snapshots" for the picker): its snapshot, state or severity counts, error, summary, screenshots and findings, and, while it runs, a **Stop** button (`POST /api/reviews/{reviewId}/stop`). The `change` field is not shown; it goes to the lead and into notes. A finding with `path` and `line` shows, under its title, the lines `line` to `end_line` plus 3 either side from that file's diff for the snapshot against the default branch (`changes?snapshot=<n>`, the diff the reviewer was given), with new-file line numbers and the finding's own lines marked; it shows nothing when those lines aren't in the diff, and "diff not available" with the error once the task is closed. Clicking a screenshot opens it full size. Each open finding has **fix** and **ignore** buttons (also on review cards in the inbox). **fix** sends the finding's severity, title, location and detail to the task's agent as a message from the user: through `POST /api/sessions/{id}/messages` to its latest live session (queued like any message while the agent is mid-turn, see "Agent sessions"), or starting a session when it has none; the view stays where it is, so several findings can be sent in a row. Then it, or **ignore** on its own, records the finding's state (`fixed` or `ignored`) with `PUT /api/reviews/{reviewId}/findings/{index}`, the index being the finding's position in `result.findings`; the review's `finding_states` (the `reviews.finding_states` column, a JSON object from index to state) holds them, and the buttons give way to "fix sent" or "ignored". Only a `done` review's findings take a state, and there is no way to clear one. The tab loads when it opens, when the task changes, and on each `review.*` event in the task's stream. The tab follows the latest `review.*` event of the highest-numbered snapshot: while that review runs, the tab label (and its entry in the More menu) carries no badge, hiding any earlier review's count; once it finishes with open findings (those with no state), the tab (or the More menu holding it) is highlighted with a badge of their count. Each snapshot row's **review** button shows that snapshot's latest `review.*` event: a border in the task's colour while the review runs, and otherwise a mark over its top-right corner: a grey ● when it was skipped, a green ✓ when it finished with no open findings, and, when it has open findings, the button highlighted with their count in a badge. A failed review leaves the button unmarked. While any of a task's reviews is `running` and its agent is idle, the task's state is `reviewing` (see "Task state in the store"), which the task switcher and the Project tab show as **Working** (see "Task state"). `GET /api/tasks/{taskId}/reviews` lists a task's reviews oldest first. `sqlite3 byre.db "SELECT id, task_id, snapshot_n, vendor, state, error FROM reviews ORDER BY created_at DESC LIMIT 20"` shows recent ones.
|
||||
- **UI.** The **Reviews** tab (`mac/Sources/Byre/Reviews.swift`) shows one review at a time, picked by snapshot (see "Snapshots" for the picker): its snapshot, state or severity counts, error, summary, screenshots and findings, and, while it runs, a **Stop** button (`POST /api/reviews/{reviewId}/stop`). The `change` field is not shown; it goes to the lead and into notes. A finding with `path` and `line` shows, under its title, the lines `line` to `end_line` plus 3 either side from that file's diff for the snapshot against the default branch (`changes?snapshot=<n>`, the diff the reviewer was given), with new-file line numbers and the finding's own lines marked; it shows nothing when those lines aren't in the diff, and "diff not available" with the error once the task is closed. Clicking a screenshot opens it full size. Each open finding has **fix** and **ignore** buttons (also on review cards in the inbox). **fix** sends the finding's severity, title, location and detail to the task's agent as a message from the user: through `POST /api/sessions/{id}/messages` to its latest live session (queued like any message while the agent is mid-turn, see "Agent sessions"), or starting a session when it has none; the view stays where it is, so several findings can be sent in a row. Then it, or **ignore** on its own, records the finding's state (`fixed` or `ignored`) with `PUT /api/reviews/{reviewId}/findings/{index}`, the index being the finding's position in `result.findings`; the review's `finding_states` (the `reviews.finding_states` column, a JSON object from index to state) holds them, and the buttons give way to "fix sent" or "ignored". Only a `done` review's findings take a state, and there is no way to clear one. The tab loads when it opens, when the task changes, and on each `review.*` event in the task's stream. The tab follows the latest `review.*` event of the highest-numbered snapshot: while that review runs, the tab label (and its entry in the More menu) carries no badge, hiding any earlier review's count; once it finishes with open findings (those with no state), the tab (or the More menu holding it) is highlighted with a badge of their count. Each snapshot row's **review** button shows that snapshot's latest `review.*` event: a fill in the accent tint (`Palette.accentTint`, the same in every task) while the review runs, and otherwise a mark over its top-right corner: a grey ● when it was skipped, a green ✓ when it finished with no open findings, and, when it has open findings, the button highlighted with their count in a badge. A failed review leaves the button unmarked. While any of a task's reviews is `running` and its agent is idle, the task's state is `reviewing` (see "Task state in the store"), which the task switcher and the Project tab show as **Working** (see "Task state"). `GET /api/tasks/{taskId}/reviews` lists a task's reviews oldest first. `sqlite3 byre.db "SELECT id, task_id, snapshot_n, vendor, state, error FROM reviews ORDER BY created_at DESC LIMIT 20"` shows recent ones.
|
||||
|
||||
## Workflows
|
||||
|
||||
|
||||
@@ -1185,7 +1185,6 @@ private struct SnapshotRow: View {
|
||||
let taskId: String?
|
||||
@Environment(Store.self) private var store
|
||||
@Environment(Overlays.self) private var overlays
|
||||
@Environment(\.paneAccent) private var accent
|
||||
@ViewState private var forking = false
|
||||
|
||||
var body: some View {
|
||||
@@ -1261,7 +1260,7 @@ private struct SnapshotRow: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttonStyle(SmallLinkButtonStyle(color: n > 0 ? Palette.warn : Palette.accent, border: review?.state == .running ? accent : Palette.border))
|
||||
.buttonStyle(SmallLinkButtonStyle(color: n > 0 ? Palette.warn : Palette.accent, fill: review?.state == .running ? Palette.accentTint : .clear))
|
||||
.help(review?.state == .running ? "Review in progress; show snapshot \(snap.n)'s review in the Reviews tab" : "Show the review of snapshot \(snap.n) in the Reviews tab")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,6 +402,7 @@ private struct WebButton: View {
|
||||
struct SmallLinkButtonStyle: ButtonStyle {
|
||||
var color = Palette.accent
|
||||
var border = Palette.border
|
||||
var fill = Color.clear
|
||||
@Environment(\.isEnabled) private var enabled
|
||||
|
||||
func makeBody(configuration: ButtonStyleConfiguration) -> some View {
|
||||
@@ -409,6 +410,7 @@ struct SmallLinkButtonStyle: ButtonStyle {
|
||||
.font(Fonts.font(11))
|
||||
.foregroundStyle(color)
|
||||
.padding(.horizontal, 6)
|
||||
.background(fill, in: RoundedRectangle(cornerRadius: 4))
|
||||
.overlay(RoundedRectangle(cornerRadius: 4).stroke(border))
|
||||
.opacity(enabled ? 1 : 0.45)
|
||||
.contentShape(Rectangle())
|
||||
|
||||
Reference in New Issue
Block a user