Skip to content

fix(tui): fix rendering corruption over multipass + Windows Terminal#709

Open
euxaristia wants to merge 10 commits into
Gitlawb:mainfrom
euxaristia:fix/multipass-remote-terminal-rendering
Open

fix(tui): fix rendering corruption over multipass + Windows Terminal#709
euxaristia wants to merge 10 commits into
Gitlawb:mainfrom
euxaristia:fix/multipass-remote-terminal-rendering

Conversation

@euxaristia

@euxaristia euxaristia commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Zero's TUI rendered corrupted/overlapping text when run inside a multipass VM and displayed through Windows Terminal on the host, worse on window resize. Two separate bugs, both in the bubbletea v2 renderer:

  • Hard scroll optimization (using terminal scroll-region sequences instead of repainting) is only disabled upstream when GOOS == "windows". That misses this case: the zero process itself runs on Linux inside the VM, but the terminal actually displaying the output is Windows Terminal reached over a remote shell. This vendors a patched bubbletea/v2 (local go.mod replace) with scroll optimization disabled unconditionally, since there's no reliable way to detect that remote hop from inside the VM.
  • Even with scroll optimization off, the renderer's incremental cell diff sometimes failed to clear the streaming-text caret's old cell when a newline moved it to a new line, leaving ghost carets behind. Fixed by firing tea.ClearScreen specifically when a streamed delta contains a newline, forcing a full redraw at exactly the moment the caret moves rather than relying on the diff.

Test plan

  • go build ./... and GOOS=linux GOARCH=amd64 go build ./...
  • go test ./... (full suite passes)
  • Verified interactively inside a multipass VM over Windows Terminal: both the original garbled-text corruption and the leftover-caret artifact are gone.

Summary by CodeRabbit

  • Bug Fixes

    • Improved streamed text rendering to prevent ghost carets and stale screen artifacts.
    • Improved terminal display reliability on Windows, including remote and virtual machine sessions.
    • Added broader support for terminal input, output, colors, mouse events, clipboard operations, and screen management.
  • Documentation

    • Clarified that versioned source installs require cloning the repository before building.
  • Tests

    • Expanded rendering, terminal lifecycle, input, and cross-platform reliability coverage.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@euxaristia, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f730044c-1e3f-4d9a-8661-d1bb6c303b1e

📥 Commits

Reviewing files that changed from the base of the PR and between 8cb5469 and 9c4d9a9.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml

Walkthrough

The PR vendors a patched Bubble Tea v2 module, adds terminal rendering and runtime APIs, repairs throttled streaming redraws, documents local-build requirements, and runs both the root and patched-module test suites.

Changes

Bubble Tea patch integration

Layer / File(s) Summary
Local Bubble Tea fork and runtime
patches/bubbletea-v2/...
Adds the Bubble Tea v2 API, terminal runtime, renderer, platform-specific TTY handling, event translation, command execution, and associated tests and golden outputs.
Streaming redraw repair
internal/tui/model.go, internal/tui/stream_clear_test.go
Throttles newline-triggered tea.ClearScreen commands, schedules deferred flushes, flushes pending clears at stream end, supports ZERO_NO_STREAM_CLEAR, and tests coalescing and mid-stream repair.
Repository wiring and build guidance
go.mod, Makefile, .github/workflows/ci.yml, README.md, docs/INSTALL.md
Redirects Bubble Tea to the local fork, adds patch-module test targets and CI coverage, and documents clone-based source builds.
Fork metadata
patches/bubbletea-v2/LICENSE, patches/bubbletea-v2/go.mod
Adds the fork license and module dependency metadata.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • Gitlawb/zero#223: Overlaps in internal/tui/model.go streaming command assembly and fade-tick handling.
  • Gitlawb/zero#669: Also modifies Bubble Tea v2 dependency resolution in go.mod.

Suggested reviewers: anandh8x, gnanam1990, vasanthdev2004

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: fixing TUI rendering corruption in multipass/Windows Terminal.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 17

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@third_party/bubbletea-v2-patched/commands.go`:
- Around line 1-175: Move the maintained Bubble Tea fork out of third_party/ to
a repository-approved location, preserving package structure and references for
commands.go, environ.go, profile.go, and options.go. Move options_test.go and
tea_test.go beside the relocated runtime, along with all four listed
TestViewModel golden fixtures. Do not leave maintained source or tests under
third_party/; obtain an explicit policy exception instead if relocation is not
possible.

In `@third_party/bubbletea-v2-patched/cursed_renderer.go`:
- Around line 605-614: Move the patched Bubble Tea integration out of
third_party into a maintained fork or non-vendored local module, preserving the
cursedRenderer scroll-optimization change in cursed_renderer.go and its
cursor.go, renderer.go, logging.go, logging_test.go, and all listed testdata
golden fixtures. Update module/package references so the application and tests
use the relocated implementation, leaving no edited dependency files under
third_party.
- Around line 734-741: Update the wrapping-row calculation in the loop over
lines to count only the additional rows required when a line exceeds the
terminal width: use ceiling division for the total wrapped rows, then add one
fewer row beyond the initial row. Ensure an exact multiple such as 160 columns
at width 80 contributes one additional row, preventing blank lines in unmanaged
output.
- Around line 410-431: Replace direct color.Color comparisons in the render diff
loop and viewEquals with a shared nil-safe helper that compares normalized RGBA
values, avoiding interface equality and panics from non-comparable
implementations. Use the helper for cc/lcc, view.ForegroundColor/lfg, and
view.BackgroundColor/lbg while preserving nil reset behavior.

In `@third_party/bubbletea-v2-patched/exec_test.go`:
- Around line 105-113: Move the spyRenderer assignment for p.renderer to before
invoking p.Run(), ensuring the wrapped renderer observes execution-time
operations. Keep the existing calledReset assertion using the injected
spyRenderer after execution.
- Around line 48-51: Implement a reset() method on spyRenderer that sets
calledReset to true instead of delegating to the embedded renderer, so reset
invocations are intercepted and recorded.

In `@third_party/bubbletea-v2-patched/focus.go`:
- Around line 1-9: Move the patched Bubble Tea implementation containing
FocusMsg and BlurMsg out of third_party/ into an allowed repository location,
then update the module wiring and imports so all producers and consumers use the
relocated implementation. Do not leave modifications under third_party/.

In `@third_party/bubbletea-v2-patched/go.mod`:
- Line 1: Remove the patched dependency and all listed metadata files from
third_party/bubbletea-v2-patched, including go.mod, .gitattributes, both issue
templates, .gitignore, .golangci.yml, .goreleaser.yml, LICENSE, README.md,
Taskfile.yaml, and UPGRADE_GUIDE_V2.md. Maintain the dependency outside
third_party and update the project’s root go.mod with a replace directive
pointing to the maintained fork.

In `@third_party/bubbletea-v2-patched/key.go`:
- Line 155: Update the key mapping entry for KeyMediaRecord to use
uv.KeyMediaRecord instead of uv.KeyMediaPrev, while leaving the neighboring
media-key mappings unchanged.

In `@third_party/bubbletea-v2-patched/keyboard.go`:
- Line 1: Move the maintained Bubble Tea fork out of third_party while
preserving the patched implementations and tests. Relocate keyboard.go,
screen.go, tty.go, termios_unix.go, termios_windows.go, input.go,
screen_test.go, and all three listed TestViewModel golden fixtures to a
maintained fork/patch directory, update the root replace directive to reference
the new module location, and leave third_party vendored sources unmodified.

In `@third_party/bubbletea-v2-patched/logging_test.go`:
- Around line 10-28: Update TestLogToFile to call t.Fatal for LogToFile and
os.ReadFile failures, preventing execution after setup or read errors. Capture
the default logger’s output, prefix, and flags before invoking LogToFile, then
restore all three with cleanup (including restoring output before the test
exits) so later tests cannot inherit the mutated logger state or closed file.

In `@third_party/bubbletea-v2-patched/mouse.go`:
- Line 41: Update the MouseButton11 enum mapping to explicitly use
uv.MouseButton11, preventing it from inheriting the MouseButton10 value.

In `@third_party/bubbletea-v2-patched/nil_renderer.go`:
- Around line 1-10: Move the patched Bubble Tea module out of third_party/ or
obtain an explicit vendoring exception. Apply this to
third_party/bubbletea-v2-patched/nil_renderer.go (lines 1-10), exec.go (lines
1-10), tty_unix.go (lines 1-10), tty_windows.go (lines 1-10), signals_unix.go
(lines 1-10), signals_windows.go (lines 1-10), termios_bsd.go (lines 1-10),
termios_other.go (lines 1-9), cursed_renderer_test.go (lines 1-10), and
exec_test.go (lines 1-10); preserve the patched module’s package structure and
update references accordingly.

In `@third_party/bubbletea-v2-patched/tea_test.go`:
- Around line 255-260: Update the goroutine surrounding the repeated p.Quit()
calls to observe a completion channel, and close that channel immediately after
Run returns so the loop exits even when shutdowns equals preventCount. Preserve
the existing shutdown-count condition while ensuring the goroutine stops
promptly on Run completion.

In `@third_party/bubbletea-v2-patched/tea.go`:
- Around line 1-1439: Relocate the maintained Bubble Tea fork out of
third_party: move third_party/bubbletea-v2-patched/tea.go#L1-L1439,
clipboard.go#L1-L70, color.go#L1-L91, commands_test.go#L1-L67, key.go#L1-L371,
mod.go#L1-L27, mouse.go#L1-L144, paste.go#L1-L20, raw.go#L1-L37,
termcap.go#L1-L48, and xterm.go#L1-L22 into a non-vendored directory, keeping
the files together and preserving package symbols such as Program and
NewProgram. Update the root module replacement to target the new directory and
ensure all imports and tests use that replacement; the listed original sites
require no direct changes beyond removal after relocation.

In `@third_party/bubbletea-v2-patched/termios_unix.go`:
- Line 13: Update the `useBackspace` assignment to read the `BSDLY`/`BS0`
output-delay flags from `s.Oflag` instead of `s.Lflag`, preserving the existing
comparison and behavior.

In `@third_party/bubbletea-v2-patched/tty_unix.go`:
- Around line 15-35: Unify the platform-specific implementations into shared
cross-platform functions while preserving each platform’s behavior. In
third_party/bubbletea-v2-patched/tty_unix.go:15-35 and tty_windows.go:13-60,
merge initInput; in tty_unix.go:37-47 and tty_windows.go:62-65, merge
suspendProcess; in signals_unix.go:15-33 and signals_windows.go:8-10, merge
listenForResize; and in termios_bsd.go:11-13 and termios_other.go:8-8, merge
checkOptimizedMovements. Replace build-tag duplication with runtime or standard
conditional checks, retain the existing Unix, Windows, BSD, and other-platform
behavior, and remove the redundant platform-specific definitions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e73a66b8-bd0f-4df9-b0bc-9d7cfc68117b

📥 Commits

Reviewing files that changed from the base of the PR and between 9acb411 and 628818b.

⛔ Files ignored due to path filters (1)
  • third_party/bubbletea-v2-patched/go.sum is excluded by !**/*.sum
📒 Files selected for processing (76)
  • go.mod
  • internal/tui/model.go
  • third_party/bubbletea-v2-patched/.gitattributes
  • third_party/bubbletea-v2-patched/.github/ISSUE_TEMPLATE/bug.yml
  • third_party/bubbletea-v2-patched/.github/ISSUE_TEMPLATE/bug_report.md
  • third_party/bubbletea-v2-patched/.github/ISSUE_TEMPLATE/config.yml
  • third_party/bubbletea-v2-patched/.github/ISSUE_TEMPLATE/feature_request.md
  • third_party/bubbletea-v2-patched/.github/dependabot.yml
  • third_party/bubbletea-v2-patched/.github/workflows/build.yml
  • third_party/bubbletea-v2-patched/.github/workflows/coverage.yml
  • third_party/bubbletea-v2-patched/.github/workflows/dependabot-sync.yml
  • third_party/bubbletea-v2-patched/.github/workflows/examples.yml
  • third_party/bubbletea-v2-patched/.github/workflows/lint-sync.yml
  • third_party/bubbletea-v2-patched/.github/workflows/lint.yml
  • third_party/bubbletea-v2-patched/.github/workflows/release.yml
  • third_party/bubbletea-v2-patched/.gitignore
  • third_party/bubbletea-v2-patched/.golangci.yml
  • third_party/bubbletea-v2-patched/.goreleaser.yml
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/README.md
  • third_party/bubbletea-v2-patched/Taskfile.yaml
  • third_party/bubbletea-v2-patched/UPGRADE_GUIDE_V2.md
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/cursor.go
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/exec.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/options_test.go
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/renderer.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/tea.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/termios_bsd.go
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/termios_unix.go
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen_autoexit.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/tty_windows.go
  • third_party/bubbletea-v2-patched/xterm.go

Comment thread patches/bubbletea-v2/commands.go Outdated
Comment thread patches/bubbletea-v2/cursed_renderer.go Outdated
Comment thread patches/bubbletea-v2/cursed_renderer.go Outdated
Comment thread patches/bubbletea-v2/cursed_renderer.go Outdated
Comment thread patches/bubbletea-v2/exec_test.go Outdated
Comment thread patches/bubbletea-v2/nil_renderer.go Outdated
Comment thread patches/bubbletea-v2/tea_test.go Outdated
Comment thread patches/bubbletea-v2/tea.go Outdated
Comment thread third_party/bubbletea-v2-patched/termios_unix.go Outdated
Comment thread patches/bubbletea-v2/tty_unix.go Outdated
@euxaristia
euxaristia force-pushed the fix/multipass-remote-terminal-rendering branch from 628818b to 6e39e6e Compare July 17, 2026 05:32
euxaristia added a commit to euxaristia/zero that referenced this pull request Jul 17, 2026
The vendored bubbletea-v2-patched module is ~99% byte-identical to
upstream charm.land/bubbletea/v2 v2.0.8; only cursed_renderer.go
differs (one line disabling hard scroll optimization). The .github
workflows, README.md, UPGRADE_GUIDE_V2.md, Taskfile.yaml and CI config
files are upstream repo metadata that serve no purpose inside this
repo, so remove them to slim the PR. The Go source and testdata golden
files are kept because Go's replace directive requires the full module
to be present and buildable.

Refs Gitlawb#709

@Vasanthdev2004 Vasanthdev2004 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Builds and vets clean and the tui suite passes on Windows, and the fix is sound for the corruption case: vendoring bubbletea/v2 with scroll-region optimization disabled, plus forcing a ClearScreen on streamed newlines, addresses the ghost-caret/repaint issue. The one thing I'd flag for kevin before this lands is that the tradeoff is now unconditional — every terminal does full repaints and a per-newline clear, not just the multipass-over-Windows-Terminal combo that motivated it. An env var to opt back into the fast path for terminals that handle scroll regions correctly would soften the blast radius; if the call is that detection isn't reliable, that's defensible, but it's a product call worth making consciously rather than a clear ship-it from me.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Do not ship a local replace directive in the release module
    go.mod:45
    This makes the standard versioned install path fail: go install github.com/Gitlawb/zero/cmd/zero@<version> evaluates the downloaded module without a main module, and Go rejects a target go.mod containing behavior-changing replace directives. Source-checkout builds and the CI matrix therefore pass while users cannot install a release by its version. Publish the patched Bubble Tea as a resolvable versioned fork (or otherwise avoid a root-module replace) before releasing; this also avoids silently pinning all future Bubble Tea upgrades to this copied v2.0.8 snapshot.

  • [P1] Make the newline redraw synchronous with the render it is meant to repair
    internal/tui/model.go:1916
    tea.ClearScreen is sent asynchronously, so the renderer can flush the new streamed view first. When the later clear message arrives, clearScreen() only appends an erase to the renderer buffer; the next frame sees the same lastView and returns without flushing that buffer. The erase/redraw is then deferred until an unrelated view change (or shutdown), leaving the ghost caret intact under the timing the workaround is intended to handle. Trigger a forced redraw in an ordered path, or invalidate the renderer's last view when handling the clear, and cover the reordered/fade-disabled case.

  • [P2] Avoid a full-screen repaint for every streamed newline on unaffected terminals
    internal/tui/model.go:1915
    Every coalesced streaming delta containing a newline now schedules tea.ClearScreen. In the always-alt-screen TUI, that erases the renderer buffer and makes the following frame repaint the complete viewport. Normal code, logs, and diffs therefore turn into repeated full-screen writes for every terminal, including SSH and slow links unrelated to the Multipass/Windows Terminal failure, causing a substantial throughput and latency regression. Scope this workaround to an explicit opt-in/affected terminal path, or coalesce/rate-limit a reliable full redraw rather than clearing once per newline.

@euxaristia

Copy link
Copy Markdown
Contributor Author

Pushed 52e7d36 addressing the concrete findings in the fork and the perf scoping: KeyMediaRecord and MouseButton11 no longer inherit the previous const's expression; BSDLY/BS0 is read from Oflag; wrapped-row counting uses (lineWidth-1)/w so exact-width lines don't insert blank rows; color comparisons go through a nil-safe normalized-RGBA helper instead of interface equality; clearScreen invalidates lastView so the queued erase flushes with the next frame instead of deferring until an unrelated view change (the reordering behind the P1 ghost-caret case); the spy renderer implements reset() and is injected before Run; the logging test restores the default logger; and the Quit-pump goroutine stops when Run returns. On the P2 repaint cost: the streamed-newline ClearScreen is now rate-limited to ~10/s and ZERO_NO_STREAM_CLEAR=1 opts a correctly-rendering terminal back into the fast incremental path. Still open and genuinely a maintainer call: the fork's location under third_party/ and the root go.mod replace directive (which breaks go install ...@version). The clean fix is publishing the patched fork as a resolvable versioned repo and pointing the require at it — happy to do that mechanical work once there's a decision on where the fork should live.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
third_party/bubbletea-v2-patched/renderer.go (1)

11-13: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Update comment to match the constant name.

The comment refers to defaultFramerate, but the constant is named defaultFPS.

📝 Proposed fix
-	// defaultFramerate specifies the maximum interval at which we should
+	// defaultFPS specifies the maximum interval at which we should
	// update the view.
	defaultFPS = 60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@third_party/bubbletea-v2-patched/renderer.go` around lines 11 - 13, Update
