Repository navigation
fix(ui): replay stopped Worker history at recorded PTY grid, copy transcript selections, link bare web hosts - #16
Conversation
…sessions Engine: a dead run never finished its subagent sinks, so after a restart the subagent doc kept a `streaming` last entry (the subagent tab spun forever) while the parent chip was already settled `failed` - the Details widget and the tab disagreed. Boot recovery now settles both sides together: chips still `running` flip to `failed`, and every chip settled by the recovery has its subagent doc's abandoned streams stamped `aborted`. A subagent that genuinely resumes reopens both as `running`. UI: a Workers worktree with sessions no longer draws its own header row; its sessions sit at the parent project's level, each led by a green branch mark (tooltip: the branch). Empty worktrees keep their header. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122ykZEFtNWWut4VkghZ1DQ
The Details "Projects worked" rows wear the green branch mark for Workers worktree projects (same rule as the Workers sidebar/titlebar), the folder otherwise. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122ykZEFtNWWut4VkghZ1DQ
Differential TUIs (Claude Code, pi, codex) redraw by moving up the rows their last frame took and rewriting only changed cells. Decoding output.bin at the panel's grid, or at 300 columns for a stopped Worker, lands those moves on the wrong rows: new words fill in over stale ones. The vendored session host now journals every PTY grid change with its output offset. The Workers terminal decodes history at the recorded grid, estimates it for sessions recorded before the journal (row-wide rule width, 24 rows), and keeps a stopped Worker at its recorded width with horizontal scroll instead of reflowing it into a narrower panel. The chat side pane now tells the terminal when its Worker has stopped. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122ykZEFtNWWut4VkghZ1DQ
…ronsh#599) Clicking the transcript blurs the composer, whose Copy action was the only handler, so the shortcut copied nothing. Ports upstream e13b18d unchanged: the main chat and right pane copy the markdown selection from a bubble-phase key-down listener. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122ykZEFtNWWut4VkghZ1DQ
`www.site.com.br` in backticks matched the filename heuristic (`.br` as an extension) and opened a missing file under the project root. Hosts with a `www.` prefix or a generic label (com/net/org/gov/edu) now render as web links with their favicon. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0122ykZEFtNWWut4VkghZ1DQ
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
| if flatten { | ||
| return div() | ||
| .w_full() | ||
| .flex() | ||
| .flex_col() | ||
| .children(rows) | ||
| .children(reveal_control) | ||
| .into_any_element(); |
There was a problem hiding this comment.
Populated worktrees lose project actions
When a worktree has a visible session, this return removes its project row before the project menu and launch controls are built. The replacement rows offer only session actions. Users cannot reach that worktree’s checkout actions or start another Worker through its sidebar controls while sessions are present.
Artifacts
Source-extracted worktree control probe
- The authored command extracts the changed Rust return, compiles a focused before-and-after runtime harness, and records each run.
Parent-revision runtime harness
- The generated Rust harness exercises the parent revision’s path past the project-row boundary with zero and one worktree session.
Parent revision: project row remains with a session
- The compiled parent-revision probe ran successfully and showed a project row alongside the session row.
- The generated Rust harness includes the early-return expression extracted from the changed source.
Current code: populated worktree has only a session row
- The compiled current-code probe ran successfully and showed that the project row is absent when a worktree has one session.
| .capture_any_mouse_down(cx.listener(|this, _, window, cx| { | ||
| this.capture_navigation_focus(true, false, window, cx); | ||
| })) | ||
| .on_key_down(|event, _, cx| navigation_focus::copy_transcript_selection(event, cx)) |
There was a problem hiding this comment.
A transcript selection can remain after focus moves to the right pane. When the focused terminal has no selection and lets Cmd+C pass through, this pane handler copies the old transcript selection instead. This non-blocking concern can unexpectedly replace the clipboard with unrelated text.
Artifacts
Source-extracted transcript-copy check
- The authored script extracts the production copy handler and generates a Rust check using the production selection module.
Executed Rust source for transcript copy
- The generated source checks clipboard behavior with a settled transcript selection and a modeled focused terminal without a selection.
Clipboard before the pane copy handler
- The before run left the clipboard unchanged and allowed the copy keystroke to propagate.
Clipboard after the pane copy handler
- The changed handler copied the earlier transcript selection and stopped propagation.
Comments Outside DiffThese findings could not be posted inline.
|
…rates/ui/src/markdown/inline_chips.rs::render`. I couldn't run those three tests here, because they only compile on Linux and Windows. The full `zeron-ui` suite passes on this Mac (2011 passed, 0 failed), and `cargo fmt --check` is clean. **Cause:** since the Codex-links commit, a paragraph containing a web link renders through `inline_chips::render`. That function gave every segment a derived key. So the first segment's text was registered as `link-fixture:0-inline-0:<nested ix>` instead of `link-fixture:0`, and the tests' lookup of `link-fixture:0` panicked with "painted text". The rule that was broken: a paragraph's leading text must keep the paragraph's own key, `{row_key}:{ix}`, whether or not it has inline chips. That key is what selection lookup and ownership use. **Fix:** only the non-chip segment whose range starts at 0 keeps the paragraph's identity: - It uses `part_ix = ix` and keeps `opts.row_key`, so it paints as `{row_key}:{ix}`. - `selection_group` is still set on it. - All later segments and every chip, including a chip at offset 0, keep their derived keys (`{group}-inline-{start}` and `nested_ix(ix, usize::MAX, start)`). Each element index stays unique, so the RowVeil concern in the existing comment still holds. The tests are unchanged and the favicon grouping is untouched. Chips only take their key from this one computation, so there was no other place to fix. The fix was checked by tracing the fixture: `[Docs](https://example.com/docs)` is a single non-chip web-link segment at 0, so it now paints as `link-fixture:0`
Intent
The developer wanted to ship three pending fixes to main in the comet fork. The first makes stopped Worker terminal tabs opened from the chat panel replay their history at the PTY grid size where they originally ran, with frozen width and horizontal scroll, so the log no longer comes out garbled. The second ports upstream zeronsh#599 so Cmd/Ctrl+C copies a text selection in the chat transcript even when the composer isn't focused, since partial selections couldn't be copied before. The third makes a bare web host written as inline code (like www.jkdistribuicao.com.br) render as a real clickable link that opens the https URL, instead of being treated as a file path relative to the project folder. They asked to commit everything, send it to main through the repo's normal no-mistakes gate flow, and then clean up the branch.
What Changed
─rules. Covered by an OpenSpec change (replay-worker-history-at-recorded-geometry) and an updatedthird_party/unpeel-upstream.toml.www.example.com.br, now renders as a link that openshttps://…instead of resolving as a path in the project.runningflip tofailed, and the subagent docs get their abandoned streams stampedaborted. New tests inrestart_resume.rscover this.🤖 Generated with Claude Code
Risk Assessment
🚨 High: The code fixes are sound (marks are re-read on each catch-up poll, and the web-host rule is narrowed as the user chose), but the fix round committed unrelated tooling config that would ship to main with hook paths pointing at a worktree that is about to be deleted, plus an unpinned
npx -yMCP server.Testing
I ran the targeted tests for each fix and all passed: the zeron-ui worker-terminal journal replay tests, the transcript Cmd/Ctrl+C gpui VisualTestContext tests (including the guard that a terminal keeps Ctrl+C), the inline-code web-host detection tests (including rejecting README.org, COMMAND.COM and example.com), and the workers-unpeel legacy-geometry test. The unpeel-core geometry journal test could not run because that crate is outside the workspace. No screenshot or video was captured. The app is a native gpui window with no headless render harness, and the only capture available was the user's live desktop, so the live checks (seeing the terminal render, pressing Cmd+C in the transcript, clicking the link) could not be driven without taking over the user's session.
www.jkdistribuicao.com.brrenders as a link that opens https://www.jkdistribuicao.com.brREADME.org,COMMAND.COMandbrain.mdstill open as project files, not web linksEvidence: Targeted zeron-ui test run
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
crates/engine/AGENTS.md- branch carries 2 commit(s) that exist on your local main branch but were never pushed to origin/main; these may be unintended bundled work (proposed PR changes 24 file(s)):Confirm these commits belong in this PR before approving, or manually separate the intended work onto origin/main before gating.
crates/ui/src/workers/terminal.rs:772- During catch-up the PTY geometry marks are read only once (load_marksfires only whilegeometry_marks.is_none(), thenstate.geometry_marks = Some(marks)at line 857 caches them for the rest of catch-up). The proposal says the same replay also applies to a live Worker's history. On a live session, the firston_grid_metrics(line ~984) sendsclient.resize(panel cols/rows), and the host writes a new mark at offset X (session_host.rs:7570). If that mark lands after the marks read in the first poll but beforebacklog_end(the first viewport'soutput_offset), thenfeed_at_recorded_geometrydecodes every byte in [X, backlog_end) at the old grid. The same happens to a chunk that crosses backlog_end with bytes past X. Those bytes are the TUI's SIGWINCH redraw at the new size, so the screen comes out garbled — the very defect this change fixes — until the TUI does another full redraw. Concrete sequence: a live Claude Code Worker whose PTY is 120x48 is opened in a 100x40 panel. The poll reads marks [..,120x48], the resize writes 100x40@X, and the output read returns the backlog plus the redraw, all fed at 120x48. Fix: re-read the journal on every catch-up poll instead of caching it once.read_pty_geometryis a small local file read, already on the background executor; for example, setload_markswheneveris_catching_up()and replacegeometry_markseach time.crates/ui/src/markdown/inline_chips.rs:64-web_host_urlcounts any label after the first that equals com/net/org/gov/edu as proof of a web host, andfile_targetnow returns None whenever it matches (line 74). So a bare filename in inline code, such asnotes.org,README.orgortodo.org(Org-mode files), and alsoCOMMAND.COM, stops opening as a project file. It renders blue with a favicon and opens https://README.org instead. Paths with a directory (docs/notes.org) are unaffected, because only the text before the first/is tested. The docstring already rejects bare TLDs because.md,.shand.rscollide with file extensions, but.orghas the same collision. Stated intent only needs hosts likewww.jkdistribuicao.com.brandsite.com/loja. A narrower rule would cover it: awww.prefix, a generic label that is not the last label (x.com.br), or a generic last label only when followed by/path. This changes which strings link, so it needs your decision.🔧 Fix applied.
1 error still open:
.cursor/hooks.json:7- Fix round 1 (commit da2c632) committed editor and agent tooling config that has nothing to do with either finding it was fixing. It looks like the graft indexer rewrote these files inside the pipeline worktree. (1).cursor/hooks.json:7,12,17: the hook paths changed from the user's real checkout (~/Documents/Projetos/SelfHosting/comet/...) to this temporary no-mistakes worktree (~/.no-mistakes/worktrees/6fec5bb7ba85/01M3MYAQS768G5B47VRFZQJD6V/...). Once this merges to main and the worktree is cleaned up (which the user asked for), every Cursor postToolUse, afterMCPExecution and sessionEnd hook will point at a file that no longer exists. (2).mcp.json:4-7and.cursor/mcp.json:4-7: the graft MCP server switched from the localgraftbinary tonpx -y @nanonets/graft, which fetches and runs whatever npm version is latest, unpinned, on every session. (3) Newopencode.jsonwith the same npx setup, new.claude/skills/graft/SKILL.md(156 lines), andstatusLine/subagentStatusLineentries in.claude/settings.json:69-76. The user wanted three UI fixes; nothing asked for these. Fix: restore these files to their 45197b0 state (git checkout 45197b07 -- .cursor/hooks.json .cursor/mcp.json .mcp.json .claude/settings.json, thengit rm opencode.json .claude/skills/graft/SKILL.md).🔧 Fix applied.
1 error still open:
.cursor/hooks.json:7- Fix round 1 (commit da2c632) committed editor and agent tooling config that has nothing to do with either finding it was fixing. It looks like the graft indexer rewrote these files inside the pipeline worktree. (1).cursor/hooks.json:7,12,17: the hook paths changed from the user's real checkout (~/Documents/Projetos/SelfHosting/comet/...) to this temporary no-mistakes worktree (~/.no-mistakes/worktrees/6fec5bb7ba85/01M3MYAQS768G5B47VRFZQJD6V/...). Once this merges to main and the worktree is cleaned up (which the user asked for), every Cursor postToolUse, afterMCPExecution and sessionEnd hook will point at a file that no longer exists. (2).mcp.json:4-7and.cursor/mcp.json:4-7: the graft MCP server switched from the localgraftbinary tonpx -y @nanonets/graft, which fetches and runs whatever npm version is latest, unpinned, on every session. (3) Newopencode.jsonwith the same npx setup, new.claude/skills/graft/SKILL.md(156 lines), andstatusLine/subagentStatusLineentries in.claude/settings.json:69-76. The user wanted three UI fixes; nothing asked for these. Fix: restore these files to their 45197b0 state (git checkout 45197b07 -- .cursor/hooks.json .cursor/mcp.json .mcp.json .claude/settings.json, thengit rm opencode.json .claude/skills/graft/SKILL.md).www.jkdistribuicao.com.brrenders as a link that opens https://www.jkdistribuicao.com.br, Adversarial: inline-code filenames such asREADME.org,COMMAND.COMandbrain.mdstill open as project files, not web linkswww.jkdistribuicao.com.brrenders as a link that opens https://www.jkdistribuicao.com.brREADME.org,COMMAND.COMandbrain.mdstill open as project files, not web linkscargo test -p zeron-ui --lib -- journal_replay bare_hosts_in_code copy_shortcut ctrl_c_in_a_terminal inline_chips(11 passed)cargo test -p zeron-workers-unpeel -- the_row_wide_rule(legacy geometry estimate, passed)cargo test -p unpeel-core --lib -- pty_geometry_journal(could not run: the crate is not a workspace member, so its dev-dependencies are unavailable)screencapture -xprobe: screen capture works, but it only captures the user's active desktop; probe deleted because it held private content✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.