52d2f72a82
* Enhance error logging in hooks
- Added detailed error logging in context-hook, new-hook, save-hook, and summary-hook to capture status, project, port, and relevant session information on failures.
- Improved error messages thrown in save-hook and summary-hook to include specific context about the failure.
* Refactor migration logging to use console.log instead of console.error
- Updated SessionSearch and SessionStore classes to replace console.error with console.log for migration-related messages.
- Added notes in the documentation to clarify the use of console.log for migration messages due to the unavailability of the structured logger during constructor execution.
* Refactor SDKAgent and silent-debug utility to simplify error handling
- Updated SDKAgent to use direct defaults instead of happy_path_error__with_fallback for non-critical fields such as last_user_message, last_assistant_message, title, filesRead, filesModified, concepts, and summary.request.
- Enhanced silent-debug documentation to clarify appropriate use cases for happy_path_error__with_fallback, emphasizing its role in handling unexpected null/undefined values while discouraging its use for nullable fields with valid defaults.
* fix: correct happy_path_error__with_fallback usage to prevent false errors
Fixes false "Missing cwd" and "Missing transcript_path" errors that were
flooding silent.log even when values were present.
Root cause: happy_path_error__with_fallback was being called unconditionally
instead of only when the value was actually missing.
Pattern changed from:
value: happy_path_error__with_fallback('Missing', {}, value || '')
To correct usage:
value: value || happy_path_error__with_fallback('Missing', {}, '')
Fixed in:
- src/hooks/save-hook.ts (PostToolUse hook)
- src/hooks/summary-hook.ts (Stop hook)
- src/services/worker/http/routes/SessionRoutes.ts (2 instances)
Impact: Eliminates false error noise, making actual errors visible.
Addresses issue #260 - users were seeing "Missing cwd" errors despite
Claude Code correctly passing all required fields.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Enhance error logging and handling across services
- Improved error messages in SessionStore to include project context when fetching boundary observations and timestamps.
- Updated ChromaSync error handling to provide more informative messages regarding client initialization failures, including the project context.
- Enhanced error logging in WorkerService to include the package path when reading version fails.
- Added detailed error logging in worker-utils to capture expected and running versions during health checks.
- Extended WorkerErrorMessageOptions to include actualError for more informative restart instructions.
* Refactor error handling in hooks to use standardized fetch error handler
- Introduced a new error handler `handleFetchError` in `shared/error-handler.ts` to standardize logging and user-facing error messages for fetch failures across hooks.
- Updated `context-hook.ts`, `new-hook.ts`, `save-hook.ts`, and `summary-hook.ts` to utilize the new error handler, improving consistency and maintainability.
- Removed redundant imports and error handling logic related to worker restart instructions from the hooks.
* feat: add comprehensive error handling tests for hooks and ChromaSync client
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
95 lines
3.3 KiB
TypeScript
95 lines
3.3 KiB
TypeScript
/**
|
|
* Happy Path Error With Fallback
|
|
*
|
|
* Semantic meaning: "When the happy path fails, this is an error, but we have a fallback."
|
|
*
|
|
* Logs to ~/.claude-mem/silent.log and returns a fallback value.
|
|
* Check logs with `npm run logs:silent`
|
|
*
|
|
* Use happy_path_error__with_fallback for:
|
|
* ✅ Unexpected null/undefined values that should theoretically never happen
|
|
* ✅ Defensive coding where silent fallback is acceptable
|
|
* ✅ Situations where you want to track unexpected nulls without breaking execution
|
|
*
|
|
* DO NOT use for:
|
|
* ❌ Nullable fields with valid default behavior (use direct || defaults)
|
|
* ❌ Critical validation failures (use logger.warn or throw Error)
|
|
* ❌ Try-catch blocks where error is already logged (redundant)
|
|
*
|
|
* Good examples:
|
|
* // Truly unexpected null (should never happen in theory)
|
|
* const id = session.id || happy_path_error__with_fallback('session.id missing', { session });
|
|
*
|
|
* Bad examples (use direct defaults instead):
|
|
* // Nullable field with valid empty default
|
|
* const title = obs.title || happy_path_error__with_fallback('obs.title missing', { obs }, '(untitled)');
|
|
* // BETTER: const title = obs.title || '(untitled)';
|
|
*
|
|
* // Array that can validly be undefined/null
|
|
* const count = obs.files?.length ?? (happy_path_error__with_fallback('obs.files missing', { obs }), 0);
|
|
* // BETTER: const count = obs.files?.length ?? 0;
|
|
*/
|
|
|
|
import { appendFileSync } from 'fs';
|
|
import { homedir } from 'os';
|
|
import { join } from 'path';
|
|
|
|
const LOG_FILE = join(homedir(), '.claude-mem', 'silent.log');
|
|
|
|
/**
|
|
* Write an error message to silent.log and return fallback value
|
|
* @param message - Error message describing what went wrong
|
|
* @param data - Optional data to include (will be JSON stringified)
|
|
* @param fallback - Value to return (defaults to empty string)
|
|
* @returns The fallback value (for use in || fallbacks)
|
|
*/
|
|
export function happy_path_error__with_fallback(message: string, data?: any, fallback: string = ''): string {
|
|
const timestamp = new Date().toISOString();
|
|
|
|
// Capture stack trace to get caller location
|
|
const stack = new Error().stack || '';
|
|
const stackLines = stack.split('\n');
|
|
// Line 0: "Error"
|
|
// Line 1: "at silentDebug ..."
|
|
// Line 2: "at <CALLER> ..." <- We want this one
|
|
const callerLine = stackLines[2] || '';
|
|
const callerMatch = callerLine.match(/at\s+(?:.*\s+)?\(?([^:]+):(\d+):(\d+)\)?/);
|
|
const location = callerMatch
|
|
? `${callerMatch[1].split('/').pop()}:${callerMatch[2]}`
|
|
: 'unknown';
|
|
|
|
let logLine = `[${timestamp}] [HAPPY-PATH-ERROR] [${location}] ${message}`;
|
|
|
|
if (data !== undefined) {
|
|
try {
|
|
logLine += ` ${JSON.stringify(data)}`;
|
|
} catch (error) {
|
|
logLine += ` [stringify error: ${error}]`;
|
|
}
|
|
}
|
|
|
|
logLine += '\n';
|
|
|
|
try {
|
|
appendFileSync(LOG_FILE, logLine);
|
|
} catch (error) {
|
|
// If we can't write to the log file, fail silently (it's a debug utility after all)
|
|
// Only write to stderr as a last resort
|
|
console.error('[silent-debug] Failed to write to log:', error);
|
|
}
|
|
|
|
return fallback;
|
|
}
|
|
|
|
/**
|
|
* Clear the silent log file
|
|
*/
|
|
export function clearSilentLog(): void {
|
|
try {
|
|
appendFileSync(LOG_FILE, `\n${'='.repeat(80)}\n[${new Date().toISOString()}] Log cleared\n${'='.repeat(80)}\n\n`);
|
|
} catch (error) {
|
|
// Expected: Log file may not be writable
|
|
}
|
|
}
|
|
|