Summary
Step 4a (a83bae8) shipped the slash-command picker inside the real InputBar/ChatPanel, but deferred the keyboard-attached tool row from the dev spike at packages/app/src/app/(main)/dev/keyboard-extender.tsx. This issue tracks bringing that into production.
What's deferred
The spike has a 40pt tool row mounted between the composer and the keyboard, holding a / button that:
- Glows accent blue (
#007aff) when the text cursor is at position 0 → tapping inserts / and opens the picker
- Muted color elsewhere → tapping just inserts a literal
/ mid-text
- Slides off-screen when the keyboard is dismissed (three-knob coordination: KSV offset, opacity animation,
pointerEvents)
Rendered via KeyboardStickyView + KeyboardBackgroundView from react-native-keyboard-controller (lib's recommended Android-fallback pattern, also works great on iOS 26).
Why deferred from V0
- Requires restructuring ChatPanel's existing
KeyboardStickyView (currently wraps just the composer); non-zero risk of regressing the inset configuration we stabilized in 3e4b6fc.
- The user-facing benefit (faster slash trigger via tool-row button) is incremental — manually typing
/ already opens the picker in 4a.
- Want a few days of dogfooding on 4a's picker-only UX before adding more keyboard chrome.
Design notes when picked up
- Spike file intact at
packages/app/src/app/(main)/dev/keyboard-extender.tsx; sidebar still links to it for visual reference.
- Keep
useSlashCommandHandler and <SlashPanel> as-is; the tool row is just another way to insert /. No protocol or hook changes needed.
- Re-validate the KSV inset pipeline (composerRef + onLayout +
reportInset SharedValue → LegendList contentInsetEndAdjustment) after wrapping the tool row inside the KSV — KCSV's useAnimatedReaction race-on-mount bug bit us once, the 0→real init-value workaround needs to survive the rewrap.
- Consider whether to also lift
text / textCursor state up to ChatPanel at the same time, so <SlashPanel> can render at a position that doesn't obscure GitStatusBar (currently overlaps it when active — acceptable V0 trade, but the keyboard-extender migration is a natural time to revisit). InputBar would become a controlled component; both screens (chat-panel + new-session) would need to manage text/cursor state.
Related
Summary
Step 4a (
a83bae8) shipped the slash-command picker inside the real InputBar/ChatPanel, but deferred the keyboard-attached tool row from the dev spike atpackages/app/src/app/(main)/dev/keyboard-extender.tsx. This issue tracks bringing that into production.What's deferred
The spike has a 40pt tool row mounted between the composer and the keyboard, holding a
/button that:#007aff) when the text cursor is at position 0 → tapping inserts/and opens the picker/mid-textpointerEvents)Rendered via
KeyboardStickyView + KeyboardBackgroundViewfromreact-native-keyboard-controller(lib's recommended Android-fallback pattern, also works great on iOS 26).Why deferred from V0
KeyboardStickyView(currently wraps just the composer); non-zero risk of regressing the inset configuration we stabilized in3e4b6fc./already opens the picker in 4a.Design notes when picked up
packages/app/src/app/(main)/dev/keyboard-extender.tsx; sidebar still links to it for visual reference.useSlashCommandHandlerand<SlashPanel>as-is; the tool row is just another way to insert/. No protocol or hook changes needed.reportInsetSharedValue → LegendListcontentInsetEndAdjustment) after wrapping the tool row inside the KSV — KCSV'suseAnimatedReactionrace-on-mount bug bit us once, the 0→real init-value workaround needs to survive the rewrap.text/textCursorstate up to ChatPanel at the same time, so<SlashPanel>can render at a position that doesn't obscure GitStatusBar (currently overlaps it when active — acceptable V0 trade, but the keyboard-extender migration is a natural time to revisit). InputBar would become a controlled component; both screens (chat-panel + new-session) would need to manage text/cursor state.Related
a83bae80bb5b6d1d3ca454fce47c