manage-profiles.js
1 #!/usr/bin/env node 2 3 /** 4 * Browser Profile Management CLI 5 * Manage persistent browser profiles for X and LinkedIn outreach 6 * 7 * Usage: 8 * npm run profiles list [platform] - List all profiles (or filter by platform) 9 * npm run profiles next <platform> - Show next profile (LRU selection) 10 * npm run profiles delete <platform> <name> - Delete a specific profile 11 */ 12 13 import { existsSync, rmSync } from 'fs'; 14 import { join } from 'path'; 15 import { listProfiles, getNextProfile } from '../src/utils/stealth-browser.js'; 16 17 const PROFILES_DIR = process.env.BROWSER_PROFILES_DIR || './.browser-profiles'; 18 19 const [, , command, arg1, arg2] = process.argv; 20 21 function printProfiles(profiles) { 22 if (profiles.length === 0) { 23 console.log('No profiles found.'); 24 return; 25 } 26 27 console.log(`Found ${profiles.length} profile(s):\n`); 28 29 for (const profile of profiles) { 30 const username = profile.username || '(no username)'; 31 const lastUsed = profile.last_used_at 32 ? new Date(profile.last_used_at).toLocaleString() 33 : 'never'; 34 const created = profile.created_at ? new Date(profile.created_at).toLocaleString() : 'unknown'; 35 36 console.log(` ${profile.platform}/${profile.profileName}`); 37 console.log(` Username: ${username}`); 38 console.log(` Created: ${created}`); 39 console.log(` Last used: ${lastUsed}`); 40 console.log(); 41 } 42 } 43 44 switch (command) { 45 case 'list': { 46 const platform = arg1 || null; 47 const profiles = listProfiles(platform); 48 printProfiles(profiles); 49 break; 50 } 51 52 case 'next': { 53 if (!arg1 || !['x', 'linkedin'].includes(arg1)) { 54 console.error('Usage: npm run profiles next <x|linkedin>'); 55 process.exit(1); 56 } 57 const nextProfile = getNextProfile(arg1); 58 const profileDir = join(PROFILES_DIR, arg1, nextProfile); 59 // eslint-disable-next-line security/detect-non-literal-fs-filename 60 const isNew = !existsSync(profileDir); 61 console.log(`Next ${arg1} profile: ${nextProfile}${isNew ? ' (new - login required)' : ''}`); 62 break; 63 } 64 65 case 'delete': { 66 if (!arg1 || !arg2) { 67 console.error('Usage: npm run profiles delete <platform> <profile-name>'); 68 process.exit(1); 69 } 70 const profileDir = join(PROFILES_DIR, arg1, arg2); 71 // eslint-disable-next-line security/detect-non-literal-fs-filename 72 if (!existsSync(profileDir)) { 73 console.error(`Profile not found: ${arg1}/${arg2}`); 74 process.exit(1); 75 } 76 77 rmSync(profileDir, { recursive: true }); 78 console.log(`Deleted profile: ${arg1}/${arg2}`); 79 break; 80 } 81 82 default: 83 console.log('Browser Profile Manager'); 84 console.log(); 85 console.log('Usage:'); 86 console.log(' npm run profiles list [platform] List all profiles'); 87 console.log(' npm run profiles next <x|linkedin> Show next profile (LRU)'); 88 console.log(' npm run profiles delete <platform> <name> Delete a profile'); 89 console.log(); 90 console.log('Platforms: x, linkedin'); 91 process.exit(command ? 1 : 0); 92 }