the comment immediately above the defaultFPS constant to refer to defaultFPS
instead of defaultFramerate, keeping the existing description unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@third_party/bubbletea-v2-patched/renderer.go`:
- Line 1: Revert changes to the vendored package under third_party, including
renderer.go. Manage the patched Bubble Tea implementation externally through a
patch workflow or a go.mod replace directive targeting a separate module,
without editing vendored files directly.

---

Nitpick comments:
In `@third_party/bubbletea-v2-patched/renderer.go`:
- Around line 11-13: Update the comment immediately above the defaultFPS
constant to refer to defaultFPS instead of defaultFramerate, keeping the
existing description unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 45da6c20-cd0f-4c13-b5cd-6fe443d67408

📥 Commits

Reviewing files that changed from the base of the PR and between 628818b and 52e7d36.

⛔ Files ignored due to path filters (1)
  • third_party/bubbletea-v2-patched/go.sum is excluded by !**/*.sum
📒 Files selected for processing (57)
  • go.mod
  • internal/tui/model.go
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/cursor.go
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/exec.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/options_test.go
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/renderer.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/tea.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/termios_bsd.go
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/termios_unix.go
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen_autoexit.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/tty_windows.go
  • third_party/bubbletea-v2-patched/xterm.go
🚧 Files skipped from review as they are similar to previous changes (54)
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/termios_unix.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/options_test.go
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/xterm.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/cursor.go
  • go.mod
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/tty_windows.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/exec.go
  • internal/tui/model.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • third_party/bubbletea-v2-patched/tea.go

Comment thread patches/bubbletea-v2/renderer.go Outdated

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Rebase this branch before merging
    package.json:3
    The head's merge-base is 9043baed, while the current review base is 378d538; it is missing the 13 intervening mainline commits. Consequently, merging this renderer-only PR deletes 9,159 current lines across 149 files, including the released 0.4.0 changelog and package metadata (this line regresses the version to 0.3.0), semantic tool-output budgeting, completion policy, execution profiles, and the missing-native zero doctor fallback. Rebase/reapply the TUI patch on current main so none of those shipped changes are reverted.

  • [P2] Preserve a redraw for rate-limited newline transitions
    internal/tui/model.go:1936
    The new throttle drops every streamed newline arriving within 100 ms instead of scheduling a deferred clear. A second newline-bearing agentTextMsg can therefore take the same incremental path that leaves the old caret behind; if that is the final delta, no later clear repairs it. Coalesce to a guaranteed deferred redraw (and add a two-newline-within-the-window regression test) rather than discarding the event.

@euxaristia

Copy link
Copy Markdown
Contributor Author

Pushed 62fd5dc.

Fixed:

  • Throttled stream-clear could silently drop the redraw when a newline landed in the last delta of a turn, leaving a ghost caret on screen. Added a deferred one-shot flush plus a flush on stream end, with 3 new regression tests.
  • Fixed a stale comment (defaultFramerate vs defaultFPS) and a test in the vendored bubbletea fork that leaked global logger state across runs.

Not fixing, with reasons:

  • Moving the vendored bubbletea fork out of third_party and dropping the local replace in go.mod: this conflicts with repo policy in AGENTS.md, but the whole PR is built on a hand-patched fork, so relocating ~30 files and standing up a versioned fork repo is a maintainer call on where the fork should live, not something to do inside a fixup pass.
  • The suggestion to unify tty_unix.go/tty_windows.go via runtime.GOOS instead of build tags: checked and it's wrong, the two files import OS-specific packages (syscall/os/signal vs golang.org/x/sys/windows) that don't compile on the other platform, so this needs to stay build-tag-separated.
  • Rebasing onto main: confirmed the branch is 15 commits behind gitlawb/main. That's a real rebase, not a code fix, so leaving it for a separate pass rather than doing it as part of this push.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/tui/model.go`:
