node-mac-recorder 2.17.18 → 2.17.19
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/index.js +32 -48
- package/package.json +1 -1
- package/src/cursor_tracker.mm +11 -14
- package/test-output/primary-fix-test-1758266910543.json +1 -0
- package/test-output/unified-cursor-1758313640878.json +1 -0
- package/test-output/unified-cursor-1758313689471.json +1 -0
- package/test-unified-cursor.js +75 -0
- package/debug-primary-cursor.js +0 -180
package/index.js
CHANGED
|
@@ -359,53 +359,10 @@ class MacRecorder extends EventEmitter {
|
|
|
359
359
|
// Start cursor tracking automatically with recording
|
|
360
360
|
let cursorOptions = {};
|
|
361
361
|
|
|
362
|
-
//
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const targetWindow = windows.find(w => w.id === this.options.windowId);
|
|
367
|
-
if (targetWindow) {
|
|
368
|
-
// Start cursor capture with simplified window-relative tracking
|
|
369
|
-
this.startCursorCapture(cursorFilePath, {
|
|
370
|
-
windowRelative: true,
|
|
371
|
-
windowInfo: {
|
|
372
|
-
// Use original global window coordinates for reference
|
|
373
|
-
x: targetWindow.x,
|
|
374
|
-
y: targetWindow.y,
|
|
375
|
-
width: targetWindow.width,
|
|
376
|
-
height: targetWindow.height,
|
|
377
|
-
displayId: this.options.displayId,
|
|
378
|
-
// Persist capture area so we can rebuild global offsets reliably
|
|
379
|
-
captureArea: this.options.captureArea,
|
|
380
|
-
// Keep a snapshot of the window details for debugging/analytics
|
|
381
|
-
originalWindow: targetWindow,
|
|
382
|
-
// Store display info for multi-display coordinate fixes
|
|
383
|
-
targetDisplay: this.recordingDisplayInfo
|
|
384
|
-
}
|
|
385
|
-
}).catch(cursorError => {
|
|
386
|
-
console.warn('Window cursor tracking failed:', cursorError.message);
|
|
387
|
-
// Fallback to display recording
|
|
388
|
-
this.startCursorCapture(cursorFilePath).catch(fallbackError => {
|
|
389
|
-
console.warn('Fallback cursor tracking failed:', fallbackError.message);
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
}).catch(error => {
|
|
394
|
-
console.warn('Could not get window info for cursor tracking:', error.message);
|
|
395
|
-
// Fallback to display cursor tracking
|
|
396
|
-
this.startCursorCapture(cursorFilePath).catch(cursorError => {
|
|
397
|
-
console.warn('Cursor tracking failed to start:', cursorError.message);
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
} else {
|
|
401
|
-
// For display recording, use display-relative cursor tracking
|
|
402
|
-
this.startCursorCapture(cursorFilePath, {
|
|
403
|
-
displayRelative: true,
|
|
404
|
-
displayInfo: this.recordingDisplayInfo
|
|
405
|
-
}).catch(cursorError => {
|
|
406
|
-
console.warn('Display cursor tracking failed:', cursorError.message);
|
|
407
|
-
});
|
|
408
|
-
}
|
|
362
|
+
// Hem window hem display recording için aynı native cursor tracking kullan
|
|
363
|
+
this.startCursorCapture(cursorFilePath).catch(cursorError => {
|
|
364
|
+
console.warn('Cursor tracking failed to start:', cursorError.message);
|
|
365
|
+
});
|
|
409
366
|
|
|
410
367
|
// Timer başlat (progress tracking için)
|
|
411
368
|
this.recordingTimer = setInterval(() => {
|
|
@@ -916,7 +873,34 @@ class MacRecorder extends EventEmitter {
|
|
|
916
873
|
/**
|
|
917
874
|
* Cursor capture durdurur - dosya yazma işlemini sonlandırır
|
|
918
875
|
*/
|
|
919
|
-
|
|
876
|
+
stopCursorCapture() {
|
|
877
|
+
if (!this.cursorCaptureInterval) {
|
|
878
|
+
return false;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
try {
|
|
882
|
+
// Native cursor tracking'i durdur
|
|
883
|
+
const success = nativeBinding.stopCursorTracking();
|
|
884
|
+
|
|
885
|
+
this.cursorCaptureInterval = null;
|
|
886
|
+
this.cursorCaptureFile = null;
|
|
887
|
+
this.cursorCaptureStartTime = null;
|
|
888
|
+
|
|
889
|
+
this.emit("cursorCaptureStopped", {
|
|
890
|
+
timestamp: Date.now()
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
return success;
|
|
894
|
+
} catch (error) {
|
|
895
|
+
console.warn("Error stopping cursor tracking:", error.message);
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* LEGACY: Eski JS-based cursor capture durdurmak için geriye uyumluluk
|
|
902
|
+
*/
|
|
903
|
+
async _legacyStopCursorCapture() {
|
|
920
904
|
return new Promise((resolve, reject) => {
|
|
921
905
|
try {
|
|
922
906
|
if (!this.cursorCaptureInterval) {
|
package/package.json
CHANGED
package/src/cursor_tracker.mm
CHANGED
|
@@ -601,13 +601,15 @@ CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef eve
|
|
|
601
601
|
}
|
|
602
602
|
|
|
603
603
|
// Cursor data oluştur
|
|
604
|
+
// Cursor data oluştur - global koordinat sistemi kullan
|
|
604
605
|
NSDictionary *cursorInfo = @{
|
|
605
606
|
@"x": @((int)location.x),
|
|
606
607
|
@"y": @((int)location.y),
|
|
607
608
|
@"timestamp": @(timestamp),
|
|
608
609
|
@"unixTimeMs": @(unixTimeMs),
|
|
609
610
|
@"cursorType": cursorType,
|
|
610
|
-
@"type": eventType
|
|
611
|
+
@"type": eventType,
|
|
612
|
+
@"coordinateSystem": @"global"
|
|
611
613
|
};
|
|
612
614
|
|
|
613
615
|
// Direkt dosyaya yaz
|
|
@@ -636,37 +638,32 @@ void cursorTimerCallback() {
|
|
|
636
638
|
// Apply DPR scaling correction for Retina displays
|
|
637
639
|
NSDictionary *scalingInfo = getDisplayScalingInfo(rawLocation);
|
|
638
640
|
CGPoint location = rawLocation;
|
|
639
|
-
|
|
641
|
+
|
|
640
642
|
if (scalingInfo) {
|
|
641
643
|
CGFloat scaleFactor = [[scalingInfo objectForKey:@"scaleFactor"] doubleValue];
|
|
642
644
|
NSRect displayBounds = [[scalingInfo objectForKey:@"displayBounds"] rectValue];
|
|
643
|
-
|
|
645
|
+
|
|
644
646
|
// Keep logical coordinates - no scaling needed here
|
|
645
647
|
location = rawLocation;
|
|
646
648
|
}
|
|
647
|
-
|
|
649
|
+
|
|
648
650
|
NSDate *currentDate = [NSDate date];
|
|
649
651
|
NSTimeInterval timestamp = [currentDate timeIntervalSinceDate:g_trackingStartTime] * 1000; // milliseconds
|
|
650
652
|
NSTimeInterval unixTimeMs = [currentDate timeIntervalSince1970] * 1000; // unix timestamp in milliseconds
|
|
651
653
|
NSString *cursorType = getCursorType();
|
|
652
|
-
|
|
653
|
-
// CRITICAL: Apply coordinate transformation if needed
|
|
654
|
-
// This should match the transformation logic in index.js cursorTimerCallback
|
|
655
|
-
|
|
656
|
-
// Use transformed coordinates from the JavaScript layer if available
|
|
657
|
-
// The transformation is handled in index.js, so we need to get the transformed position
|
|
658
|
-
// For now, we'll write the raw coordinates and let the JS layer handle transformation
|
|
659
|
-
|
|
654
|
+
|
|
660
655
|
// Cursor data oluştur
|
|
656
|
+
// Cursor data oluştur - global koordinat sistemi kullan
|
|
661
657
|
NSDictionary *cursorInfo = @{
|
|
662
658
|
@"x": @((int)location.x),
|
|
663
659
|
@"y": @((int)location.y),
|
|
664
660
|
@"timestamp": @(timestamp),
|
|
665
661
|
@"unixTimeMs": @(unixTimeMs),
|
|
666
662
|
@"cursorType": cursorType,
|
|
667
|
-
@"type": @"move"
|
|
663
|
+
@"type": @"move",
|
|
664
|
+
@"coordinateSystem": @"global"
|
|
668
665
|
};
|
|
669
|
-
|
|
666
|
+
|
|
670
667
|
// Direkt dosyaya yaz
|
|
671
668
|
writeToFile(cursorInfo);
|
|
672
669
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"x":702,"y":607,"timestamp":119,"unixTimeMs":1758313640997,"cursorType":"text","type":"move","coordinateSystem":"display-relative"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"x":702,"y":607,"timestamp":132,"unixTimeMs":1758313689604,"cursorType":"text","type":"move","coordinateSystem":"display-relative"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const MacRecorder = require('./index.js');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
async function testUnifiedCursorTracking() {
|
|
8
|
+
const recorder = new MacRecorder();
|
|
9
|
+
|
|
10
|
+
console.log('🎯 Testing unified cursor tracking...');
|
|
11
|
+
|
|
12
|
+
// Create test output directory
|
|
13
|
+
const outputDir = './test-output';
|
|
14
|
+
if (!fs.existsSync(outputDir)) {
|
|
15
|
+
fs.mkdirSync(outputDir);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const cursorFilePath = path.join(outputDir, `unified-cursor-${Date.now()}.json`);
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
console.log('Starting native cursor tracking...');
|
|
22
|
+
|
|
23
|
+
// Test native cursor tracking
|
|
24
|
+
const result = await recorder.startCursorCapture(cursorFilePath);
|
|
25
|
+
console.log('✅ Cursor tracking started:', result);
|
|
26
|
+
|
|
27
|
+
console.log('\n🔥 Move your mouse around for 5 seconds...');
|
|
28
|
+
|
|
29
|
+
// Wait 5 seconds
|
|
30
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
31
|
+
|
|
32
|
+
console.log('\nStopping cursor tracking...');
|
|
33
|
+
const stopped = recorder.stopCursorCapture();
|
|
34
|
+
console.log('✅ Cursor tracking stopped:', stopped);
|
|
35
|
+
|
|
36
|
+
// Wait a bit for file to be written
|
|
37
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
38
|
+
|
|
39
|
+
// Check if file exists and has content
|
|
40
|
+
if (fs.existsSync(cursorFilePath)) {
|
|
41
|
+
const fileContent = fs.readFileSync(cursorFilePath, 'utf8');
|
|
42
|
+
console.log('📁 File size:', fileContent.length, 'bytes');
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const cursorData = JSON.parse(fileContent);
|
|
46
|
+
console.log('📊 Cursor data points:', cursorData.length);
|
|
47
|
+
|
|
48
|
+
if (cursorData.length > 0) {
|
|
49
|
+
console.log('📍 First point:', cursorData[0]);
|
|
50
|
+
console.log('📍 Last point:', cursorData[cursorData.length - 1]);
|
|
51
|
+
|
|
52
|
+
// Check coordinate system
|
|
53
|
+
const coordinateSystems = [...new Set(cursorData.map(p => p.coordinateSystem))];
|
|
54
|
+
console.log('🔧 Coordinate systems used:', coordinateSystems);
|
|
55
|
+
}
|
|
56
|
+
} catch (parseError) {
|
|
57
|
+
console.log('⚠️ File content (first 500 chars):', fileContent.substring(0, 500));
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
console.log('❌ Output file not found:', cursorFilePath);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('❌ Test failed:', error.message);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Run test
|
|
69
|
+
testUnifiedCursorTracking().then(() => {
|
|
70
|
+
console.log('\n✨ Test completed');
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}).catch(error => {
|
|
73
|
+
console.error('💥 Test error:', error);
|
|
74
|
+
process.exit(1);
|
|
75
|
+
});
|
package/debug-primary-cursor.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
const MacRecorder = require('./index.js');
|
|
2
|
-
|
|
3
|
-
async function debugPrimaryCursor() {
|
|
4
|
-
console.log('🔍 Detailed debugging of primary display cursor coordinates...');
|
|
5
|
-
|
|
6
|
-
const recorder = new MacRecorder();
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
const displays = await recorder.getDisplays();
|
|
10
|
-
const windows = await recorder.getWindows();
|
|
11
|
-
|
|
12
|
-
const primaryDisplay = displays.find(d => d.isPrimary);
|
|
13
|
-
console.log('\n📱 Primary Display:');
|
|
14
|
-
console.log(` Bounds: (${primaryDisplay.x}, ${primaryDisplay.y}) ${primaryDisplay.width}x${primaryDisplay.height}`);
|
|
15
|
-
|
|
16
|
-
// Find a window on primary display
|
|
17
|
-
const primaryWindows = windows.filter(window => {
|
|
18
|
-
const windowCenterX = window.x + window.width / 2;
|
|
19
|
-
const windowCenterY = window.y + window.height / 2;
|
|
20
|
-
return (windowCenterX >= primaryDisplay.x &&
|
|
21
|
-
windowCenterX < primaryDisplay.x + primaryDisplay.width &&
|
|
22
|
-
windowCenterY >= primaryDisplay.y &&
|
|
23
|
-
windowCenterY < primaryDisplay.y + primaryDisplay.height);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
if (primaryWindows.length === 0) {
|
|
27
|
-
console.log('❌ No windows found on primary display');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const testWindow = primaryWindows[0];
|
|
32
|
-
console.log('\n🪟 Test Window:');
|
|
33
|
-
console.log(` Title: "${testWindow.title}"`);
|
|
34
|
-
console.log(` Global position: (${testWindow.x}, ${testWindow.y})`);
|
|
35
|
-
console.log(` Size: ${testWindow.width}x${testWindow.height}`);
|
|
36
|
-
console.log(` Global bounds: (${testWindow.x}, ${testWindow.y}) to (${testWindow.x + testWindow.width}, ${testWindow.y + testWindow.height})`);
|
|
37
|
-
|
|
38
|
-
// Manual cursor position check
|
|
39
|
-
console.log('\n🖱️ Current cursor position:');
|
|
40
|
-
const currentPos = recorder.getCursorPosition();
|
|
41
|
-
console.log(` Global cursor: (${currentPos.x}, ${currentPos.y})`);
|
|
42
|
-
|
|
43
|
-
// Manual transformation calculation
|
|
44
|
-
console.log('\n🧮 Manual transformation calculation:');
|
|
45
|
-
const manualWindowRelativeX = currentPos.x - testWindow.x;
|
|
46
|
-
const manualWindowRelativeY = currentPos.y - testWindow.y;
|
|
47
|
-
console.log(` Manual window-relative: (${manualWindowRelativeX}, ${manualWindowRelativeY})`);
|
|
48
|
-
|
|
49
|
-
const isInWindow = (manualWindowRelativeX >= 0 && manualWindowRelativeX < testWindow.width &&
|
|
50
|
-
manualWindowRelativeY >= 0 && manualWindowRelativeY < testWindow.height);
|
|
51
|
-
console.log(` Is cursor in window? ${isInWindow ? '✅ YES' : '❌ NO'}`);
|
|
52
|
-
|
|
53
|
-
if (!isInWindow) {
|
|
54
|
-
console.log('\n⚠️ Move cursor to the test window for accurate testing...');
|
|
55
|
-
console.log(' Waiting 3 seconds for you to move cursor to the window...');
|
|
56
|
-
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
57
|
-
|
|
58
|
-
const newPos = recorder.getCursorPosition();
|
|
59
|
-
console.log(`\n🖱️ New cursor position: (${newPos.x}, ${newPos.y})`);
|
|
60
|
-
const newManualX = newPos.x - testWindow.x;
|
|
61
|
-
const newManualY = newPos.y - testWindow.y;
|
|
62
|
-
console.log(` New manual window-relative: (${newManualX}, ${newManualY})`);
|
|
63
|
-
|
|
64
|
-
const newIsInWindow = (newManualX >= 0 && newManualX < testWindow.width &&
|
|
65
|
-
newManualY >= 0 && newManualY < testWindow.height);
|
|
66
|
-
console.log(` Is cursor in window now? ${newIsInWindow ? '✅ YES' : '❌ NO'}`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Now test with cursor capture to see what actually gets recorded
|
|
70
|
-
console.log('\n🎬 Testing actual cursor capture...');
|
|
71
|
-
|
|
72
|
-
// Create a custom logger to see what coordinates are being processed
|
|
73
|
-
const originalLog = console.log;
|
|
74
|
-
const capturedLogs = [];
|
|
75
|
-
|
|
76
|
-
// Temporarily override console.log to capture coordinate logs
|
|
77
|
-
console.log = (...args) => {
|
|
78
|
-
const message = args.join(' ');
|
|
79
|
-
if (message.includes('cursor') || message.includes('position') || message.includes('coordinate')) {
|
|
80
|
-
capturedLogs.push(message);
|
|
81
|
-
}
|
|
82
|
-
originalLog(...args);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const outputFile = `./test-output/debug-primary-${Date.now()}.json`;
|
|
86
|
-
|
|
87
|
-
// Start capture with detailed logging
|
|
88
|
-
await recorder.startCursorCapture(outputFile, {
|
|
89
|
-
windowRelative: true,
|
|
90
|
-
windowInfo: {
|
|
91
|
-
x: testWindow.x,
|
|
92
|
-
y: testWindow.y,
|
|
93
|
-
width: testWindow.width,
|
|
94
|
-
height: testWindow.height,
|
|
95
|
-
displayId: primaryDisplay.id
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
console.log('\n📍 Cursor capture started. Move mouse in the window for 3 seconds...');
|
|
100
|
-
console.log(` Expected window bounds: (0, 0) to (${testWindow.width}, ${testWindow.height})`);
|
|
101
|
-
|
|
102
|
-
// Capture for 3 seconds with manual checking
|
|
103
|
-
for (let i = 0; i < 6; i++) {
|
|
104
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
105
|
-
const pos = recorder.getCursorPosition();
|
|
106
|
-
const windowRelX = pos.x - testWindow.x;
|
|
107
|
-
const windowRelY = pos.y - testWindow.y;
|
|
108
|
-
|
|
109
|
-
console.log(` Sample ${i+1}: Global(${pos.x}, ${pos.y}) → Window-rel(${windowRelX}, ${windowRelY})`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
await recorder.stopCursorCapture();
|
|
113
|
-
|
|
114
|
-
// Restore console.log
|
|
115
|
-
console.log = originalLog;
|
|
116
|
-
|
|
117
|
-
// Analyze results
|
|
118
|
-
const fs = require('fs');
|
|
119
|
-
if (fs.existsSync(outputFile)) {
|
|
120
|
-
const cursorData = JSON.parse(fs.readFileSync(outputFile, 'utf8'));
|
|
121
|
-
|
|
122
|
-
console.log('\n📊 Analysis Results:');
|
|
123
|
-
console.log(` Captured events: ${cursorData.length}`);
|
|
124
|
-
|
|
125
|
-
if (cursorData.length > 0) {
|
|
126
|
-
console.log('\n📍 Sample recorded coordinates:');
|
|
127
|
-
cursorData.slice(0, 5).forEach((event, i) => {
|
|
128
|
-
console.log(` Event ${i+1}: (${event.x}, ${event.y}) - ${event.coordinateSystem}`);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Check bounds
|
|
132
|
-
const inBounds = cursorData.filter(event =>
|
|
133
|
-
event.x >= 0 && event.x < testWindow.width &&
|
|
134
|
-
event.y >= 0 && event.y < testWindow.height
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
const outOfBounds = cursorData.filter(event =>
|
|
138
|
-
event.x < 0 || event.x >= testWindow.width ||
|
|
139
|
-
event.y < 0 || event.y >= testWindow.height
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
console.log(`\n✅ Events in bounds: ${inBounds.length}/${cursorData.length} (${Math.round(inBounds.length/cursorData.length*100)}%)`);
|
|
143
|
-
|
|
144
|
-
if (outOfBounds.length > 0) {
|
|
145
|
-
console.log(`❌ Events out of bounds: ${outOfBounds.length}`);
|
|
146
|
-
console.log(' Problem coordinates:');
|
|
147
|
-
outOfBounds.slice(0, 3).forEach(event => {
|
|
148
|
-
console.log(` (${event.x}, ${event.y}) - Expected: 0-${testWindow.width}, 0-${testWindow.height}`);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Calculate offset pattern
|
|
152
|
-
const xOffsets = outOfBounds.map(e => e.x - (e.x >= 0 ? 0 : testWindow.width));
|
|
153
|
-
const yOffsets = outOfBounds.map(e => e.y - (e.y >= 0 ? 0 : testWindow.height));
|
|
154
|
-
|
|
155
|
-
console.log(`\n🔍 Offset analysis:`);
|
|
156
|
-
console.log(` X offset pattern: ${xOffsets.slice(0, 3).join(', ')}`);
|
|
157
|
-
console.log(` Y offset pattern: ${yOffsets.slice(0, 3).join(', ')}`);
|
|
158
|
-
} else {
|
|
159
|
-
console.log('✅ All coordinates are within bounds!');
|
|
160
|
-
}
|
|
161
|
-
} else {
|
|
162
|
-
console.log('❌ No events captured - cursor might not be in window or transformation is dropping events');
|
|
163
|
-
}
|
|
164
|
-
} else {
|
|
165
|
-
console.log('❌ No output file created');
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
console.log('\n🔍 Captured system logs:');
|
|
169
|
-
if (capturedLogs.length > 0) {
|
|
170
|
-
capturedLogs.forEach(log => console.log(` ${log}`));
|
|
171
|
-
} else {
|
|
172
|
-
console.log(' No relevant coordinate logs captured');
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
} catch (error) {
|
|
176
|
-
console.error('❌ Debug failed:', error.message);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
debugPrimaryCursor().catch(console.error);
|