UNPKG

chromancer

Version:

A powerful command-line interface for automating Chrome browser using Playwright. Perfect for web scraping, automation, testing, and browser workflows.

207 lines (206 loc) โ€ข 8.18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const core_1 = require("@oclif/core"); const core_2 = require("@oclif/core"); const child_process_1 = require("child_process"); const os = tslib_1.__importStar(require("os")); class Sessions extends core_2.Command { static description = 'List all Chrome instances with remote debugging enabled'; static examples = [ '<%= config.bin %> <%= command.id %>', '<%= config.bin %> <%= command.id %> --kill 9222', '<%= config.bin %> <%= command.id %> --kill-all', ]; static flags = { kill: core_1.Flags.integer({ description: 'Kill Chrome instance on specified port', required: false, }), 'kill-all': core_1.Flags.boolean({ description: 'Kill all Chrome instances with debugging enabled', default: false, }), verbose: core_1.Flags.boolean({ char: 'v', description: 'Show detailed information about each instance', default: false, }), }; async run() { const { flags } = await this.parse(Sessions); // Find all Chrome instances with debugging ports const instances = await this.findChromeInstances(); if (flags.verbose) { this.log('๐Ÿ” Searching for Chrome instances...'); } if (flags.kill) { await this.killInstance(flags.kill); return; } if (flags['kill-all']) { await this.killAllInstances(instances); return; } // Display found instances this.displayInstances(instances, flags.verbose); } async findChromeInstances() { const instances = []; // Get all Chrome processes const platform = os.platform(); let chromeProcesses = ''; try { if (platform === 'darwin') { chromeProcesses = (0, child_process_1.execSync)('ps aux | grep -i "chrome.*remote-debugging-port" | grep -v grep', { encoding: 'utf8' }); } else if (platform === 'linux') { chromeProcesses = (0, child_process_1.execSync)('ps aux | grep -i "chrom.*remote-debugging-port" | grep -v grep', { encoding: 'utf8' }); } else if (platform === 'win32') { chromeProcesses = (0, child_process_1.execSync)('wmic process where "name like \'%chrome%\'" get processid,commandline /format:csv', { encoding: 'utf8' }); } } catch (error) { // No Chrome processes found return instances; } // Parse process list to find ports const portRegex = /--remote-debugging-port=(\d+)/; const lines = chromeProcesses.split('\n').filter(line => line.trim()); for (const line of lines) { const portMatch = line.match(portRegex); if (portMatch) { const port = parseInt(portMatch[1]); const pidMatch = line.match(/^\s*\w+\s+(\d+)/); const pid = pidMatch ? parseInt(pidMatch[1]) : undefined; // Try to connect to this port const instance = await this.checkChromeInstance(port, pid); instances.push(instance); } } // Also check common ports const commonPorts = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229]; for (const port of commonPorts) { // Skip if already found if (instances.find(i => i.port === port)) continue; const instance = await this.checkChromeInstance(port); if (!instance.error) { instances.push(instance); } } // Also check saved session try { const savedSession = await fetch('http://localhost:9222/json/version'); if (savedSession.ok) { const instance = await this.checkChromeInstance(9222); if (!instance.error && !instances.find(i => i.port === 9222)) { instances.push(instance); } } } catch (error) { // No saved session } return instances.filter(i => !i.error); } async checkChromeInstance(port, pid) { const instance = { port, pid }; try { // Try to get version info const versionResponse = await fetch(`http://localhost:${port}/json/version`); if (versionResponse.ok) { const versionData = await versionResponse.json(); instance.version = versionData.Browser || 'Unknown'; // Get tabs/pages const tabsResponse = await fetch(`http://localhost:${port}/json/list`); if (tabsResponse.ok) { instance.tabs = await tabsResponse.json(); } } } catch (error) { instance.error = 'Not responding'; } return instance; } displayInstances(instances, verbose) { if (instances.length === 0) { this.log('โŒ No Chrome instances with remote debugging found'); this.log('๐Ÿ’ก Start Chrome with: chromancer spawn'); return; } this.log(`๐Ÿ” Found ${instances.length} Chrome instance(s) with remote debugging:\n`); for (const instance of instances) { this.log(`๐Ÿ“ Port: ${instance.port}`); if (instance.pid) { this.log(` PID: ${instance.pid}`); } if (instance.version) { this.log(` Version: ${instance.version}`); } if (instance.tabs) { this.log(` Open tabs: ${instance.tabs.length}`); if (verbose) { for (const tab of instance.tabs) { this.log(` - ${tab.title || 'Untitled'} (${tab.url})`); } } } this.log(''); } this.log('๐Ÿ’ก To connect: cdp navigate <url> --port <port>'); this.log('๐Ÿ’ก To kill: cdp sessions --kill <port>'); } async killInstance(port) { const instances = await this.findChromeInstances(); const instance = instances.find(i => i.port === port); if (!instance) { this.error(`No Chrome instance found on port ${port}`); } if (instance.pid) { try { if (os.platform() === 'win32') { (0, child_process_1.execSync)(`taskkill /F /PID ${instance.pid}`); } else { (0, child_process_1.execSync)(`kill -9 ${instance.pid}`); } this.log(`โœ… Killed Chrome instance on port ${port} (PID: ${instance.pid})`); } catch (error) { this.error(`Failed to kill Chrome instance: ${error}`); } } else { this.error(`Could not find PID for Chrome instance on port ${port}`); } } async killAllInstances(instances) { if (instances.length === 0) { this.log('โŒ No Chrome instances to kill'); return; } let killed = 0; for (const instance of instances) { if (instance.pid) { try { if (os.platform() === 'win32') { (0, child_process_1.execSync)(`taskkill /F /PID ${instance.pid}`); } else { (0, child_process_1.execSync)(`kill -9 ${instance.pid}`); } this.log(`โœ… Killed Chrome on port ${instance.port} (PID: ${instance.pid})`); killed++; } catch (error) { this.log(`โŒ Failed to kill Chrome on port ${instance.port}: ${error}`); } } } this.log(`\n๐Ÿงน Killed ${killed} Chrome instance(s)`); } } exports.default = Sessions;