* Migrate TUI to Bubble Tea v2
Move the TUI stack to charm.land Bubble Tea, Bubbles, and Lip Gloss v2, including key, paste, mouse, and view handling changes for the v2 APIs.
Add compatibility helpers for the new input event shapes and update TUI tests accordingly.
Refresh related Go dependencies and make the PDF truncation fixture deterministic across poppler and pure-Go extraction.
Tested: GOCACHE=/tmp/zero-go-cache GOMODCACHE=/tmp/zero-go-mod-cache go test ./internal/tui
Tested: GOCACHE=/tmp/zero-go-cache GOMODCACHE=/tmp/zero-go-mod-cache go test ./internal/imageinput -count=1 -v
Tested: GOCACHE=/tmp/zero-go-cache GOMODCACHE=/tmp/zero-go-mod-cache go test ./...
* Address provider wizard OAuth review feedback
Remove the unused mouseButton compatibility helper flagged by lint.
Correlate provider wizard OAuth and device-code async results with the active provider and attempt id so stale results from abandoned attempts are ignored.
Add regression coverage for stale browser OAuth and stale device-code results.
Tested: GOCACHE=/tmp/zero-go-cache GOMODCACHE=/tmp/zero-go-mod-cache go test ./internal/tui -run 'ProviderWizard.*OAuth|ProviderWizard.*Device|ApplyProviderWizardOAuth|RenderCredentialStepShowsOAuth' -count=1 -v
Tested: GOCACHE=/tmp/zero-go-cache GOMODCACHE=/tmp/zero-go-mod-cache go test ./internal/tui
Tested: GOCACHE=/tmp/zero-go-cache GOMODCACHE=/tmp/zero-go-mod-cache go test ./...
Tested: git diff --check
* Smooth TUI mouse scrolling
* stage 12: PDF ingestion
Add PDF ingestion to internal/imageinput so specs, design docs, and tickets
that arrive as PDF can be attached the same way images are.
- internal/imageinput/pdf.go: LoadDocument detects PDFs by magic bytes
(%PDF-, never extension alone), enforces a 32 MiB raw-file cap and a
256 KiB extracted-text cap (truncated with a marker, not rejected), and
extracts the text layer in pure Go via github.com/ledongthuc/pdf. The
parser can panic on malformed structures, so extraction is wrapped in a
recover that turns a bad PDF into a clean error. A textless PDF with no
rasterizer returns an explicit "no extractable text; OCR not available"
error rather than silent empty success.
- Dependency posture: default build is pure-Go text extraction (no CGO, no
transitive deps) so the static binary still cross-compiles. The optional
poppler tools (pdftotext / pdftoppm) are used for richer extraction and
page rasterization ONLY when present on PATH (same posture as the LSP
language servers); when absent, extraction degrades to the pure-Go text
path and never errors.
- Vision path: with a vision model and pdftoppm available, the first N pages
(default 10) render to PNG and flow through the existing image pipeline
(NormalizeImageMediaType, per-image cap, allow-list). Without a rasterizer
it degrades to the text layer.
- TUI integration: /image <file.pdf> routes to the document path. The text
layer attaches for any model and is prepended to the next prompt as a
labeled preamble; rendered pages attach as images for vision models. The
chip row and /image clear cover documents too.
Tests cover magic-byte detection, text extraction on a generated fixture,
both size caps, the no-text/no-raster message, malformed-input safety, the
pure-Go fallback, and the TUI attach/submit/clear wiring. go build, go test,
and gofmt are clean; CGO_ENABLED=0 cross-compiles for linux/amd64,
windows/arm64, and darwin/arm64.
* stage 12: address review (pdf page count, text cap, content-based routing)