mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
fix(x): hide grant-scope buttons where no grant persistence exists
The permission card offered "Allow for Session" and "Always Allow" on the turns path (full-screen chat and side-pane), but the sessions layer never persists grants — the scope rode respondToPermission metadata that nothing consumes, so both buttons behaved exactly like "Approve" once while telling the user otherwise. Grant persistence itself is deferred until there is a sound notion of grant keys (executeCommand parsing is not AST-based), and auto-permission mode covers the fatigue meanwhile. The dropdown now renders only when the caller wires the scope handlers. The legacy code-mode chat keeps them (runs:authorizePermission does persist grants there); the turns-path call sites stop passing them and drop the dead scope plumbing from their handlers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7b01d1b404
commit
8a41cd480a
3 changed files with 10 additions and 9 deletions
|
|
@ -3150,7 +3150,6 @@ function App() {
|
||||||
toolCallId: string,
|
toolCallId: string,
|
||||||
subflow: string[],
|
subflow: string[],
|
||||||
response: 'approve' | 'deny',
|
response: 'approve' | 'deny',
|
||||||
scope?: 'once' | 'session' | 'always',
|
|
||||||
) => {
|
) => {
|
||||||
if (!runId) return
|
if (!runId) return
|
||||||
|
|
||||||
|
|
@ -3159,7 +3158,6 @@ function App() {
|
||||||
await sessionChat.respondToPermission(
|
await sessionChat.respondToPermission(
|
||||||
toolCallId,
|
toolCallId,
|
||||||
response === 'approve' ? 'allow' : 'deny',
|
response === 'approve' ? 'allow' : 'deny',
|
||||||
scope ? { scope } : undefined,
|
|
||||||
)
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to authorize permission:', error)
|
console.error('Failed to authorize permission:', error)
|
||||||
|
|
@ -6834,8 +6832,6 @@ function App() {
|
||||||
toolCall={permRequest.toolCall}
|
toolCall={permRequest.toolCall}
|
||||||
permission={permRequest.permission}
|
permission={permRequest.permission}
|
||||||
onApprove={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve')}
|
onApprove={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve')}
|
||||||
onApproveSession={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'session')}
|
|
||||||
onApproveAlways={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'always')}
|
|
||||||
onDeny={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny')}
|
onDeny={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny')}
|
||||||
isProcessing={isActive && activeIsWorking}
|
isProcessing={isActive && activeIsWorking}
|
||||||
response={response}
|
response={response}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,13 @@ export const PermissionRequest = ({
|
||||||
const isResponded = response !== null;
|
const isResponded = response !== null;
|
||||||
const isApproved = response === 'approve';
|
const isApproved = response === 'approve';
|
||||||
|
|
||||||
|
// Scope actions ("Allow for Session"/"Always Allow") render only when the
|
||||||
|
// caller wires them: the legacy code-mode path persists grants, but the
|
||||||
|
// turns path has no grant persistence yet and must not show dead buttons.
|
||||||
|
const hasScopeActions =
|
||||||
|
Boolean(onApproveSession || onApproveAlways) &&
|
||||||
|
Boolean(command || filePermission);
|
||||||
|
|
||||||
// Once a response is chosen, collapse the details to just the header.
|
// Once a response is chosen, collapse the details to just the header.
|
||||||
// Users can click the header to expand them again.
|
// Users can click the header to expand them again.
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
@ -180,12 +187,12 @@ export const PermissionRequest = ({
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={onApprove}
|
onClick={onApprove}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
className={cn("flex-1", (command || filePermission) && "rounded-r-none")}
|
className={cn("flex-1", hasScopeActions && "rounded-r-none")}
|
||||||
>
|
>
|
||||||
<CheckIcon className="size-4" />
|
<CheckIcon className="size-4" />
|
||||||
Approve
|
Approve
|
||||||
</Button>
|
</Button>
|
||||||
{(command || filePermission) && (
|
{hasScopeActions && (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,7 @@ interface ChatSidebarProps {
|
||||||
allPermissionRequests?: ChatTabViewState['allPermissionRequests']
|
allPermissionRequests?: ChatTabViewState['allPermissionRequests']
|
||||||
permissionResponses?: ChatTabViewState['permissionResponses']
|
permissionResponses?: ChatTabViewState['permissionResponses']
|
||||||
autoPermissionDecisions?: ChatTabViewState['autoPermissionDecisions']
|
autoPermissionDecisions?: ChatTabViewState['autoPermissionDecisions']
|
||||||
onPermissionResponse?: (toolCallId: string, subflow: string[], response: PermissionResponse, scope?: 'once' | 'session' | 'always') => void
|
onPermissionResponse?: (toolCallId: string, subflow: string[], response: PermissionResponse) => void
|
||||||
onAskHumanResponse?: (toolCallId: string, subflow: string[], response: string) => void
|
onAskHumanResponse?: (toolCallId: string, subflow: string[], response: string) => void
|
||||||
isToolOpenForTab?: (tabId: string, toolId: string) => boolean
|
isToolOpenForTab?: (tabId: string, toolId: string) => boolean
|
||||||
onToolOpenChangeForTab?: (tabId: string, toolId: string, open: boolean) => void
|
onToolOpenChangeForTab?: (tabId: string, toolId: string, open: boolean) => void
|
||||||
|
|
@ -706,8 +706,6 @@ export function ChatSidebar({
|
||||||
toolCall={permRequest.toolCall}
|
toolCall={permRequest.toolCall}
|
||||||
permission={permRequest.permission}
|
permission={permRequest.permission}
|
||||||
onApprove={() => onPermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve')}
|
onApprove={() => onPermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve')}
|
||||||
onApproveSession={() => onPermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'session')}
|
|
||||||
onApproveAlways={() => onPermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'always')}
|
|
||||||
onDeny={() => onPermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny')}
|
onDeny={() => onPermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny')}
|
||||||
isProcessing={isActive && isProcessing && !isWaitingOnHuman}
|
isProcessing={isActive && isProcessing && !isWaitingOnHuman}
|
||||||
response={response}
|
response={response}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue