mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 15:09:42 +02:00
feat: add Claude Code hooks for desktop notifications
Wire Claude Code's official hooks system (Notification, Stop) to POST back to Claudeman's new /api/hook-event endpoint, which broadcasts SSE events consumed by the existing NotificationManager for desktop alerts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ import { ScreenManager } from '../screen-manager.js';
|
||||
import { getStore } from '../state-store.js';
|
||||
import { generateClaudeMd } from '../templates/claude-md.js';
|
||||
import { parseRalphLoopConfig, extractCompletionPhrase } from '../ralph-config.js';
|
||||
import { writeHooksConfig } from '../hooks-config.js';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import {
|
||||
getErrorMessage,
|
||||
@@ -39,6 +40,7 @@ import {
|
||||
type QuickStartRequest,
|
||||
type CreateScheduledRunRequest,
|
||||
type QuickRunRequest,
|
||||
type HookEventRequest,
|
||||
type ApiResponse,
|
||||
type SessionResponse,
|
||||
type QuickStartResponse,
|
||||
@@ -1081,6 +1083,9 @@ export class WebServer extends EventEmitter {
|
||||
// Write .mcp.json for Claude Code to discover spawn tools
|
||||
this.writeMcpConfig(casePath);
|
||||
|
||||
// Write .claude/settings.local.json with hooks for desktop notifications
|
||||
writeHooksConfig(casePath);
|
||||
|
||||
this.broadcast('case:created', { name, path: casePath });
|
||||
|
||||
return { success: true, case: { name, path: casePath } };
|
||||
@@ -1221,6 +1226,9 @@ export class WebServer extends EventEmitter {
|
||||
// Write .mcp.json for Claude Code to discover spawn tools
|
||||
this.writeMcpConfig(casePath);
|
||||
|
||||
// Write .claude/settings.local.json with hooks for desktop notifications
|
||||
writeHooksConfig(casePath);
|
||||
|
||||
this.broadcast('case:created', { name: caseName, path: casePath });
|
||||
} catch (err) {
|
||||
return { success: false, error: `Failed to create case: ${getErrorMessage(err)}` };
|
||||
@@ -1447,6 +1455,21 @@ export class WebServer extends EventEmitter {
|
||||
}
|
||||
return { success: true, data: { agentId } };
|
||||
});
|
||||
|
||||
// ========== Hook Events ==========
|
||||
|
||||
this.app.post('/api/hook-event', async (req) => {
|
||||
const { event, sessionId } = req.body as HookEventRequest;
|
||||
const validEvents = ['idle_prompt', 'permission_prompt', 'stop'] as const;
|
||||
if (!event || !validEvents.includes(event as typeof validEvents[number])) {
|
||||
return createErrorResponse(ApiErrorCode.INVALID_INPUT, 'Invalid event type');
|
||||
}
|
||||
if (!sessionId || !this.sessions.has(sessionId)) {
|
||||
return createErrorResponse(ApiErrorCode.NOT_FOUND, 'Session not found');
|
||||
}
|
||||
this.broadcast(`hook:${event}`, { sessionId, timestamp: Date.now() });
|
||||
return { success: true };
|
||||
});
|
||||
}
|
||||
|
||||
/** Persists full session state including respawn config to state.json */
|
||||
|
||||
Reference in New Issue
Block a user