feat(scene): render the SessionPicker list inside the scene frame#997
Merged
Conversation
Under REASONIX_RENDERER=rust the Ink-side SessionPicker rendered to
the null stdout, so a user opening /sessions saw nothing but the
"awaiting input" composer they couldn't actually type into. The scene
producer now mirrors the picker:
- New SceneSessionItem ({ title, meta? }) surfaced via useSceneTrace
as a JSON-encoded array plus a primitive sessionsFocusedIndex.
- buildTraceFrame: when sessions is non-empty, replace composer (and
any approval / slash overlay) with a header row + one focused
windowed row per session (cap 8, with a "…N more" tail when the
list is longer) + a hint footer.
- listWindow extracted as a generic so the same centering logic
serves the slash and sessions blocks.
- SessionPicker gains a tiny onFocusChange callback (useEffect
publishes the local focus state); App.tsx mirrors it into a useState
and into the scene input. No restructuring of SessionPicker beyond
the prop — its useKeystroke handling stays exactly as is.
- App.tsx builds sessionsJson via useMemo from sessionsPickerList
with `${branch} · ${turns} turns` as the meta line; gated on
pendingSessionsPicker so the overlay only appears while the picker
is actually open.
Refs #868
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fifth sub-PR under the rust direction-B plan (#868) — last of the
B-line items from the original handoff.
Why
Under `REASONIX_RENDERER=rust` the Ink-side SessionPicker rendered
to the null stdout, so a user opening `/sessions` saw nothing but
the "awaiting input" composer they couldn't actually type into.
Keystrokes still flowed (SessionPicker already uses `useKeystroke`),
but the user was navigating an invisible list. The scene producer
now mirrors the picker so the fresh-user-with-saved-sessions path
works without falling back to Ink.
What
```
📂 sessions (3 saved)
▸ feat-foo main · 12 turns
hotfix-bar release/4.5 · 3 turns
spike-baz main · 47 turns
↑↓ navigate · ⏎ open · n new · esc cancel
```
`useSceneTrace` as a JSON-encoded array plus a primitive
`sessionsFocusedIndex`, same primitive-deps pattern as the other
picker fields.
(and any approval / slash overlay) with a header row + one focused
windowed row per session (cap `MAX_SESSION_ROWS = 8`, with a
`…N more` tail when the list is longer) + a hint footer.
blocks share centering logic; `slashWindow` becomes a thin wrapper.
`useEffect` publishes the local `focus` state. App.tsx mirrors it
into a `useState` and into the scene input. No restructuring of
`SessionPicker` beyond the prop; its `useKeystroke` handling stays
exactly as is (per the handoff's "don't touch SessionPicker for
useKeystroke purposes" rule — this is state exposure, not
restructuring).
`sessionsPickerList` with `${branch} · ${turns} turns` as the
meta line; gated on `pendingSessionsPicker` so the overlay only
appears while the picker is actually open.
Out of scope
scene doesn't reflect the in-progress rename buffer when the user
presses `r`. The Ink picker still owns that interactive flow.
later sub-PRs as they show up as felt gaps.
Tests
`tests/scene-trace-frame.test.ts` — 7 new cases:
returns `[]` on undefined / empty / non-array / non-JSON input
`npm run verify` green via prepush gate.
Refs #868