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
JavaScript
;
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;