/** * Save Hook - PostToolUse * * Pure HTTP client - sends data to worker, worker handles all database operations * including privacy checks. This allows the hook to run under any runtime * (Node.js or Bun) since it has no native module dependencies. */ import { stdin } from 'process'; import { createHookResponse } from './hook-response.js'; import { logger } from '../utils/logger.js'; import { ensureWorkerRunning, getWorkerPort } from '../shared/worker-utils.js'; import { HOOK_TIMEOUTS } from '../shared/hook-constants.js'; import { happy_path_error__with_fallback } from '../utils/silent-debug.js'; import { handleWorkerError } from '../shared/hook-error-handler.js'; export interface PostToolUseInput { session_id: string; cwd: string; tool_name: string; tool_input: any; tool_response: any; } /** * Save Hook Main Logic - Fire-and-forget HTTP client */ async function saveHook(input?: PostToolUseInput): Promise { // Ensure worker is running before any other logic await ensureWorkerRunning(); if (!input) { throw new Error('saveHook requires input'); } const { session_id, cwd, tool_name, tool_input, tool_response } = input; const port = getWorkerPort(); const toolStr = logger.formatTool(tool_name, tool_input); logger.dataIn('HOOK', `PostToolUse: ${toolStr}`, { workerPort: port }); try { // Send to worker - worker handles privacy check and database operations const response = await fetch(`http://127.0.0.1:${port}/api/sessions/observations`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ claudeSessionId: session_id, tool_name, tool_input, tool_response, cwd: happy_path_error__with_fallback( 'Missing cwd in PostToolUse hook input', { session_id, tool_name }, cwd || '' ) }), signal: AbortSignal.timeout(HOOK_TIMEOUTS.DEFAULT) }); if (!response.ok) { const errorText = await response.text(); logger.failure('HOOK', 'Failed to send observation', { status: response.status }, errorText); throw new Error(`Failed to send observation to worker: ${response.status} ${errorText}`); } logger.debug('HOOK', 'Observation sent successfully', { toolName: tool_name }); } catch (error: any) { handleWorkerError(error); } console.log(createHookResponse('PostToolUse', true)); } // Entry Point let input = ''; stdin.on('data', (chunk) => input += chunk); stdin.on('end', async () => { const parsed = input ? JSON.parse(input) : undefined; await saveHook(parsed); });