import type { Command } from 'commander' import type { AgentPermissionRequest } from '@paseo/server' import { connectToDaemon, getDaemonHost, resolveAgentId } from '../../utils/client.js' import type { CommandOptions, ListResult, OutputSchema, CommandError } from '../../output/index.js' /** Permission response item for display */ export interface PermissionResponseItem { requestId: string agentId: string agentShortId: string name: string result: string } /** Schema for permit allow/deny output */ export const permitResponseSchema: OutputSchema = { idField: 'requestId', columns: [ { header: 'REQUEST ID', field: 'requestId', width: 12 }, { header: 'AGENT', field: 'agentShortId', width: 10 }, { header: 'TOOL', field: 'name', width: 20 }, { header: 'RESULT', field: 'result', width: 10, color: (value) => { if (value === 'allowed') return 'green' if (value === 'denied') return 'red' return undefined }, }, ], } export type PermitAllowResult = ListResult export interface PermitAllowOptions extends CommandOptions { all?: boolean input?: string host?: string } export async function runAllowCommand( agentIdOrPrefix: string, reqId: string | undefined, options: PermitAllowOptions, _command: Command ): Promise { const host = getDaemonHost({ host: options.host }) // No validation needed - if no reqId provided, allow all by default // Parse input JSON if provided let updatedInput: Record | undefined if (options.input) { try { updatedInput = JSON.parse(options.input) } catch (err) { const error: CommandError = { code: 'INVALID_JSON', message: `Invalid JSON for --input: ${err instanceof Error ? err.message : String(err)}`, details: 'Provide valid JSON, e.g., --input \'{"key": "value"}\'', } throw error } } let client try { client = await connectToDaemon({ host: options.host }) } catch (err) { const message = err instanceof Error ? err.message : String(err) const error: CommandError = { code: 'DAEMON_NOT_RUNNING', message: `Cannot connect to daemon at ${host}: ${message}`, details: 'Start the daemon with: paseo daemon start', } throw error } try { // Request session state to get agent information client.requestSessionState() await new Promise((resolve) => setTimeout(resolve, 500)) const agents = client.listAgents() // Resolve agent ID const resolvedAgentId = resolveAgentId(agentIdOrPrefix, agents) if (!resolvedAgentId) { await client.close() const error: CommandError = { code: 'AGENT_NOT_FOUND', message: `Agent not found: ${agentIdOrPrefix}`, details: 'Use "paseo ls" to list available agents', } throw error } // Find the agent const agent = agents.find((a) => a.id === resolvedAgentId) if (!agent) { await client.close() const error: CommandError = { code: 'AGENT_NOT_FOUND', message: `Agent not found: ${resolvedAgentId}`, } throw error } // Get pending permissions for this agent const pendingPermissions = agent.pendingPermissions || [] if (pendingPermissions.length === 0) { await client.close() const error: CommandError = { code: 'NO_PENDING_PERMISSIONS', message: `No pending permissions for agent ${agent.id.slice(0, 7)}`, } throw error } // Determine which permissions to allow let permissionsToAllow: AgentPermissionRequest[] if (!reqId || options.all) { // Default: allow all pending permissions if no req_id specified // --all flag is kept as an explicit alias for clarity permissionsToAllow = pendingPermissions } else { // Find permission by ID prefix const permission = pendingPermissions.find( (p) => p.id === reqId || p.id.startsWith(reqId!) ) if (!permission) { await client.close() const error: CommandError = { code: 'PERMISSION_NOT_FOUND', message: `Permission request not found: ${reqId}`, details: `Available requests: ${pendingPermissions.map((p) => p.id.slice(0, 8)).join(', ')}`, } throw error } permissionsToAllow = [permission] } // Allow permissions const results: PermissionResponseItem[] = [] for (const permission of permissionsToAllow) { await client.respondToPermission(resolvedAgentId, permission.id, { behavior: 'allow', ...(updatedInput ? { updatedInput } : {}), }) results.push({ requestId: permission.id.slice(0, 8), agentId: resolvedAgentId, agentShortId: resolvedAgentId.slice(0, 7), name: permission.name, result: 'allowed', }) } await client.close() return { type: 'list', data: results, schema: permitResponseSchema, } } catch (err) { await client.close().catch(() => {}) // Re-throw CommandErrors if (err && typeof err === 'object' && 'code' in err) { throw err } const message = err instanceof Error ? err.message : String(err) const error: CommandError = { code: 'ALLOW_PERMISSION_FAILED', message: `Failed to allow permission: ${message}`, } throw error } }