UNPKG

browser-debugger-cli

Version:

DevTools telemetry in your terminal. For humans and agents. Direct WebSocket to Chrome's debugging port.

261 lines 8.68 kB
/** * Machine-readable help generation using Commander.js introspection API. */ import { getAllDomainSummaries } from '../cdp/schema.js'; import { getOptionBehavior } from '../commands/optionBehaviors.js'; import { isDaemonRunning } from '../daemon/launcher.js'; import { readPid } from '../session/pid.js'; import { getAllDecisionTrees } from '../utils/decisionTrees.js'; import { EXIT_CODE_REGISTRY } from '../utils/exitCodes.js'; import { isProcessAlive } from '../utils/process.js'; import { getAllTaskMappings } from '../utils/taskMappings.js'; /** * Converts a Commander Option to OptionMetadata. * * Builds the metadata object directly with proper types, * only including optional fields when they have values. * Enriches with behavioral metadata when available. * * @param option - Commander option instance * @param commandName - Name of the command containing this option * @returns Option metadata with behavioral context */ function convertOption(option, commandName) { const metadata = { flags: option.flags, description: option.description, required: option.required, optional: option.optional, }; if (option.defaultValue !== undefined) { metadata.defaultValue = option.defaultValue; } if (option.defaultValueDescription) { metadata.defaultValueDescription = option.defaultValueDescription; } if (option.argChoices) { metadata.choices = option.argChoices; } const behavior = getOptionBehavior(commandName, option.flags); if (behavior) { metadata.behavior = behavior; } return metadata; } /** * Converts a Commander Argument to ArgumentMetadata. * * Builds the metadata object directly with proper types, * only including optional fields when they have values. * * @param argument - Commander argument instance * @returns Argument metadata */ function convertArgument(argument) { const metadata = { name: argument.name(), description: argument.description, required: argument.required, variadic: argument.variadic, }; if (argument.defaultValue !== undefined) { metadata.defaultValue = argument.defaultValue; } if (argument.argChoices) { metadata.choices = argument.argChoices; } return metadata; } /** * Recursively converts a Commander Command to CommandMetadata. * * Passes command name to option converter for behavioral metadata lookup. * * @param command - Commander command instance * @returns Command metadata with enriched options */ function convertCommand(command) { const commandName = command.name(); return { name: commandName, aliases: command.aliases(), description: command.description(), usage: command.usage(), arguments: command.registeredArguments.map(convertArgument), options: command.options.map((opt) => convertOption(opt, commandName)), subcommands: command.commands.map(convertCommand), }; } /** * Checks if a session is currently active. * * @returns True if session is active, false otherwise */ function isSessionActive() { const sessionPid = readPid(); if (sessionPid === null) { return false; } return isProcessAlive(sessionPid); } /** * Generates runtime state information. * * Checks current daemon and session status to provide state-aware * command availability information. * * @returns Runtime state object */ function generateRuntimeState() { const daemonRunning = isDaemonRunning(); const sessionActive = isSessionActive(); const availableCommands = []; if (!daemonRunning && !sessionActive) { availableCommands.push('bdg <url>', 'cleanup', '--help', '--version'); } else if (daemonRunning && sessionActive) { availableCommands.push('peek', 'tail', 'details', 'dom', 'network', 'console', 'cdp', 'status', 'stop'); } else if (daemonRunning && !sessionActive) { availableCommands.push('bdg <url>', 'cleanup', 'status'); } return { sessionActive, daemonRunning, availableCommands, }; } /** * Extracts unique command strings from task mappings. * * Flattens all command arrays from task mappings and deduplicates them. * * @param taskMappings - Task mapping registry * @returns Sorted array of unique command strings */ function extractCommandList(taskMappings) { const allCommands = Object.values(taskMappings).flatMap((mapping) => mapping.commands); const uniqueCommands = [...new Set(allCommands)]; return uniqueCommands.sort(); } /** * Exit code documentation derived from the central registry. * * Uses EXIT_CODE_REGISTRY as the single source of truth to prevent * documentation drift from actual exit code values. */ const EXIT_CODE_DOCS = EXIT_CODE_REGISTRY; /** * Generates capabilities summary. * * Dynamically calculates CDP and high-level command capabilities * from protocol schema and task mappings. * * @returns Capabilities object */ function generateCapabilities() { const domainSummaries = getAllDomainSummaries(); const taskMappings = getAllTaskMappings(); const totalMethods = domainSummaries.reduce((sum, domain) => sum + domain.commandCount, 0); const commandList = extractCommandList(taskMappings); return { cdp: { domains: domainSummaries.length, methods: totalMethods.toString(), }, highLevel: { commands: commandList, coverage: ['dom', 'network', 'console', 'session', 'monitoring'], }, }; } /** * Generates machine-readable help from a Commander program. * * Includes comprehensive metadata for agent discovery: * - Command structure and options * - Exit codes with semantic meanings * - Task-to-command mappings with CDP alternatives * - Runtime state and command availability * - Intent-based decision trees * - Capabilities summary * * @param program - Commander program instance * @returns Machine-readable help structure * * @example * ```typescript * import { program } from 'commander'; * import { generateMachineReadableHelp } from './help/machineReadableHelp.js'; * * const help = generateMachineReadableHelp(program); * console.log(JSON.stringify(help, null, 2)); * ``` */ export function generateMachineReadableHelp(program) { return { name: program.name(), version: program.version() ?? 'unknown', description: program.description(), command: convertCommand(program), exitCodes: [...EXIT_CODE_DOCS], taskMappings: getAllTaskMappings(), runtimeState: generateRuntimeState(), decisionTrees: getAllDecisionTrees(), capabilities: generateCapabilities(), }; } /** * Finds a subcommand by traversing the command path. * * @param program - Root Commander program instance * @param commandPath - Array of command names to traverse (e.g., ['dom', 'query']) * @returns The target Command if found, null otherwise */ function findSubcommand(program, commandPath) { let current = program; for (const name of commandPath) { const found = current.commands.find((cmd) => cmd.name() === name || cmd.aliases().includes(name)); if (!found) { return null; } current = found; } return current; } /** * Generates machine-readable help for a specific subcommand. * * Returns the same structure as generateMachineReadableHelp but with * the command field focused on the requested subcommand. If the subcommand * is not found, falls back to full root help. * * @param program - Root Commander program instance * @param commandPath - Array of command names (e.g., ['dom', 'query']) * @returns Machine-readable help structure for the subcommand * * @example * ```typescript * // Get help for 'bdg dom query' * const help = generateSubcommandHelp(program, ['dom', 'query']); * console.log(help.command.name); // 'query' * ``` */ export function generateSubcommandHelp(program, commandPath) { const targetCommand = findSubcommand(program, commandPath); if (!targetCommand) { return generateMachineReadableHelp(program); } return { name: program.name(), version: program.version() ?? 'unknown', description: program.description(), command: convertCommand(targetCommand), exitCodes: [...EXIT_CODE_DOCS], taskMappings: getAllTaskMappings(), runtimeState: generateRuntimeState(), decisionTrees: getAllDecisionTrees(), capabilities: generateCapabilities(), }; } //# sourceMappingURL=helpJson.js.map