Skip to content

fix(scene): wire KeystrokeProvider around <Setup> so MaskedInput receives keys under rust mode#999

Merged
esengine merged 1 commit into
mainfrom
rust-scene-setup-keystroke
May 16, 2026
Merged

fix(scene): wire KeystrokeProvider around <Setup> so MaskedInput receives keys under rust mode#999
esengine merged 1 commit into
mainfrom
rust-scene-setup-keystroke

Conversation

@esengine
Copy link
Copy Markdown
Owner

Closes the keystroke half of the rust-renderer Setup gap. The visible
mirror landed in #998; this one makes the form actually interactive
under `REASONIX_RENDERER=rust`.

Why

Under `REASONIX_RENDERER=rust` the JS process runs Ink with a null
stdin (see `src/cli/ui/scene/null-stdin.ts`). `MaskedInput` was
calling Ink's `useInput`, which subscribes to that null stream, so
keys never reached the form. Combined with the previously-invisible
Ink stdout, a fresh user with no saved key sat at a completely dead
prompt.

What

  • `chat.tsx`: the pre-App `` branch is now wrapped in
    `` — the same reader
    the main `` tree below it already uses. So under rust mode
    keys flow from the spawned `reasonix-render --emit-input` child,
    and under the default mode they flow from the singleton
    `StdinReader`.
  • `MaskedInput.tsx`: `useInput` → `useKeystroke`. The hook in
    `keystroke-context.tsx` already falls back to Ink's `useInput`
    when no provider is mounted, so any future caller that mounts
    `MaskedInput` outside a provider keeps working unchanged.

That's the whole change — 15 added / 12 removed across two files.

Result

Combined with #998 (`useSetupSceneTrace` visible feedback), the
`REASONIX_RENDERER=rust` fresh-user path now works end-to-end:

  • User launches with no `DEEPSEEK_API_KEY` set
  • Rust renderer draws the welcome / "enter your DeepSeek API key:"
    / masked-input row in the scene frame
  • Keys typed in the terminal flow through the rust input child and
    back into `MaskedInput` via the provider
  • `saveApiKey` runs on Enter; Setup resolves; `` mounts

Not in scope

  • Stage 3 smoke verification — running the binary on Windows Terminal
    end-to-end to confirm both halves work in practice — is a separate
    step. The unit tests cover the wiring; the UX needs human eyes.
  • `pendingReviseEditor` (full-screen editor takeover) is still
    Ink-only; it's a richer modal and gets its own follow-up.

Refs #868

…ives keys under rust mode

Closes the keystroke half of the rust-renderer Setup gap (visible
mirror landed in the previous PR). Under REASONIX_RENDERER=rust the
JS process runs Ink with a null stdin (src/cli/ui/scene/null-stdin.ts);
MaskedInput used Ink's useInput, which subscribes to that null stream,
so the masked input received nothing and the fresh-user path was a
hard dead end.

- chat.tsx: the pre-App <Setup> branch is now wrapped in
  <KeystrokeProvider reader={keystrokeReader}> — same reader the App
  tree already uses, so under rust mode keys come from the spawned
  reasonix-render --emit-input child, and under default mode they
  come from the stdin reader singleton.
- MaskedInput.tsx: useInput → useKeystroke. The hook already falls
  back to useInput when no provider is mounted, so non-rust callers
  (none today, but future ones) keep working unchanged.

Refs #868
@esengine esengine merged commit 00f9efa into main May 16, 2026
5 checks passed
@esengine esengine deleted the rust-scene-setup-keystroke branch May 16, 2026 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant