Skip to content

feat(scene): render approval/confirm modals as a y/n stub row#996

Merged
esengine merged 1 commit into
mainfrom
rust-scene-approval-modal
May 16, 2026
Merged

feat(scene): render approval/confirm modals as a y/n stub row#996
esengine merged 1 commit into
mainfrom
rust-scene-approval-modal

Conversation

@esengine
Copy link
Copy Markdown
Owner

Fourth sub-PR under the rust direction-B plan (#868).

What

Under `REASONIX_RENDERER=rust` the various pending* confirmation
modals — shell command, sandbox path, edit review, free-form choice,
plan approval — had no scene representation. The user saw the
composer prompt while the loop was actually waiting on a y/n. The
composer is now replaced with a stub row whenever any of those
states is set:

```
❓ [shell] rm -rf /tmp/x [y/n]
```

  • New `SceneTraceInput.approvalKind` / `approvalPrompt` scalar pair
    — primitives keep effect deps stable (no JSON encoding needed for
    one object with two strings).
  • `buildTraceFrame`: when `approvalPrompt` is set, push `approvalRow`
    in place of `composerRow`, and suppress the slash overlay so the
    modal owns the bottom of the frame.
  • Prompt clipped to 60 chars with a trailing ellipsis so a long
    shell command stays readable.
  • `App.tsx` derives the pair via `useMemo` from `pendingShell` /
    `pendingPath` / `pendingEditReview` / `pendingChoice` /
    `pendingPlan`, in that priority order.

Deliberately a stub

Per-modal refinement (the choice options for `pendingChoice`, a diff
preview for `pendingEditReview`, the full plan text and Approve/Refine/
Cancel for `pendingPlan`, etc.) lives in later sub-PRs — this is the
"smallest visible win" so the user at least knows the loop is blocked
on a yes/no question.

Also skipped on purpose: `pendingSessionsPicker` /
`pendingCheckpointPicker` / `pendingMcpHub` (list-pickers, get their
own scene step — handoff step #5), `pendingReviseEditor` (full editor
takeover, owns the screen), `stagedInput` / `stagedChoiceCustom`
(free-form input where the composer should remain visible).

Tests

`tests/scene-trace-frame.test.ts` — 4 new cases:

  • approval row replaces composer; the run sequence contains the kind
    tag, the prompt, and the `[y/n]` suffix
  • overlong prompts are clipped to 60 chars with an ellipsis
  • kind tag is omitted when `approvalKind` is undefined
  • slash overlay is suppressed while an approval is active

`npm run verify` green via prepush gate.

Refs #868

Under REASONIX_RENDERER=rust the various pending* confirmation modals
(shell command, sandbox path, edit review, free-form choice, plan
approval) had no scene representation, so the user saw the composer
prompt while the loop was actually waiting on a y/n. The composer is
now replaced with a `❓ [kind] <prompt>  [y/n]` row whenever any of
those states is set:

- New SceneTraceInput.approvalKind / approvalPrompt scalar pair —
  primitives keep effect deps stable.
- buildTraceFrame: when approvalPrompt is set, push approvalRow in
  place of composerRow and suppress the slash overlay.
- Prompt clipped to 60 chars with a trailing ellipsis so long
  shell commands stay readable.
- App.tsx derives the pair via useMemo from pendingShell / pendingPath
  / pendingEditReview / pendingChoice / pendingPlan, in that priority
  order.

Per-modal refinement (selected option for choice, diff preview for
edits, full plan text, etc.) lives in later sub-PRs — this is the
"smallest visible win" stub.

Refs #868
@esengine esengine merged commit 7c831fc into main May 16, 2026
5 checks passed
@esengine esengine deleted the rust-scene-approval-modal branch May 16, 2026 02:08
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