- Around line 1963-1971: Use a shared streamClearThrottle constant instead of
duplicating the 100ms duration, and update both agentTextMsg
(internal/tui/model.go:1963-1971) and streamClearFlushMsg
(internal/tui/model.go:2069-2074) to calculate elapsed time and assign
timestamps through m.now() rather than time.Since or time.Now().

In `@internal/tui/stream_clear_test.go`:
- Around line 21-37: Update msgIncludesClearScreen to inspect tea.BatchMsg
commands without invoking c(), avoiding synchronous side effects such as timer
scheduling. Add the reflect import and compare each command’s function pointer
with the tea.ClearScreen function pointer, preserving nil handling and the
existing false result when no match is found; nested batches do not need to be
supported.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7b4bab70-41ba-47da-9f7b-b8083805180c

📥 Commits

Reviewing files that changed from the base of the PR and between 52e7d36 and 62fd5dc.

📒 Files selected for processing (4)
  • internal/tui/model.go
  • internal/tui/stream_clear_test.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/renderer.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/renderer.go

Comment thread internal/tui/model.go Outdated
Comment thread internal/tui/stream_clear_test.go
euxaristia added a commit to euxaristia/zero that referenced this pull request Jul 19, 2026
The vendored bubbletea-v2-patched module is ~99% byte-identical to
upstream charm.land/bubbletea/v2 v2.0.8; only cursed_renderer.go
differs (one line disabling hard scroll optimization). The .github
workflows, README.md, UPGRADE_GUIDE_V2.md, Taskfile.yaml and CI config
files are upstream repo metadata that serve no purpose inside this
repo, so remove them to slim the PR. The Go source and testdata golden
files are kept because Go's replace directive requires the full module
to be present and buildable.

Refs Gitlawb#709
@euxaristia
euxaristia force-pushed the fix/multipass-remote-terminal-rendering branch from 62fd5dc to cb25d5b Compare July 19, 2026 08:56
@euxaristia

Copy link
Copy Markdown
Contributor Author

@jatmn follow-up on your latest review (52e7d36):

[P1] Rebase — resolved. Branch is on tip of gitlawb/main (behind:0, merge-base ce4a996). package.json stays at 0.4.0; the PR only adds files (no mainline deletions).

[P2] Preserve redraw for rate-limited newlines — resolved across cb25d5b + c889f6a:

  • Throttled newlines set pendingStreamClear and schedule a one-shot streamClearFlushMsg instead of dropping the redraw.
  • Stream end also flushes any still-pending clear.
  • Regression coverage: deferred-not-dropped, mid-stream flush, and an explicit two-newline-within-window coalesce test.
  • Bonus from CodeRabbit: throttle math goes through m.now() + shared streamClearThrottle; tests detect ClearScreen without evaluating Tick side effects.

Still open as a maintainer call (not a code fix in this pass): publishing the bubbletea fork as a versioned remote module so the root replace can go away for go install ...@version.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/tui/stream_clear_test.go (1)

30-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid executing side effects and prevent potential CI flakiness.

While the 20ms timeout prevents the test from blocking on Tick commands, executing cmd() in a background goroutine still triggers the command's side effects. Additionally, a 20ms timeout can cause test flakiness in heavily loaded CI environments where goroutine scheduling might be delayed.

You can safely identify a tea.Batch command without evaluating it by comparing its code pointer to a known batch closure. This allows you to expand batches instantly and synchronously, safely ignoring all other commands.

⚡ Proposed fix
-	// Expand batches (and any other immediately-returning cmds). Bound the
-	// wait so a deferred stream-clear Tick is never a multi-100ms sleep.
-	ch := make(chan tea.Msg, 1)
-	go func() { ch <- cmd() }()
-	select {
-	case msg := <-ch:
-		return msgIncludesClearScreen(msg)
-	case <-time.After(20 * time.Millisecond):
-		return false
-	}
+	// Identify tea.Batch closures by code pointer to safely expand them
+	// without executing arbitrary side-effect commands (like Tick).
+	batchPtr := reflect.ValueOf(tea.Batch(tea.ClearScreen)).Pointer()
+	if reflect.ValueOf(cmd).Pointer() == batchPtr {
+		// It's a batch. Executing it just returns the BatchMsg instantly.
+		return msgIncludesClearScreen(cmd())
+	}
+	
+	return false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/tui/stream_clear_test.go` around lines 30 - 39, Update the command
inspection helper around the goroutine and 20ms timeout so it never executes
commands or waits on scheduling. Identify tea.Batch commands by comparing their
function code pointer with the known batch closure, expand those batches
synchronously, and ignore all other commands while preserving clear-screen
detection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@third_party/bubbletea-v2-patched/tty_windows.go`:
- Around line 1-64: Remove direct edits under third_party/ by relocating or
otherwise managing the patched Bubble Tea fork outside the vendored tree. Apply
this to third_party/bubbletea-v2-patched/tty_windows.go (lines 1-64),
third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
(line 1), and third_party/bubbletea-v2-patched/logging_test.go (lines 1-42),
preserving the patched implementation and its associated test data and test
coverage.

---

Nitpick comments:
In `@internal/tui/stream_clear_test.go`:
- Around line 30-39: Update the command inspection helper around the goroutine
and 20ms timeout so it never executes commands or waits on scheduling. Identify
tea.Batch commands by comparing their function code pointer with the known batch
closure, expand those batches synchronously, and ignore all other commands while
preserving clear-screen detection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 80c24974-c2ae-4bfc-a707-1d1e9f2cd122

📥 Commits

Reviewing files that changed from the base of the PR and between 62fd5dc and c889f6a.

⛔ Files ignored due to path filters (1)
  • third_party/bubbletea-v2-patched/go.sum is excluded by !**/*.sum
📒 Files selected for processing (58)
  • go.mod
  • internal/tui/model.go
  • internal/tui/stream_clear_test.go
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/cursor.go
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/exec.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/options_test.go
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/renderer.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/tea.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/termios_bsd.go
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/termios_unix.go
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen_autoexit.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/tty_windows.go
  • third_party/bubbletea-v2-patched/xterm.go
🚧 Files skipped from review as they are similar to previous changes (54)
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/xterm.go
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen_autoexit.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/termios_bsd.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/termios_unix.go
  • go.mod
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/options_test.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/renderer.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/cursor.go
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/exec.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • internal/tui/model.go
  • third_party/bubbletea-v2-patched/tea.go

Comment thread patches/bubbletea-v2/tty_windows.go Outdated
@euxaristia
euxaristia marked this pull request as draft July 19, 2026 20:42
euxaristia added a commit to euxaristia/zero that referenced this pull request Jul 19, 2026
The vendored bubbletea-v2-patched module is ~99% byte-identical to
upstream charm.land/bubbletea/v2 v2.0.8; only cursed_renderer.go
differs (one line disabling hard scroll optimization). The .github
workflows, README.md, UPGRADE_GUIDE_V2.md, Taskfile.yaml and CI config
files are upstream repo metadata that serve no purpose inside this
repo, so remove them to slim the PR. The Go source and testdata golden
files are kept because Go's replace directive requires the full module
to be present and buildable.

Refs Gitlawb#709
@euxaristia
euxaristia force-pushed the fix/multipass-remote-terminal-rendering branch from c889f6a to 9fdccbc Compare July 19, 2026 20:45
@euxaristia

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (fbf8598), no conflicts. Full test suite passes locally except TestAltScreenTranscriptScrollKeepsFooterFixed, which also fails on unmodified main when the checkout path is long enough to push the title bar into a narrower width tier, so it is pre-existing and unrelated to this branch. The vendored fork tests pass as well. The remaining review items (the third_party placement question and the newline throttle) are still open; this push is just the rebase.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden`:
- Line 1: Revert the modification to the vendored golden fixture under
third_party/. If the fixture must be maintained, relocate the test and fixture
to a repository-owned path outside third_party/; otherwise leave the third-party
file unchanged and obtain a documented policy exception.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ea849e73-d98b-4f9b-bb74-20c9cca4fddc

📥 Commits

Reviewing files that changed from the base of the PR and between c889f6a and 9fdccbc.

⛔ Files ignored due to path filters (1)
  • third_party/bubbletea-v2-patched/go.sum is excluded by !**/*.sum
📒 Files selected for processing (58)
  • go.mod
  • internal/tui/model.go
  • internal/tui/stream_clear_test.go
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/cursor.go
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/exec.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/options_test.go
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/renderer.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/tea.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/termios_bsd.go
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/termios_unix.go
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/bg_fg_cur_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen_autoexit.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/tty_windows.go
  • third_party/bubbletea-v2-patched/xterm.go
🚧 Files skipped from review as they are similar to previous changes (56)
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen_autoexit.golden
  • third_party/bubbletea-v2-patched/termios_windows.go
  • third_party/bubbletea-v2-patched/signals_unix.go
  • third_party/bubbletea-v2-patched/focus.go
  • third_party/bubbletea-v2-patched/environ.go
  • third_party/bubbletea-v2-patched/input.go
  • third_party/bubbletea-v2-patched/xterm.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/clear_screen.golden
  • third_party/bubbletea-v2-patched/cursor.go
  • third_party/bubbletea-v2-patched/signals_windows.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hide.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_cellmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_disable.golden
  • third_party/bubbletea-v2-patched/termios_bsd.go
  • third_party/bubbletea-v2-patched/testdata/TestClearMsg/read_set_clipboard.golden
  • third_party/bubbletea-v2-patched/paste.go
  • third_party/bubbletea-v2-patched/logging.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bp_stop_start.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/altscreen.golden
  • third_party/bubbletea-v2-patched/termios_unix.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/cursor_hideshow.golden
  • third_party/bubbletea-v2-patched/LICENSE
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/mouse_allmotion.golden
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/kitty_stop_startreleases.golden
  • third_party/bubbletea-v2-patched/termcap.go
  • third_party/bubbletea-v2-patched/nil_renderer.go
  • third_party/bubbletea-v2-patched/profile.go
  • third_party/bubbletea-v2-patched/screen.go
  • third_party/bubbletea-v2-patched/mod.go
  • third_party/bubbletea-v2-patched/raw.go
  • third_party/bubbletea-v2-patched/tty_windows.go
  • third_party/bubbletea-v2-patched/testdata/TestViewModel/bg_set_color.golden
  • third_party/bubbletea-v2-patched/go.mod
  • third_party/bubbletea-v2-patched/clipboard.go
  • third_party/bubbletea-v2-patched/termios_other.go
  • third_party/bubbletea-v2-patched/keyboard.go
  • third_party/bubbletea-v2-patched/logging_test.go
  • third_party/bubbletea-v2-patched/commands_test.go
  • third_party/bubbletea-v2-patched/screen_test.go
  • third_party/bubbletea-v2-patched/tty.go
  • third_party/bubbletea-v2-patched/renderer.go
  • third_party/bubbletea-v2-patched/options_test.go
  • internal/tui/stream_clear_test.go
  • third_party/bubbletea-v2-patched/tty_unix.go
  • third_party/bubbletea-v2-patched/exec_test.go
  • third_party/bubbletea-v2-patched/cursed_renderer_test.go
  • third_party/bubbletea-v2-patched/exec.go
  • third_party/bubbletea-v2-patched/color.go
  • third_party/bubbletea-v2-patched/key.go
  • third_party/bubbletea-v2-patched/mouse.go
  • third_party/bubbletea-v2-patched/options.go
  • third_party/bubbletea-v2-patched/tea_test.go
  • internal/tui/model.go
  • third_party/bubbletea-v2-patched/commands.go
  • third_party/bubbletea-v2-patched/cursed_renderer.go
  • third_party/bubbletea-v2-patched/tea.go

Comment thread patches/bubbletea-v2/testdata/TestClearMsg/bg_fg_cur_color.golden Outdated
euxaristia added a commit to euxaristia/zero that referenced this pull request Jul 20, 2026
Dune was rendering as a light/sandy theme with a 55/55/55 grey surface,
which did not match Claude Code's dark colorblind mode. Rebase the
palette on a near-black surface (#0e0e10) with the brand-orange accent
from openclaude's dark-daltonized theme, and move the warm grey to the
user-prompt bubble only. Brighten the muted/faint/faintest gray ramp and
darken selBg/addBg/delBg so all WCAG-AA and xterm-256 contrast invariants
hold. Updates the stale test that still marked Dune as light.

Refs Gitlawb#709
euxaristia added a commit to euxaristia/zero that referenced this pull request Jul 20, 2026
The vendored bubbletea-v2-patched module is ~99% byte-identical to
upstream charm.land/bubbletea/v2 v2.0.8; only cursed_renderer.go
differs (one line disabling hard scroll optimization). The .github
workflows, README.md, UPGRADE_GUIDE_V2.md, Taskfile.yaml and CI config
files are upstream repo metadata that serve no purpose inside this
repo, so remove them to slim the PR. The Go source and testdata golden
files are kept because Go's replace directive requires the full module
to be present and buildable.

Refs Gitlawb#709
@euxaristia
euxaristia force-pushed the fix/multipass-remote-terminal-rendering branch from 9fdccbc to d7b3525 Compare July 20, 2026 11:17
@euxaristia

Copy link
Copy Markdown
Contributor Author

Follow-up (rebase + review fixes)

[P1] Rebase

Rebased onto current gitlawb/main (da9fb50). Merge-base is tip of main; the PR only adds files (no mainline deletions). package.json stays at 0.4.0.

[P2] Throttled stream-clear redraw

Already on the branch (from earlier commits, still present after rebase):

  • Newlines inside the 100ms window set pendingStreamClear and schedule a one-shot streamClearFlushMsg instead of dropping the redraw.
  • Stream end also flushes any still-pending clear.
  • Regression coverage includes deferred-not-dropped, mid-stream flush, and explicit two-newline-within-window (TestStreamClearTwoNewlinesWithinThrottleWindow).

third_party policy

Moved the maintained bubbletea/v2 fork from third_party/bubbletea-v2-patched to patches/bubbletea-v2 (d7b3525). Root go.mod replace updated accordingly. third_party/ is empty/gone on this branch. Replied on the seven CodeRabbit threads with the same detail.

The fork is still required for unconditional SetScrollOptim(false) (upstream only gates on GOOS=="windows").

Still open before non-draft / release

Root-module replace still breaks go install github.com/Gitlawb/zero/cmd/zero@<version>. Source-checkout builds work. Publishing a versioned remote fork (or another install-safe approach) is a maintainer decision and is why this stays draft.

Verification

  • go test ./internal/tui/ -count=1 (pass, including all StreamClear tests)
  • go test in patches/bubbletea-v2 (pass)
  • go build ./cmd/zero (pass)
  • git diff HEAD --check clean

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found issues that need to be addressed before this is ready.

Findings

  • [P2] Preserve the project’s intended versioned Go-install contract
    go.mod:47
    The local replace charm.land/bubbletea/v2 => ./patches/bubbletea-v2 makes versioned go install github.com/Gitlawb/zero/cmd/zero@<version> unusable: versioned installs cannot use a module containing a replacement directive, and the local replacement is not a resolvable dependency for that install. The PR discussion identifies this as a release concern. If versioned Go installs are a supported distribution path, publish the patched module at a resolvable version or use an install-safe integration; otherwise document that this path is intentionally unsupported before merging.

  • [P2] Exercise the patched Bubble Tea module in CI
    go.mod:47
    patches/bubbletea-v2 is a separate Go module, so the repository's existing go test ./... jobs stop at that module boundary. None of the seven fork test files added here run in the PR's required CI checks, despite the fork carrying renderer, terminal, platform, and lifecycle changes in addition to the targeted scroll setting. Add a CI step that runs the fork's tests (including the appropriate platform coverage) so future changes to the replacement cannot pass solely because the consumer module compiles.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator

Thanks for chasing this down @euxaristia, the corruption repro is real, and the model.go side of it (forcing a repaint on the streamed newline to clear the ghost caret) is a solid, self-contained fix.

The part we can't take is the vendored bubbletea fork. jatmn's P1 is a blocker on its own: a replace in the release go.mod breaks go install ...@version, so it can't ship this way. And stepping back, carrying a full in-tree copy of our TUI framework is a maintenance commitment we do not want to sign up for lightly, and it turns off the scroll optimization for every terminal to fix one narrow remote-VM case.

So the direction we would like: drop the fork, keep the lightweight fix. For the scroll-region issue the better homes are (1) upstream it to bubbletea, or (2) a runtime toggle if bubbletea already exposes one, so we set it without vendoring anything. If neither works out and a patch really is unavoidable, that is an owner-level call since it means owning a fork, not something to land via replace.

Genuinely appreciate the work, the debugging was the hard part here. If you want, split the model.go fix into its own small PR and we can move that one quickly.

Vendors a patched charm.land/bubbletea/v2 (via a local go.mod replace)
with hard scroll optimization (using terminal scroll-region sequences
to shift existing lines instead of repainting) disabled unconditionally,
instead of only on GOOS=="windows".

That GOOS check only catches a Windows terminal driving the program
directly. It misses a Linux process running inside a multipass VM
whose output is ultimately displayed by Windows Terminal over a
remote shell, which corrupts rendering badly (garbled/overlapping
text, worse on resize) the same way the check exists to prevent.
There's no reliable way to detect that remote hop from inside the VM,
so scroll optimization is now off in all cases.
The streaming caret (appendStreamingCursor) is appended to whichever
visual line is currently last. Over a remote terminal chain
(multipass VM output displayed by Windows Terminal), the renderer's
incremental cell diff sometimes fails to clear the caret's old cell
when a newline moves it to a new line, leaving ghost carets behind.

Fire tea.ClearScreen when a streamed delta contains a newline: that's
exactly the moment the caret moves and the risk exists, so it forces
a full redraw right then instead of leaving it to the incremental
diff, without doing so on every animation tick.
The vendored bubbletea-v2-patched module is ~99% byte-identical to
upstream charm.land/bubbletea/v2 v2.0.8; only cursed_renderer.go
differs (one line disabling hard scroll optimization). The .github
workflows, README.md, UPGRADE_GUIDE_V2.md, Taskfile.yaml and CI config
files are upstream repo metadata that serve no purpose inside this
repo, so remove them to slim the PR. The Go source and testdata golden
files are kept because Go's replace directive requires the full module
to be present and buildable.

Refs Gitlawb#709
euxaristia and others added 5 commits July 22, 2026 03:19
…ed fork

Fork correctness fixes (all flagged by review):

- key.go: KeyMediaRecord repeated the previous const expression and
  decoded record presses as previous-track; map it to uv.KeyMediaRecord.
- mouse.go: MouseButton11 likewise collapsed onto MouseButton10.
- termios_unix.go: BSDLY/BS0 are output-delay bits; read them from Oflag
  instead of Lflag so useBackspace is set correctly.
- cursed_renderer.go: count wrapped rows with (lineWidth-1)/w so an
  exact terminal-width multiple no longer inserts a blank line; compare
  colors by normalized RGBA via a nil-safe helper instead of interface
  equality (which panics on non-comparable implementations); and make
  clearScreen invalidate lastView so the queued erase flushes with the
  next frame instead of deferring until an unrelated view change — the
  reordering that could leave the ghost caret in place.
- exec_test.go: implement reset() on the spy renderer and inject it
  before Run; assert exec preserves renderer state (releaseTerminal
  with reset=false).
- logging_test.go: restore the default logger's output/prefix/flags and
  fail fast on setup errors.
- tea_test.go: tie the Quit-pumping goroutine to a channel closed when
  Run returns instead of leaking it until process exit.

TUI scoping (review P2): the forced redraw on streamed newlines is now
rate-limited to ~10/s so heavy streaming output no longer turns every
newline into a full-screen repaint, and ZERO_NO_STREAM_CLEAR=1 opts a
correctly-rendering terminal back into the fast incremental path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A throttled stream-clear could drop the redraw entirely when a
newline arrived in the last delta of a turn, leaving a ghost caret on
screen. Add a one-shot deferred flush timer plus a flush on stream
end. Fix a stale comment and a test that leaked global logger state
in the vendored bubbletea fork.
Drive stream-clear rate limiting through the mockable clock and a
shared streamClearThrottle constant so both the agentTextMsg and
flush paths stay in sync. Add an explicit two-newline-within-window
regression and detect ClearScreen by function pointer so tests do not
evaluate Tick side effects.
Move the maintained bubbletea/v2 hard-scroll patch from
third_party/bubbletea-v2-patched to patches/bubbletea-v2 and update the
root go.mod replace. third_party/ is immutable vendored content per
AGENTS.md; a maintained fork belongs outside that tree.
…ted go install path

patches/bubbletea-v2 is its own Go module so `go test ./...` from the repo
root never touched its 7 test files. Add a CI step (and a make test-patches
target for local use) that runs the fork's own suite across the smoke
matrix.

The root go.mod's local `replace charm.land/bubbletea/v2 =>
./patches/bubbletea-v2` also breaks `go install
github.com/Gitlawb/zero/cmd/zero@<version>`, since a versioned install can't
resolve a replace pointing at a filesystem path. Document that path as
unsupported in README.md and docs/INSTALL.md and point at git clone + go
build instead, per jatmn's review findings on PR Gitlawb#709.
@euxaristia
euxaristia force-pushed the fix/multipass-remote-terminal-rendering branch from d7b3525 to 8cb5469 Compare July 22, 2026 07:27
@euxaristia

Copy link
Copy Markdown
Contributor Author

Rebased this branch onto current upstream main (was 17 commits behind and had regressed package.json back to 0.4.0) and pushed a fixup commit for the two objective findings from jatmn's latest review:

  1. The local replace charm.land/bubbletea/v2 => ./patches/bubbletea-v2 in go.mod breaks go install github.com/Gitlawb/zero/cmd/zero@<version>, since a versioned install can't resolve a replace directive pointing at a filesystem path. I'm not publishing the fork to a resolvable location in this pass, so I documented go install ...@version as unsupported in README.md and docs/INSTALL.md and pointed installers at git clone + go build/go run instead, which was already the documented source-build path.

  2. patches/bubbletea-v2 is its own Go module, so the existing go test ./... CI step never ran its 7 test files. Added a CI step in .github/workflows/ci.yml that runs go test ./... in patches/bubbletea-v2 across the smoke job's OS matrix (useful since the fork has platform-specific files), plus a make test-patches target for running it locally. Verified it passes: ok charm.land/bubbletea/v2 0.705s.

I did not act on Vasanthdev2004's comment about the overall approach of vendoring a patched bubbletea fork versus splitting out the model.go fix or pursuing an upstream fix/runtime toggle. That's a product/architecture call for the maintainers and me to make, not something to resolve as part of these two fixes.

Also, the CodeRabbit thread objecting to edits under third_party/ looks stale: the fork was relocated to patches/bubbletea-v2 in a later commit on this branch, so that specific concern no longer applies. I can't mark the thread resolved from here, flagging it for a maintainer to close out.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
patches/bubbletea-v2/cursed_renderer_test.go (1)

1-81: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Run the vendored bubbletea tests with -race in CI. The patches/bubbletea-v2 job in .github/workflows/ci.yml uses go test ./... today, so this concurrency regression can still pass even if it introduces a race.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@patches/bubbletea-v2/cursed_renderer_test.go` around lines 1 - 81, Update the
`patches/bubbletea-v2` CI job in `.github/workflows/ci.yml` to run the vendored
Bubble Tea tests with Go’s race detector by adding `-race` to its `go test
./...` command. Keep the existing package scope and job behavior unchanged.

Source: Coding guidelines

🧹 Nitpick comments (3)
patches/bubbletea-v2/tea.go (1)

192-205: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate/orphaned KeyboardEnhancements doc blocks.

Lines 192-197 are dangling comments attached to nothing, and 199-205 repeats the 196-197 text. Collapse into a single doc block above the type declaration to avoid confusing future fork maintainers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@patches/bubbletea-v2/tea.go` around lines 192 - 205, Remove the orphaned and
duplicated KeyboardEnhancements documentation, leaving one consolidated doc
block immediately above the KeyboardEnhancements type declaration that retains
the relevant request and response behavior.
patches/bubbletea-v2/tty.go (1)

62-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Local var term shadows the imported term package.

term := p.environ.Getenv("TERM") shadows the github.com/charmbracelet/x/term import for the rest of initInputReader. Harmless today, but risky if someone adds a term.* call to this function later.

♻️ Proposed rename
-	term := p.environ.Getenv("TERM")
+	termEnv := p.environ.Getenv("TERM")
 	...
-	drv := uv.NewTerminalReader(p.cancelReader, term)
+	drv := uv.NewTerminalReader(p.cancelReader, termEnv)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@patches/bubbletea-v2/tty.go` at line 62, Rename the local variable term in
initInputReader to a non-conflicting name such as termName, and update its
subsequent references while preserving the imported term package for any
package-qualified calls.
patches/bubbletea-v2/cursed_renderer_test.go (1)

52-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Sleep-based readiness makes this regression test flaky.

time.Sleep(150 * time.Millisecond) before firing 100 concurrent mouse events is a best-effort guess that p.Run() has reached a renderable state. Under CI load this can under-shoot (test doesn't actually exercise the race window it's meant to catch, giving false confidence) or just add flakiness. Since this specifically guards against a hard-to-repro race (charmbracelet/bubbletea#1690), a deterministic readiness signal (e.g., block on a first-render/ready notification from Program rather than a fixed delay) would make the regression test dependable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@patches/bubbletea-v2/cursed_renderer_test.go` around lines 52 - 59, Replace
the fixed time.Sleep readiness delay in the cursed renderer regression test with
a deterministic signal that confirms p.Run has reached its first renderable
state, such as a first-render or program-ready notification. Start firing the
concurrent mouse events only after that signal, while preserving the existing
runDone cleanup and regression scenario.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 55-57: Update the “Test vendored bubbletea fork” workflow step to
run the fork’s Go test suite with the race detector by adding the -race option
to go test ./....

In `@patches/bubbletea-v2/tea.go`:
- Around line 1372-1390: Update Program.Println and Program.Printf to send their
printLineMessage values through the existing Send method instead of writing
directly to p.msgs. Preserve the current message formatting and ensure both
methods honor ctx.Done() so calls after shutdown cannot block.

In `@patches/bubbletea-v2/tty.go`:
- Around line 12-38: Update suspend and restoreTerminalState to surface errors
from RestoreTerminal and flush instead of discarding them; route failures
through the same p.errs mechanism used by checkResize, while preserving the
existing release and restore flow.

---

Outside diff comments:
In `@patches/bubbletea-v2/cursed_renderer_test.go`:
- Around line 1-81: Update the `patches/bubbletea-v2` CI job in
`.github/workflows/ci.yml` to run the vendored Bubble Tea tests with Go’s race
detector by adding `-race` to its `go test ./...` command. Keep the existing
package scope and job behavior unchanged.

---

Nitpick comments:
In `@patches/bubbletea-v2/cursed_renderer_test.go`:
- Around line 52-59: Replace the fixed time.Sleep readiness delay in the cursed
renderer regression test with a deterministic signal that confirms p.Run has
reached its first renderable state, such as a first-render or program-ready
notification. Start firing the concurrent mouse events only after that signal,
while preserving the existing runDone cleanup and regression scenario.

In `@patches/bubbletea-v2/tea.go`:
- Around line 192-205: Remove the orphaned and duplicated KeyboardEnhancements
documentation, leaving one consolidated doc block immediately above the
KeyboardEnhancements type declaration that retains the relevant request and
response behavior.

In `@patches/bubbletea-v2/tty.go`:
- Line 62: Rename the local variable term in initInputReader to a
non-conflicting name such as termName, and update its subsequent references
while preserving the imported term package for any package-qualified calls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cd7aae1f-6145-4a05-90d0-bd45e2cdcb53

📥 Commits

Reviewing files that changed from the base of the PR and between 9fdccbc and 8cb5469.

⛔ Files ignored due to path filters (1)
  • patches/bubbletea-v2/go.sum is excluded by !**/*.sum
📒 Files selected for processing (62)
  • .github/workflows/ci.yml
  • Makefile
  • README.md
  • docs/INSTALL.md
  • go.mod
  • internal/tui/model.go
  • internal/tui/stream_clear_test.go
  • patches/bubbletea-v2/LICENSE
  • patches/bubbletea-v2/clipboard.go
  • patches/bubbletea-v2/color.go
  • patches/bubbletea-v2/commands.go
  • patches/bubbletea-v2/commands_test.go
  • patches/bubbletea-v2/cursed_renderer.go
  • patches/bubbletea-v2/cursed_renderer_test.go
  • patches/bubbletea-v2/cursor.go
  • patches/bubbletea-v2/environ.go
  • patches/bubbletea-v2/exec.go
  • patches/bubbletea-v2/exec_test.go
  • patches/bubbletea-v2/focus.go
  • patches/bubbletea-v2/go.mod
  • patches/bubbletea-v2/input.go
  • patches/bubbletea-v2/key.go
  • patches/bubbletea-v2/keyboard.go
  • patches/bubbletea-v2/logging.go
  • patches/bubbletea-v2/logging_test.go
  • patches/bubbletea-v2/mod.go
  • patches/bubbletea-v2/mouse.go
  • patches/bubbletea-v2/nil_renderer.go
  • patches/bubbletea-v2/options.go
  • patches/bubbletea-v2/options_test.go
  • patches/bubbletea-v2/paste.go
  • patches/bubbletea-v2/profile.go
  • patches/bubbletea-v2/raw.go
  • patches/bubbletea-v2/renderer.go
  • patches/bubbletea-v2/screen.go
  • patches/bubbletea-v2/screen_test.go
  • patches/bubbletea-v2/signals_unix.go
  • patches/bubbletea-v2/signals_windows.go
  • patches/bubbletea-v2/tea.go
  • patches/bubbletea-v2/tea_test.go
  • patches/bubbletea-v2/termcap.go
  • patches/bubbletea-v2/termios_bsd.go
  • patches/bubbletea-v2/termios_other.go
  • patches/bubbletea-v2/termios_unix.go
  • patches/bubbletea-v2/termios_windows.go
  • patches/bubbletea-v2/testdata/TestClearMsg/bg_fg_cur_color.golden
  • patches/bubbletea-v2/testdata/TestClearMsg/clear_screen.golden
  • patches/bubbletea-v2/testdata/TestClearMsg/read_set_clipboard.golden
  • patches/bubbletea-v2/testdata/TestViewModel/altscreen.golden
  • patches/bubbletea-v2/testdata/TestViewModel/altscreen_autoexit.golden
  • patches/bubbletea-v2/testdata/TestViewModel/bg_set_color.golden
  • patches/bubbletea-v2/testdata/TestViewModel/bp_stop_start.golden
  • patches/bubbletea-v2/testdata/TestViewModel/cursor_hide.golden
  • patches/bubbletea-v2/testdata/TestViewModel/cursor_hideshow.golden
  • patches/bubbletea-v2/testdata/TestViewModel/kitty_stop_startreleases.golden
  • patches/bubbletea-v2/testdata/TestViewModel/mouse_allmotion.golden
  • patches/bubbletea-v2/testdata/TestViewModel/mouse_cellmotion.golden
  • patches/bubbletea-v2/testdata/TestViewModel/mouse_disable.golden
  • patches/bubbletea-v2/tty.go
  • patches/bubbletea-v2/tty_unix.go
  • patches/bubbletea-v2/tty_windows.go
  • patches/bubbletea-v2/xterm.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • go.mod
  • internal/tui/stream_clear_test.go
  • internal/tui/model.go

Comment thread .github/workflows/ci.yml Outdated
Comment thread patches/bubbletea-v2/tea.go Outdated
Comment thread patches/bubbletea-v2/tty.go Outdated
CodeRabbit review on this PR. The fork exists specifically to patch a
concurrency bug (charmbracelet/bubbletea#1690), so its regression test
needs the race detector to actually catch a reintroduced race instead
of just passing on a benign-looking run.
@euxaristia

Copy link
Copy Markdown
Contributor Author

Addressed CodeRabbit's review, mostly.

Fixed: the vendored bubbletea fork's CI step now runs with -race. The fork exists specifically to patch a concurrency bug (charmbracelet/bubbletea#1690), so the race detector actually matters here, not just as general hygiene.

Not fixing here: the rest of CodeRabbit's findings (duplicate doc comments in tea.go, a shadowed term variable in tty.go, discarded errors in suspend/restoreTerminalState, Program.Println/Printf writing directly to p.msgs instead of through Send, and a sleep-based readiness delay in the concurrency regression test) are all pre-existing in the vendored third-party source itself, not something this PR's own fix touches. Given Vasanthdev2004's still-open objection to keeping this vendored fork at all, I don't think it's the right call to spend more effort polishing the vendored copy until that direction question is settled. Happy to pick these up if the fork stays.

euxaristia added a commit to euxaristia/zero that referenced this pull request Jul 22, 2026
Dune was rendering as a light/sandy theme with a 55/55/55 grey surface,
which did not match Claude Code's dark colorblind mode. Rebase the
palette on a near-black surface (#0e0e10) with the brand-orange accent
from openclaude's dark-daltonized theme, and move the warm grey to the
user-prompt bubble only. Brighten the muted/faint/faintest gray ramp and
darken selBg/addBg/delBg so all WCAG-AA and xterm-256 contrast invariants
hold. Updates the stale test that still marked Dune as light.

Refs Gitlawb#709
Maintainers asked not to ship an in-tree bubbletea replace: it breaks
versioned go install and is a large maintenance surface for a narrow
multipass/Windows Terminal scroll bug. Remove patches/bubbletea-v2 and
the replace directive; keep the model.go full-redraw-on-streamed-newline
workaround (ZERO_NO_STREAM_CLEAR to opt out). Restore normal install docs.

Refs Gitlawb#709
@euxaristia

Copy link
Copy Markdown
Contributor Author

Followed maintainer direction (5d81745): drop the vendored bubbletea fork; keep the lightweight stream-clear workaround.

Removed

  • patches/bubbletea-v2 and the go.mod replace
  • CI test-patches / fork test step and Makefile test-patches
  • Install docs that said go install @version was unsupported because of the replace

Kept

  • model.go full-redraw-on-streamed-newline caret repair (ZERO_NO_STREAM_CLEAR to opt out)
  • Existing stream-clear tests

Versioned go install is usable again. Still draft until you confirm multipass/WT rendering is acceptable with stream-clear alone (no hard-scroll disable).

@euxaristia
euxaristia marked this pull request as ready for review July 22, 2026 08:22
@euxaristia

Copy link
Copy Markdown
Contributor Author

@jatmn following up on your latest review (the go.mod replace directive and the missing CI coverage for patches/bubbletea-v2).

Both are moot as of 5d81745: I dropped the vendored bubbletea fork entirely per Vasanthdev2004's objection to keeping it. There is no more replace directive in go.mod, no patches/bubbletea-v2 module, and no separate CI step for it. Versioned go install works again through the normal path.

What's left on the branch is just the model.go stream-clear workaround (ZERO_NO_STREAM_CLEAR to opt out) plus its existing tests. Still marked draft until you or another maintainer confirms that's sufficient for the multipass/Windows Terminal rendering issue without a hard-scroll disable.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants