Repository navigation
Add a repository-scoped PR board and native inspection - #484
Conversation
7d8447c to
56b46c0
Compare
5f15414 to
dbcde26
Compare
7ff7f8c to
67157dd
Compare
|
Findings, all validated manually, here's my clanker's briefing of each one of them: I reviewed commit 1. Duplicate comment submission after closing and reopening the PRRelevant code:
Reproduction:
The original request continues after the view closes, but the replacement view has no knowledge of it. Both requests can succeed, publishing the same comment twice. The existing guard prevents duplicate submissions only within one view instance. Recommended fix: Track pending submissions in shared state keyed by device and PR URL. Reopened views should observe that state, display the pending submission, and prevent resubmitting it until its outcome is known. Keep the submitted body separate from subsequent draft edits so completing the request cannot overwrite newer text. Add a regression test that holds the first response pending, closes and reopens the view, attempts another submission, and asserts that only one POST occurred. 2. Refreshing the board can still reopen an outdated detail and diffRelevant code:
Reproduction:
The detail view can restore commit A and its cached diff despite receiving a preview that already identifies commit B. This can cause the user to review an outdated patch. The new Recommended fix: Compare the cached detail's Add a regression test with a cached detail/diff for A and an incoming board preview for B, without calling the detail view's Refresh action. Assert that the old patch is invalidated and a fresh request is made. 3. Agent handoff can use the wrong project or deviceRelevant code:
Reproduction:
The generated prompt identifies the selected PR, but session creation does not receive its repository/project or target device. The session can therefore inherit project A or the previous canvas's device. This leaves the agent with a prompt for one repository and a working environment associated with another. Checkout commands may fail, or the agent may begin work from an unintended checkout or machine. Recommended fix: Extend the handoff action to carry the selected device and repository/project context alongside the prompt. Resolve a matching checkout on that device before staging the session. When no matching checkout exists, offer an explicit project selection or clone flow instead of silently inheriting unrelated context. Add coverage where the sidebar/canvas context differs from the board's selected repository and device, and assert that the resulting session uses the intended environment. 4. “Address feedback” omits inline review commentsRelevant code:
A reviewer can request changes and put the actionable instructions entirely in inline threads. The agent then sees the review summary or decision without receiving the actual feedback it was asked to address. Those threads are also absent from Activity. Recommended fix: Retrieve review threads through the GitHub GraphQL API, including:
Update the handoff instructions to retrieve and inspect these threads, prioritizing unresolved feedback while retaining enough context to interpret it. If Activity is intended to show review feedback, include the threads there as well. Add a fixture with a changes-requested review whose actionable feedback exists only in an unresolved inline thread. Verify that the handoff's retrieval path includes that feedback and distinguishes resolved threads. |
|
This includes the text selection bug plus a few others.
Overall validation: 123 existing tests passed. |
Co-authored-by: José Gurruchaga <jsgrrchg@gmail.com>
Co-authored-by: José Gurruchaga <jsgrrchg@gmail.com>
Co-authored-by: José Gurruchaga <jsgrrchg@gmail.com>
Co-authored-by: José Gurruchaga <jsgrrchg@gmail.com>
Show every changed file in one virtualized stream with foldable, sticky file headers, a directory-grouped tree that follows the scroll position, and a compact picker on narrow windows. The tab bar gains counts, neutral selection, and tablist keyboard navigation.
Add ListChangeRequestPage, which follows GitHub search cursors 50 at a time and reports the total match count. Cursors are validated before they reach gh, and the single-page listing keeps serving older clients.
The board shows GitHub's total count and appends further pages on request, without repeating a PR that moved between pages. Engines without paging fall back to the single-page listing.
…eronsh#777) * Fix durable remote send and host wake recovery * Couple accepted chat rows to durable server host wakes * Make Linux browser captures wait for mapped and presented frames --------- Co-authored-by: Wing <contact@winglee.io> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Explorer: group finished subagents, show running counts The Subagents section lists running subagents as plain rows, then folds everything finished into a Finished dropdown (closed by default) with Completed and Failed lists inside it. Each list collapses on its own and pages at ten rows. A "● N" pill shows how many subagents are running: on sidebar chat rows (in place of the working spinner), under the titlebar's explorer button, and beside the Subagents title. To badge chats that are not open, the session row now carries `running_subagents`, published by the engine as subagents open and settle. It is optional on the wire and stale rows count as zero, like the working indicator. * Explorer button: pulse and count badge for running subagents The pill hung under the button and crossed the titlebar hairline. Mark the button itself instead: its face breathes in the activity tone and a small count badge sits on its corner, both drawn over the button so titlebar layout is unchanged. * Sidebar: running-subagents pill takes the time stamp's place The pill no longer replaces the row's own activity indicator, so compact titles stop shifting. In compact rows it stands where the time stamp is while subagents run; in regular rows it leads the status label. * Running-count pill and badge: centre the digits The titlebar badge had no explicit line height and used the UI font, so its digit sat about a pixel high; the sidebar pill's digits sat half a pixel low. Both now draw their count through one helper: mono digits in a box exactly as tall as the pill or badge, with a small optical lift (and, for the badge, a rightward shift) measured from rendered captures at one, two and three characters. * Running count: centre digits by font metrics, drop hand-tuned offsets Geist Mono's digits are centred on the line box and each digit's ink is centred in its advance (checked from the font tables), so with the line height equal to the box height nothing needs nudging. The earlier optical offsets were fitted to two monitor scales and gave the same result there as none; at a whole-number scale they would only add error. Residual misalignment is device-pixel rounding of the baseline, at most half a device pixel. * Running-count pill: hang dot and digits off one baseline; balance the 99+ badge The pill's dot was a box centred in the pill while the digits' vertical position followed the text engine's own metrics and rounding, so at fractional display scales the two could differ by a device pixel. The pill now paints its background, dot and digits in one canvas: the digits' baseline is snapped to a device pixel and the dot is centred on the digits' middle from that baseline, so they share a centre at any scale. A capped label ends in '+', whose thin arms leave the eye a wider gap than a digit does; trim the padding after it by a pixel in both the pill and the titlebar badge. * Titlebar count badge: paint it so the digit is centred exactly The badge was a laid-out box, whose text landed on a rounded device pixel and read as the digit sitting left of centre. Paint the badge and its digits in one canvas instead: the digits are centred on the badge's real middle, with the baseline placed as in the sidebar pill. Measured for every digit 1-9 on 1.25x and 1.875x captures: centred to within half a device pixel, exactly for most. * Add running_subagents to Session fixtures added on main Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: wing-anara <wing@anara.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
@wingleeio couldn't find any more edge cases, bugs or improvements for now, LGTM. Thanks @gaelcado 😊 |
…eronsh#522) * feat(transcript): open tool-call files in the files panel Clicking the file badge on a Read/Write/Edit/Patch tool row now opens that file in the right-hand files panel, instead of only expanding the row to show its path. The badge goes through the transcript's existing workspace-link handler, the same route Markdown file links take, so it resolves against the same roots (the chat's checkout, its parent's, and this device's projects) and opens outside absolute paths read-only. The badge stops propagation, so clicking it does not also toggle the row's accordion; the rest of the header still expands the output or diff. Paths the link handler cannot open keep an inert badge rather than looking clickable and doing nothing. * feat(files): open the active file in the default editor Add an "Open in default editor" button to the file viewer's breadcrumb toolbar, next to "Reveal file in tree". It hands the file to the platform's default application (xdg-open, open, ShellExecute) via gpui's open_with_system. The button only appears for workspaces on this device: a remote space's files live on another machine, where the local default app cannot reach them.
|
Found one more issue CMD/Ctrl+C does not copy selected text in Summary. After selecting “First” in the description and pressing Ctrl+C, the clipboard remained unchanged. The PR view lacks the copy handler used by chat and Markdown preview. |
…views Security - Images in pull request text load through the app's bounded decoder (4096 px per side, 64 MiB, one frame, sanitized SVG), at most four at once, instead of GPUI's unbounded image loader. - The image transport refuses NAT64, 6to4, Teredo, IPv4-compatible, multicast, reserved and benchmarking addresses, never uses a proxy (which would resolve names past the public-address check), and sends no Referer on redirects. - Check links open only https pages; handoff prompts drop invisible bidi, zero-width and tag characters; the handoff names the repository from the engine's URL; GetChangeRequestRepository accepts only chat or project checkouts on the device. Board - Virtualized results list (the transcript's ListState pattern), so long boards scroll smoothly; scroll position holds across paging. - The engine keeps the board's first pages in SQLite, one row per pull request per gh account plus each query's ordered results, so the board opens instantly and a pull request reads the same in every filter. An aged page shows at once and refreshes behind it; Refresh always reads GitHub. - Filters read as controls; header controls share one height, refresh sits left of the repository; Load more is a filled button. - Repository identity follows renames and SSH host aliases. Pull request view - Back/forward history covers the board and each pull request; the header is a plain title like the session header. - The code viewer clips to its rounded card per pixel (zui 361ff20, Window::with_rounded_clip). - Your reviews and comments read as yours before you comment (the engine reports the viewer's login); quieter posting and inline-thread rows; Cmd/Ctrl+C copies selected text. - Summary/Code/Activity pill uses the composer's material with spaced segments; the Pull requests entry sits beside Settings; the copy icon no longer overlaps itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main's UI test build fails after zeronsh#522 and zeronsh#813 met: the fixture predates ToolItem::images. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wing-anara
left a comment
There was a problem hiding this comment.
Thanks, Gaël. Approving with follow-ups pushed onto the branch:
- Security: images in PR text now load through the app's bounded decoder (4096 px, 64 MiB, one frame, sanitized SVG, at most 4 at once); the image transport refuses more private/embedded address ranges, never uses a proxy, and sends no Referer; check links open only https; handoff prompts drop invisible bidi/zero-width/tag characters; GetChangeRequestRepository only accepts chat or project checkouts.
- Board: virtualized list, SQLite cache of first pages (one row per PR per gh account), repo identity that follows renames and SSH host aliases, back/forward history, header/filter polish.
- Detail: per-pixel rounded clipping for the code card (zui 361ff20), own-comment detection via the viewer's login, Cmd/Ctrl+C copy, quieter posting and inline-thread rows.
- Also fixes main's broken ReadFile fixture (#522/#813) so UI tests build.
CI is green on 38e2f57.
…acklog window Source: .scratch/upstream-drift/2026-10-11.md. Tickets 01-18 actionable (quick ports, chips supersedes wave-6 03, the sidebar series 06-09, the older missed fixes 13-16, parity verification 17-18); 19 is the GPUI pin sync gating 20 (zeronsh#856) and 22 (zeronsh#813 Windows browser); 21 (zeronsh#484 PR board) PARKED on a product decision.
… push URL is disabled Upstream 73051ec (wave7 ticket 03, upstream zeronsh#863): a push URL that doesn't parse as a remote (a fork's DISABLED--push-to-your-fork-origin- instead placeholder) is ignored, so the checkout inspector falls back to the remote's fetch URL — which still identifies the repository. Deliberately excluded: upstream's repository_for_checkout assertion and helper — that machinery belongs to the zeronsh#484 PR board (ticket 21). Test fixture uses acme/roboco. 28/28 source_control tests.
Wave-7 ticket 06 — port of upstream 05f5f2b + ae19fe3 + 672cc14, with the 2026-10-22 riders 26c8e84 (zeronsh#909, drag-reorder) and 81e04e1 (zeronsh#901, Archived toggle) folded in; the 05f5f2b/ae19fe31 head start came from the saved ticket-06 fold-ins patch. Upstream 672cc14 (searchable popovers, ordered sidebar sections, titlebar sidebar options): - popover: every searchable popover (project, device, branch, spaces, changes ref, font) shares the model picker's search row (40px, magnifier, full-bleed hairline) and 32px picker rows in one tone with scroll edge fades and rails (search_input_frame/search_row rework + picker_row/picker_icon_slot/picker_divider). - Project rows in both project dropdowns wear the project artwork (ProjectIcons extracted from Shell's inline cache into the shared pipeline shape, now owned by Shell and Pickers); the device tag is gone from the spaces dropdown and the sidebar filter trigger. - All sidebar section headings share one header; collapsed sections show a muted count badge (monospace, cut like the PR badge) instead of a "(N)" label suffix; header glyphs share the label's tone. - Custom sections keep a placed order, as Pinned does: assign carries optional after/before anchors (section_insert_index, the pin rule), drags reorder members in place (sidebar_section_drop_anchors reads the preview gap), and the sidebar lists section members in placed order rather than by activity. - The view options moved to the titlebar at the sidebar's trailing edge (render_sidebar_options_titlebar, sliding/fading with the sidebar, occluded over the drag strip); View > Show gains a Project filter toggle (hiding it clears the filter) and SIDEBAR_MIN widened 224 -> 242 so the options button fits beside the titlebar controls. - Polish: agent-update pill summary fits the card border (no left strip), thinking/tool-call group headers roll as their summary changes. Rider 26c8e84 (zeronsh#909): dragging a section header lifts the section (frosted, in the list's movement layer) and slides its siblings aside; releasing outside the sidebar sends it home. Roboco's engine-local equivalent of SidebarSectionChange::Move: the reorder splices the sections list and pushes the SetSidebarSections snapshot. Rider 81e04e1 (zeronsh#901): sidebar toggle for the Archived section (sidebar_show_archived) — hidden removes the whole shelf without touching its chats or disclosure state; a reveal into it re-enables it. Wire change: the SidebarSection proto doc now states the placed-order contract — membership and the section list carry their placed order in the array order through the engine-local LWW replaces. Upstream's per-member fractional orderKey registry rows + HLC clocks exist only for cross-device convergence, which roboco excludes (ADR 0004); the engine store already preserves list order, so no per-key minting and no sidebar-section-order-v1 capability gate were carried. Wiregen regenerated (SidebarSection.ts doc); --check gate green. The web peer (sectionRows) lists members in placed order, with tests. Excluded by intent: crates/client hunks (cloud), pull_requests.rs popover hunks (rides parked zeronsh#484/ticket 21), crates/mobile FFI pin_session_at/place_session (Android parity — held for a mobile follow-up per ticket step 6), iOS hunks, and the registry cross-device convergence tests (replaced by the engine-side placed-order restart test plus UI placed-order/drag/anchor tests). Verification: cargo check -p roboco-doc -p roboco-proto -p roboco-ui; cargo test -p roboco-ui (1618 passed); sidebar-sections/spaces/ pickers/appearance/changes/chat-rename/transcript/harness-updates tests; cargo test -p roboco-engine sidebar_state (10 passed); wiregen --check green; pnpm -r build green; web vitest sidebar suites green (6 unrelated failures reproduce on clean main).
Upstream a408a81 (wave7 ticket 09, the standalone half): - toast.rs (new, verbatim port): Sonner-style toasts stacked in the window's bottom-right corner — 4s countdown that pauses while hovered or the window is inactive, up to three visible with 5% step-narrowed cards, fan-out on hover, rise-in/fade-out motion, swipe-right-to- dismiss, and repeat-toasts restarting the front one instead of stacking. Push with show/error/success/info; take_error lifts a view's pending Option<error> into a toast (deferred — never mid-render). The shell mounts render_toaster once per window, over every phase and route. - shell.rs: show_notice() replaces every direct sidebar_notice write (deep-link notices Info, copy confirmations Success, mutation/ rename/pin failures Error); the field survives as the toast-message mirror the pin-write seam matches (clear_pin_write_notice). The sidebar's inline mutation-failure strip is gone. The chat context menu's Copy row now opens a nested submenu beside the card — hover intent with a grace toward the open submenu (the sidebar options menu's HoverIntent recipe), side-aware placement, presses inside the submenu no longer dismiss the menu first, and the old in-place Copy page (Back row) is deleted. Copy confirmations are success toasts. - Call-sites swapped to toasts: actions_ui (setup action failures), harness_updates (agent update failure), sidebar_pins (set_pin_write_notice), sidebar_sections (engine/archive failures), spaces (project-filter rename refusal). - Settings + dictation: accounts, appearance (background_error), archived, devices, harnesses, thread_naming and the voice card surface their transient action errors as toasts via take_error at render top; the inline dismissable error strips are removed. Roboco-specific: devices keeps the durable registry configuration_error inline (engine-local config state, not a transient action error). notify.rs (OS desktop banners) and notice.rs (composer/transcript notice chip) are not the surface this commit replaces — untouched. - Tests: the toast.rs suite (expiry/pause, dedupe, glide reversal) and copying_from_the_copy_submenu_shows_a_toast in sidebar_sections (chat-copy-roboco); the archived delete-all failure test now asserts the toast surface. Deliberately excluded: every pull_requests.rs repository-menu hunk (roboco has no pull_requests.rs; the picker-style repository menu rides parked ticket 21 / upstream zeronsh#484), and the cloud sign-in / cancel-sign-in notice hunks in shell.rs (roboco has no cloud sync — no counterpart call sites). No wire changes. Verification: cargo check -p roboco-ui clean (no new warnings); cargo test -p roboco-ui 1617 passed.
Adds a Pull requests board for one GitHub repository, a native pull request view (Summary, Code, Activity), comment posting, and "hand off to an agent" actions. Everything goes through the
ghCLI already installed and signed in on the selected device.Builds on José Gurruchaga's (@jsgrrchg) pull request dashboard from #181 (closed, unmerged). His pull request contracts, GitHub CLI queries and board foundation were ported onto current
main; the commits carrying that work credit him withCo-authored-by. The detail view, code review, activity, media, handoff and paging are new.Board
Pull request view
@suggests the pull request's participants.Engine and protocol
ListChangeRequestPage,GetChangeRequestRepository,GetChangeRequest,GetChangeRequestDiff,PostChangeRequestComment. Repository, URL and cursor are validated before they reachgh;GH_HOSTis pinned to github.com.RpcError::Capability), never asghoutput. The UI turns them into instructions.ghcall, distinct reads run side by side, and a read finishes and is cached even if its caller leaves. Writes are never retried.ghon standard input. A comment keeps posting if the view is closed; a failed one comes back as a draft with the reason.ServerFramenow delivers a unary reply whose value isnull(previously the caller waited for its own timeout). This affects every RPC that can answernull.Privacy
Out of scope
Review submission and merging stay on GitHub. GitHub Enterprise hosts open in the browser.
Rebase validation
Rebased the 37-commit series onto
mainatd5c1cdc124c8d403eb0a11e94a8dae4a381fc958. New head:12c9d5241844040efcfed651354c33d5fb24fb32.cargo check -p zeron -p zeron-engine -p zeron-ui -p zeron-mobile --all-targetspassed at8300b646. The final head differs from that tested head only by formatting the shared tooltip signature.cargo test -p zeron-ui --lib -- --test-threads=1: 1,617 passed at8300b646.12c9d524,cargo test -p zeron-engine -p zeron-rpc -p zeron-proto -p zeron-client --lib -- --test-threads=1: engine 406 passed / 2 ignored, RPC 17 passed, protocol 64 passed, client 21 passed.12c9d524, the engine integration testpull_request_list_dispatch_returns_provider_itemspassed.cargo check -p zeron -p zeron-engine --all-targetsindependently.12c9d524,cargo check -p zeron-ui --example pull-request-fixture --features pull-request-fixturepassed.main;git diff --checkpasses.The rebase preserves upstream's repository identity fields, composer attachment chips, icon registry and animated sidebar glyph. No new runtime screenshots were captured during this rebase. The visual evidence below is from the earlier published head.
Earlier validation
At
9a236a8b, on macOS:cargo test -p zeron-ui --lib -- --test-threads=1: 1,466 pass.cargo test -p zeron-engine --lib: 405 pass.cargo test -p zeron-rpc -p zeron-proto: pass.cargo test -p zeron-engine --test e2e: 26 pass;generated_image_is_materialized_before_publication_and_survives_reopenfails locally and fails the same way onmain.cargo test -p zeron-client -p zeron-mobile -p zeron-markdown: pass.cargo run -p zeron-ui --example pull-request-fixture --features pull-request-fixture -- <dir> zeronsh/zeron 484) loads the board, Summary, Code and Activity against real GitHub in dark and light themes.All comment submissions in tests use fakes; no live comment was posted.