Skip to content

feat(tui): redesign permission prompts#36726

Open
kitlangton wants to merge 1 commit into
v2from
permission-panel
Open

feat(tui): redesign permission prompts#36726
kitlangton wants to merge 1 commit into
v2from
permission-panel

Conversation

@kitlangton

Copy link
Copy Markdown
Contributor

What

Redesign the V2 TUI permission dock around the operation the user is reviewing, revisiting the direction from #20594 against the current V2 permission model.

  • Number permission choices and support direct 1-9 selection.
  • Name shell and external file operations concretely instead of exposing only external_directory.
  • Show compact content summaries with fullscreen inspection for complete writes, edits, patches, shell commands, and diffs.
  • Stack controls and preserve the saved external scope at narrow terminal widths.
  • Show the exact durable scope before confirming Allow always.

1. Compact review
A routine request stays docked and exposes its direct keyboard choices.

△ Permission required
  # Run shell command

  $ printf 'permission demo\n'

  1. Allow once   2. Allow always   3. Reject

2. Full inspection
External mutations summarize their content in the dock and expand to the complete operation with ctrl+f.

3. One external file decision
Approving a built-in external file operation covers its exact, call-scoped read or edit follow-up. A resource mismatch or configured deny still uses normal permission evaluation.

Before / After

Before: An external write first asked for generic directory patterns, then immediately asked again for the write's edit permission. The first prompt did not describe the file content. Permission choices had no numeric shortcuts, every prompt advertised fullscreen, and saved-scope copy described restart-scoped behavior even though V2 approvals are durable and project-scoped.

After: The first prompt identifies the external write, file, canonical directory, saved scope, and content summary. Fullscreen reveals the complete content. Approval suppresses only the exact built-in follow-up action and resources from the same session/message/tool call, while explicit denies still win. Allow always keeps a confirmation step that shows the saved scope.

How

  • packages/tui/src/routes/session/permission.tsx derives operation-specific display data from the source tool, adds numbered controls, responsive geometry, scope confirmation, and fullscreen external-content inspection.
  • packages/tui/src/routes/session/index.tsx keys permission prompts by request ID so stage, selection, and fullscreen state cannot leak into the next request.
  • packages/core/src/permission.ts stores one bounded, one-shot external follow-up keyed by the exact tool source and exact action/resources.
  • Built-in file tools attach their expected follow-up to the blocking external assertion; shell intentionally remains a separate command decision.
  • packages/docs/permissions.mdx documents project-scoped approvals and exact external file follow-ups.

Scope

This PR updates the full V2 TUI and V2 Core permission flow. It does not redesign the web app dock or direct-mode mini footer.

Testing

  • bun turbo typecheck --concurrency=3 (push hook, 32 packages)
  • bun run test in packages/core (1,278 passed, 6 skipped)
  • bun run test in packages/tui (217 passed, 1 skipped)
  • bun validate in packages/docs
  • bun broken-links in packages/docs
  • opencode-drive check ./permission-panel.drive.ts
  • OpenCode Drive walkthrough at 120x36 and 44x30: shell scope confirmation, external write summary, fullscreen content, numeric approval, and completion without a second edit prompt

Demo

The captures use an isolated OpenCode Drive instance with a simulated model and real V2 permission/tool execution.

Project-scoped Allow always confirmation

https://github.com/user-attachments/assets/fbf3be2a-bce1-4258-9fdb-ad9cc638690b

External write dock

https://github.com/user-attachments/assets/8a0d01c9-65b7-4bc7-9c7c-a045a8988763

Fullscreen content inspection

https://github.com/user-attachments/assets/d68e2e89-c7c6-47f2-82b8-cdea96f3dfdd

44-column layout

https://github.com/user-attachments/assets/169c652e-a47f-433f-8ed6-2567ff7cebda

Flow

flowchart TD
  A[Built-in file tool resolves external target] --> B[Assert external_directory with exact follow-up]
  B --> C[User reviews operation and scope]
  C -->|Reject| D[Stop tool]
  C -->|Allow once / always| E[Remember one exact call-scoped follow-up]
  E --> F[Tool asserts read or edit]
  F --> G{Action and resources match?}
  G -->|Yes, no configured deny| H[Consume grant and execute]
  G -->|No or denied| I[Use normal permission evaluation]
Loading

@Robin1987China

Copy link
Copy Markdown
Contributor

In consumeExternalFollowup, externalFollowups.delete(key) runs before the match check, so a non-matching request from the same source (different action, reordered resources, or a per-file request when the followup listed multiple files) permanently destroys the followup — a later request that would have matched then falls back to prompting.

Also, the resource comparison is exact array equality (same length + same order). Is the order sensitivity intended, or should it be set-based? If the tool can list resources in a different order between the followup metadata and the actual request, the auto-approval silently fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants