From 6393e00e958c00325bc40ac82a1ff9597583ea6a Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 24 Jan 2026 03:58:51 +0100 Subject: [PATCH] fix: forward hook event data to notifications The server was dropping the `data` field from hook-event POST requests, so notifications always showed generic messages. Now forwards tool name, command, question text, and reason to the frontend. Notifications now show: - permission_prompt: "Bash: docker push prod:latest" - elicitation_dialog: "Merge PR #42 to main?" - idle_prompt: custom message if provided - stop: reason if provided Co-Authored-By: Claude Opus 4.5 --- src/types.ts | 2 ++ src/web/public/app.js | 9 +++++---- src/web/server.ts | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/types.ts b/src/types.ts index 8c6bb28c..37c14f2f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -382,6 +382,8 @@ export interface HookEventRequest { event: HookEventType; /** Session ID from CLAUDEMAN_SESSION_ID env var */ sessionId: string; + /** Additional event data (tool name, command, question, etc.) */ + data?: Record; } // ========== API Response Types ========== diff --git a/src/web/public/app.js b/src/web/public/app.js index 01645367..6382328c 100644 --- a/src/web/public/app.js +++ b/src/web/public/app.js @@ -1135,7 +1135,7 @@ class ClaudemanApp { sessionId: data.sessionId, sessionName: session?.name || data.sessionId, title: 'Waiting for Input', - message: 'Claude is idle and waiting for a prompt', + message: data.message || 'Claude is idle and waiting for a prompt', }); }); @@ -1146,13 +1146,14 @@ class ClaudemanApp { this.tabAlerts.set(data.sessionId, 'action'); this.renderSessionTabs(); } + const toolInfo = data.tool ? `${data.tool}${data.command ? ': ' + data.command : data.file ? ': ' + data.file : ''}` : ''; this.notificationManager?.notify({ urgency: 'critical', category: 'hook-permission', sessionId: data.sessionId, sessionName: session?.name || data.sessionId, title: 'Permission Required', - message: 'Claude needs tool approval to continue', + message: toolInfo || 'Claude needs tool approval to continue', }); }); @@ -1169,7 +1170,7 @@ class ClaudemanApp { sessionId: data.sessionId, sessionName: session?.name || data.sessionId, title: 'Question Asked', - message: 'Claude is asking a question and waiting for your answer', + message: data.question || 'Claude is asking a question and waiting for your answer', }); }); @@ -1182,7 +1183,7 @@ class ClaudemanApp { sessionId: data.sessionId, sessionName: session?.name || data.sessionId, title: 'Response Complete', - message: 'Claude has finished responding', + message: data.reason || 'Claude has finished responding', }); }); } diff --git a/src/web/server.ts b/src/web/server.ts index 82481a08..9ede6c83 100644 --- a/src/web/server.ts +++ b/src/web/server.ts @@ -1459,7 +1459,7 @@ export class WebServer extends EventEmitter { // ========== Hook Events ========== this.app.post('/api/hook-event', async (req) => { - const { event, sessionId } = req.body as HookEventRequest; + const { event, sessionId, data } = req.body as HookEventRequest; const validEvents = ['idle_prompt', 'permission_prompt', 'elicitation_dialog', 'stop'] as const; if (!event || !validEvents.includes(event as typeof validEvents[number])) { return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid event type'); @@ -1476,7 +1476,7 @@ export class WebServer extends EventEmitter { } } - this.broadcast(`hook:${event}`, { sessionId, timestamp: Date.now() }); + this.broadcast(`hook:${event}`, { sessionId, timestamp: Date.now(), ...data }); return { success: true }; }); }