/** * El nodo de GitHub como AI toolkit: sus catorce operaciones como herramientas * que un AI Node, un servidor MCP o un agente de voz pueden llamar. * * ## Qué pidió Ariel (2026-09-27) * * «Ahora GitHub AI toolkit», con el criterio de los anteriores: como si fuera * single operation, con TODOS los campos de cada operación * (`GITHUB_OPERATION_SPECS`). Y sus decisiones: * * - Nacen BLOQUEADAS `merge_pull_request` (mete código en la rama base y no * se deshace limpio), `dispatch_workflow` (puede ser un deploy) y * `create_or_update_file` (un commit directo que pisa el fichero). * - El alcance nace en el REPO del nodo, y el dueño lo puede abrir a todos * los de la credencial (`toolkitScope: 'any'`), como el proyecto de Jira. * - `create_or_update_file`, aunque el dueño lo desbloquee, NUNCA escribe en * la rama por defecto: el agente crea una rama y abre un PR para que lo * revise una persona. * * ## Los nombres * * Jira ya tiene `create_issue`, `get_issue`, `update_issue` y `search_issues`, * así que las de incidencias de GitHub llevan `github` en el nombre. Las de * pull requests no chocan con nadie. */ import type { CampoDeToolkit } from './argumentos-de-toolkit.js'; export type GithubToolkitOperation = 'createIssue' | 'updateIssue' | 'getIssue' | 'commentIssue' | 'listIssues' | 'createPullRequest' | 'getPullRequest' | 'mergePullRequest' | 'listPullRequests' | 'getFile' | 'createOrUpdateFile' | 'createBranch' | 'dispatchWorkflow' | 'searchIssues'; export interface GithubToolkitParameter { name: string; type: 'string' | 'number' | 'boolean'; description: string; required: boolean; } export interface GithubToolkitSpec { operation: GithubToolkitOperation; label: string; toolName: string; description: string; parameters: GithubToolkitParameter[]; destructive?: boolean; /** Nace bloqueada en el nodo; el dueño la desbloquea. Ver `toolkits.ts`. */ bloqueadaPorDefecto?: boolean; } /** Los parámetros que el nodo puede traer configurados: el modelo los omite * y se usa el repo del nodo. */ export declare const GITHUB_TOOLKIT_DEFAULTABLE: readonly ["repo"]; /** Cuántos elementos devuelven las listas y la búsqueda si el modelo no dice * otra cosa: cada uno entra en su contexto. */ export declare const GITHUB_TOOLKIT_RESULTADOS_POR_DEFECTO = 20; /** Hasta dónde llega el modelo. `node` (el de fábrica): el repo del nodo. * `any`: cualquier repo que alcance la credencial. */ export declare const GITHUB_TOOLKIT_ALCANCES: readonly ["node", "any"]; export type GithubToolkitAlcance = (typeof GITHUB_TOOLKIT_ALCANCES)[number]; export declare const GITHUB_TOOLKIT_SPECS: GithubToolkitSpec[]; export declare const GITHUB_TOOLKIT_SPECS_BY_TOOL_NAME: Readonly>; export declare const GITHUB_TOOLKIT_CAMPOS: Readonly>>>; /** `owner/name` normalizado (sin espacios ni `.git`, en minúsculas para * comparar: GitHub no distingue mayúsculas en owner ni en name). */ export declare function repoNormalizado(repo: string): string; /** ¿Tiene forma de `owner/name`? */ export declare function esRepo(repo: string): boolean; /** * Acota una búsqueda al repo: `repo:owner/name `. * * 🔒 La consulta la escribe el modelo, así que se lee como hostil. Con el * alcance del nodo no puede nombrar OTRO sitio (`repo:`, `org:`, `user:`). * * No se envuelve en paréntesis a propósito: agrupar es de la búsqueda * «avanzada» de GitHub, y en la clásica un paréntesis es texto que rompe los * calificadores de dentro. Sin paréntesis, un `OR` del modelo podría ensanchar * la búsqueda (`… OR crash` en todo GitHub), y por eso la defensa que manda * es la SEGUNDA: hw-nodes descarta cualquier resultado que no sea del repo. */ export declare function consultaDelRepo(consulta: string, repo: string): { query: string; } | { error: string; }; /** ¿Es de este repo un resultado de la búsqueda? GitHub pone en cada uno * `repository_url` (`https://api.github.com/repos/owner/name`). */ export declare function esDelRepo(item: unknown, repo: string): boolean;