mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39:42 +02:00
feat: hooks forward stdin data from Claude Code to notifications
The hook commands now read stdin JSON from Claude Code (contains tool_name, tool_input, etc.) and forward it as the data field to the API. This enables richer notifications showing actual context (e.g., "Bash: docker push prod"). Previously the curl commands only sent event type and session ID, losing all hook context data. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+10
-4
@@ -16,14 +16,20 @@ import type { HookEventType } from './types.js';
|
||||
/**
|
||||
* Generates the hooks section for .claude/settings.local.json
|
||||
*
|
||||
* The curl commands reference env vars that are resolved at runtime by
|
||||
* the shell, so the same config works for any session in the case dir.
|
||||
* The hook commands read stdin JSON from Claude Code (contains tool_name,
|
||||
* tool_input, etc.) and forward it as the `data` field to Claudeman's API.
|
||||
* Env vars are resolved at runtime by the shell, so the config is static
|
||||
* per case directory.
|
||||
*/
|
||||
export function generateHooksConfig(): { hooks: Record<string, unknown[]> } {
|
||||
// Read Claude Code's stdin JSON and forward it as the data field.
|
||||
// Falls back to empty object if stdin is unavailable or malformed.
|
||||
const curlCmd = (event: HookEventType) =>
|
||||
`curl -s -X POST $CLAUDEMAN_API_URL/api/hook-event ` +
|
||||
`HOOK_DATA=$(cat 2>/dev/null || echo '{}'); ` +
|
||||
`curl -s -X POST "$CLAUDEMAN_API_URL/api/hook-event" ` +
|
||||
`-H 'Content-Type: application/json' ` +
|
||||
`-d '{"event":"${event}","sessionId":"'$CLAUDEMAN_SESSION_ID'"}' 2>/dev/null || true`;
|
||||
`-d "{\\"event\\":\\"${event}\\",\\"sessionId\\":\\"$CLAUDEMAN_SESSION_ID\\",\\"data\\":$HOOK_DATA}" ` +
|
||||
`2>/dev/null || true`;
|
||||
|
||||
return {
|
||||
hooks: {
|
||||
|
||||
@@ -74,11 +74,19 @@ describe('generateHooksConfig', () => {
|
||||
it('should include correct event names in curl payloads', () => {
|
||||
const config = generateHooksConfig();
|
||||
const notifHooks = config.hooks.Notification as Array<{ hooks: Array<{ command: string }> }>;
|
||||
expect(notifHooks[0].hooks[0].command).toContain('"idle_prompt"');
|
||||
expect(notifHooks[1].hooks[0].command).toContain('"permission_prompt"');
|
||||
expect(notifHooks[2].hooks[0].command).toContain('"elicitation_dialog"');
|
||||
expect(notifHooks[0].hooks[0].command).toContain('idle_prompt');
|
||||
expect(notifHooks[1].hooks[0].command).toContain('permission_prompt');
|
||||
expect(notifHooks[2].hooks[0].command).toContain('elicitation_dialog');
|
||||
const stopHooks = config.hooks.Stop as Array<{ hooks: Array<{ command: string }> }>;
|
||||
expect(stopHooks[0].hooks[0].command).toContain('"stop"');
|
||||
expect(stopHooks[0].hooks[0].command).toContain('stop');
|
||||
});
|
||||
|
||||
it('should read stdin and forward as data field', () => {
|
||||
const config = generateHooksConfig();
|
||||
const notifHooks = config.hooks.Notification as Array<{ hooks: Array<{ command: string }> }>;
|
||||
// Should capture stdin via cat and include as $HOOK_DATA
|
||||
expect(notifHooks[0].hooks[0].command).toContain('HOOK_DATA=$(cat');
|
||||
expect(notifHooks[0].hooks[0].command).toContain('$HOOK_DATA');
|
||||
});
|
||||
|
||||
it('should set hook type to command', () => {
|
||||
|
||||
Reference in New Issue
Block a user