buddy-workbench 0.1.96 → 0.1.98
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
CHANGED
|
@@ -12,6 +12,8 @@ import { readWindowsClipboard } from './windows.js';
|
|
|
12
12
|
|
|
13
13
|
const execFileAsync = promisify(execFile);
|
|
14
14
|
const previewLimit = 2000;
|
|
15
|
+
const macClipboardCommandMaxBuffer = 100 * 1024 * 1024;
|
|
16
|
+
const macClipboardCommandTimeout = 10 * 1000;
|
|
15
17
|
let lastValue = '';
|
|
16
18
|
let lastImageHash = '';
|
|
17
19
|
let suppressImageCaptureUntil = 0;
|
|
@@ -101,7 +103,10 @@ async function getMacClipboardImageData() {
|
|
|
101
103
|
}
|
|
102
104
|
`;
|
|
103
105
|
try {
|
|
104
|
-
const { stdout } = await execFileAsync('osascript', ['-l', 'JavaScript', '-e', jsaScript], {
|
|
106
|
+
const { stdout } = await execFileAsync('osascript', ['-l', 'JavaScript', '-e', jsaScript], {
|
|
107
|
+
timeout: macClipboardCommandTimeout,
|
|
108
|
+
maxBuffer: macClipboardCommandMaxBuffer
|
|
109
|
+
});
|
|
105
110
|
const str = stdout.trim();
|
|
106
111
|
markClipboardSuccess('macOS image clipboard read (osascript)');
|
|
107
112
|
if (!str) return null;
|
|
@@ -113,8 +118,7 @@ async function getMacClipboardImageData() {
|
|
|
113
118
|
const base64 = str.slice(secondColon + 1);
|
|
114
119
|
if (!width || !height || !base64) return null;
|
|
115
120
|
return { width, height, rgbaBuf: Buffer.from(base64, 'base64') };
|
|
116
|
-
} catch
|
|
117
|
-
logClipboardError('macOS image clipboard read (osascript)', error);
|
|
121
|
+
} catch {
|
|
118
122
|
// If osascript failed with an error, attempt the Swift fallback for image capture
|
|
119
123
|
const rawBuffer = await getMacClipboardImageBuffer();
|
|
120
124
|
if (rawBuffer && rawBuffer.length > 0) {
|
|
@@ -141,20 +145,20 @@ if let data = pb.data(forType: .png) {
|
|
|
141
145
|
}
|
|
142
146
|
`;
|
|
143
147
|
try {
|
|
144
|
-
const { stdout } = await execFileAsync('swift', ['-e', swiftCode], {
|
|
148
|
+
const { stdout } = await execFileAsync('swift', ['-e', swiftCode], {
|
|
149
|
+
encoding: 'buffer',
|
|
150
|
+
timeout: macClipboardCommandTimeout,
|
|
151
|
+
maxBuffer: macClipboardCommandMaxBuffer
|
|
152
|
+
});
|
|
145
153
|
if (stdout && stdout.length > 0) {
|
|
146
154
|
markClipboardSuccess('macOS image clipboard read (Swift)');
|
|
147
155
|
swiftClipboardRetryAt = 0;
|
|
148
156
|
return stdout;
|
|
149
157
|
}
|
|
150
|
-
} catch
|
|
158
|
+
} catch {
|
|
151
159
|
// Back off before trying Swift again. A failed `swift -e` invocation is
|
|
152
160
|
// commonly persistent and clipboard polling runs every two seconds.
|
|
153
161
|
swiftClipboardRetryAt = Date.now() + 5 * 60 * 1000;
|
|
154
|
-
logClipboardError('macOS image clipboard read (Swift)', error);
|
|
155
|
-
// This failure is now rate-limited by the retry window; don't let the
|
|
156
|
-
// displayed "consecutive failures" grow without bound.
|
|
157
|
-
clipboardErrorCounts.delete('macOS image clipboard read (Swift)');
|
|
158
162
|
try {
|
|
159
163
|
const jsaScript = `
|
|
160
164
|
ObjC.import("AppKit");
|
|
@@ -174,15 +178,16 @@ if let data = pb.data(forType: .png) {
|
|
|
174
178
|
"";
|
|
175
179
|
}
|
|
176
180
|
`;
|
|
177
|
-
const { stdout } = await execFileAsync('osascript', ['-l', 'JavaScript', '-e', jsaScript], {
|
|
181
|
+
const { stdout } = await execFileAsync('osascript', ['-l', 'JavaScript', '-e', jsaScript], {
|
|
182
|
+
timeout: macClipboardCommandTimeout,
|
|
183
|
+
maxBuffer: macClipboardCommandMaxBuffer
|
|
184
|
+
});
|
|
178
185
|
const str = stdout.trim();
|
|
179
186
|
if (str) {
|
|
180
187
|
markClipboardSuccess('macOS image clipboard fallback read (osascript)');
|
|
181
188
|
return Buffer.from(str, 'base64');
|
|
182
189
|
}
|
|
183
|
-
} catch
|
|
184
|
-
logClipboardError('macOS image clipboard fallback read (osascript)', fallbackError);
|
|
185
|
-
}
|
|
190
|
+
} catch {}
|
|
186
191
|
}
|
|
187
192
|
return null;
|
|
188
193
|
}
|
|
@@ -394,11 +399,11 @@ export async function captureClipboard() {
|
|
|
394
399
|
}
|
|
395
400
|
}
|
|
396
401
|
|
|
397
|
-
lastImageHash = hash;
|
|
398
402
|
if (!isDuplicate) {
|
|
399
403
|
try {
|
|
400
404
|
const mozjpegBuf = await compressMozjpeg(imageData.rgbaBuf, imageData.width, imageData.height, 75);
|
|
401
405
|
saveClipboardImage(mozjpegBuf, 'jpg', hash);
|
|
406
|
+
lastImageHash = hash;
|
|
402
407
|
markClipboardSuccess('image compression or save (WASM/JPEG)', 'image save');
|
|
403
408
|
} catch (error) {
|
|
404
409
|
logClipboardError('image compression or save (WASM/JPEG)', error);
|
|
@@ -406,12 +411,15 @@ export async function captureClipboard() {
|
|
|
406
411
|
if (rawBuf) {
|
|
407
412
|
try {
|
|
408
413
|
saveClipboardImage(rawBuf, 'png', hash);
|
|
414
|
+
lastImageHash = hash;
|
|
409
415
|
markClipboardSuccess('raw image save after compression fallback', 'image save');
|
|
410
416
|
} catch (fallbackError) {
|
|
411
417
|
logClipboardError('raw image save after compression fallback', fallbackError);
|
|
412
418
|
}
|
|
413
419
|
}
|
|
414
420
|
}
|
|
421
|
+
} else {
|
|
422
|
+
lastImageHash = hash;
|
|
415
423
|
}
|
|
416
424
|
}
|
|
417
425
|
} else if (imageData.rawBuffer && imageData.rawBuffer.length > 0) {
|
|
@@ -431,14 +439,16 @@ export async function captureClipboard() {
|
|
|
431
439
|
}
|
|
432
440
|
}
|
|
433
441
|
|
|
434
|
-
lastImageHash = hash;
|
|
435
442
|
if (!isDuplicate) {
|
|
436
443
|
try {
|
|
437
444
|
saveClipboardImage(imageData.rawBuffer, 'png', hash);
|
|
445
|
+
lastImageHash = hash;
|
|
438
446
|
markClipboardSuccess('image save');
|
|
439
447
|
} catch (error) {
|
|
440
448
|
logClipboardError('image save', error);
|
|
441
449
|
}
|
|
450
|
+
} else {
|
|
451
|
+
lastImageHash = hash;
|
|
442
452
|
}
|
|
443
453
|
}
|
|
444
454
|
}
|
|
@@ -446,7 +456,22 @@ export async function captureClipboard() {
|
|
|
446
456
|
}
|
|
447
457
|
}
|
|
448
458
|
|
|
449
|
-
export function startClipboardCapture() {
|
|
459
|
+
export function startClipboardCapture() {
|
|
460
|
+
let captureInProgress = false;
|
|
461
|
+
const capture = async () => {
|
|
462
|
+
if (captureInProgress) return;
|
|
463
|
+
captureInProgress = true;
|
|
464
|
+
try {
|
|
465
|
+
await captureClipboard();
|
|
466
|
+
} finally {
|
|
467
|
+
captureInProgress = false;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
void capture();
|
|
472
|
+
const timer = setInterval(() => { void capture(); }, 2000);
|
|
473
|
+
timer.unref();
|
|
474
|
+
}
|
|
450
475
|
|
|
451
476
|
export async function markClipboardCopied(date, id) {
|
|
452
477
|
let targetDate = date;
|