UNPKG

browser-debugger-cli

Version:

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

254 lines 7.26 kB
/** * CDP Schema Introspection * * Provides structured, agent-friendly schema information for all CDP domains and methods. * Follows principles from docs/AGENT_FRIENDLY_TOOLS.md: * - Machine-readable output (JSON schema) * - Self-describing tools * - Structured context without verbosity */ import { loadProtocol, findDomain, findCommand } from './protocol.js'; /** * Get structured schema for a specific method. * * @param domainName - Domain name (case-insensitive) * @param methodName - Method name (case-insensitive) * @returns Method schema or undefined if not found * * @example * ```typescript * const schema = getMethodSchema('Network', 'getCookies'); * console.log(schema.parameters); // [{ name: 'urls', type: 'array', required: false, ... }] * ``` */ export function getMethodSchema(domainName, methodName) { const domain = findDomain(domainName); if (!domain) { return undefined; } const command = findCommand(domain.domain, methodName); if (!command) { return undefined; } return buildMethodSchema(domain.domain, command); } /** * Build method schema from protocol command. * * @param domainName - Domain name * @param command - Command from protocol * @returns Structured method schema */ function buildMethodSchema(domainName, command) { const parameters = command.parameters?.map(paramToSchema) ?? []; const returns = command.returns?.map(returnToSchema) ?? []; const example = { command: `bdg cdp ${domainName}.${command.name}`, }; if (parameters.length > 0) { const exampleParams = {}; parameters.forEach((p) => { if (!p.required) return; // Skip optional params in example exampleParams[p.name] = getExampleValue(p); }); if (Object.keys(exampleParams).length > 0) { example.params = exampleParams; example.command += ` --params '${JSON.stringify(exampleParams)}'`; } } const schema = { name: `${domainName}.${command.name}`, domain: domainName, method: command.name, parameters, returns, example, }; if (command.description) schema.description = command.description; if (command.experimental) schema.experimental = command.experimental; if (command.deprecated) schema.deprecated = command.deprecated; return schema; } /** * Convert protocol parameter to schema. */ function paramToSchema(param) { const schema = { name: param.name, type: resolveType(param), required: !param.optional, }; if (param.description) schema.description = param.description; if (param.deprecated) schema.deprecated = param.deprecated; if (param.enum) schema.enum = param.enum; if (param.items) schema.items = resolveType(param.items); return schema; } /** * Convert protocol return value to schema. */ function returnToSchema(ret) { const schema = { name: ret.name, type: resolveType(ret), optional: ret.optional ?? false, }; if (ret.description) schema.description = ret.description; if (ret.items) schema.items = resolveType(ret.items); return schema; } /** * Resolve type from parameter/return value. * * @param typeRef - Type reference from protocol * @returns Type string (e.g., 'string', 'integer', 'Network.Cookie') */ function resolveType(typeRef) { if (typeRef.$ref) { return typeRef.$ref; } return typeRef.type ?? 'any'; } /** * Get example value for a parameter type. * * @param param - Parameter schema * @returns Example value */ function getExampleValue(param) { if (param.enum && param.enum.length > 0) { return param.enum[0]; } switch (param.type) { case 'string': return 'example'; case 'integer': case 'number': return 0; case 'boolean': return true; case 'array': return []; case 'object': return {}; default: return null; } } /** * Get all methods in a domain. * * @param domainName - Domain name (case-insensitive) * @returns Array of method schemas * * @example * ```typescript * const methods = getDomainMethods('Network'); * console.log(methods.length); // 39 * console.log(methods[0].name); // 'Network.getIPProtectionProxyStatus' * ``` */ export function getDomainMethods(domainName) { const domain = findDomain(domainName); if (!domain?.commands) { return []; } return domain.commands.map((cmd) => buildMethodSchema(domain.domain, cmd)); } /** * Get summary information for a domain. * * @param domainName - Domain name (case-insensitive) * @returns Domain summary or undefined if not found * * @example * ```typescript * const summary = getDomainSummary('Network'); * console.log(summary.commandCount); // 39 * console.log(summary.eventCount); // 12 * ``` */ export function getDomainSummary(domainName) { const domain = findDomain(domainName); if (!domain) { return undefined; } return buildDomainSummary(domain); } /** * Build domain summary from protocol domain. */ function buildDomainSummary(domain) { const summary = { name: domain.domain, commandCount: domain.commands?.length ?? 0, eventCount: domain.events?.length ?? 0, }; if (domain.description) summary.description = domain.description; if (domain.experimental) summary.experimental = domain.experimental; if (domain.deprecated) summary.deprecated = domain.deprecated; if (domain.dependencies) summary.dependencies = domain.dependencies; return summary; } /** * Get summaries for all domains. * * @returns Array of domain summaries * * @example * ```typescript * const summaries = getAllDomainSummaries(); * console.log(summaries.length); // 53 * console.log(summaries.find(d => d.name === 'Network').commandCount); // 39 * ``` */ export function getAllDomainSummaries() { const protocol = loadProtocol(); return protocol.domains.map(buildDomainSummary); } /** * Search methods by keyword (case-insensitive). * * Searches in method names and descriptions. * * @param query - Search query * @returns Array of matching method schemas * * @example * ```typescript * const cookies = searchMethods('cookie'); * // Returns: Network.getCookies, Network.setCookie, Network.deleteCookies, etc. * ``` */ export function searchMethods(query) { const protocol = loadProtocol(); const results = []; const lowerQuery = query.toLowerCase(); protocol.domains.forEach((domain) => { if (!domain.commands) return; domain.commands.forEach((command) => { const nameMatch = command.name.toLowerCase().includes(lowerQuery); const descMatch = command.description?.toLowerCase().includes(lowerQuery) ?? false; if (nameMatch || descMatch) { results.push(buildMethodSchema(domain.domain, command)); } }); }); return results; } //# sourceMappingURL=schema.js.map