ktg-plugin-marketplace/plugins/linkedin-thought-leadership/hooks/scripts/clipboard-helper.mjs
Kjell Tore Guttormsen 214675d0a0 feat(linkedin): add clipboard-helper.mjs — cross-platform clipboard utility
TDD: 13 tests written first, then implementation.
Exports copyToClipboard(text) and clipboardAvailable() — never throws.
Supports darwin (pbcopy), win32 (clip), linux (xclip/xsel fallback).
Dual standalone/import mode following personalization-score.mjs pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 15:08:42 +02:00

102 lines
2.9 KiB
JavaScript

#!/usr/bin/env node
// Cross-platform clipboard helper for linkedin-thought-leadership plugin
// Copies text to system clipboard using platform-native commands.
// Standalone: reads stdin and copies it. Import: export { copyToClipboard, clipboardAvailable }
import { execSync } from 'node:child_process';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const PLATFORM_COMMANDS = {
darwin: { copy: 'pbcopy', check: 'which pbcopy' },
win32: { copy: 'clip', check: 'where clip' },
linux: { copy: 'xclip -selection clipboard', check: 'which xclip' },
};
const LINUX_FALLBACK = { copy: 'xsel --clipboard --input', check: 'which xsel' };
/**
* Check if clipboard is available on this platform.
* @returns {{ available: boolean, platform: string }}
*/
export function clipboardAvailable() {
const platform = process.platform;
const commands = PLATFORM_COMMANDS[platform];
if (!commands) {
return { available: false, platform };
}
try {
execSync(commands.check, { stdio: 'ignore' });
return { available: true, platform };
} catch {
// Linux fallback: try xsel if xclip not found
if (platform === 'linux') {
try {
execSync(LINUX_FALLBACK.check, { stdio: 'ignore' });
return { available: true, platform };
} catch {
return { available: false, platform };
}
}
return { available: false, platform };
}
}
/**
* Copy text to the system clipboard.
* Never throws — always returns a result object.
* @param {string} text - The text to copy
* @returns {{ success: boolean, platform: string }}
*/
export function copyToClipboard(text) {
const platform = process.platform;
if (typeof text !== 'string') {
return { success: false, platform };
}
const commands = PLATFORM_COMMANDS[platform];
if (!commands) {
return { success: false, platform };
}
// Determine which copy command to use
let copyCmd = commands.copy;
if (platform === 'linux') {
try {
execSync(commands.check, { stdio: 'ignore' });
} catch {
try {
execSync(LINUX_FALLBACK.check, { stdio: 'ignore' });
copyCmd = LINUX_FALLBACK.copy;
} catch {
return { success: false, platform };
}
}
}
try {
execSync(copyCmd, { input: text, stdio: ['pipe', 'ignore', 'ignore'] });
return { success: true, platform };
} catch {
return { success: false, platform };
}
}
// Standalone execution: read stdin and copy
if (process.argv[1] === fileURLToPath(import.meta.url)) {
let input = '';
process.stdin.setEncoding('utf-8');
process.stdin.on('data', (chunk) => { input += chunk; });
process.stdin.on('end', () => {
const result = copyToClipboard(input);
if (result.success) {
process.stdout.write('COPIED\n');
} else {
process.stdout.write(`FAILED:${result.platform}\n`);
process.exitCode = 1;
}
});
}