browser-debugger-cli
Version:
DevTools telemetry in your terminal. For humans and agents. Direct WebSocket to Chrome's debugging port.
91 lines • 4.15 kB
JavaScript
import os from 'node:os';
import { startSessionViaDaemon } from '../commands/shared/startHelpers.js';
import { positiveIntRule } from '../commands/shared/validation.js';
import { DEFAULT_DEBUG_PORT, PORT_OPTION_DESCRIPTION } from '../constants.js';
import { startCommandHelpMessage } from '../ui/messages/commands.js';
import { genericError } from '../ui/messages/errors.js';
import { EXIT_CODES } from '../utils/exitCodes.js';
/**
* Apply shared telemetry options to a command
*
* @param command - Commander.js Command instance to apply options to
* @returns The modified Command instance with all telemetry options applied
*/
function applyCollectorOptions(command) {
return command
.option('-p, --port <number>', PORT_OPTION_DESCRIPTION, DEFAULT_DEBUG_PORT)
.option('-t, --timeout <seconds>', 'Auto-stop after timeout in seconds (unlimited if not specified)')
.option('-u, --user-data-dir <path>', 'Chrome user data directory', '~/.bdg/chrome-profile')
.option('-a, --all', 'Include all data (disable filtering of tracking/analytics)', false)
.option('-m, --max-body-size <megabytes>', 'Maximum response body size in MB', '5')
.option('--compact', 'Use compact JSON format (no indentation) for output files', false)
.option('--headless', 'Launch Chrome in headless mode (no visible browser window)', false)
.option('--chrome-ws-url <url>', 'Connect to existing Chrome via WebSocket URL (e.g., ws://localhost:9222/devtools/page/...)')
.option('-q, --quiet', 'Quiet mode - minimal output for AI agents', false);
}
/**
* Transform CLI options into session options
*
* @param options - Parsed command-line options from Commander
* @returns Session options object with parsed and normalized values
*/
function buildSessionOptions(options) {
const maxBodySizeRule = positiveIntRule({ min: 1, max: 100, required: false });
const timeoutRule = positiveIntRule({ min: 1, max: 3600, required: false });
const maxBodySizeMB = options.maxBodySize
? maxBodySizeRule.validate(options.maxBodySize)
: undefined;
const timeout = options.timeout ? timeoutRule.validate(options.timeout) : undefined;
let userDataDir = options.userDataDir;
if (userDataDir?.startsWith('~/')) {
userDataDir = userDataDir.replace(/^~/, os.homedir());
}
return {
port: parseInt(options.port, 10),
timeout,
userDataDir,
includeAll: options.all ?? false,
maxBodySize: maxBodySizeMB !== undefined ? maxBodySizeMB * 1024 * 1024 : undefined,
compact: options.compact ?? false,
headless: options.headless ?? false,
chromeWsUrl: options.chromeWsUrl,
quiet: options.quiet ?? false,
};
}
/**
* Common action handler for telemetry commands
*
* @param url - Target URL to collect telemetry from
* @param options - Parsed command-line options from Commander
* @returns Promise that resolves when session completes or is stopped
*/
async function collectorAction(url, options) {
const sessionOptions = buildSessionOptions(options);
const telemetry = ['dom', 'network', 'console'];
await startSessionViaDaemon(url, sessionOptions, telemetry);
}
/**
* Register the start command
*
* @param program - Commander.js Command instance to register command on
* @returns void
*/
export function registerStartCommands(program) {
applyCollectorOptions(program.argument('[url]', 'Target URL (example.com or localhost:3000)')).action(async (url, options) => {
if (!url) {
console.error(startCommandHelpMessage());
process.exit(0);
}
const { validateUrl } = await import('../utils/url.js');
const validation = validateUrl(url);
if (!validation.valid) {
console.error(genericError(validation.error ?? 'Invalid URL'));
if (validation.suggestion) {
console.error(`Suggestion: ${validation.suggestion}`);
}
process.exit(EXIT_CODES.INVALID_URL);
}
await collectorAction(url, options);
});
}
//# sourceMappingURL=start.js.map