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 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-24 03:58:51 +01:00
co-authored by Claude Opus 4.5
parent a2d4303300
commit 6393e00e95
3 changed files with 9 additions and 6 deletions
+2
View File
@@ -382,6 +382,8 @@ export interface HookEventRequest {
event: HookEventType; event: HookEventType;
/** Session ID from CLAUDEMAN_SESSION_ID env var */ /** Session ID from CLAUDEMAN_SESSION_ID env var */
sessionId: string; sessionId: string;
/** Additional event data (tool name, command, question, etc.) */
data?: Record<string, unknown>;
} }
// ========== API Response Types ========== // ========== API Response Types ==========
+5 -4
View File
@@ -1135,7 +1135,7 @@ class ClaudemanApp {
sessionId: data.sessionId, sessionId: data.sessionId,
sessionName: session?.name || data.sessionId, sessionName: session?.name || data.sessionId,
title: 'Waiting for Input', 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.tabAlerts.set(data.sessionId, 'action');
this.renderSessionTabs(); this.renderSessionTabs();
} }
const toolInfo = data.tool ? `${data.tool}${data.command ? ': ' + data.command : data.file ? ': ' + data.file : ''}` : '';
this.notificationManager?.notify({ this.notificationManager?.notify({
urgency: 'critical', urgency: 'critical',
category: 'hook-permission', category: 'hook-permission',
sessionId: data.sessionId, sessionId: data.sessionId,
sessionName: session?.name || data.sessionId, sessionName: session?.name || data.sessionId,
title: 'Permission Required', 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, sessionId: data.sessionId,
sessionName: session?.name || data.sessionId, sessionName: session?.name || data.sessionId,
title: 'Question Asked', 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, sessionId: data.sessionId,
sessionName: session?.name || data.sessionId, sessionName: session?.name || data.sessionId,
title: 'Response Complete', title: 'Response Complete',
message: 'Claude has finished responding', message: data.reason || 'Claude has finished responding',
}); });
}); });
} }
+2 -2
View File
@@ -1459,7 +1459,7 @@ export class WebServer extends EventEmitter {
// ========== Hook Events ========== // ========== Hook Events ==========
this.app.post('/api/hook-event', async (req) => { 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; const validEvents = ['idle_prompt', 'permission_prompt', 'elicitation_dialog', 'stop'] as const;
if (!event || !validEvents.includes(event as typeof validEvents[number])) { if (!event || !validEvents.includes(event as typeof validEvents[number])) {
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid event type'); 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 }; return { success: true };
}); });
} }