chromancer
Version:
A powerful command-line interface for automating Chrome browser using Playwright. Perfect for web scraping, automation, testing, and browser workflows.
157 lines (156 loc) • 6.45 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const base_js_1 = require("../../base.js");
class TabsSwitch extends base_js_1.BaseCommand {
static description = 'Switch between browser tabs';
static examples = [
'<%= config.bin %> <%= command.id %> 0',
'<%= config.bin %> <%= command.id %> next',
'<%= config.bin %> <%= command.id %> prev',
'<%= config.bin %> <%= command.id %> last',
'<%= config.bin %> <%= command.id %> --interactive',
];
static flags = {
...base_js_1.BaseCommand.baseFlags,
interactive: core_1.Flags.boolean({
char: 'i',
description: 'Interactively select a tab to switch to',
default: false,
}),
};
static args = {
target: core_1.Args.string({
description: 'Tab index or keyword (next, prev, previous, last, first)',
required: false,
}),
};
async run() {
const { args, flags } = await this.parse(TabsSwitch);
await this.connectToChrome(flags.port, flags.host, flags.launch, flags.profile, flags.headless, flags.verbose, flags.keepOpen);
if (!this.browser) {
this.error('No browser available');
}
try {
const context = this.browser.contexts()[0];
const pages = context.pages();
if (pages.length === 0) {
this.log('No tabs available');
return;
}
if (pages.length === 1) {
this.log('Only one tab open');
return;
}
const currentIndex = pages.indexOf(this.page);
let targetIndex;
if (flags.interactive) {
// Interactive selection
const tabChoices = await Promise.all(pages.map(async (page, index) => {
const title = await page.title();
const url = page.url();
const isCurrent = index === currentIndex;
return {
name: `${isCurrent ? '▶ ' : ' '}[${index}] ${title || 'Untitled'} - ${url}`,
value: index,
short: `[${index}] ${title}`,
};
}));
const { select } = await Promise.resolve().then(() => __importStar(require('@inquirer/prompts')));
const selectedIndex = await select({
message: 'Select tab to switch to:',
choices: tabChoices.map(c => ({ name: c.name, value: c.value })),
default: currentIndex
});
targetIndex = selectedIndex;
}
else if (!args.target) {
// Default to next tab
targetIndex = (currentIndex + 1) % pages.length;
}
else {
// Parse target argument
const target = args.target.toLowerCase();
switch (target) {
case 'next':
targetIndex = (currentIndex + 1) % pages.length;
break;
case 'prev':
case 'previous':
targetIndex = currentIndex === 0 ? pages.length - 1 : currentIndex - 1;
break;
case 'first':
targetIndex = 0;
break;
case 'last':
targetIndex = pages.length - 1;
break;
default:
// Try to parse as number
targetIndex = parseInt(target, 10);
if (isNaN(targetIndex) || targetIndex < 0 || targetIndex >= pages.length) {
this.error(`Invalid tab target: ${args.target}. Use index (0-${pages.length - 1}) or keyword (next, prev, first, last)`);
}
}
}
if (targetIndex === currentIndex) {
this.log('Already on selected tab');
return;
}
// Switch to target tab
const targetPage = pages[targetIndex];
await targetPage.bringToFront();
this.page = targetPage;
const title = await targetPage.title();
const url = targetPage.url();
this.log(`🔄 Switched to tab [${targetIndex}]`);
this.log(` Title: ${title || 'Untitled'}`);
this.log(` URL: ${url}`);
if (flags.verbose) {
this.logVerbose('Tab switch details', {
from: currentIndex,
to: targetIndex,
totalTabs: pages.length,
direction: args.target,
});
}
}
catch (error) {
this.error(`Failed to switch tabs: ${error.message}`);
}
}
}
exports.default = TabsSwitch;