diff --git a/ui-tui-opentui-v2/src/test/render.test.tsx b/ui-tui-opentui-v2/src/test/render.test.tsx index 56bda3ea04c..5f1825c756c 100644 --- a/ui-tui-opentui-v2/src/test/render.test.tsx +++ b/ui-tui-opentui-v2/src/test/render.test.tsx @@ -177,6 +177,28 @@ describe('App render (Phase 1, themed)', () => { expect(frame).toContain('Tab complete') // dropdown hint }) + test('the empty transcript shows the home hint (item 12)', async () => { + const store = createSessionStore() + store.apply({ type: 'gateway.ready' }) + + const frame = await captureFrame( + () => ( + store.state.theme}> + + + ), + { until: '/help', width: 72, height: 20 } + ) + + // (theme-independent assertions — testRender reuses a global root, so a prior + // test's skin/brand can bleed; the real app has one store. The home hint's + // content is what matters here.) + expect(frame).toContain('/help') // common command + expect(frame).toContain('/agents') + expect(frame).toContain('resume a session') + expect(frame).toContain('to mention') // the input tips line + }) + test('the status bar renders model · context% · cwd (item 14)', async () => { const store = createSessionStore() store.apply({ type: 'gateway.ready' }) diff --git a/ui-tui-opentui-v2/src/view/homeHint.tsx b/ui-tui-opentui-v2/src/view/homeHint.tsx new file mode 100644 index 00000000000..cdac3b8bc83 --- /dev/null +++ b/ui-tui-opentui-v2/src/view/homeHint.tsx @@ -0,0 +1,50 @@ +/** + * HomeHint — the empty-transcript home screen (item 12; Ink's `helpHint.tsx`). + * Shown when there are no messages yet: the brand line, a few common commands, + * and the key input tips. Replaced by the transcript as soon as a turn lands. + * Fully themed; decorative, so `selectable={false}` (item 4). + */ +import { For } from 'solid-js' + +import { useTheme } from './theme.tsx' + +const COMMANDS: ReadonlyArray = [ + ['/help', 'list all commands'], + ['/model', 'switch model'], + ['/sessions', 'resume a session'], + ['/skills', 'browse skills'], + ['/agents', 'live delegation trace'], + ['/clear', 'clear the transcript'] +] + +export function HomeHint() { + const theme = useTheme() + return ( + + + {theme().brand.icon} + {theme().brand.name} + + + {theme().brand.welcome} + + + + {([cmd, desc]) => ( + + {cmd.padEnd(11)} + {desc} + + )} + + + + + + Type to chat · ↑↓ history · @file to mention · Ctrl+C to stop/quit + + + + + ) +} diff --git a/ui-tui-opentui-v2/src/view/transcript.tsx b/ui-tui-opentui-v2/src/view/transcript.tsx index d8d3380e3f2..7bf8415ed65 100644 --- a/ui-tui-opentui-v2/src/view/transcript.tsx +++ b/ui-tui-opentui-v2/src/view/transcript.tsx @@ -11,15 +11,20 @@ * measurement → phantom scroll offset that clips the top + leaves a gap), * - `stickyScroll` + `stickyStart="bottom"` to pin the latest line. */ -import { For } from 'solid-js' +import { For, Show } from 'solid-js' import type { SessionStore } from '../logic/store.ts' +import { HomeHint } from './homeHint.tsx' import { MessageLine } from './messageLine.tsx' export function Transcript(props: { store: SessionStore }) { return ( + {/* empty-transcript home screen (item 12); replaced by messages on the first turn */} + + + {message => }