Full UI port: Bubble Tea/lipgloss to Limoni (core + extra) #33

Open
opened 2026-10-14 17:40:33 +00:00 by muse-lantern · 4 comments
Member

Goal

Port every remaining Bubble Tea / lipgloss UI surface in core/ and extra/ to Limoni, on the unified limoni-port branch (same name in both repos). Follows the res-edit (#30) and res-code (#32) PoCs, whose branches are merged into limoni-port as the starting point.

Workspace

Dedicated workspace at ~/workspace/limoni-port/: .agent as root, core/ and extra/ cloned inside.

Scope

Core shared libs (first):

  • lib/tui/theme, lib/tui/list, lib/tui/overlay
  • lib/cmd/ui (confirm, input, menu, palette, status)

Core tools:

  • cmd/res-demo, cmd/res-theme
  • cmd/residual-login + internal/libs/auth (login, selector)
  • internal/libs/console menus/statusbar (lipgloss)
  • internal/libs/shell/remnant/prompt.go (lipgloss)

Extra (after core libs):

  • cmd/res-calc, cmd/res-sheets + lib/sheets/tui
  • res-code already ported (#32).

Order

Core libs → core tools → extra tools. Extra may depend on the new core lib APIs.

Constraints

  • Amber palette non-negotiable; Ctrl-modkey contract (never Alt); slow-terminal handling.
  • Minimal impact; go build/go vet/go test green per repo; static binaries; uitest verification.
  • Do not merge to main.
## Goal Port every remaining Bubble Tea / lipgloss UI surface in `core/` and `extra/` to Limoni, on the unified `limoni-port` branch (same name in both repos). Follows the res-edit (#30) and res-code (#32) PoCs, whose branches are merged into `limoni-port` as the starting point. ## Workspace Dedicated workspace at `~/workspace/limoni-port/`: `.agent` as root, `core/` and `extra/` cloned inside. ## Scope **Core shared libs (first):** - `lib/tui/theme`, `lib/tui/list`, `lib/tui/overlay` - `lib/cmd/ui` (confirm, input, menu, palette, status) **Core tools:** - `cmd/res-demo`, `cmd/res-theme` - `cmd/residual-login` + `internal/libs/auth` (login, selector) - `internal/libs/console` menus/statusbar (lipgloss) - `internal/libs/shell/remnant/prompt.go` (lipgloss) **Extra (after core libs):** - `cmd/res-calc`, `cmd/res-sheets` + `lib/sheets/tui` - res-code already ported (#32). ## Order Core libs → core tools → extra tools. Extra may depend on the new core lib APIs. ## Constraints - Amber palette non-negotiable; Ctrl-modkey contract (never Alt); slow-terminal handling. - Minimal impact; `go build`/`go vet`/`go test` green per repo; static binaries; uitest verification. - Do not merge to main.
Author
Member

Step 2 done — core tool UIs ported (commit f1ddb46, pushed to limoni-port)

Ported to Limoni with no behavioral changes beyond the renderer swap:

  • cmd/res-demo: full Limoni app (tabbed demo harness). Per Zachs correction, the demo went first alongside the libs — it surfaced the need for theme.Render/theme.Width/theme.StripANSI, which were added to the lib.
  • cmd/res-theme: full Limoni app; OSC live preview now writes to stdout only when the sequence changes.
  • internal/libs/auth/login: bubbletea model → Draw/HandleKey model; PAM runs in a goroutine, result via channel + limoni.Wakeup() (res-code PTY pattern); spinner via WithFPS(10). Branding() now returns styled lines instead of an ANSI string.
  • internal/libs/auth/selector: bubbletea program → Limoni app with explicit selected/quit state.
  • internal/libs/console (menus, statusbar): keeps the direct-write path (menu draws over live PTY content) — theme.Render/theme.Width replace lipgloss; removed list.RenderListRow/overlay.RenderHelpOverlay string APIs reimplemented locally with identical layout.
  • internal/libs/shell/remnant prompt: cell.Style + theme.Render.

Verification: CGO_ENABLED=0 go build/vet/test green (24 pkgs ok; only pre-existing lib/log failures); default CGO build fails only on missing PAM headers (verified pre-existing on base). Static ELF for res-demo (~6MB). uitest: res-demo tabs/help/quit, res-theme navigate/edit/quit; login state-machine unit tests; theme render tests. Headless dumps checked for demo + theme layouts.

Known Limoni gap: Run has no input/output redirection, so login_ui.go dups the configured TTY onto stdio around the run (preserves old tea.WithInput/WithOutput behavior).

Next: step 3 — extra (res-calc, res-sheets).

## Step 2 done — core tool UIs ported (commit f1ddb46, pushed to limoni-port) Ported to Limoni with no behavioral changes beyond the renderer swap: - **cmd/res-demo**: full Limoni app (tabbed demo harness). Per Zachs correction, the demo went first alongside the libs — it surfaced the need for `theme.Render`/`theme.Width`/`theme.StripANSI`, which were added to the lib. - **cmd/res-theme**: full Limoni app; OSC live preview now writes to stdout only when the sequence changes. - **internal/libs/auth/login**: bubbletea model → Draw/HandleKey model; PAM runs in a goroutine, result via channel + `limoni.Wakeup()` (res-code PTY pattern); spinner via `WithFPS(10)`. `Branding()` now returns styled lines instead of an ANSI string. - **internal/libs/auth/selector**: bubbletea program → Limoni app with explicit selected/quit state. - **internal/libs/console** (menus, statusbar): keeps the direct-write path (menu draws over live PTY content) — `theme.Render`/`theme.Width` replace lipgloss; removed `list.RenderListRow`/`overlay.RenderHelpOverlay` string APIs reimplemented locally with identical layout. - **internal/libs/shell/remnant** prompt: `cell.Style` + `theme.Render`. Verification: `CGO_ENABLED=0 go build/vet/test` green (24 pkgs ok; only pre-existing `lib/log` failures); default CGO build fails only on missing PAM headers (verified pre-existing on base). Static ELF for res-demo (~6MB). uitest: res-demo tabs/help/quit, res-theme navigate/edit/quit; login state-machine unit tests; theme render tests. Headless dumps checked for demo + theme layouts. Known Limoni gap: `Run` has no input/output redirection, so `login_ui.go` dups the configured TTY onto stdio around the run (preserves old `tea.WithInput/WithOutput` behavior). Next: step 3 — extra (res-calc, res-sheets).
Author
Member

Progress: core libs + core tools ported

Step 1 — shared libs (commits bfab57e, a8cbff5): lib/tui/theme, lib/tui/list, lib/tui/overlay, lib/cmd/ui → Limoni. uitest coverage added.

Step 2 — core tools (per Zach's sequencing, res-demo first):

  • 93344c1 Port res-demo to Limoni (own commit, uitest-verified). The demo surfaced a real lib gap → added lib/tui/theme/render.go (Render/Width/StripANSI string-rendering helpers).
  • 3b1fa0b Port res-theme to Limoni
  • 87c9f71 Port residual-login and auth UI libs to Limoni
  • eae365a Port res-console menus and statusbar to Limoni
  • 54fef37 Port shell remnant prompt to Limoni

Verification: go build/go vet/go test green across core except pre-existing environmental issues (PAM headers absent for residual-login/internal/libs/auth; lib/log test failures on clean base). Static ELF check passed for res-demo. The auth port could not be compile-verified here — needs a build with libpam-dev.

Note: the branch was force-pushed once during the res-demo split (93344c1 replaced a bundled commit). Anyone who pulled limoni-port before 2026-10-14 13:16 PDT should git fetch origin && git reset --hard origin/limoni-port.

Next: extra tools (res-calc, res-sheets).

## Progress: core libs + core tools ported **Step 1 — shared libs** (commits `bfab57e`, `a8cbff5`): `lib/tui/theme`, `lib/tui/list`, `lib/tui/overlay`, `lib/cmd/ui` → Limoni. uitest coverage added. **Step 2 — core tools** (per Zach's sequencing, res-demo first): - `93344c1` Port res-demo to Limoni (own commit, uitest-verified). The demo surfaced a real lib gap → added `lib/tui/theme/render.go` (`Render`/`Width`/`StripANSI` string-rendering helpers). - `3b1fa0b` Port res-theme to Limoni - `87c9f71` Port residual-login and auth UI libs to Limoni - `eae365a` Port res-console menus and statusbar to Limoni - `54fef37` Port shell remnant prompt to Limoni **Verification:** `go build`/`go vet`/`go test` green across core except pre-existing environmental issues (PAM headers absent for `residual-login`/`internal/libs/auth`; `lib/log` test failures on clean base). Static ELF check passed for res-demo. The auth port could not be compile-verified here — needs a build with libpam-dev. **Note:** the branch was force-pushed once during the res-demo split (`93344c1` replaced a bundled commit). Anyone who pulled `limoni-port` before 2026-10-14 13:16 PDT should `git fetch origin && git reset --hard origin/limoni-port`. **Next:** extra tools (res-calc, res-sheets).
Author
Member

Demo+lib expansion (Zach's directive)

Inventory: cataloged every UI element across core/extra. Found 9 copies of drawLabel/drawText, 3 copies of the command Palette, 2 MenuBars, plus unused lib widgets (InputPrompt, ConfirmDialog, MenuBar, StatusMessage had zero users).

Extracted to core lib:

  • New lib/tui/draw package: Label (clipped styled text), Span/Spans/SpansWidth, Truncate (ellipsis), LabelW (fixed-width), Box (bordered box). Replaced all copies in both repos.
  • lib/cmd/ui.Palette: added PaletteStyles + SetStyles for tools with their own chrome (dual unified/neutral theming).

Reconciled:

  • res-edit → shared ui.Palette (deleted 300-line copy; pixel-identical via injected chrome styles; dropdown restores original bubbletea dim-desc rendering).
  • res-code → shared ui.Palette (deleted 300-line copy; same).
  • res-code MenuBar deferred: structural API differences (separate DrawBar/DrawDropdown vs unified Draw) need more care — follow-up.

res-demo: new interactive Widgets tab (tab 9) — live playground for Palette, InputPrompt, MenuBar, ConfirmDialog, StatusMessage, tui.List, help overlay, and draw primitives. uitest-covered.

Verification: go build/go vet/go test green in both repos (excluding pre-existing PAM/lib-log env issues).

## Demo+lib expansion (Zach's directive) **Inventory:** cataloged every UI element across core/extra. Found 9 copies of drawLabel/drawText, 3 copies of the command Palette, 2 MenuBars, plus unused lib widgets (InputPrompt, ConfirmDialog, MenuBar, StatusMessage had zero users). **Extracted to core lib:** - New `lib/tui/draw` package: `Label` (clipped styled text), `Span`/`Spans`/`SpansWidth`, `Truncate` (ellipsis), `LabelW` (fixed-width), `Box` (bordered box). Replaced all copies in both repos. - `lib/cmd/ui.Palette`: added `PaletteStyles` + `SetStyles` for tools with their own chrome (dual unified/neutral theming). **Reconciled:** - res-edit → shared `ui.Palette` (deleted 300-line copy; pixel-identical via injected chrome styles; dropdown restores original bubbletea dim-desc rendering). - res-code → shared `ui.Palette` (deleted 300-line copy; same). - res-code MenuBar deferred: structural API differences (separate DrawBar/DrawDropdown vs unified Draw) need more care — follow-up. **res-demo:** new interactive Widgets tab (tab 9) — live playground for Palette, InputPrompt, MenuBar, ConfirmDialog, StatusMessage, tui.List, help overlay, and draw primitives. uitest-covered. **Verification:** `go build`/`go vet`/`go test` green in both repos (excluding pre-existing PAM/lib-log env issues).
Author
Member

MenuBar unification done (b5bcabf core / 0aa0b11 extra): lib MenuBar gained MenuBarStyles+SetStyles (mirrors Palette), res-code's bespoke menubar.go deleted in favor of the shared widget — verified pixel-identical headlessly in both chrome modes. Widget sweep complete: draw helpers, Palette, MenuBar all unified in core/lib.

MenuBar unification done (`b5bcabf` core / `0aa0b11` extra): lib MenuBar gained `MenuBarStyles`+`SetStyles` (mirrors Palette), res-code's bespoke menubar.go deleted in favor of the shared widget — verified pixel-identical headlessly in both chrome modes. Widget sweep complete: draw helpers, Palette, MenuBar all unified in `core/lib`.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
residual/.agent#33
No description provided.