Repository navigation
Description
Summary
In the web UI at a narrow (phone) viewport, a permission prompt whose shell
command wraps to many lines grows until it hits its max-height and pushes its
action buttons (Deny / Allow always / Allow once) below the visible
viewport. The request cannot be answered from the phone.
Environment
- opencode version: 2.0.22
- OS: Linux 6.18.33.1-microsoft-standard-WSL2 (x64) — server runs in WSL2, also exposed over a tailnet
- Terminal: N/A for this issue (web UI). Server side:
TERM=xterm-256color - Shell:
/bin/bash(server); client is a mobile browser - Install/channel: release, curl install (
~/.opencode/bin/opencode),update: disablein config - Active plugins: none — no
pluginskey in~/.config/opencode/opencode.jsonc. One local MCP server (zvec_grep) is configured and unrelated. - Client: Chrome on Android (exact Android/Chrome version not captured — the server does not log client user agents)
- Web bundle served by 2.0.22:
index-Ddx0tBUE.css,index-CN8iru5i.js,route-gEGib-yE.js
Reproduction
- Start the server (
opencode serve --service) and open the web UI on a phone. - Configure
permissionsso shell commands ask (e.g.{ "action": "shell", "resource": "*", "effect": "ask" }). - Have the agent run a shell command long enough to wrap across many lines.
- The permission dock appears. As the command text wraps, the dock grows.
- The footer holding Deny / Allow always / Allow once ends up below the bottom edge of the viewport and cannot be reached or tapped, leaving the request stuck.
Consistently reproducible with long commands. Short commands that fit without
wrapping are unaffected, because the dock never reaches its max-height.
Expected Behavior
The action buttons remain visible and tappable. The dock should be bounded by
the space actually available to it, so the scrollable command area absorbs the
overflow instead of the footer being pushed out of view.
Actual Behavior
The footer is clipped below the fold. With a long enough command the prompt is
impossible to answer from the phone.
Additional Context
Component structure
Built in route-gEGib-yE.js (data-component=dock-prompt, data-kind=permission):
<div data-component="dock-prompt" data-kind="permission"> <!-- max-height: 100dvh -->
<div data-slot="permission-body"> <!-- flex:1; min-height:0 -->
<div data-slot="permission-header">…</div>
<div data-slot="permission-content"> <!-- flex:1; min-height:0 -->
<div data-slot="permission-row">…hint…</div>
<div data-slot="permission-row">
<span data-slot="permission-spacer"></span>
<div data-slot="permission-patterns"> <!-- flex:1; overflow-y:auto -->
<code class="text-12-regular text-text-base break-all">…long command…</code>
</div>
</div>
</div>
</div>
<div data-slot="permission-footer"> <!-- flex-shrink:0 -->
<div data-slot="permission-footer-actions">
<button>Deny</button><button>Allow always</button><button>Allow once</button>
</div>
</div>
</div>The footer is also mounted as a data-dock-surface="tray" wrapper
(overflow: clip; border-radius: 12px).
Relevant CSS (verbatim from index-Ddx0tBUE.css in 2.0.22)
[data-component=dock-prompt][data-kind=permission]{flex-direction:column;gap:0;min-height:0;max-height:100dvh;display:flex;position:relative}
[data-component=dock-prompt][data-kind=permission] [data-slot=permission-content]{flex-direction:column;flex:1;gap:4px;min-height:0;display:flex}
[data-component=dock-prompt][data-kind=permission] [data-slot=permission-patterns]{scrollbar-width:none;-ms-overflow-style:none;flex-direction:column;flex:1;gap:6px;min-height:0;margin-top:8px;margin-bottom:16px;padding:1px 0 8px;display:flex;overflow-y:auto}
[data-component=dock-prompt][data-kind=permission] [data-slot=permission-patterns]::-webkit-scrollbar{display:none}
[data-component=dock-prompt][data-kind=permission] [data-slot=permission-footer]{flex-shrink:0;justify-content:space-between;align-items:center;margin-top:-24px;padding:32px 8px 8px;display:flex}Analysis
- The dock caps itself at
max-height: 100dvh— the whole viewport — rather
than the height actually available where it is docked. - The footer is the last flex child and has
flex-shrink: 0, so when the
content overflows it is the footer that ends up outside the visible area. permission-patternsalready hasflex: 1andoverflow-y: auto, so it
can absorb the overflow — but only if the dock's height is bounded by its
container.100dvhdoes not bound it against the visible viewport when
browser chrome or the on-screen keyboard is showing.- The page sets
interactive-widget=resizes-content
(<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content, viewport-fit=cover" />),
which widens the gap betweendvhand the actually visible area on Android. - Secondary: because the scroll container hides its scrollbar
(scrollbar-width: noneplus::-webkit-scrollbar{display:none}), there is no
affordance indicating that the command text scrolls.
Suggested fix
Bound the dock by the space available to it rather than the viewport, e.g. cap
against the parent (max-height: 100% inside a bounded container) or
max-height: min(100dvh, <available>), keeping the footer visible while
permission-patterns scrolls. Consider revealing the scrollbar or adding a fade
so the scrollable command area is discoverable.
Workarounds
- Rotate to landscape (fewer wrapped lines, shorter dock).
- Dismiss the on-screen keyboard and let the URL bar retract.
- Swipe inside the command text — it is a scroll container with a hidden scrollbar.
- Toggle Auto-accept permissions from the command palette
(permissions.autoaccept) to skip the prompt entirely. - Answer the request out of band:
POST /api/session/{sessionID}/permission/{requestID}/replywith
{"decision":"once"}(once|always|reject), e.g. from the TUI or CLI.
Activity
opencode-agent commentedon Oct 18, 2026
Thanks for the very thorough report and CSS analysis! I think this is a duplicate of #49644, which is still open. It describes the same problem: a long command makes the permission prompt taller than the space it has, so the Deny / Allow buttons are pushed off-screen and the request can't be answered.
Possible duplicates and closely related issues, ordered from most to least likely:
Your finding that the dock is capped at
100dvhrather than at the space actually available (it still is ondev), and the phone andinteractive-widget=resizes-contentangle, would be very useful on #49644. Please consider adding them there.The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different.
opencode-agent commentedon Oct 19, 2026
Closing this as a duplicate of #49644, which is still open. It covers the same problem: a long command makes the permission prompt grow until the Deny / Allow buttons are pushed out of view. We waited a day in case your case was different, and since there was no reply, we're tracking it there.
Your analysis would help a lot on #49644, so please consider posting it there. That covers the
max-height: 100dvhcap on the dock, the footer being pushed out, and the Androidinteractive-widget=resizes-contentangle. If your problem turns out to be different after all, reply here and we can reopen it.