@dynamicu/chromedebug-mcp 2.5.14 → 2.6.1
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.
- package/package.json +3 -1
- package/scripts/webpack.config.pro.cjs +2 -2
- package/src/capture/memory-manager.js +3 -3
- package/src/cli.js +4 -0
- package/src/commands/install-pro.js +37 -37
- package/src/firebase-license-manager.js +4 -4
- package/src/http-server.js +144 -140
- package/src/index-modular.js +1 -1
- package/src/index.js +6 -1
- package/src/logger.js +102 -11
- package/src/mcp/handlers/chrome-tool-handler.js +3 -3
- package/src/mcp/handlers/frame-tool-handler.js +10 -10
- package/src/mcp/handlers/workflow-tool-handler.js +2 -2
- package/src/middleware/security.js +4 -4
- package/src/services/browser-daemon.js +17 -17
- package/src/services/git-safety-service.js +3 -3
- package/src/services/heartbeat-manager.js +7 -7
- package/src/services/process-manager.js +1 -1
- package/src/services/process-tracker.js +22 -22
- package/src/services/profile-manager.js +18 -18
- package/src/services/session-manager.js +21 -21
- package/src/services/session-registry.js +21 -21
- package/src/services/unified-session-manager.js +13 -13
- package/src/standalone-server.js +21 -17
- package/src/utils/extension-path.js +9 -9
- package/src/utils.js +2 -2
- package/src/validation/schemas.js +2 -2
|
@@ -27,7 +27,7 @@ function getSessionId() {
|
|
|
27
27
|
export function setSessionId(sessionId) {
|
|
28
28
|
if (typeof sessionId === 'string' && sessionId.match(/^[a-zA-Z0-9_-]+$/)) {
|
|
29
29
|
currentSessionId = sessionId;
|
|
30
|
-
console.
|
|
30
|
+
console.error(`ChromeDebug session ID set to: ${sessionId}`);
|
|
31
31
|
} else {
|
|
32
32
|
throw new Error('Session ID must be alphanumeric with dashes/underscores only');
|
|
33
33
|
}
|
|
@@ -126,7 +126,7 @@ export function registerProcess(pid, type = 'unknown') {
|
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
writePidFile(data);
|
|
129
|
-
console.
|
|
129
|
+
console.error(`Registered ChromeDebug process: PID ${validatedPid} (${type})`);
|
|
130
130
|
return true;
|
|
131
131
|
}
|
|
132
132
|
|
|
@@ -145,7 +145,7 @@ export function unregisterProcess(pid) {
|
|
|
145
145
|
|
|
146
146
|
if (data.processes.length < initialLength) {
|
|
147
147
|
writePidFile(data);
|
|
148
|
-
console.
|
|
148
|
+
console.error(`Unregistered ChromeDebug process: PID ${validatedPid}`);
|
|
149
149
|
return true;
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -190,7 +190,7 @@ export function cleanupDeadProcesses() {
|
|
|
190
190
|
if (isProcessRunning(proc.pid)) {
|
|
191
191
|
aliveProcesses.push(proc);
|
|
192
192
|
} else {
|
|
193
|
-
console.
|
|
193
|
+
console.error(`Removing dead process from tracking: PID ${proc.pid} (${proc.type})`);
|
|
194
194
|
removedCount++;
|
|
195
195
|
}
|
|
196
196
|
}
|
|
@@ -198,7 +198,7 @@ export function cleanupDeadProcesses() {
|
|
|
198
198
|
if (removedCount > 0) {
|
|
199
199
|
data.processes = aliveProcesses;
|
|
200
200
|
writePidFile(data);
|
|
201
|
-
console.
|
|
201
|
+
console.error(`Cleaned up ${removedCount} dead processes from tracking`);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
return removedCount;
|
|
@@ -223,7 +223,7 @@ export async function killRegisteredProcess(pid, signal = 'SIGTERM') {
|
|
|
223
223
|
|
|
224
224
|
try {
|
|
225
225
|
process.kill(validatedPid, signal);
|
|
226
|
-
console.
|
|
226
|
+
console.error(`Sent ${signal} to registered ChromeDebug process: PID ${validatedPid}`);
|
|
227
227
|
|
|
228
228
|
// If successful and using SIGKILL, unregister immediately
|
|
229
229
|
if (signal === 'SIGKILL') {
|
|
@@ -258,11 +258,11 @@ export async function killAllRegisteredProcesses() {
|
|
|
258
258
|
};
|
|
259
259
|
|
|
260
260
|
if (processes.length === 0) {
|
|
261
|
-
console.
|
|
261
|
+
console.error('No registered ChromeDebug processes to kill');
|
|
262
262
|
return results;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
console.
|
|
265
|
+
console.error(`Found ${processes.length} registered ChromeDebug processes, cleaning up...`);
|
|
266
266
|
|
|
267
267
|
// First try SIGTERM for graceful shutdown
|
|
268
268
|
for (const proc of processes) {
|
|
@@ -276,7 +276,7 @@ export async function killAllRegisteredProcesses() {
|
|
|
276
276
|
|
|
277
277
|
// Wait for graceful shutdown
|
|
278
278
|
if (results.failed.length > 0) {
|
|
279
|
-
console.
|
|
279
|
+
console.error('Waiting 2 seconds for graceful shutdown...');
|
|
280
280
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
281
281
|
|
|
282
282
|
// Try SIGKILL for remaining processes
|
|
@@ -390,20 +390,20 @@ export async function killUntrackedChromePilotProcesses() {
|
|
|
390
390
|
};
|
|
391
391
|
|
|
392
392
|
if (untrackedProcesses.length === 0) {
|
|
393
|
-
console.
|
|
393
|
+
console.error('No untracked ChromeDebug processes found');
|
|
394
394
|
return results;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
console.
|
|
397
|
+
console.error(`Found ${untrackedProcesses.length} untracked ChromeDebug processes:`);
|
|
398
398
|
untrackedProcesses.forEach(proc => {
|
|
399
|
-
console.
|
|
399
|
+
console.error(` - ${proc.description}`);
|
|
400
400
|
});
|
|
401
401
|
|
|
402
402
|
// Try SIGTERM first
|
|
403
403
|
for (const proc of untrackedProcesses) {
|
|
404
404
|
try {
|
|
405
405
|
process.kill(proc.pid, 'SIGTERM');
|
|
406
|
-
console.
|
|
406
|
+
console.error(`Sent SIGTERM to untracked process: PID ${proc.pid}`);
|
|
407
407
|
results.killed.push(proc.pid);
|
|
408
408
|
} catch (error) {
|
|
409
409
|
if (error.code === 'ESRCH') {
|
|
@@ -418,7 +418,7 @@ export async function killUntrackedChromePilotProcesses() {
|
|
|
418
418
|
|
|
419
419
|
// Wait for graceful shutdown
|
|
420
420
|
if (results.failed.length > 0) {
|
|
421
|
-
console.
|
|
421
|
+
console.error('Waiting 2 seconds for graceful shutdown...');
|
|
422
422
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
423
423
|
|
|
424
424
|
// Try SIGKILL for remaining processes
|
|
@@ -426,7 +426,7 @@ export async function killUntrackedChromePilotProcesses() {
|
|
|
426
426
|
for (const pid of results.failed) {
|
|
427
427
|
try {
|
|
428
428
|
process.kill(pid, 'SIGKILL');
|
|
429
|
-
console.
|
|
429
|
+
console.error(`Sent SIGKILL to stubborn process: PID ${pid}`);
|
|
430
430
|
// Move from failed to killed
|
|
431
431
|
const index = results.failed.indexOf(pid);
|
|
432
432
|
results.failed.splice(index, 1);
|
|
@@ -464,7 +464,7 @@ export function setupProcessTracking(type = 'mcp-server') {
|
|
|
464
464
|
// Set up robust cleanup on process exit
|
|
465
465
|
const cleanup = (reason = 'unknown') => {
|
|
466
466
|
try {
|
|
467
|
-
console.
|
|
467
|
+
console.error(`Process ${currentPid} exiting (${reason}), cleaning up...`);
|
|
468
468
|
unregisterProcess(currentPid);
|
|
469
469
|
} catch (error) {
|
|
470
470
|
console.error(`Error during process cleanup: ${error.message}`);
|
|
@@ -496,7 +496,7 @@ export function setupProcessTracking(type = 'mcp-server') {
|
|
|
496
496
|
process.exit(1);
|
|
497
497
|
});
|
|
498
498
|
|
|
499
|
-
console.
|
|
499
|
+
console.error(`Process tracking setup complete for PID ${currentPid} (${type}) [Session: ${getSessionId()}]`);
|
|
500
500
|
return currentPid;
|
|
501
501
|
}
|
|
502
502
|
|
|
@@ -518,15 +518,15 @@ export function setupProcessTrackingWithOptions(type = 'mcp-server', options = {
|
|
|
518
518
|
const currentSessionId = getSessionId();
|
|
519
519
|
|
|
520
520
|
if (verbose) {
|
|
521
|
-
console.
|
|
522
|
-
console.
|
|
521
|
+
console.error(`ChromeDebug MCP starting with session ID: ${currentSessionId}`);
|
|
522
|
+
console.error(`Skip cleanup: ${skipCleanup}`);
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
// Optionally skip cleanup of dead processes
|
|
526
526
|
if (!skipCleanup) {
|
|
527
527
|
const removedCount = cleanupDeadProcesses();
|
|
528
528
|
if (removedCount > 0 && verbose) {
|
|
529
|
-
console.
|
|
529
|
+
console.error(`Cleaned up ${removedCount} dead processes from session ${currentSessionId}`);
|
|
530
530
|
}
|
|
531
531
|
}
|
|
532
532
|
|
|
@@ -554,7 +554,7 @@ export function getSessionInfo() {
|
|
|
554
554
|
*/
|
|
555
555
|
export async function cleanupCurrentSession() {
|
|
556
556
|
const sessionId = getSessionId();
|
|
557
|
-
console.
|
|
557
|
+
console.error(`Cleaning up session: ${sessionId}`);
|
|
558
558
|
|
|
559
559
|
// Kill all processes in this session
|
|
560
560
|
const results = await killAllRegisteredProcesses();
|
|
@@ -564,7 +564,7 @@ export async function cleanupCurrentSession() {
|
|
|
564
564
|
try {
|
|
565
565
|
if (fs.existsSync(pidFilePath)) {
|
|
566
566
|
fs.unlinkSync(pidFilePath);
|
|
567
|
-
console.
|
|
567
|
+
console.error(`Removed session PID file: ${pidFilePath}`);
|
|
568
568
|
}
|
|
569
569
|
} catch (error) {
|
|
570
570
|
console.error(`Failed to remove PID file: ${error.message}`);
|
|
@@ -32,7 +32,7 @@ export class ProfileManager {
|
|
|
32
32
|
...options
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
console.
|
|
35
|
+
console.error(`[ProfileManager] Initialized with profiles directory: ${this.profilesDir}`);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -49,7 +49,7 @@ export class ProfileManager {
|
|
|
49
49
|
await this.cleanupOrphanedProfiles();
|
|
50
50
|
|
|
51
51
|
this.initialized = true;
|
|
52
|
-
console.
|
|
52
|
+
console.error('[ProfileManager] Initialized successfully');
|
|
53
53
|
} catch (error) {
|
|
54
54
|
console.error('[ProfileManager] Initialization failed:', error);
|
|
55
55
|
throw error;
|
|
@@ -143,7 +143,7 @@ export class ProfileManager {
|
|
|
143
143
|
|
|
144
144
|
this.activeProfiles.set(sessionId, profileInfo);
|
|
145
145
|
|
|
146
|
-
console.
|
|
146
|
+
console.error(`[ProfileManager] Created profile for session ${sessionId}: ${resolvedProfilePath}`);
|
|
147
147
|
return resolvedProfilePath;
|
|
148
148
|
} catch (error) {
|
|
149
149
|
console.error(`[ProfileManager] Failed to create profile for session ${sessionId}:`, error);
|
|
@@ -152,7 +152,7 @@ export class ProfileManager {
|
|
|
152
152
|
const profilePath = path.join(this.profilesDir, `session-${sessionId}`);
|
|
153
153
|
await fs.rm(profilePath, { recursive: true, force: true });
|
|
154
154
|
} catch (cleanupError) {
|
|
155
|
-
console.
|
|
155
|
+
console.error('[ProfileManager] Failed to cleanup partial profile:', cleanupError);
|
|
156
156
|
}
|
|
157
157
|
throw error;
|
|
158
158
|
}
|
|
@@ -227,7 +227,7 @@ export class ProfileManager {
|
|
|
227
227
|
const localStatePath = path.join(profilePath, 'Local State');
|
|
228
228
|
await fs.writeFile(localStatePath, JSON.stringify(localState, null, 2));
|
|
229
229
|
|
|
230
|
-
console.
|
|
230
|
+
console.error(`[ProfileManager] Created profile configuration for session ${sessionId}`);
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
/**
|
|
@@ -237,7 +237,7 @@ export class ProfileManager {
|
|
|
237
237
|
*/
|
|
238
238
|
async cleanupProfile(sessionId) {
|
|
239
239
|
if (!sessionId || !this.activeProfiles.has(sessionId)) {
|
|
240
|
-
console.
|
|
240
|
+
console.error(`[ProfileManager] Attempted to cleanup non-existent profile: ${sessionId}`);
|
|
241
241
|
return false;
|
|
242
242
|
}
|
|
243
243
|
|
|
@@ -256,9 +256,9 @@ export class ProfileManager {
|
|
|
256
256
|
// Calculate profile size for logging
|
|
257
257
|
try {
|
|
258
258
|
const stats = await this.calculateDirectorySize(profilePath);
|
|
259
|
-
console.
|
|
259
|
+
console.error(`[ProfileManager] Profile ${sessionId} size: ${(stats.size / 1024 / 1024).toFixed(2)}MB (${stats.files} files)`);
|
|
260
260
|
} catch (sizeError) {
|
|
261
|
-
console.
|
|
261
|
+
console.error('[ProfileManager] Could not calculate profile size:', sizeError);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
// Remove profile directory
|
|
@@ -267,7 +267,7 @@ export class ProfileManager {
|
|
|
267
267
|
// Remove from active profiles
|
|
268
268
|
this.activeProfiles.delete(sessionId);
|
|
269
269
|
|
|
270
|
-
console.
|
|
270
|
+
console.error(`[ProfileManager] Cleaned up profile for session ${sessionId}`);
|
|
271
271
|
return true;
|
|
272
272
|
} catch (error) {
|
|
273
273
|
console.error(`[ProfileManager] Error cleaning up profile for session ${sessionId}:`, error);
|
|
@@ -287,12 +287,12 @@ export class ProfileManager {
|
|
|
287
287
|
throw new Error(`Total profiles size (${totalSizeMB.toFixed(2)}MB) exceeds limit (${this.config.maxTotalProfilesMB}MB)`);
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
-
console.
|
|
290
|
+
console.error(`[ProfileManager] Current profiles size: ${totalSizeMB.toFixed(2)}MB / ${this.config.maxTotalProfilesMB}MB`);
|
|
291
291
|
} catch (error) {
|
|
292
292
|
if (error.message.includes('exceeds limit')) {
|
|
293
293
|
throw error;
|
|
294
294
|
}
|
|
295
|
-
console.
|
|
295
|
+
console.error('[ProfileManager] Could not check space quota:', error);
|
|
296
296
|
}
|
|
297
297
|
}
|
|
298
298
|
|
|
@@ -317,7 +317,7 @@ export class ProfileManager {
|
|
|
317
317
|
|
|
318
318
|
return totalSize;
|
|
319
319
|
} catch (error) {
|
|
320
|
-
console.
|
|
320
|
+
console.error('[ProfileManager] Error calculating total profiles size:', error);
|
|
321
321
|
return 0;
|
|
322
322
|
}
|
|
323
323
|
}
|
|
@@ -377,18 +377,18 @@ export class ProfileManager {
|
|
|
377
377
|
if (age > this.config.profileCleanupAgeMs) {
|
|
378
378
|
await fs.rm(sessionDirPath, { recursive: true, force: true });
|
|
379
379
|
cleanedCount++;
|
|
380
|
-
console.
|
|
380
|
+
console.error(`[ProfileManager] Cleaned up orphaned profile: ${sessionDir}`);
|
|
381
381
|
}
|
|
382
382
|
} catch (error) {
|
|
383
|
-
console.
|
|
383
|
+
console.error(`[ProfileManager] Error processing orphaned profile ${sessionDir}:`, error);
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
if (cleanedCount > 0) {
|
|
388
|
-
console.
|
|
388
|
+
console.error(`[ProfileManager] Cleaned up ${cleanedCount} orphaned profiles`);
|
|
389
389
|
}
|
|
390
390
|
} catch (error) {
|
|
391
|
-
console.
|
|
391
|
+
console.error('[ProfileManager] Error during orphaned profile cleanup:', error);
|
|
392
392
|
}
|
|
393
393
|
}
|
|
394
394
|
|
|
@@ -436,7 +436,7 @@ export class ProfileManager {
|
|
|
436
436
|
* Cleanup method for graceful shutdown
|
|
437
437
|
*/
|
|
438
438
|
async cleanup() {
|
|
439
|
-
console.
|
|
439
|
+
console.error('[ProfileManager] Cleaning up active profiles...');
|
|
440
440
|
|
|
441
441
|
// Clean up all active profiles
|
|
442
442
|
const sessionIds = Array.from(this.activeProfiles.keys());
|
|
@@ -444,6 +444,6 @@ export class ProfileManager {
|
|
|
444
444
|
await this.cleanupProfile(sessionId);
|
|
445
445
|
}
|
|
446
446
|
|
|
447
|
-
console.
|
|
447
|
+
console.error('[ProfileManager] Cleanup completed');
|
|
448
448
|
}
|
|
449
449
|
}
|
|
@@ -47,9 +47,9 @@ export class SessionManager {
|
|
|
47
47
|
if (this.sessionData && this.sessionData.portLockFile) {
|
|
48
48
|
try {
|
|
49
49
|
await releasePortLock(this.sessionData.portLockFile);
|
|
50
|
-
console.
|
|
50
|
+
console.error(`[SessionManager] Released port lock on process exit for session ${this.sessionData.sessionId}`);
|
|
51
51
|
} catch (error) {
|
|
52
|
-
console.
|
|
52
|
+
console.error('[SessionManager] Error releasing port lock on exit:', error);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
};
|
|
@@ -72,12 +72,12 @@ export class SessionManager {
|
|
|
72
72
|
const projectInfo = this.projectManager.detectProject();
|
|
73
73
|
if (projectInfo) {
|
|
74
74
|
await this.projectManager.initializeProjectStructure();
|
|
75
|
-
console.
|
|
75
|
+
console.error(`[SessionManager] Using project-local storage: ${this.projectManager.getCurrentMode()}`);
|
|
76
76
|
} else {
|
|
77
|
-
console.
|
|
77
|
+
console.error('[SessionManager] Using global storage mode');
|
|
78
78
|
}
|
|
79
79
|
} catch (error) {
|
|
80
|
-
console.
|
|
80
|
+
console.error('[SessionManager] Failed to initialize project mode, falling back to global:', error.message);
|
|
81
81
|
} finally {
|
|
82
82
|
this._projectModeInitialized = true;
|
|
83
83
|
}
|
|
@@ -136,7 +136,7 @@ export class SessionManager {
|
|
|
136
136
|
portLockFile: portLockResult.lockFile // Store lock file for cleanup
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
-
console.
|
|
139
|
+
console.error(`[SessionManager] Created session ${sessionId} with profile: ${profilePath}`);
|
|
140
140
|
|
|
141
141
|
// Start heartbeat automatically
|
|
142
142
|
this.startHeartbeat();
|
|
@@ -155,7 +155,7 @@ export class SessionManager {
|
|
|
155
155
|
async updateHeartbeat() {
|
|
156
156
|
if (this.sessionData) {
|
|
157
157
|
this.sessionData.lastHeartbeat = new Date();
|
|
158
|
-
console.
|
|
158
|
+
console.error(`[SessionManager] Updated heartbeat for session ${this.sessionData.sessionId}`);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -171,7 +171,7 @@ export class SessionManager {
|
|
|
171
171
|
await this.updateHeartbeat();
|
|
172
172
|
}, this.HEARTBEAT_INTERVAL);
|
|
173
173
|
|
|
174
|
-
console.
|
|
174
|
+
console.error(`[SessionManager] Started heartbeat for session ${this.sessionId}`);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
/**
|
|
@@ -181,7 +181,7 @@ export class SessionManager {
|
|
|
181
181
|
if (this.heartbeatInterval) {
|
|
182
182
|
clearInterval(this.heartbeatInterval);
|
|
183
183
|
this.heartbeatInterval = null;
|
|
184
|
-
console.
|
|
184
|
+
console.error(`[SessionManager] Stopped heartbeat for session ${this.sessionId}`);
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -240,7 +240,7 @@ export class SessionManager {
|
|
|
240
240
|
setProcessId(processId) {
|
|
241
241
|
if (this.sessionData) {
|
|
242
242
|
this.sessionData.processId = processId;
|
|
243
|
-
console.
|
|
243
|
+
console.error(`[SessionManager] Set process ID ${processId} for session ${this.sessionId}`);
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
@@ -279,11 +279,11 @@ export class SessionManager {
|
|
|
279
279
|
if (this.projectManager.isProjectModeAvailable()) {
|
|
280
280
|
const projectSessionsDir = path.resolve(this.projectManager.getProjectSessionsDir());
|
|
281
281
|
if (!resolvedPath.startsWith(projectSessionsDir)) {
|
|
282
|
-
console.
|
|
282
|
+
console.error(`[SessionManager] Refusing to clean unsafe project directory: ${dirPath}`);
|
|
283
283
|
return false;
|
|
284
284
|
}
|
|
285
285
|
} else {
|
|
286
|
-
console.
|
|
286
|
+
console.error(`[SessionManager] Cannot clean project directory when not in project mode: ${dirPath}`);
|
|
287
287
|
return false;
|
|
288
288
|
}
|
|
289
289
|
} else {
|
|
@@ -293,13 +293,13 @@ export class SessionManager {
|
|
|
293
293
|
|
|
294
294
|
if (!resolvedPath.startsWith(resolvedTmpDir) ||
|
|
295
295
|
!path.basename(resolvedPath).startsWith('chromedebug-')) {
|
|
296
|
-
console.
|
|
296
|
+
console.error(`[SessionManager] Refusing to clean unsafe global directory: ${dirPath}`);
|
|
297
297
|
return false;
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
await fs.rm(resolvedPath, { recursive: true, force: true });
|
|
302
|
-
console.
|
|
302
|
+
console.error(`[SessionManager] Cleaned up ${isProjectLocal ? 'project-local' : 'global'} directory: ${resolvedPath}`);
|
|
303
303
|
return true;
|
|
304
304
|
} catch (error) {
|
|
305
305
|
if (error.code === 'ENOENT') {
|
|
@@ -336,7 +336,7 @@ export class SessionManager {
|
|
|
336
336
|
isProjectLocal: true
|
|
337
337
|
})));
|
|
338
338
|
} catch (error) {
|
|
339
|
-
console.
|
|
339
|
+
console.error('[SessionManager] Could not read project sessions directory:', error.message);
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -350,7 +350,7 @@ export class SessionManager {
|
|
|
350
350
|
isProjectLocal: false
|
|
351
351
|
})));
|
|
352
352
|
|
|
353
|
-
console.
|
|
353
|
+
console.error(`[SessionManager] Found ${dirsToCheck.length} directories to evaluate`);
|
|
354
354
|
|
|
355
355
|
for (const dirInfo of dirsToCheck) {
|
|
356
356
|
try {
|
|
@@ -403,7 +403,7 @@ export class SessionManager {
|
|
|
403
403
|
}
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
console.
|
|
406
|
+
console.error(`[SessionManager] Cleanup complete: ${cleanupResult.cleanedSessions.length} cleaned, ${cleanupResult.activeSessionsRemaining} active remaining`);
|
|
407
407
|
} catch (error) {
|
|
408
408
|
console.error('[SessionManager] Error during stale session cleanup:', error);
|
|
409
409
|
throw error;
|
|
@@ -437,7 +437,7 @@ export class SessionManager {
|
|
|
437
437
|
process.kill(this.sessionData.processId, 'SIGKILL');
|
|
438
438
|
}
|
|
439
439
|
} catch (error) {
|
|
440
|
-
console.
|
|
440
|
+
console.error(`[SessionManager] Error killing process ${this.sessionData.processId}:`, error);
|
|
441
441
|
}
|
|
442
442
|
}
|
|
443
443
|
|
|
@@ -447,9 +447,9 @@ export class SessionManager {
|
|
|
447
447
|
if (this.sessionData.portLockFile) {
|
|
448
448
|
try {
|
|
449
449
|
await releasePortLock(this.sessionData.portLockFile);
|
|
450
|
-
console.
|
|
450
|
+
console.error(`[SessionManager] Released port lock for session ${sessionId}`);
|
|
451
451
|
} catch (error) {
|
|
452
|
-
console.
|
|
452
|
+
console.error(`[SessionManager] Error releasing port lock for session ${sessionId}:`, error);
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
455
|
|
|
@@ -486,7 +486,7 @@ export class SessionManager {
|
|
|
486
486
|
* Cleanup method called when SessionManager is destroyed
|
|
487
487
|
*/
|
|
488
488
|
async cleanup() {
|
|
489
|
-
console.
|
|
489
|
+
console.error(`[SessionManager] Cleaning up session manager for ${this.sessionId}`);
|
|
490
490
|
|
|
491
491
|
this.stopHeartbeat();
|
|
492
492
|
|
|
@@ -39,7 +39,7 @@ export class PersistentRegistry {
|
|
|
39
39
|
...options
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
console.
|
|
42
|
+
console.error(`[SessionRegistry] Initialized with registry directory: ${this.registryDir}`);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
@@ -59,7 +59,7 @@ export class PersistentRegistry {
|
|
|
59
59
|
await this.cleanupStaleSessions();
|
|
60
60
|
|
|
61
61
|
this.initialized = true;
|
|
62
|
-
console.
|
|
62
|
+
console.error(`[SessionRegistry] Initialized successfully with ${this.sessions.size} existing sessions`);
|
|
63
63
|
} catch (error) {
|
|
64
64
|
console.error('[SessionRegistry] Initialization failed:', error);
|
|
65
65
|
throw error;
|
|
@@ -107,7 +107,7 @@ export class PersistentRegistry {
|
|
|
107
107
|
// Persist to disk
|
|
108
108
|
await this.saveSessions();
|
|
109
109
|
|
|
110
|
-
console.
|
|
110
|
+
console.error(`[SessionRegistry] Updated session ${sessionId}`);
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
|
|
@@ -135,7 +135,7 @@ export class PersistentRegistry {
|
|
|
135
135
|
try {
|
|
136
136
|
await fs.access(sessionData.profilePath);
|
|
137
137
|
} catch (error) {
|
|
138
|
-
console.
|
|
138
|
+
console.error(`[SessionRegistry] Profile no longer exists for session ${sessionId}, removing from registry`);
|
|
139
139
|
await this.removeSession(sessionId);
|
|
140
140
|
return null;
|
|
141
141
|
}
|
|
@@ -161,7 +161,7 @@ export class PersistentRegistry {
|
|
|
161
161
|
await this.withFileLock(async () => {
|
|
162
162
|
this.sessions.delete(sessionId);
|
|
163
163
|
await this.saveSessions();
|
|
164
|
-
console.
|
|
164
|
+
console.error(`[SessionRegistry] Removed session ${sessionId}`);
|
|
165
165
|
});
|
|
166
166
|
|
|
167
167
|
return true;
|
|
@@ -241,7 +241,7 @@ export class PersistentRegistry {
|
|
|
241
241
|
const lockAge = Date.now() - existingLockData.timestamp;
|
|
242
242
|
|
|
243
243
|
if (lockAge > this.config.lockTimeoutMs) {
|
|
244
|
-
console.
|
|
244
|
+
console.error('[SessionRegistry] Removing stale lock file');
|
|
245
245
|
await fs.unlink(this.lockFile);
|
|
246
246
|
continue; // Retry
|
|
247
247
|
}
|
|
@@ -253,14 +253,14 @@ export class PersistentRegistry {
|
|
|
253
253
|
} catch (processError) {
|
|
254
254
|
if (processError.code === 'ESRCH') {
|
|
255
255
|
// Process doesn't exist, remove stale lock
|
|
256
|
-
console.
|
|
256
|
+
console.error('[SessionRegistry] Removing lock file from dead process');
|
|
257
257
|
await fs.unlink(this.lockFile);
|
|
258
258
|
continue; // Retry
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
} catch (parseError) {
|
|
262
262
|
// Corrupted lock file, remove it
|
|
263
|
-
console.
|
|
263
|
+
console.error('[SessionRegistry] Removing corrupted lock file');
|
|
264
264
|
await fs.unlink(this.lockFile);
|
|
265
265
|
continue; // Retry
|
|
266
266
|
}
|
|
@@ -284,7 +284,7 @@ export class PersistentRegistry {
|
|
|
284
284
|
await fs.unlink(this.lockFile);
|
|
285
285
|
} catch (error) {
|
|
286
286
|
if (error.code !== 'ENOENT') {
|
|
287
|
-
console.
|
|
287
|
+
console.error('[SessionRegistry] Error releasing lock:', error);
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
290
|
}
|
|
@@ -310,13 +310,13 @@ export class PersistentRegistry {
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
console.
|
|
313
|
+
console.error(`[SessionRegistry] Loaded ${this.sessions.size} sessions from disk`);
|
|
314
314
|
} catch (error) {
|
|
315
315
|
if (error.code === 'ENOENT') {
|
|
316
|
-
console.
|
|
316
|
+
console.error('[SessionRegistry] No existing registry file found, starting fresh');
|
|
317
317
|
this.sessions.clear();
|
|
318
318
|
} else {
|
|
319
|
-
console.
|
|
319
|
+
console.error('[SessionRegistry] Error loading sessions, attempting backup recovery:', error);
|
|
320
320
|
await this.loadFromBackup();
|
|
321
321
|
}
|
|
322
322
|
}
|
|
@@ -339,7 +339,7 @@ export class PersistentRegistry {
|
|
|
339
339
|
await fs.writeFile(tempFile, data, 'utf-8');
|
|
340
340
|
await fs.rename(tempFile, this.registryFile);
|
|
341
341
|
|
|
342
|
-
console.
|
|
342
|
+
console.error(`[SessionRegistry] Saved ${this.sessions.size} sessions to disk`);
|
|
343
343
|
} catch (error) {
|
|
344
344
|
console.error('[SessionRegistry] Error saving sessions:', error);
|
|
345
345
|
throw error;
|
|
@@ -364,7 +364,7 @@ export class PersistentRegistry {
|
|
|
364
364
|
await this.cleanupOldBackups();
|
|
365
365
|
} catch (error) {
|
|
366
366
|
if (error.code !== 'ENOENT') {
|
|
367
|
-
console.
|
|
367
|
+
console.error('[SessionRegistry] Error creating backup:', error);
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
370
|
}
|
|
@@ -381,7 +381,7 @@ export class PersistentRegistry {
|
|
|
381
381
|
.reverse(); // Most recent first
|
|
382
382
|
|
|
383
383
|
if (backupFiles.length === 0) {
|
|
384
|
-
console.
|
|
384
|
+
console.error('[SessionRegistry] No backup files found, starting fresh');
|
|
385
385
|
this.sessions.clear();
|
|
386
386
|
return;
|
|
387
387
|
}
|
|
@@ -397,7 +397,7 @@ export class PersistentRegistry {
|
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
-
console.
|
|
400
|
+
console.error(`[SessionRegistry] Recovered ${this.sessions.size} sessions from backup: ${backupFiles[0]}`);
|
|
401
401
|
} catch (error) {
|
|
402
402
|
console.error('[SessionRegistry] Error loading from backup:', error);
|
|
403
403
|
this.sessions.clear();
|
|
@@ -423,10 +423,10 @@ export class PersistentRegistry {
|
|
|
423
423
|
}
|
|
424
424
|
|
|
425
425
|
if (filesToDelete.length > 0) {
|
|
426
|
-
console.
|
|
426
|
+
console.error(`[SessionRegistry] Cleaned up ${filesToDelete.length} old backup files`);
|
|
427
427
|
}
|
|
428
428
|
} catch (error) {
|
|
429
|
-
console.
|
|
429
|
+
console.error('[SessionRegistry] Error cleaning up old backups:', error);
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
|
|
@@ -456,7 +456,7 @@ export class PersistentRegistry {
|
|
|
456
456
|
await this.saveSessions();
|
|
457
457
|
});
|
|
458
458
|
|
|
459
|
-
console.
|
|
459
|
+
console.error(`[SessionRegistry] Cleaned up ${staleSessions.length} stale sessions`);
|
|
460
460
|
}
|
|
461
461
|
}
|
|
462
462
|
|
|
@@ -478,7 +478,7 @@ export class PersistentRegistry {
|
|
|
478
478
|
* Cleanup method for graceful shutdown
|
|
479
479
|
*/
|
|
480
480
|
async cleanup() {
|
|
481
|
-
console.
|
|
481
|
+
console.error('[SessionRegistry] Performing final save...');
|
|
482
482
|
|
|
483
483
|
if (this.sessions.size > 0) {
|
|
484
484
|
await this.withFileLock(async () => {
|
|
@@ -486,6 +486,6 @@ export class PersistentRegistry {
|
|
|
486
486
|
});
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
console.
|
|
489
|
+
console.error('[SessionRegistry] Cleanup completed');
|
|
490
490
|
}
|
|
491
491
|
}
|