418e38ee46
Reduce timeouts to eliminate 10-30s startup delay when worker is dead (common on WSL2 after hibernate). Add stale PID detection, graceful error handling across all handlers, and error classification that distinguishes worker unavailability from handler bugs. - HEALTH_CHECK 30s→3s, new POST_SPAWN_WAIT (5s), PORT_IN_USE_WAIT (3s) - isProcessAlive() with EPERM handling, cleanStalePidFile() - getPluginVersion() try-catch for shutdown race (#1042) - isWorkerUnavailableError: transport+5xx+429→exit 0, 4xx→exit 2 - No-op handler for unknown event types (#984) - Wrap all handler fetch calls in try-catch for graceful degradation - CLAUDE_MEM_HEALTH_TIMEOUT_MS env var override with validation
59 lines
2.3 KiB
TypeScript
59 lines
2.3 KiB
TypeScript
/**
|
|
* User Message Handler - SessionStart (parallel)
|
|
*
|
|
* Displays context info to user via stderr.
|
|
* Uses exit code 0 (SUCCESS) - stderr is not shown to Claude with exit 0.
|
|
*/
|
|
|
|
import { basename } from 'path';
|
|
import type { EventHandler, NormalizedHookInput, HookResult } from '../types.js';
|
|
import { ensureWorkerRunning, getWorkerPort } from '../../shared/worker-utils.js';
|
|
import { HOOK_EXIT_CODES } from '../../shared/hook-constants.js';
|
|
|
|
export const userMessageHandler: EventHandler = {
|
|
async execute(input: NormalizedHookInput): Promise<HookResult> {
|
|
// Ensure worker is running
|
|
const workerReady = await ensureWorkerRunning();
|
|
if (!workerReady) {
|
|
// Worker not available — skip user message gracefully
|
|
return { exitCode: HOOK_EXIT_CODES.SUCCESS };
|
|
}
|
|
|
|
const port = getWorkerPort();
|
|
const project = basename(input.cwd ?? process.cwd());
|
|
|
|
// Fetch formatted context directly from worker API
|
|
// Note: Removed AbortSignal.timeout to avoid Windows Bun cleanup issue (libuv assertion)
|
|
try {
|
|
const response = await fetch(
|
|
`http://127.0.0.1:${port}/api/context/inject?project=${encodeURIComponent(project)}&colors=true`,
|
|
{ method: 'GET' }
|
|
);
|
|
|
|
if (!response.ok) {
|
|
// Don't throw - context fetch failure should not block the user's prompt
|
|
return { exitCode: HOOK_EXIT_CODES.SUCCESS };
|
|
}
|
|
|
|
const output = await response.text();
|
|
|
|
// Write to stderr for user visibility
|
|
// Note: Using process.stderr.write instead of console.error to avoid
|
|
// Claude Code treating this as a hook error. The actual hook output
|
|
// goes to stdout via hook-command.ts JSON serialization.
|
|
process.stderr.write(
|
|
"\n\n" + String.fromCodePoint(0x1F4DD) + " Claude-Mem Context Loaded\n\n" +
|
|
output +
|
|
"\n\n" + String.fromCodePoint(0x1F4A1) + " Wrap any message with <private> ... </private> to prevent storing sensitive information.\n" +
|
|
"\n" + String.fromCodePoint(0x1F4AC) + " Community https://discord.gg/J4wttp9vDu" +
|
|
`\n` + String.fromCodePoint(0x1F4FA) + ` Watch live in browser http://localhost:${port}/\n`
|
|
);
|
|
} catch (error) {
|
|
// Worker unreachable — skip user message gracefully
|
|
// User message context error is non-critical — skip gracefully
|
|
}
|
|
|
|
return { exitCode: HOOK_EXIT_CODES.SUCCESS };
|
|
}
|
|
};
|