principles-disciple 1.190.0 → 1.192.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,22 @@ export declare const SystemLogger: {
3
3
  /**
4
4
  * Force refresh of the cached log file path.
5
5
  * Call this at midnight or when the date changes to ensure proper rotation.
6
+ *
7
+ * PRI-504: clears log-file and log-date caches for ALL workspaces (preserves
8
+ * the original "force refresh" semantics). Does NOT clear lastCleanupDates
9
+ * to avoid re-triggering cleanup for every workspace on the same day.
6
10
  */
7
11
  refreshCache(): void;
8
12
  };
13
+ /**
14
+ * PRI-504: dispose the SystemLogger cache for a single workspace.
15
+ * Useful for tests and for workspace teardown in multi-workspace processes.
16
+ * Pattern follows evolution-engine.ts:564-570 (disposeEvolutionEngine).
17
+ */
18
+ export declare function disposeSystemLogger(workspaceDir: string): void;
19
+ /**
20
+ * PRI-504: dispose ALL SystemLogger caches. Call this in test afterEach
21
+ * hooks to prevent state leakage between tests. Pattern follows
22
+ * evolution-engine.ts:572-577 (disposeAllEvolutionEngines).
23
+ */
24
+ export declare function disposeAllSystemLoggers(): void;
@@ -11,9 +11,13 @@ import { resolvePdPath, PD_FILES } from './paths.js';
11
11
  * Automatically rotates to a new file at midnight.
12
12
  * Old log files are automatically cleaned up based on retention policy.
13
13
  */
14
- // Cache for current log file path, invalidated when date changes
15
- let cachedLogFile;
16
- let cachedLogDate;
14
+ // PRI-504: per-workspace caches keyed by path.resolve(workspaceDir).
15
+ // Previously these were module-level `let` variables, so the first workspace
16
+ // to call log() would pin the log file path for ALL subsequent workspaces in
17
+ // the same process — causing cross-workspace log leakage (ERR-092).
18
+ // Pattern follows evolution-engine.ts:551-577 (Map + path.resolve + dispose).
19
+ const cachedLogFiles = new Map();
20
+ const cachedLogDates = new Map();
17
21
  /**
18
22
  * Log retention: delete SYSTEM logs older than this many days.
19
23
  * Set to 0 to disable cleanup.
@@ -64,28 +68,33 @@ function cleanupOldLogs(workspaceDir) {
64
68
  // Silently fail cleanup - don't crash logging for cleanup failures
65
69
  }
66
70
  }
67
- // Track if cleanup has run today
68
- let lastCleanupDate;
71
+ // PRI-504: per-workspace cleanup tracker (was module-level `let`).
72
+ // Keyed by path.resolve(workspaceDir) so each workspace runs its own
73
+ // daily cleanup independently.
74
+ const lastCleanupDates = new Map();
69
75
  export const SystemLogger = {
70
76
  log(workspaceDir, eventType, message) {
71
77
  if (!workspaceDir)
72
78
  return;
73
79
  try {
80
+ const resolved = path.resolve(workspaceDir);
74
81
  const today = getTodayStr();
75
- // Check if date changed - invalidate cache and run cleanup
76
- if (cachedLogDate !== today) {
77
- cachedLogDate = today;
78
- cachedLogFile = undefined;
79
- // Run cleanup once per day when date changes
80
- if (lastCleanupDate !== today) {
81
- lastCleanupDate = today;
82
+ // Check if date changed for THIS workspace - invalidate its cache and run cleanup
83
+ if (cachedLogDates.get(resolved) !== today) {
84
+ cachedLogDates.set(resolved, today);
85
+ cachedLogFiles.delete(resolved);
86
+ // Run cleanup once per day per workspace when date changes
87
+ if (lastCleanupDates.get(resolved) !== today) {
88
+ lastCleanupDates.set(resolved, today);
82
89
  cleanupOldLogs(workspaceDir);
83
90
  }
84
91
  }
85
- // Get or create log file path
86
- if (!cachedLogFile) {
87
- cachedLogFile = getSystemLogPath(workspaceDir, new Date());
88
- const logDir = path.dirname(cachedLogFile);
92
+ // Get or create log file path for this workspace
93
+ let logFile = cachedLogFiles.get(resolved);
94
+ if (!logFile) {
95
+ logFile = getSystemLogPath(workspaceDir, new Date());
96
+ cachedLogFiles.set(resolved, logFile);
97
+ const logDir = path.dirname(logFile);
89
98
  if (!fs.existsSync(logDir)) {
90
99
  fs.mkdirSync(logDir, { recursive: true });
91
100
  }
@@ -94,7 +103,7 @@ export const SystemLogger = {
94
103
  // Format: [YYYY-MM-DDTHH:mm:ss.sssZ] [EVENT_TYPE] Message
95
104
  const logEntry = `[${timestamp}] [${eventType.padEnd(15)}] ${message}\n`;
96
105
  // Use fire-and-forget async append to prevent blocking
97
- fs.appendFile(cachedLogFile, logEntry, 'utf8', (_err) => {
106
+ fs.appendFile(logFile, logEntry, 'utf8', (_err) => {
98
107
  // Silently drop errors (e.g. disk full) to not crash the gateway
99
108
  });
100
109
  }
@@ -105,9 +114,34 @@ export const SystemLogger = {
105
114
  /**
106
115
  * Force refresh of the cached log file path.
107
116
  * Call this at midnight or when the date changes to ensure proper rotation.
117
+ *
118
+ * PRI-504: clears log-file and log-date caches for ALL workspaces (preserves
119
+ * the original "force refresh" semantics). Does NOT clear lastCleanupDates
120
+ * to avoid re-triggering cleanup for every workspace on the same day.
108
121
  */
109
122
  refreshCache() {
110
- cachedLogDate = undefined;
111
- cachedLogFile = undefined;
123
+ cachedLogFiles.clear();
124
+ cachedLogDates.clear();
112
125
  }
113
126
  };
127
+ /**
128
+ * PRI-504: dispose the SystemLogger cache for a single workspace.
129
+ * Useful for tests and for workspace teardown in multi-workspace processes.
130
+ * Pattern follows evolution-engine.ts:564-570 (disposeEvolutionEngine).
131
+ */
132
+ export function disposeSystemLogger(workspaceDir) {
133
+ const resolved = path.resolve(workspaceDir);
134
+ cachedLogFiles.delete(resolved);
135
+ cachedLogDates.delete(resolved);
136
+ lastCleanupDates.delete(resolved);
137
+ }
138
+ /**
139
+ * PRI-504: dispose ALL SystemLogger caches. Call this in test afterEach
140
+ * hooks to prevent state leakage between tests. Pattern follows
141
+ * evolution-engine.ts:572-577 (disposeAllEvolutionEngines).
142
+ */
143
+ export function disposeAllSystemLoggers() {
144
+ cachedLogFiles.clear();
145
+ cachedLogDates.clear();
146
+ lastCleanupDates.clear();
147
+ }
@@ -2,7 +2,7 @@
2
2
  "id": "principles-disciple",
3
3
  "name": "Principles Disciple",
4
4
  "description": "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
5
- "version": "1.190.0",
5
+ "version": "1.192.0",
6
6
  "activation": {
7
7
  "onCapabilities": [
8
8
  "hook"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "principles-disciple",
3
- "version": "1.190.0",
3
+ "version": "1.192.0",
4
4
  "description": "Native OpenClaw plugin for Principles Disciple",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",