feat(tui): flip the terminal UI to the designed LEM mockup#21
Conversation
Aligns both layers to the canonical design (files/Lethean-tui/tui/LEM TUI.html):
the .ctml structure/labels and the host-provided runtime text in the .go where
the design's strings actually live.
- Tabs: ○/● glyphs, canonical panel names at every width (no narrow rename)
- Chat: designed empty-state ("no model loaded — open Models and choose one.
The prompt below stays put either way."), SESSIONS bar, teal hierarchy
- Models: dense three-column table (Model / Engine / Snapshot path)
- Service: state toggle, ‹ :36911 › address stepper, OpenAI/Anthropic/Ollama
client-hint grid at localhost:36911, smoke curl, shared-lane note
- Work / Data: designed empty-states
- Inspector: per-tab sections match the mockup (SESSION/MODEL/GENERATION/
SETTINGS/MODE/TOOLS/KNOWLEDGE; MODEL DETAIL/LOADED; ADDRESS/REQUESTS/STATE)
- Footer: "tab panels · ctrl+k commands · ctrl+o inspector · f1 help"
Panel update loops and domain behaviour preserved. Intentional render changes
pinned in the sibling _test.go (new service_test.go); no golden files gamed.
Gates: go build ./cli/... (exit 0), go test ./cli/tui/... (424 pass), frames
render exact at 150x44 (every line 150 cols).
Co-Authored-By: Virgil <virgil@lethean.io>
📝 WalkthroughWalkthroughThe TUI now uses canonical panel copy, a borderless fixed-width Models table, revised service and inspector indicators, dynamic chat/session/footer rendering, consistent panel labels, updated styling, and expanded rendering tests. ChangesTUI rendering and interaction
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
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 `@cli/tui/inspector.go`:
- Around line 208-212: Update the loaded indicator logic in the models body
rendering to track the loaded model path from loadedMsg rather than the display
name. Compare selected.path against the loaded path when determining loadedClass
and loaded, while preserving the existing success and default indicator values.
In `@cli/tui/palette.go`:
- Around line 168-169: Update the go-html render-version notes in
cli/tui/palette.go and cli/tui/palette.ctml to cite v0.16.0, or revise both
notes to use version-neutral wording; keep the surrounding rendering guidance
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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ec2a7e9-d2af-4811-8a28-7ab94fa7c24a
📒 Files selected for processing (22)
cli/tui/README.mdcli/tui/app.gocli/tui/app_test.gocli/tui/datalist.ctmlcli/tui/datapanel.gocli/tui/datapanel_test.gocli/tui/inspector.gocli/tui/inspector_test.gocli/tui/layout.gocli/tui/layout_test.gocli/tui/palette.ctmlcli/tui/palette.gocli/tui/picker.ctmlcli/tui/picker.gocli/tui/picker_test.gocli/tui/service.gocli/tui/service_test.gocli/tui/style.gocli/tui/tabs.gocli/tui/tabs_test.gocli/tui/work.gocli/tui/work_test.go
| loadedClass, loaded := "c-status", "○ none" | ||
| if target.modelName != "" { | ||
| loadedClass, loaded = "c-success", "● "+target.modelName | ||
| if selected, ok := target.picker.SelectedItem().(modelItem); ok && target.modelName == selected.name { | ||
| loadedClass, loaded = "c-success", "● loaded" | ||
| } | ||
| sequences["modelsBody"] = append(sequences["modelsBody"], map[string]any{"loadedClass": loadedClass, "loaded": loaded}) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== repo files matching inspector.go/app.go =="
fd -a '^(inspector\.go|app\.go)$' . | sed 's#^\./##'
echo "== outline cli/tui/inspector.go =="
ast-grep outline cli/tui/inspector.go --view expanded || true
echo "== relevant inspector.go lines =="
cat -n cli/tui/inspector.go | sed -n '170,230p'
echo "== search modelName/modelName assignment and beginModelLoad/loadedMsg =="
rg -n "modelName|modelPath|loading|beginModelLoad|loadedMsg|SelectedItem\\(\\)|modelsBody" cli/tui app.go || true
echo "== app.go relevant lines if present =="
if [ -f cli/tui/app.go ]; then
cat -n cli/tui/app.go | sed -n '1,260p'
fiRepository: dAppCore/go-inference
Length of output: 20339
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== app.go model item/build/discovery/load relevant sections =="
cat -n cli/tui/app.go | sed -n '330,390p'
cat -n cli/tui/app.go | sed -n '1320,1380p'
cat -n cli/tui/app.go | sed -n '2085,2125p'
cat -n cli/tui/app.go | sed -n '2248,2280p'
echo "== searches for item types and duplicate handling =="
rg -n "type modelItem|struct .*modelItem|DisplayName|displayName|modelItem|deduplicat|duplicate|map\\[string\\]|modelPath|pendingModel|a\\.modelName|target\\.modelName|beginModelLoad|loading = \"\"" cli/tui
echo "== dataListItem/type definitions =="
rg -n "type dataListItem|itemModel|ListItem|SelectedItem\\(\\)\\.(modelItem|dataListItem|workListItem)|\\bItem\\b:=" cli/tuiRepository: dAppCore/go-inference
Length of output: 39378
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== cli/tui/picker.go =="
cat -n cli/tui/picker.go | sed -n '1,85p'
echo "== inspector_test.go model same-name probe =="
cat -n cli/tui/inspector_test.go
echo "== model item path/name usage occurrences in cli/tui =="
python3 - <<'PY'
from pathlib import Path
p = Path("cli/tui")
for f in p.iterdir():
if f.suffix != ".go":
continue
txt = f.read_text()
if "modelItem" in txt or "modelPath" in txt or "modelName" in txt or "displayName(path)" in txt:
print(f"\n--- {f} ---")
for i, line in enumerate(txt.splitlines(), 1):
if any(s in line for s in ["modelItem", "modelPath", "modelName", "displayName(path)"]):
print(f"{i}: {line}")
PYRepository: dAppCore/go-inference
Length of output: 13565
Use the loaded model path for the “loaded” indicator.
selected.name is the display name derived from displayName(m.Path), while model discovery de-duplicates by path. If two entries share the same name from different snapshot paths, selecting the wrong row can show ● loaded because only target.modelName == selected.name is checked. Track the selected loaded path through loadedMsg and compare selected.path instead.
🤖 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 `@cli/tui/inspector.go` around lines 208 - 212, Update the loaded indicator
logic in the models body rendering to track the loaded model path from loadedMsg
rather than the display name. Compare selected.path against the loaded path when
determining loadedClass and loaded, while preserving the existing success and
default indicator values.
| // go-html v0.13.0) and the marker glyph rides the row, the same form-row | ||
| // idiom settings.ctml uses — plus the zero-or-one-row conditional sections |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -eu
rg -n 'dappco\.re/go/html' -g 'go.mod' -g 'go.sum' .
rg -n 'go-html v0\.13\.0|go-html v0\.16\.0' cli/tui/palette.go cli/tui/palette.ctmlRepository: dAppCore/go-inference
Length of output: 1742
Update the go-html render-version note.
cli/go.mod declares dappco.re/go/html v0.16.0, but these render notes still cite go-html v0.13.0. Update the version in both cli/tui/palette.go and cli/tui/palette.ctml, or make the wording version-neutral.
🤖 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 `@cli/tui/palette.go` around lines 168 - 169, Update the go-html render-version
notes in cli/tui/palette.go and cli/tui/palette.ctml to cite v0.16.0, or revise
both notes to use version-neutral wording; keep the surrounding rendering
guidance unchanged.



Aligns the
lem tuito the canonical design mockup (files/Lethean-tui/tui/LEM TUI.html) across both layers — the.ctmlstructure/labels and the host-provided runtime text in the.gowhere the design's strings live.What changed, by panel
‹ :36911 ›address stepper, OpenAI/Anthropic/Ollama client-hint grid atlocalhost:36911, smoke curl, shared-lane notetab panels · ctrl+k commands · ctrl+o inspector · f1 helpPanel update loops and domain behaviour preserved. Intentional render changes are pinned in the sibling
_test.go(incl. newservice_test.go); no golden files gamed.Gates
go build ./cli/...— exit 0go test ./cli/tui/...— 424 pass🤖 Generated with Claude Code
Co-Authored-By: Virgil virgil@lethean.io
Summary by CodeRabbit