detached c0f685f

tui: show /help at the bottom of the transcript instead of the top

the help block was prepended to the chat, which pushed any existing
conversation off the top of the viewport on anything but the
shortest sessions. appending it (with scrollOffset=0 so the viewport
sticks to the bottom) means /help is always visible right above the
editor, exactly where the user's eye is already looking.

login / model / sessions dialogs already render in the bottom-sticky
band between chat and editor, so they weren't affected.
commit
c0f685f498c54c98b26a5f9956bdaf9a01f831da
author
patriceckhart · · 2026-04-18 09:31 UTC
parent
8a13141
signature
unsigned
refs
tag: v0.0.3
1 file · +9 -2
M internal/agent/modes/interactive.go +9 -2
@@ -349,9 +349,12 @@ func (i *Interactive) redraw() {
349349 chat = append(welcomeBanner(i.cfg.Theme), chat...)
350350 }
351351
352- // /help block: rendered above the welcome / transcript when active.
352+ // /help block: appended to the transcript so it appears at the
353+ // bottom of the chat area (right above the status bar / editor).
354+ // Prepending it would push long conversations off the top of the
355+ // viewport, which users would miss entirely.
353356 if len(i.helpBlock) > 0 {
354- chat = append(append([]string(nil), i.helpBlock...), chat...)
357+ chat = append(chat, i.helpBlock...)
355358 }
356359
357360 if i.statusOK != "" {
@@ -716,6 +719,10 @@ func (i *Interactive) runSlash(ctx context.Context, cmd string) (done bool) {
716719 i.helpBlock = renderHelpBlock(i.cfg.Theme, i.lastCols())
717720 i.statusErr = ""
718721 i.statusOK = ""
722+ // Pin the viewport to the newest content so the help block,
723+ // which we just appended to the end of the transcript, is
724+ // what the user actually sees.
725+ i.scrollOffset = 0
719726 i.mu.Unlock()
720727 case "/login":
721728 i.dialog.Open()
@@ -349,9 +349,12 @@ func (i *Interactive) redraw() {
349 chat = append(welcomeBanner(i.cfg.Theme), chat...)349 chat = append(welcomeBanner(i.cfg.Theme), chat...)
350 }350 }
351 351
352- // /help block: rendered above the welcome / transcript when active.352+ // /help block: appended to the transcript so it appears at the
353+ // bottom of the chat area (right above the status bar / editor).
354+ // Prepending it would push long conversations off the top of the
355+ // viewport, which users would miss entirely.
353 if len(i.helpBlock) > 0 {356 if len(i.helpBlock) > 0 {
354- chat = append(append([]string(nil), i.helpBlock...), chat...)357+ chat = append(chat, i.helpBlock...)
355 }358 }
356 359
357 if i.statusOK != "" {360 if i.statusOK != "" {
@@ -716,6 +719,10 @@ func (i *Interactive) runSlash(ctx context.Context, cmd string) (done bool) {
716 i.helpBlock = renderHelpBlock(i.cfg.Theme, i.lastCols())719 i.helpBlock = renderHelpBlock(i.cfg.Theme, i.lastCols())
717 i.statusErr = ""720 i.statusErr = ""
718 i.statusOK = ""721 i.statusOK = ""
722+ // Pin the viewport to the newest content so the help block,
723+ // which we just appended to the end of the transcript, is
724+ // what the user actually sees.
725+ i.scrollOffset = 0
719 i.mu.Unlock()726 i.mu.Unlock()
720 case "/login":727 case "/login":
721 i.dialog.Open()728 i.dialog.Open()

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close