UNPKG

cui-server

Version:

Web UI Agent Platform based on Claude Code

116 lines 4.92 kB
import { Router } from 'express'; import { CUIError } from '../types/index.js'; import { createLogger } from '../services/logger.js'; export function createPermissionRoutes(permissionTracker) { const router = Router(); const logger = createLogger('PermissionRoutes'); // Notify endpoint - called by MCP server when permission is requested router.post('/notify', async (req, res, next) => { const requestId = req.requestId; logger.debug('Permission notification received', { requestId, body: req.body }); try { const { toolName, toolInput, streamingId } = req.body; if (!toolName) { throw new CUIError('MISSING_TOOL_NAME', 'toolName is required', 400); } // Add permission request with the provided streamingId const request = permissionTracker.addPermissionRequest(toolName, toolInput, streamingId); logger.debug('Permission request tracked', { requestId, permissionId: request.id, toolName, streamingId: request.streamingId }); res.json({ success: true, id: request.id }); } catch (error) { logger.debug('Permission notification failed', { requestId, error: error instanceof Error ? error.message : String(error) }); next(error); } }); // List permissions router.get('/', async (req, res, next) => { const requestId = req.requestId; logger.debug('List permissions request', { requestId, query: req.query }); try { const { streamingId, status } = req.query; const permissions = permissionTracker.getPermissionRequests({ streamingId, status }); logger.debug('Permissions listed successfully', { requestId, count: permissions.length, filter: { streamingId, status } }); res.json({ permissions }); } catch (error) { logger.debug('List permissions failed', { requestId, error: error instanceof Error ? error.message : String(error) }); next(error); } }); // Permission decision endpoint - called by frontend to approve/deny permissions router.post('/:requestId/decision', async (req, res, next) => { const requestIdHeader = req.requestId; const { requestId } = req.params; const decisionRequest = req.body; logger.debug('Permission decision request', { requestId: requestIdHeader, permissionRequestId: requestId, decision: decisionRequest }); try { // Validate request body if (!decisionRequest.action || !['approve', 'deny'].includes(decisionRequest.action)) { throw new CUIError('INVALID_ACTION', 'Action must be either "approve" or "deny"', 400); } // Get the permission request to validate it exists and is pending const permissions = permissionTracker.getPermissionRequests({ status: 'pending' }); const permission = permissions.find(p => p.id === requestId); if (!permission) { throw new CUIError('PERMISSION_NOT_FOUND', 'Permission request not found or not pending', 404); } // Update permission status let updated; if (decisionRequest.action === 'approve') { updated = permissionTracker.updatePermissionStatus(requestId, 'approved', { modifiedInput: decisionRequest.modifiedInput }); } else { updated = permissionTracker.updatePermissionStatus(requestId, 'denied', { denyReason: decisionRequest.denyReason }); } if (!updated) { throw new CUIError('UPDATE_FAILED', 'Failed to update permission status', 500); } logger.debug('Permission decision processed', { requestId: requestIdHeader, permissionRequestId: requestId, action: decisionRequest.action }); const response = { success: true, message: `Permission ${decisionRequest.action === 'approve' ? 'approved' : 'denied'} successfully` }; res.json(response); } catch (error) { logger.debug('Permission decision failed', { requestId: requestIdHeader, permissionRequestId: requestId, error: error instanceof Error ? error.message : String(error) }); next(error); } }); return router; } //# sourceMappingURL=permission.routes.js.map