import React, { useCallback, useMemo } from 'react'; import { Box, Text, useTheme } from '@anthropic/ink'; import { getTheme } from 'src/utils/theme.js'; import { env } from 'src/utils/env.js'; import { shouldShowAlwaysAllowOptions } from 'src/utils/permissions/permissionsLoader.js'; import { logUnaryEvent } from 'src/utils/unaryLogging.js'; import { PermissionDialog } from 'src/components/permissions/PermissionDialog.js'; import { PermissionPrompt, type PermissionPromptOption } from 'src/components/permissions/PermissionPrompt.js'; import type { PermissionRequestProps } from 'src/components/permissions/PermissionRequest.js'; import { PermissionRuleExplanation } from 'src/components/permissions/PermissionRuleExplanation.js'; type OptionValue = 'yes' | 'yes-dont-ask-again' | 'no'; /** * Permission request UI for the WorkflowTool. Asks the user to confirm * executing a workflow script. * Follows the MonitorPermissionRequest / FallbackPermissionRequest pattern. */ export function WorkflowPermissionRequest({ toolUseConfirm, onDone, onReject, workerBadge, }: PermissionRequestProps): React.ReactNode { const [themeName] = useTheme(); const theme = getTheme(themeName); const input = toolUseConfirm.input as { workflow: string; args?: string; }; const showAlwaysAllowOptions = useMemo(() => shouldShowAlwaysAllowOptions(), []); const options: PermissionPromptOption[] = useMemo(() => { const opts: PermissionPromptOption[] = [ { label: 'Yes', value: 'yes', feedbackConfig: { type: 'accept' as const }, }, ]; if (showAlwaysAllowOptions) { opts.push({ label: ( Yes, and don{'\u2019'}t ask again for {toolUseConfirm.tool.name} commands ), value: 'yes-dont-ask-again', }); } opts.push({ label: 'No', value: 'no', feedbackConfig: { type: 'reject' as const }, }); return opts; }, [showAlwaysAllowOptions, toolUseConfirm.tool.name]); const handleSelect = useCallback( (value: OptionValue, feedback?: string) => { switch (value) { case 'yes': logUnaryEvent({ completion_type: 'tool_use_single', event: 'accept', metadata: { language_name: 'none', message_id: toolUseConfirm.assistantMessage.message.id ?? '', platform: env.platform, }, }); toolUseConfirm.onAllow(toolUseConfirm.input, [], feedback); onDone(); break; case 'yes-dont-ask-again': logUnaryEvent({ completion_type: 'tool_use_single', event: 'accept', metadata: { language_name: 'none', message_id: toolUseConfirm.assistantMessage.message.id ?? '', platform: env.platform, }, }); toolUseConfirm.onAllow(toolUseConfirm.input, [ { type: 'addRules', rules: [{ toolName: toolUseConfirm.tool.name }], behavior: 'allow', destination: 'localSettings', }, ]); onDone(); break; case 'no': logUnaryEvent({ completion_type: 'tool_use_single', event: 'reject', metadata: { language_name: 'none', message_id: toolUseConfirm.assistantMessage.message.id ?? '', platform: env.platform, }, }); toolUseConfirm.onReject(feedback); onReject(); onDone(); break; } }, [toolUseConfirm, onDone, onReject], ); const handleCancel = useCallback(() => { logUnaryEvent({ completion_type: 'tool_use_single', event: 'reject', metadata: { language_name: 'none', message_id: toolUseConfirm.assistantMessage.message.id ?? '', platform: env.platform, }, }); toolUseConfirm.onReject(); onReject(); onDone(); }, [toolUseConfirm, onDone, onReject]); return ( Execute workflow: {input.workflow} {input.args && Arguments: {input.args}} options={options} onSelect={handleSelect} onCancel={handleCancel} /> ); }