@dynamicu/chromedebug-mcp 2.3.0 → 2.3.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/chrome-extension/background.js +5 -5
- package/dist/chromedebug-extension-free.zip +0 -0
- package/package.json +1 -1
- package/scripts/postinstall.js +13 -4
- package/src/chrome-controller.js +107 -106
- package/src/config-loader.js +18 -17
- package/src/database.js +81 -80
- package/src/index.js +35 -24
- package/src/middleware/auth.js +30 -29
- package/src/port-discovery.js +7 -6
- package/src/services/failover-manager.js +19 -18
- package/src/services/project-manager.js +16 -15
- package/src/utils/logger.js +63 -0
package/src/database.js
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'path';
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import { ProjectManager } from './services/project-manager.js';
|
|
7
|
+
import logger from './utils/logger.js';
|
|
7
8
|
|
|
8
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
|
|
@@ -24,7 +25,7 @@ function getDatabasePath() {
|
|
|
24
25
|
fs.mkdirSync(dbDir, { recursive: true });
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
logger.debug(`[Database] Using global database: ${globalDbPath}`);
|
|
28
29
|
return globalDbPath;
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -52,7 +53,7 @@ class ChromePilotDatabase {
|
|
|
52
53
|
// Create tables
|
|
53
54
|
this.createTables();
|
|
54
55
|
this.initialized = true;
|
|
55
|
-
|
|
56
|
+
logger.debug(`ChromeDebug MCP database initialized at: ${DB_PATH}`);
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
createTables() {
|
|
@@ -89,11 +90,11 @@ class ChromePilotDatabase {
|
|
|
89
90
|
// Add interactions column to existing frames table if it doesn't exist
|
|
90
91
|
try {
|
|
91
92
|
this.db.exec(`ALTER TABLE frames ADD COLUMN interactions TEXT DEFAULT '[]'`);
|
|
92
|
-
|
|
93
|
+
logger.debug('[Database] Added interactions column to frames table');
|
|
93
94
|
} catch (error) {
|
|
94
95
|
// Column already exists, ignore error
|
|
95
96
|
if (!error.message.includes('duplicate column name')) {
|
|
96
|
-
|
|
97
|
+
logger.warn('[Database] Unexpected error adding interactions column:', error.message);
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -214,41 +215,41 @@ class ChromePilotDatabase {
|
|
|
214
215
|
|
|
215
216
|
if (!hasComponent) {
|
|
216
217
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN component TEXT');
|
|
217
|
-
|
|
218
|
+
logger.debug('[Database] Added component column to workflow_actions');
|
|
218
219
|
}
|
|
219
220
|
if (!hasArgs) {
|
|
220
221
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN args TEXT');
|
|
221
|
-
|
|
222
|
+
logger.debug('[Database] Added args column to workflow_actions');
|
|
222
223
|
}
|
|
223
224
|
if (!hasStack) {
|
|
224
225
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN stack TEXT');
|
|
225
|
-
|
|
226
|
+
logger.debug('[Database] Added stack column to workflow_actions');
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
// Add enhanced click tracking columns
|
|
229
230
|
if (!hasElementHtml) {
|
|
230
231
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN element_html TEXT');
|
|
231
|
-
|
|
232
|
+
logger.debug('[Database] Added element_html column to workflow_actions');
|
|
232
233
|
}
|
|
233
234
|
if (!hasComponentData) {
|
|
234
235
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN component_data TEXT');
|
|
235
|
-
|
|
236
|
+
logger.debug('[Database] Added component_data column to workflow_actions');
|
|
236
237
|
}
|
|
237
238
|
if (!hasEventHandlers) {
|
|
238
239
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN event_handlers TEXT');
|
|
239
|
-
|
|
240
|
+
logger.debug('[Database] Added event_handlers column to workflow_actions');
|
|
240
241
|
}
|
|
241
242
|
if (!hasElementState) {
|
|
242
243
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN element_state TEXT');
|
|
243
|
-
|
|
244
|
+
logger.debug('[Database] Added element_state column to workflow_actions');
|
|
244
245
|
}
|
|
245
246
|
if (!hasPerformanceMetrics) {
|
|
246
247
|
this.db.exec('ALTER TABLE workflow_actions ADD COLUMN performance_metrics TEXT');
|
|
247
|
-
|
|
248
|
+
logger.debug('[Database] Added performance_metrics column to workflow_actions');
|
|
248
249
|
}
|
|
249
250
|
} catch (error) {
|
|
250
251
|
// Columns might already exist, that's ok
|
|
251
|
-
|
|
252
|
+
logger.debug('[Database] Function trace columns already exist or migration failed:', error.message);
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
// Add enhanced columns to screen_interactions table
|
|
@@ -263,27 +264,27 @@ class ChromePilotDatabase {
|
|
|
263
264
|
// Add enhanced click tracking columns to screen_interactions
|
|
264
265
|
if (!hasScreenElementHtml) {
|
|
265
266
|
this.db.exec('ALTER TABLE screen_interactions ADD COLUMN element_html TEXT');
|
|
266
|
-
|
|
267
|
+
logger.debug('[Database] Added element_html column to screen_interactions');
|
|
267
268
|
}
|
|
268
269
|
if (!hasScreenComponentData) {
|
|
269
270
|
this.db.exec('ALTER TABLE screen_interactions ADD COLUMN component_data TEXT');
|
|
270
|
-
|
|
271
|
+
logger.debug('[Database] Added component_data column to screen_interactions');
|
|
271
272
|
}
|
|
272
273
|
if (!hasScreenEventHandlers) {
|
|
273
274
|
this.db.exec('ALTER TABLE screen_interactions ADD COLUMN event_handlers TEXT');
|
|
274
|
-
|
|
275
|
+
logger.debug('[Database] Added event_handlers column to screen_interactions');
|
|
275
276
|
}
|
|
276
277
|
if (!hasScreenElementState) {
|
|
277
278
|
this.db.exec('ALTER TABLE screen_interactions ADD COLUMN element_state TEXT');
|
|
278
|
-
|
|
279
|
+
logger.debug('[Database] Added element_state column to screen_interactions');
|
|
279
280
|
}
|
|
280
281
|
if (!hasScreenPerformanceMetrics) {
|
|
281
282
|
this.db.exec('ALTER TABLE screen_interactions ADD COLUMN performance_metrics TEXT');
|
|
282
|
-
|
|
283
|
+
logger.debug('[Database] Added performance_metrics column to screen_interactions');
|
|
283
284
|
}
|
|
284
285
|
} catch (error) {
|
|
285
286
|
// Columns might already exist, that's ok
|
|
286
|
-
|
|
287
|
+
logger.debug('[Database] Screen interactions enhanced columns already exist or migration failed:', error.message);
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
// Restore points table
|
|
@@ -461,12 +462,12 @@ class ChromePilotDatabase {
|
|
|
461
462
|
const hasScreenshotSettings = columns.some(col => col.name === 'screenshot_settings');
|
|
462
463
|
|
|
463
464
|
if (!hasNameColumn) {
|
|
464
|
-
|
|
465
|
+
logger.debug('[Database] Migrating workflow_recordings table to add name column');
|
|
465
466
|
this.db.exec(`ALTER TABLE workflow_recordings ADD COLUMN name TEXT`);
|
|
466
467
|
}
|
|
467
468
|
|
|
468
469
|
if (!hasScreenshotSettings) {
|
|
469
|
-
|
|
470
|
+
logger.debug('[Database] Migrating workflow_recordings table to add screenshot_settings column');
|
|
470
471
|
this.db.exec(`ALTER TABLE workflow_recordings ADD COLUMN screenshot_settings TEXT`);
|
|
471
472
|
}
|
|
472
473
|
|
|
@@ -475,7 +476,7 @@ class ChromePilotDatabase {
|
|
|
475
476
|
const hasScreenshotData = actionColumns.some(col => col.name === 'screenshot_data');
|
|
476
477
|
|
|
477
478
|
if (!hasScreenshotData) {
|
|
478
|
-
|
|
479
|
+
logger.debug('[Database] Migrating workflow_actions table to add screenshot_data column');
|
|
479
480
|
this.db.exec(`ALTER TABLE workflow_actions ADD COLUMN screenshot_data TEXT`);
|
|
480
481
|
}
|
|
481
482
|
|
|
@@ -484,7 +485,7 @@ class ChromePilotDatabase {
|
|
|
484
485
|
const hasSequenceNumber = logColumns.some(col => col.name === 'sequence_number');
|
|
485
486
|
|
|
486
487
|
if (!hasSequenceNumber) {
|
|
487
|
-
|
|
488
|
+
logger.debug('[Database] Migrating console_logs table to add sequence_number column');
|
|
488
489
|
this.db.exec(`ALTER TABLE console_logs ADD COLUMN sequence_number INTEGER DEFAULT 0`);
|
|
489
490
|
}
|
|
490
491
|
|
|
@@ -495,17 +496,17 @@ class ChromePilotDatabase {
|
|
|
495
496
|
const hasName = recordingsColumns.some(col => col.name === 'name');
|
|
496
497
|
|
|
497
498
|
if (!hasRecordingType) {
|
|
498
|
-
|
|
499
|
+
logger.debug('[Database] Migrating recordings table to add recording_type column');
|
|
499
500
|
this.db.exec(`ALTER TABLE recordings ADD COLUMN recording_type TEXT DEFAULT 'continuous'`);
|
|
500
501
|
}
|
|
501
502
|
|
|
502
503
|
if (!hasUserNote) {
|
|
503
|
-
|
|
504
|
+
logger.debug('[Database] Migrating recordings table to add user_note column');
|
|
504
505
|
this.db.exec(`ALTER TABLE recordings ADD COLUMN user_note TEXT`);
|
|
505
506
|
}
|
|
506
507
|
|
|
507
508
|
if (!hasName) {
|
|
508
|
-
|
|
509
|
+
logger.debug('[Database] Migrating recordings table to add name column');
|
|
509
510
|
this.db.exec(`ALTER TABLE recordings ADD COLUMN name TEXT`);
|
|
510
511
|
}
|
|
511
512
|
}
|
|
@@ -523,9 +524,9 @@ class ChromePilotDatabase {
|
|
|
523
524
|
const recordingId = sessionId;
|
|
524
525
|
const timestamp = Date.now();
|
|
525
526
|
|
|
526
|
-
|
|
527
|
+
logger.debug(`[Database] Storing recording: ${recordingId} for session: ${sessionId}, type: ${recordingType}, name: ${name || 'none'}`);
|
|
527
528
|
const result = stmt.run(recordingId, sessionId, type, timestamp, recordingType, userNote, name);
|
|
528
|
-
|
|
529
|
+
logger.debug(`[Database] Recording stored with changes: ${result.changes}, lastInsertRowid: ${result.lastInsertRowid}`);
|
|
529
530
|
|
|
530
531
|
return recordingId;
|
|
531
532
|
}
|
|
@@ -562,7 +563,7 @@ class ChromePilotDatabase {
|
|
|
562
563
|
this.storeFrameBatch(sessionId, [frameData]);
|
|
563
564
|
}
|
|
564
565
|
|
|
565
|
-
|
|
566
|
+
logger.debug(`[Database] Snapshot stored: ${recordingId} with note: ${userNote || 'none'}`);
|
|
566
567
|
return recordingId;
|
|
567
568
|
}
|
|
568
569
|
|
|
@@ -590,26 +591,26 @@ class ChromePilotDatabase {
|
|
|
590
591
|
// Use base ID instead of prefixed ID
|
|
591
592
|
const recordingId = sessionId;
|
|
592
593
|
|
|
593
|
-
|
|
594
|
+
logger.debug(`[storeFrameBatch] DEATH SPIRAL FIX: Processing ${frames.length} frames for session ${sessionId}`);
|
|
594
595
|
|
|
595
596
|
// Ensure recording exists (but don't overwrite existing)
|
|
596
597
|
const existingRecording = this.getRecording(sessionId);
|
|
597
598
|
if (!existingRecording) {
|
|
598
599
|
this.storeRecording(sessionId, 'frame_capture', 'continuous', null, name);
|
|
599
600
|
} else {
|
|
600
|
-
|
|
601
|
+
logger.debug(`[storeFrameBatch] Using existing recording: ${existingRecording.id}`);
|
|
601
602
|
// Update name if provided and different
|
|
602
603
|
if (name && name !== existingRecording.name) {
|
|
603
604
|
const updateStmt = this.db.prepare(`UPDATE recordings SET name = ? WHERE id = ?`);
|
|
604
605
|
updateStmt.run(name, sessionId);
|
|
605
|
-
|
|
606
|
+
logger.debug(`[storeFrameBatch] Updated recording name to: ${name}`);
|
|
606
607
|
}
|
|
607
608
|
}
|
|
608
609
|
|
|
609
610
|
// Check existing frame count BEFORE insertion
|
|
610
611
|
const preCountStmt = this.db.prepare(`SELECT COUNT(*) as count FROM frames WHERE recording_id = ?`);
|
|
611
612
|
const preCount = preCountStmt.get(recordingId).count;
|
|
612
|
-
|
|
613
|
+
logger.debug(`[storeFrameBatch] PRE-INSERT: ${preCount} existing frames in database`);
|
|
613
614
|
|
|
614
615
|
// Use INSERT OR REPLACE instead of INSERT OR IGNORE to handle updates
|
|
615
616
|
const frameStmt = this.db.prepare(`
|
|
@@ -626,7 +627,7 @@ class ChromePilotDatabase {
|
|
|
626
627
|
// Use frame.index from extension (properly tracked per session), fallback to i for backward compatibility
|
|
627
628
|
const frameIndex = frame.index !== undefined ? frame.index : i;
|
|
628
629
|
|
|
629
|
-
|
|
630
|
+
logger.debug(`[storeFrameBatch] Inserting frame ${frameIndex}: timestamp=${frame.timestamp}, absoluteTimestamp=${frame.absoluteTimestamp}`);
|
|
630
631
|
|
|
631
632
|
try {
|
|
632
633
|
// Serialize interactions as JSON
|
|
@@ -643,18 +644,18 @@ class ChromePilotDatabase {
|
|
|
643
644
|
|
|
644
645
|
if (result.changes > 0) {
|
|
645
646
|
insertedCount++;
|
|
646
|
-
|
|
647
|
+
logger.debug(`[storeFrameBatch] SUCCESS: Frame ${frameIndex} inserted/updated`);
|
|
647
648
|
} else {
|
|
648
649
|
skippedCount++;
|
|
649
|
-
|
|
650
|
+
logger.debug(`[storeFrameBatch] WARNING: Frame ${frameIndex} not changed`);
|
|
650
651
|
}
|
|
651
652
|
} catch (error) {
|
|
652
|
-
|
|
653
|
+
logger.error(`[storeFrameBatch] ERROR inserting frame ${frameIndex}:`, error.message);
|
|
653
654
|
throw error; // Fail fast on SQL errors
|
|
654
655
|
}
|
|
655
656
|
}
|
|
656
657
|
|
|
657
|
-
|
|
658
|
+
logger.debug(`[storeFrameBatch] Transaction complete: ${insertedCount} inserted, ${skippedCount} skipped`);
|
|
658
659
|
|
|
659
660
|
// Update total frames count
|
|
660
661
|
const updateStmt = this.db.prepare(`
|
|
@@ -668,13 +669,13 @@ class ChromePilotDatabase {
|
|
|
668
669
|
// Debug: Check the actual count after update
|
|
669
670
|
const finalCountStmt = this.db.prepare(`SELECT COUNT(*) as count FROM frames WHERE recording_id = ?`);
|
|
670
671
|
const finalCount = finalCountStmt.get(recordingId).count;
|
|
671
|
-
|
|
672
|
+
logger.debug(`[storeFrameBatch] FINAL: ${finalCount} frames in database (was ${preCount})`);
|
|
672
673
|
|
|
673
674
|
return { insertedCount, skippedCount, finalCount };
|
|
674
675
|
});
|
|
675
676
|
|
|
676
677
|
const result = transaction(frames);
|
|
677
|
-
|
|
678
|
+
logger.debug(`[storeFrameBatch] DEATH SPIRAL RESOLVED: ${result.insertedCount}/${frames.length} frames stored successfully`);
|
|
678
679
|
|
|
679
680
|
// Verify what was actually stored
|
|
680
681
|
const verifyStmt = this.db.prepare(`
|
|
@@ -683,10 +684,10 @@ class ChromePilotDatabase {
|
|
|
683
684
|
ORDER BY frame_index ASC
|
|
684
685
|
`);
|
|
685
686
|
const storedFrames = verifyStmt.all(recordingId);
|
|
686
|
-
|
|
687
|
+
logger.debug(`[storeFrameBatch] VERIFICATION: ${storedFrames.length} frames with indices: [${storedFrames.map(f => f.frame_index).join(', ')}]`);
|
|
687
688
|
|
|
688
689
|
if (storedFrames.length === 0) {
|
|
689
|
-
|
|
690
|
+
logger.error(`[storeFrameBatch] DEATH SPIRAL DETECTED: NO FRAMES STORED! Check SQL constraints and frame data.`);
|
|
690
691
|
throw new Error(`Frame storage failed: 0 frames stored for session ${sessionId}`);
|
|
691
692
|
}
|
|
692
693
|
|
|
@@ -716,13 +717,13 @@ class ChromePilotDatabase {
|
|
|
716
717
|
`);
|
|
717
718
|
const frames = framesStmt.all(recordingId);
|
|
718
719
|
|
|
719
|
-
|
|
720
|
-
|
|
720
|
+
logger.debug(`[associateLogsWithFrames] Found ${frames.length} frames for log association`);
|
|
721
|
+
logger.debug(`[associateLogsWithFrames] Frame indices found: [${frames.map(f => f.frame_index).join(', ')}]`);
|
|
721
722
|
|
|
722
723
|
// Debug: Check total frames before processing
|
|
723
724
|
const countStmt = this.db.prepare(`SELECT COUNT(*) as count FROM frames WHERE recording_id = ?`);
|
|
724
725
|
const frameCount = countStmt.get(recordingId).count;
|
|
725
|
-
|
|
726
|
+
logger.debug(`[associateLogsWithFrames] Total frames in database before log association: ${frameCount}`);
|
|
726
727
|
|
|
727
728
|
if (frames.length === 0) {
|
|
728
729
|
return { success: false, message: 'No frames found for session' };
|
|
@@ -775,11 +776,11 @@ class ChromePilotDatabase {
|
|
|
775
776
|
|
|
776
777
|
const associatedCount = transaction(logs, frames);
|
|
777
778
|
|
|
778
|
-
|
|
779
|
+
logger.debug(`Associated ${associatedCount} of ${logs.length} logs with frames`);
|
|
779
780
|
|
|
780
781
|
// Debug: Check total frames after processing
|
|
781
782
|
const finalFrameCount = countStmt.get(recordingId).count;
|
|
782
|
-
|
|
783
|
+
logger.debug(`[associateLogsWithFrames] Total frames in database after log association: ${finalFrameCount}`);
|
|
783
784
|
|
|
784
785
|
return {
|
|
785
786
|
success: true,
|
|
@@ -796,7 +797,7 @@ class ChromePilotDatabase {
|
|
|
796
797
|
// Use base ID instead of prefixed ID
|
|
797
798
|
const recordingId = sessionId;
|
|
798
799
|
|
|
799
|
-
|
|
800
|
+
logger.debug(`[streamLogsToFrames] Processing ${logs.length} logs for session: ${sessionId}`);
|
|
800
801
|
|
|
801
802
|
// Get all frames sorted by timestamp for efficient association
|
|
802
803
|
const framesStmt = this.db.prepare(`
|
|
@@ -808,7 +809,7 @@ class ChromePilotDatabase {
|
|
|
808
809
|
const frames = framesStmt.all(recordingId);
|
|
809
810
|
|
|
810
811
|
if (frames.length === 0) {
|
|
811
|
-
|
|
812
|
+
logger.debug(`[streamLogsToFrames] No frames found for session: ${sessionId}, storing ${logs.length} logs as deferred`);
|
|
812
813
|
return this.storeDeferredLogs(sessionId, logs);
|
|
813
814
|
}
|
|
814
815
|
|
|
@@ -882,7 +883,7 @@ class ChromePilotDatabase {
|
|
|
882
883
|
|
|
883
884
|
const associatedCount = transaction(logs, frames);
|
|
884
885
|
|
|
885
|
-
|
|
886
|
+
logger.debug(`[streamLogsToFrames] Streamed ${associatedCount} of ${logs.length} logs to frames`);
|
|
886
887
|
|
|
887
888
|
return {
|
|
888
889
|
success: true,
|
|
@@ -897,7 +898,7 @@ class ChromePilotDatabase {
|
|
|
897
898
|
storeDeferredLogs(sessionId, logs) {
|
|
898
899
|
this.init();
|
|
899
900
|
|
|
900
|
-
|
|
901
|
+
logger.debug(`[storeDeferredLogs] Storing ${logs.length} deferred logs for session: ${sessionId}`);
|
|
901
902
|
|
|
902
903
|
const deferredLogStmt = this.db.prepare(`
|
|
903
904
|
INSERT INTO deferred_logs (session_id, level, message, timestamp, sequence_number, args)
|
|
@@ -918,7 +919,7 @@ class ChromePilotDatabase {
|
|
|
918
919
|
);
|
|
919
920
|
stored++;
|
|
920
921
|
} catch (error) {
|
|
921
|
-
|
|
922
|
+
logger.error(`[storeDeferredLogs] Failed to store deferred log:`, error, log);
|
|
922
923
|
}
|
|
923
924
|
}
|
|
924
925
|
return stored;
|
|
@@ -926,7 +927,7 @@ class ChromePilotDatabase {
|
|
|
926
927
|
|
|
927
928
|
const storedCount = transaction(logs);
|
|
928
929
|
|
|
929
|
-
|
|
930
|
+
logger.debug(`[storeDeferredLogs] Stored ${storedCount} of ${logs.length} deferred logs`);
|
|
930
931
|
|
|
931
932
|
return {
|
|
932
933
|
success: true,
|
|
@@ -941,7 +942,7 @@ class ChromePilotDatabase {
|
|
|
941
942
|
associateDeferredLogs(sessionId) {
|
|
942
943
|
this.init();
|
|
943
944
|
|
|
944
|
-
|
|
945
|
+
logger.debug(`[associateDeferredLogs] Checking for deferred logs for session: ${sessionId}`);
|
|
945
946
|
|
|
946
947
|
// Get deferred logs for this session
|
|
947
948
|
const deferredLogsStmt = this.db.prepare(`
|
|
@@ -953,11 +954,11 @@ class ChromePilotDatabase {
|
|
|
953
954
|
const deferredLogs = deferredLogsStmt.all(sessionId);
|
|
954
955
|
|
|
955
956
|
if (deferredLogs.length === 0) {
|
|
956
|
-
|
|
957
|
+
logger.debug(`[associateDeferredLogs] No deferred logs found for session: ${sessionId}`);
|
|
957
958
|
return { success: true, logsAssociated: 0 };
|
|
958
959
|
}
|
|
959
960
|
|
|
960
|
-
|
|
961
|
+
logger.debug(`[associateDeferredLogs] Found ${deferredLogs.length} deferred logs, attempting to associate with frames`);
|
|
961
962
|
|
|
962
963
|
// Convert deferred logs back to the format expected by streamLogsToFrames
|
|
963
964
|
const logs = deferredLogs.map(log => ({
|
|
@@ -975,7 +976,7 @@ class ChromePilotDatabase {
|
|
|
975
976
|
// Successfully associated - clean up deferred logs
|
|
976
977
|
const cleanupStmt = this.db.prepare(`DELETE FROM deferred_logs WHERE session_id = ?`);
|
|
977
978
|
cleanupStmt.run(sessionId);
|
|
978
|
-
|
|
979
|
+
logger.debug(`[associateDeferredLogs] Successfully associated ${result.logsStreamed} logs and cleaned up deferred storage`);
|
|
979
980
|
|
|
980
981
|
return {
|
|
981
982
|
success: true,
|
|
@@ -984,7 +985,7 @@ class ChromePilotDatabase {
|
|
|
984
985
|
};
|
|
985
986
|
}
|
|
986
987
|
|
|
987
|
-
|
|
988
|
+
logger.debug(`[associateDeferredLogs] Frames still not available for session: ${sessionId}`);
|
|
988
989
|
return { success: false, message: 'Frames still not available' };
|
|
989
990
|
}
|
|
990
991
|
|
|
@@ -992,13 +993,13 @@ class ChromePilotDatabase {
|
|
|
992
993
|
getRecording(recordingId) {
|
|
993
994
|
this.init();
|
|
994
995
|
|
|
995
|
-
|
|
996
|
+
logger.debug(`[getRecording] Looking for recording with ID: ${recordingId}`);
|
|
996
997
|
|
|
997
998
|
// Handle both old format (frame_<id>) and new format (base id)
|
|
998
999
|
let baseId = recordingId;
|
|
999
1000
|
if (recordingId.startsWith('frame_')) {
|
|
1000
1001
|
baseId = recordingId.substring(6); // Remove 'frame_' prefix
|
|
1001
|
-
|
|
1002
|
+
logger.debug(`[getRecording] Converting old format ID ${recordingId} to base ID: ${baseId}`);
|
|
1002
1003
|
}
|
|
1003
1004
|
|
|
1004
1005
|
// Priority order: exact id match, then session_id match with frames, then any session_id match
|
|
@@ -1020,11 +1021,11 @@ class ChromePilotDatabase {
|
|
|
1020
1021
|
const recording = stmt.get(recordingId, baseId, recordingId, baseId, recordingId, baseId, recordingId);
|
|
1021
1022
|
|
|
1022
1023
|
if (recording) {
|
|
1023
|
-
|
|
1024
|
+
logger.debug(`[getRecording] Found recording with ID: ${recording.id}, total_frames: ${recording.total_frames}`);
|
|
1024
1025
|
return recording;
|
|
1025
1026
|
}
|
|
1026
1027
|
|
|
1027
|
-
|
|
1028
|
+
logger.debug(`[getRecording] No recording found for: ${recordingId} or base ID: ${baseId}`);
|
|
1028
1029
|
return null;
|
|
1029
1030
|
}
|
|
1030
1031
|
|
|
@@ -1086,7 +1087,7 @@ class ChromePilotDatabase {
|
|
|
1086
1087
|
try {
|
|
1087
1088
|
embeddedInteractions = JSON.parse(frame.interactions || '[]');
|
|
1088
1089
|
} catch (error) {
|
|
1089
|
-
|
|
1090
|
+
logger.warn(`[getFrame] Failed to parse embedded interactions for frame ${frameIndex}:`, error);
|
|
1090
1091
|
embeddedInteractions = [];
|
|
1091
1092
|
}
|
|
1092
1093
|
|
|
@@ -1122,7 +1123,7 @@ class ChromePilotDatabase {
|
|
|
1122
1123
|
WHERE recording_id = ?
|
|
1123
1124
|
`);
|
|
1124
1125
|
const frameStats = allFramesStmt.get(recording.id);
|
|
1125
|
-
|
|
1126
|
+
logger.debug(`[getFrameSession] Database stats for ${recording.id}: ${frameStats.count} frames, indices ${frameStats.min_index} to ${frameStats.max_index}`);
|
|
1126
1127
|
|
|
1127
1128
|
const framesStmt = this.db.prepare(`
|
|
1128
1129
|
SELECT frame_index, timestamp, absolute_timestamp, image_data, interactions
|
|
@@ -1132,8 +1133,8 @@ class ChromePilotDatabase {
|
|
|
1132
1133
|
`);
|
|
1133
1134
|
const frames = framesStmt.all(recording.id);
|
|
1134
1135
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1136
|
+
logger.debug(`[getFrameSession] Found ${frames.length} frames in database for session ${sessionId}`);
|
|
1137
|
+
logger.debug(`[getFrameSession] Frame indices: [${frames.map(f => f.frame_index).join(', ')}]`);
|
|
1137
1138
|
|
|
1138
1139
|
// Get logs and interactions for all frames
|
|
1139
1140
|
for (const frame of frames) {
|
|
@@ -1172,7 +1173,7 @@ class ChromePilotDatabase {
|
|
|
1172
1173
|
try {
|
|
1173
1174
|
embeddedInteractions = JSON.parse(frame.interactions || '[]');
|
|
1174
1175
|
} catch (error) {
|
|
1175
|
-
|
|
1176
|
+
logger.warn(`[getFrameSession] Failed to parse embedded interactions for frame ${frame.frame_index}:`, error);
|
|
1176
1177
|
embeddedInteractions = [];
|
|
1177
1178
|
}
|
|
1178
1179
|
|
|
@@ -1316,7 +1317,7 @@ class ChromePilotDatabase {
|
|
|
1316
1317
|
storeWorkflowRecording(sessionId, url, title, includeLogs = false, name = null, screenshotSettings = null) {
|
|
1317
1318
|
this.init();
|
|
1318
1319
|
|
|
1319
|
-
|
|
1320
|
+
logger.debug('[Database] Storing workflow recording with name:', name, 'sessionId:', sessionId);
|
|
1320
1321
|
|
|
1321
1322
|
const stmt = this.db.prepare(`
|
|
1322
1323
|
INSERT OR REPLACE INTO workflow_recordings (id, session_id, name, url, title, timestamp, include_logs, screenshot_settings, updated_at)
|
|
@@ -1360,7 +1361,7 @@ class ChromePilotDatabase {
|
|
|
1360
1361
|
if (!data) return null;
|
|
1361
1362
|
let jsonStr = typeof data === 'string' ? data : JSON.stringify(data);
|
|
1362
1363
|
if (jsonStr.length > maxSize) {
|
|
1363
|
-
|
|
1364
|
+
logger.warn(`[Database] Truncating data field from ${jsonStr.length} to ${maxSize} bytes`);
|
|
1364
1365
|
jsonStr = jsonStr.substring(0, maxSize - 50) + '...[TRUNCATED]';
|
|
1365
1366
|
}
|
|
1366
1367
|
return jsonStr;
|
|
@@ -1676,7 +1677,7 @@ class ChromePilotDatabase {
|
|
|
1676
1677
|
const deleteRecordingsStmt = this.db.prepare(`DELETE FROM workflow_recordings`);
|
|
1677
1678
|
const result = deleteRecordingsStmt.run();
|
|
1678
1679
|
|
|
1679
|
-
|
|
1680
|
+
logger.debug(`[Database] Cleared workflow recordings: ${result.changes} recordings deleted`);
|
|
1680
1681
|
return result.changes;
|
|
1681
1682
|
});
|
|
1682
1683
|
|
|
@@ -1715,7 +1716,7 @@ class ChromePilotDatabase {
|
|
|
1715
1716
|
|
|
1716
1717
|
return { success: true, restorePointId };
|
|
1717
1718
|
} catch (error) {
|
|
1718
|
-
|
|
1719
|
+
logger.error('Error storing restore point:', error);
|
|
1719
1720
|
return { success: false, error: error.message };
|
|
1720
1721
|
}
|
|
1721
1722
|
}
|
|
@@ -1785,7 +1786,7 @@ class ChromePilotDatabase {
|
|
|
1785
1786
|
`);
|
|
1786
1787
|
|
|
1787
1788
|
stmt.run(pid, mode);
|
|
1788
|
-
|
|
1789
|
+
logger.debug(`Registered server instance: PID ${pid}, mode: ${mode}`);
|
|
1789
1790
|
}
|
|
1790
1791
|
|
|
1791
1792
|
async getSingleServerInstance() {
|
|
@@ -1824,7 +1825,7 @@ class ChromePilotDatabase {
|
|
|
1824
1825
|
// Process is dead, remove it
|
|
1825
1826
|
const deleteStmt = this.db.prepare(`DELETE FROM server_instances WHERE pid = ?`);
|
|
1826
1827
|
deleteStmt.run(instance.pid);
|
|
1827
|
-
|
|
1828
|
+
logger.debug(`Cleaned up dead server instance: PID ${instance.pid}`);
|
|
1828
1829
|
}
|
|
1829
1830
|
}
|
|
1830
1831
|
}
|
|
@@ -1836,7 +1837,7 @@ class ChromePilotDatabase {
|
|
|
1836
1837
|
const result = stmt.run(pid);
|
|
1837
1838
|
|
|
1838
1839
|
if (result.changes > 0) {
|
|
1839
|
-
|
|
1840
|
+
logger.debug(`Unregistered server instance: PID ${pid}`);
|
|
1840
1841
|
}
|
|
1841
1842
|
}
|
|
1842
1843
|
|
|
@@ -1893,7 +1894,7 @@ class ChromePilotDatabase {
|
|
|
1893
1894
|
transaction();
|
|
1894
1895
|
return { success: true, count: interactions.length };
|
|
1895
1896
|
} catch (error) {
|
|
1896
|
-
|
|
1897
|
+
logger.error('Error storing screen interactions:', error);
|
|
1897
1898
|
return { success: false, error: error.message };
|
|
1898
1899
|
}
|
|
1899
1900
|
}
|
|
@@ -1907,7 +1908,7 @@ class ChromePilotDatabase {
|
|
|
1907
1908
|
let baseId = recordingId;
|
|
1908
1909
|
if (recordingId.startsWith('frame_')) {
|
|
1909
1910
|
baseId = recordingId.substring(6); // Remove 'frame_' prefix
|
|
1910
|
-
|
|
1911
|
+
logger.debug(`[getScreenInteractions] Converting old format ID ${recordingId} to base ID: ${baseId}`);
|
|
1911
1912
|
}
|
|
1912
1913
|
|
|
1913
1914
|
// Priority order: exact recording_id match, then baseId match
|
|
@@ -1972,11 +1973,11 @@ class ChromePilotDatabase {
|
|
|
1972
1973
|
const interactions = stmt.all(frameTimestamp, recordingId, lowerBound, upperBound);
|
|
1973
1974
|
|
|
1974
1975
|
// Diagnostic logging for interaction association debugging
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1976
|
+
logger.debug(`[getInteractionsForFrame] DEBUGGING - recordingId: ${recordingId}, frameTimestamp: ${frameTimestamp}, window: ±${windowMs}ms`);
|
|
1977
|
+
logger.debug(`[getInteractionsForFrame] Search range: ${lowerBound} to ${upperBound}`);
|
|
1978
|
+
logger.debug(`[getInteractionsForFrame] Found ${interactions.length} interactions`);
|
|
1978
1979
|
if (interactions.length > 0) {
|
|
1979
|
-
|
|
1980
|
+
logger.debug(`[getInteractionsForFrame] First interaction:`, interactions[0]);
|
|
1980
1981
|
}
|
|
1981
1982
|
|
|
1982
1983
|
// Convert to InteractionData format with metadata
|