import { useMemo, useState } from 'react'
import { useTranslation } from '../../i18n'
import { computerUseApi } from '../../api/computerUse'
import { useChatStore } from '../../stores/chatStore'
import type {
ComputerUsePermissionRequest,
ComputerUsePermissionResponse,
} from '../../types/chat'
import { Button } from '../shared/Button'
import { Modal } from '../shared/Modal'
type Props = {
sessionId: string
request: ComputerUsePermissionRequest | null
}
const DEFAULT_GRANT_FLAGS = {
clipboardRead: false,
clipboardWrite: false,
systemKeyCombos: false,
} as const
function denyAllResponse(): ComputerUsePermissionResponse {
return {
granted: [],
denied: [],
flags: { ...DEFAULT_GRANT_FLAGS },
userConsented: false,
}
}
function buildAllowResponse(
request: ComputerUsePermissionRequest,
): ComputerUsePermissionResponse {
const now = Date.now()
const granted = request.apps.flatMap((app) => {
if (!app.resolved || app.alreadyGranted) return []
return [{
bundleId: app.resolved.bundleId,
displayName: app.resolved.displayName,
grantedAt: now,
tier: app.proposedTier,
}]
})
const denied = request.apps.flatMap((app) => {
if (app.resolved) return []
return [{
bundleId: app.requestedName,
reason: 'not_installed' as const,
}]
})
const flags = {
...DEFAULT_GRANT_FLAGS,
...Object.fromEntries(
Object.entries(request.requestedFlags).filter(([, value]) => value === true),
),
}
return {
granted,
denied,
flags,
userConsented: true,
}
}
export function ComputerUsePermissionModal({ sessionId, request }: Props) {
const t = useTranslation()
const respondToComputerUsePermission = useChatStore(
(s) => s.respondToComputerUsePermission,
)
const [openingPane, setOpeningPane] = useState<
'Privacy_Accessibility' | 'Privacy_ScreenCapture' | null
>(null)
const requestedFlags = useMemo(
() =>
request
? Object.entries(request.requestedFlags)
.filter(([, enabled]) => enabled)
.map(([flag]) => flag)
: [],
[request],
)
if (!request) return null
const handleDeny = () => {
respondToComputerUsePermission(
sessionId,
request.requestId,
denyAllResponse(),
)
}
const handleAllow = () => {
respondToComputerUsePermission(
sessionId,
request.requestId,
buildAllowResponse(request),
)
}
const openSettings = async (
pane: 'Privacy_Accessibility' | 'Privacy_ScreenCapture',
) => {
setOpeningPane(pane)
try {
await computerUseApi.openSettings(pane)
} finally {
setOpeningPane(null)
}
}
const tccState = request.tccState
return (
{t('computerUseApproval.tccHint')}
{t('computerUseApproval.notInstalled')}
{t('computerUseApproval.alreadyGranted')}
{t('computerUseApproval.sensitiveApp')}