/ scripts / manage-profiles.js
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  }