BREAKING CHANGE: the marketplace slug, the agent namespace (linkedin-studio:<agent>), and the runtime state-file path (~/.claude/linkedin-studio.local.md) all change. Reinstall required; existing state migrated in place (post metrics, streak, history preserved). The /linkedin:* commands are unchanged — the command namespace is set per-command in frontmatter and was always independent of the plugin slug. Functionality is byte-identical to v2.4.0; this release is pure identity. - dir + manifests: plugins/linkedin-studio + plugin.json + root marketplace.json - agent namespace updated in commands/newsletter.md (only functional invoker) - state path updated in 4 hook scripts + topic-rotation prompt + state template - catch-all skill dir renamed skills/linkedin-studio (5 functional skills unchanged) - docs + version bump to 3.0.0 across README badge, CHANGELOG, root README/CLAUDE.md - historical records (CHANGELOG past entries, docs/ build artifacts, config-audit v5.0.0 snapshots) intentionally retain the old slug Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
86 lines
3.1 KiB
JavaScript
86 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// Quick-import helper for linkedin-studio plugin
|
|
// Opens LinkedIn analytics in browser, watches ~/Downloads for new CSV files
|
|
|
|
import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync } from 'node:fs';
|
|
import { join, dirname } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { exec } from 'node:child_process';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const PLUGIN_ROOT = join(__dirname, '..', '..');
|
|
const HOME = process.env.HOME || process.env.USERPROFILE || '';
|
|
const EXPORTS_DIR = join(PLUGIN_ROOT, 'assets', 'analytics', 'exports');
|
|
const DOWNLOADS_DIR = join(HOME, 'Downloads');
|
|
const POLL_INTERVAL = 3000;
|
|
const MAX_WAIT = 300000; // 5 minutes
|
|
|
|
mkdirSync(EXPORTS_DIR, { recursive: true });
|
|
|
|
// Snapshot existing CSV files
|
|
function getCsvFiles() {
|
|
try {
|
|
return readdirSync(DOWNLOADS_DIR)
|
|
.filter(f => f.endsWith('.csv'))
|
|
.sort();
|
|
} catch { return []; }
|
|
}
|
|
|
|
// Cross-platform browser open
|
|
function openUrl(url) {
|
|
const cmd = process.platform === 'darwin' ? 'open'
|
|
: process.platform === 'win32' ? 'start ""'
|
|
: 'xdg-open';
|
|
exec(`${cmd} "${url}"`, () => {});
|
|
}
|
|
|
|
const beforeFiles = new Set(getCsvFiles());
|
|
|
|
console.log('Opening LinkedIn Analytics in your browser...');
|
|
openUrl('https://www.linkedin.com/analytics/creator/content/');
|
|
|
|
console.log('\nInstructions:');
|
|
console.log(' 1. Click \'Export\' (top right) in LinkedIn Analytics');
|
|
console.log(' 2. LinkedIn will download a CSV to ~/Downloads');
|
|
console.log(' 3. This script will detect it automatically\n');
|
|
console.log('Watching ~/Downloads for new CSV files (max 5 minutes)...\n');
|
|
|
|
let elapsed = 0;
|
|
const timer = setInterval(() => {
|
|
elapsed += POLL_INTERVAL;
|
|
|
|
const currentFiles = getCsvFiles();
|
|
const newFiles = currentFiles.filter(f => !beforeFiles.has(f));
|
|
|
|
for (const filename of newFiles) {
|
|
const filePath = join(DOWNLOADS_DIR, filename);
|
|
try {
|
|
const age = (Date.now() - statSync(filePath).mtime.getTime()) / 1000;
|
|
if (/linkedin|analytics|content|export/i.test(filename) || age < 60) {
|
|
console.log(`Detected: ${filename}`);
|
|
copyFileSync(filePath, join(EXPORTS_DIR, filename));
|
|
console.log(`Copied to: ${EXPORTS_DIR}/${filename}\n`);
|
|
console.log('File is ready for import. Run:');
|
|
console.log(' /linkedin:import\n');
|
|
console.log('Or import directly with:');
|
|
console.log(` ANALYTICS_ROOT="${PLUGIN_ROOT}/assets/analytics" node --import tsx "${PLUGIN_ROOT}/scripts/analytics/src/cli.ts" import "${filename}"`);
|
|
clearInterval(timer);
|
|
process.exit(0);
|
|
}
|
|
} catch { /* ignore */ }
|
|
}
|
|
|
|
if (elapsed % 15000 === 0) {
|
|
const remaining = Math.floor((MAX_WAIT - elapsed) / 60000);
|
|
console.log(` Still waiting... (${remaining}m remaining)`);
|
|
}
|
|
|
|
if (elapsed >= MAX_WAIT) {
|
|
console.log('\nTimed out after 5 minutes. No new CSV detected.\n');
|
|
console.log('You can manually copy the file:');
|
|
console.log(` mv ~/Downloads/<linkedin-csv-file>.csv ${EXPORTS_DIR}/`);
|
|
console.log(' /linkedin:import');
|
|
clearInterval(timer);
|
|
process.exit(1);
|
|
}
|
|
}, POLL_INTERVAL);
|