Fix circular dependency crash in worker service

**Problem:**
Worker service crashed on startup with:
  TypeError: Cannot read properties of undefined (reading 'get')
  at new Wd (.../worker-service.cjs:52:131469)

**Root Cause:**
Circular dependency between SettingsDefaultsManager and logger:
  1. SettingsDefaultsManager imports logger
  2. logger imports SettingsDefaultsManager
  3. logger constructor calls SettingsDefaultsManager.get() at init time
  4. When CommonJS resolves the cycle, SettingsDefaultsManager is undefined

**Solution:**
Break the circular dependency by making logger lazy-load its configuration:
  - Change logger.level from initialized in constructor to lazy-loaded
  - Add getLevel() method that loads on first access
  - Update all level checks to use getLevel()

This allows SettingsDefaultsManager to import logger without triggering
the circular dependency, since logger no longer accesses SettingsDefaultsManager
during module initialization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2025-12-09 16:13:10 -05:00
parent 005a80c540
commit c2015c4dfc
13 changed files with 200 additions and 157 deletions
+15 -8
View File
@@ -23,18 +23,25 @@ interface LogContext {
}
class Logger {
private level: LogLevel;
private level: LogLevel | null = null;
private useColor: boolean;
constructor() {
// Parse log level from settings
const envLevel = SettingsDefaultsManager.get('CLAUDE_MEM_LOG_LEVEL').toUpperCase();
this.level = LogLevel[envLevel as keyof typeof LogLevel] ?? LogLevel.INFO;
// Disable colors when output is not a TTY (e.g., PM2 logs)
this.useColor = process.stdout.isTTY ?? false;
}
/**
* Lazy-load log level from settings (breaks circular dependency with SettingsDefaultsManager)
*/
private getLevel(): LogLevel {
if (this.level === null) {
const envLevel = SettingsDefaultsManager.get('CLAUDE_MEM_LOG_LEVEL').toUpperCase();
this.level = LogLevel[envLevel as keyof typeof LogLevel] ?? LogLevel.INFO;
}
return this.level;
}
/**
* Create correlation ID for tracking an observation through the pipeline
*/
@@ -62,7 +69,7 @@ class Logger {
if (typeof data === 'object') {
// If it's an error, show message and stack in debug mode
if (data instanceof Error) {
return this.level === LogLevel.DEBUG
return this.getLevel() === LogLevel.DEBUG
? `${data.message}\n${data.stack}`
: data.message;
}
@@ -134,7 +141,7 @@ class Logger {
context?: LogContext,
data?: any
): void {
if (level < this.level) return;
if (level < this.getLevel()) return;
const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 23);
const levelStr = LogLevel[level].padEnd(5);
@@ -151,7 +158,7 @@ class Logger {
// Build data part
let dataStr = '';
if (data !== undefined && data !== null) {
if (this.level === LogLevel.DEBUG && typeof data === 'object') {
if (this.getLevel() === LogLevel.DEBUG && typeof data === 'object') {
// In debug mode, show full JSON for objects
dataStr = '\n' + JSON.stringify(data, null, 2);
} else {