Implement terminal approval UI system

Phase 1: Backend approval tracking
- Add PendingApprovalsManager class to track pending approvals
- Add approval-request, approval-response, approval-expired WebSocket handlers
- Add requestApproval() method to ClaudeCodeService
- Add event forwarding for approval requests

Phase 2: Frontend approval card component
- Create approval-card.js with interactive UI
- Create approval-card.css with styled component
- Add Approve, Custom Instructions, Reject buttons
- Add expandable custom command input

Phase 3: Wire up approval flow end-to-end
- Add handleApprovalRequest, handleApprovalConfirmed, handleApprovalExpired handlers
- Add detectApprovalRequest() to parse AI approval request patterns
- Integrate approval card into WebSocket message flow
- Route approval responses based on source (server vs AI conversational)

This allows the AI agent to request command approval through a clean
UI instead of confusing conversational text responses.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
uroma
2026-01-21 14:24:13 +00:00
Unverified
parent 153e365c7b
commit a45b71e1e4
7 changed files with 1564 additions and 15 deletions

View File

@@ -293,6 +293,38 @@ class ClaudeCodeService extends EventEmitter {
return { success: true };
}
/**
* Request approval for a command (instead of executing directly)
* @param {string} sessionId - Session ID
* @param {string} command - Command requiring approval
* @param {string} explanation - Human-readable explanation of what will happen
*/
requestApproval(sessionId, command, explanation) {
const session = this.sessions.get(sessionId);
if (!session) {
throw new Error(`Session ${sessionId} not found`);
}
console.log(`[ClaudeService] Requesting approval for session ${sessionId}:`, command);
// Track the pending request in session context
session.context.messages.push({
role: 'system',
content: `[AWAITING APPROVAL: ${command}]`,
timestamp: new Date().toISOString()
});
// Emit approval-request event for WebSocket to handle
this.emit('approval-request', {
sessionId,
command,
explanation
});
return { success: true, awaitingApproval: true };
}
/**
* Get session details (handles both active and historical sessions)
*/