diff --git a/src/application/handlers/CommitMsgHandler.ts b/src/application/handlers/CommitMsgHandler.ts index f30e5b1c..dfee6d6b 100644 --- a/src/application/handlers/CommitMsgHandler.ts +++ b/src/application/handlers/CommitMsgHandler.ts @@ -122,11 +122,15 @@ export class CommitMsgHandler implements IEventHandler { success: true, }; } catch (error) { - this.logger.error('Failed to process commit-msg hook', { error }); + const err = error instanceof Error ? error : new Error(String(error)); + this.logger.error('Failed to process commit-msg hook', { + error: err.message, + stack: err.stack, + }); return { handler: 'CommitMsgHandler', success: false, - error: error instanceof Error ? error : new Error(String(error)), + error: err, }; } } diff --git a/src/application/handlers/PostCommitHandler.ts b/src/application/handlers/PostCommitHandler.ts index 29ba17c0..dd7810a9 100644 --- a/src/application/handlers/PostCommitHandler.ts +++ b/src/application/handlers/PostCommitHandler.ts @@ -81,11 +81,15 @@ export class PostCommitHandler implements IPostCommitHandler { success: true, }; } catch (error) { - this.logger?.error('Post-commit handler failed', { error }); + const err = error instanceof Error ? error : new Error(String(error)); + this.logger?.error('Post-commit handler failed', { + error: err.message, + stack: err.stack, + }); return { handler: 'PostCommitHandler', success: false, - error: error instanceof Error ? error : new Error(String(error)), + error: err, }; } } diff --git a/src/application/handlers/PromptSubmitHandler.ts b/src/application/handlers/PromptSubmitHandler.ts index c645da67..30e3a640 100644 --- a/src/application/handlers/PromptSubmitHandler.ts +++ b/src/application/handlers/PromptSubmitHandler.ts @@ -121,11 +121,15 @@ export class PromptSubmitHandler implements IPromptSubmitHandler { output, }; } catch (error) { - this.logger?.error('Prompt submit handler failed', { error }); + const err = error instanceof Error ? error : new Error(String(error)); + this.logger?.error('Prompt submit handler failed', { + error: err.message, + stack: err.stack, + }); return { handler: 'PromptSubmitHandler', success: false, - error: error instanceof Error ? error : new Error(String(error)), + error: err, }; } } diff --git a/src/application/handlers/SessionStartHandler.ts b/src/application/handlers/SessionStartHandler.ts index 5be99a9b..fa5f4b46 100644 --- a/src/application/handlers/SessionStartHandler.ts +++ b/src/application/handlers/SessionStartHandler.ts @@ -53,11 +53,15 @@ export class SessionStartHandler implements ISessionStartHandler { output, }; } catch (error) { - this.logger?.error('Session start handler failed', { error }); + const err = error instanceof Error ? error : new Error(String(error)); + this.logger?.error('Session start handler failed', { + error: err.message, + stack: err.stack, + }); return { handler: 'SessionStartHandler', success: false, - error: error instanceof Error ? error : new Error(String(error)), + error: err, }; } } diff --git a/src/application/handlers/SessionStopHandler.ts b/src/application/handlers/SessionStopHandler.ts index b93b9126..49b65b2b 100644 --- a/src/application/handlers/SessionStopHandler.ts +++ b/src/application/handlers/SessionStopHandler.ts @@ -40,11 +40,15 @@ export class SessionStopHandler implements ISessionStopHandler { output: result.summary, }; } catch (error) { - this.logger?.error('Session stop handler failed', { error }); + const err = error instanceof Error ? error : new Error(String(error)); + this.logger?.error('Session stop handler failed', { + error: err.message, + stack: err.stack, + }); return { handler: 'SessionStopHandler', success: false, - error: error instanceof Error ? error : new Error(String(error)), + error: err, }; } } diff --git a/src/infrastructure/logging/Logger.ts b/src/infrastructure/logging/Logger.ts index 12e2f5f3..5938b574 100644 --- a/src/infrastructure/logging/Logger.ts +++ b/src/infrastructure/logging/Logger.ts @@ -22,6 +22,21 @@ const LEVEL_COLORS: Record = { const RESET = '\x1b[0m'; +/** JSON.stringify that handles circular references and Error objects. */ +function safeStringify(obj: unknown): string { + const seen = new WeakSet(); + return JSON.stringify(obj, (_key, value) => { + if (value instanceof Error) { + return { message: value.message, stack: value.stack }; + } + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) return '[Circular]'; + seen.add(value); + } + return value; + }); +} + function formatTimestamp(): string { const now = new Date(); const pad = (n: number, len = 2) => String(n).padStart(len, '0'); @@ -85,7 +100,7 @@ export class Logger implements ILogger { if (!this.isLevelEnabled(level)) return; const merged = { ...this.bindings, ...context }; - const contextStr = Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : ''; + const contextStr = Object.keys(merged).length > 0 ? ` ${safeStringify(merged)}` : ''; const timestamp = formatTimestamp(); const levelUpper = level.toUpperCase().padEnd(5);