mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-06 16:31:12 +08:00
feat(a2ui): Implement A2UI backend with question handling and WebSocket support
- Added A2UITypes for defining question structures and answers. - Created A2UIWebSocketHandler for managing WebSocket connections and message handling. - Developed ask-question tool for interactive user questions via A2UI. - Introduced platformUtils for platform detection and shell command handling. - Centralized TypeScript types in index.ts for better organization. - Implemented compatibility checks for hook templates based on platform requirements.
This commit is contained in:
156
ccw/frontend/src/hooks/useWebSocketNotifications.ts
Normal file
156
ccw/frontend/src/hooks/useWebSocketNotifications.ts
Normal file
@@ -0,0 +1,156 @@
|
||||
// ========================================
|
||||
// useWebSocketNotifications Hook
|
||||
// ========================================
|
||||
// Watches wsLastMessage from notificationStore and maps WebSocket events
|
||||
// to persistent notifications for the notification panel
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useNotificationStore } from '@/stores';
|
||||
import type { WebSocketMessage } from '@/types/store';
|
||||
|
||||
// WebSocket message types that should create persistent notifications
|
||||
type NotificationEventType =
|
||||
| 'SESSION_CREATED'
|
||||
| 'TASK_COMPLETED'
|
||||
| 'TASK_FAILED'
|
||||
| 'CLI_EXECUTION_STARTED'
|
||||
| 'CLI_EXECUTION_COMPLETED'
|
||||
| 'MEMORY_UPDATED';
|
||||
|
||||
interface SessionCreatedPayload {
|
||||
sessionId: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
interface TaskEventPayload {
|
||||
sessionId?: string;
|
||||
taskId?: string;
|
||||
summary?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
interface CliExecutionPayload {
|
||||
executionId: string;
|
||||
tool: string;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
interface MemoryUpdatedPayload {
|
||||
memoryId?: string;
|
||||
operation?: string;
|
||||
}
|
||||
|
||||
export function useWebSocketNotifications(): void {
|
||||
const wsLastMessage = useNotificationStore((state) => state.wsLastMessage);
|
||||
const setWsLastMessage = useNotificationStore((state) => state.setWsLastMessage);
|
||||
const addPersistentNotification = useNotificationStore(
|
||||
(state) => state.addPersistentNotification
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Only process when we have a message
|
||||
if (!wsLastMessage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { type, payload } = wsLastMessage as WebSocketMessage & {
|
||||
payload?: unknown;
|
||||
};
|
||||
|
||||
// Route message type to appropriate notification
|
||||
switch (type as NotificationEventType) {
|
||||
case 'SESSION_CREATED': {
|
||||
const data = payload as SessionCreatedPayload | undefined;
|
||||
const sessionId = data?.sessionId || 'unknown';
|
||||
const title = data?.title ? `"${data.title}"` : '';
|
||||
|
||||
addPersistentNotification({
|
||||
type: 'info',
|
||||
title: 'Session Created',
|
||||
message: `New session ${title}created (${sessionId})`,
|
||||
read: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'TASK_COMPLETED': {
|
||||
const data = payload as TaskEventPayload | undefined;
|
||||
const summary = data?.summary || 'Task completed successfully';
|
||||
const taskId = data?.taskId;
|
||||
|
||||
addPersistentNotification({
|
||||
type: 'success',
|
||||
title: 'Task Completed',
|
||||
message: taskId ? `${summary} (${taskId})` : summary,
|
||||
read: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'TASK_FAILED': {
|
||||
const data = payload as TaskEventPayload | undefined;
|
||||
const error = data?.error || 'Task execution failed';
|
||||
const taskId = data?.taskId;
|
||||
|
||||
addPersistentNotification({
|
||||
type: 'error',
|
||||
title: 'Task Failed',
|
||||
message: taskId ? `${error} (${taskId})` : error,
|
||||
duration: 0, // Errors don't auto-dismiss
|
||||
read: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'CLI_EXECUTION_STARTED': {
|
||||
const data = payload as CliExecutionPayload | undefined;
|
||||
const tool = data?.tool || 'CLI';
|
||||
|
||||
addPersistentNotification({
|
||||
type: 'info',
|
||||
title: 'CLI Execution Started',
|
||||
message: `${tool} execution started`,
|
||||
read: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'CLI_EXECUTION_COMPLETED': {
|
||||
const data = payload as CliExecutionPayload | undefined;
|
||||
const tool = data?.tool || 'CLI';
|
||||
const duration = data?.duration;
|
||||
const durationText = duration ? ` (${duration}ms)` : '';
|
||||
|
||||
addPersistentNotification({
|
||||
type: 'success',
|
||||
title: 'CLI Execution Completed',
|
||||
message: `${tool} execution completed${durationText}`,
|
||||
read: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'MEMORY_UPDATED': {
|
||||
const data = payload as MemoryUpdatedPayload | undefined;
|
||||
const operation = data?.operation || 'update';
|
||||
|
||||
addPersistentNotification({
|
||||
type: 'info',
|
||||
title: 'Memory Updated',
|
||||
message: `Memory ${operation} completed`,
|
||||
read: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// Unknown message type - ignore
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the message after processing to prevent duplicate handling
|
||||
setWsLastMessage(null);
|
||||
}, [wsLastMessage, addPersistentNotification, setWsLastMessage]);
|
||||
}
|
||||
|
||||
export default useWebSocketNotifications;
|
||||
Reference in New Issue
Block a user