Hermes ahora pide aprobación antes de desinstalar un paquete

Un paquete npm global te está ralentizando las builds sin motivo aparente. Das con él y escribes npm uninstall -g some-package sin pensarlo dos veces. Dos días después falta en CI y todos los proyectos de esa máquina quedan arrastrados. Instalar algo se nota enseguida; borrar algo se olvida con facilidad, y el daño casi siempre es compartido. Y, aun así, cuando Hermes Agent ejecutaba ese comando por ti, nada se detenía a preguntar: la puerta de aprobación de comandos peligrosos solo conocía primitivas de shell como rm -rf. El PR #109170 tapa justo ese hueco.
Instalar casi nunca duele. Desinstalar sí.
Primero, el mecanismo. La aprobación de comandos peligrosos es un conjunto de reglas de patrones integradas en Hermes: cuando el agente está a punto de ejecutar un comando cuyas consecuencias no se pueden deshacer, muestra un aviso de aprobación y espera tu respuesta en lugar de ejecutarlo. La intención de diseño es sencilla: que una operación irreversible no se te cuele sin que te enteres.
Visto así, instalar y desinstalar no son simétricos. Instalar suma: lo que aparece lo acabas notando, y si da problemas lo borras. Desinstalar resta, y normalmente es una resta compartida: quitas un paquete global y todos los proyectos de la máquina que dependían de él se ven afectados, sin que nada te avise de que algo acaba de desaparecer.
Esa asimetría es exactamente la razón de que este cambio solo frene las desinstalaciones. npm update -g, pip install, brew upgrade y yarn install siguen sin marcarse y siguen sin preguntar. Si también frenara las instalaciones, la barra de aprobación se convertiría en ruido que aceptas una docena de veces al día: peor que no tener ninguna barrera.
La tabla de patrones solo conocía primitivas de shell
El problema estaba en DANGEROUS_PATTERNS, la tabla de patrones de tools/approval_detection.py. Lo que detectaba eran primitivas de shell: rm -rf, git reset --hard y compañía, comandos contundentes, archiconocidos y evidentes a simple vista. No había ni una sola regla para los verbos de borrado de los gestores de paquetes.
Por eso, cuando ocurrió de verdad el incidente del issue #10199, el comando se ejecutó de principio a fin sin ningún aviso. No fue un veredicto equivocado: es que ninguna regla cubría ese comando.
Las cinco formas de borrar que ahora se detienen
El PR #109170 va por la vía directa: añade una regla "package manager uninstall" por cada gestor de paquetes en DANGEROUS_PATTERNS. El cambio completo son +34 / −0 repartidos en dos archivos, tools/approval_detection.py y tests/tools/test_approval.py.
A partir de ahora, todo esto pasa por la aprobación de comandos peligrosos:
- npm —
npm uninstall -g some-package. Verbos de borrado:uninstall/unlink/remove/rm/r/un - pnpm —
pnpm remove. Verbos de borrado:uninstall/remove/rm/un - yarn —
yarn remove. La regla admite unglobalopcional delante y despuésuninstall/remove - pip / pip3 —
pip uninstall. El verbo de borrado esuninstall - brew —
brew uninstall. Verbos de borrado:uninstall/remove/rm
Fíjate en qué hacen match las reglas: el verbo de borrado del gestor, no un nombre de paquete concreto. Da igual sobre qué apunte el verbo y cuántos objetivos lleve detrás — el comando se marca.
Dos puntos donde evitaron falsos positivos
La forma clásica de romper una tabla de reglas es hacerla demasiado amplia y empezar a frenar comandos legítimos. Aquí hay dos detalles que merecen mención.
Primero, las reglas están ancladas a la posición del comando mediante _CMDPOS. Igual que el resto de reglas de nombres de comando de ese archivo, el patrón solo coincide donde el comando empieza de verdad. Por eso el texto entre comillas no se malinterpreta: git commit -m "document npm uninstall usage" es solo un mensaje de commit y no dispara nada.
Segundo, cada opción global admite un argumento que no sea un guion. Es decir, npm --prefix DIR uninstall x, pip --proxy URL uninstall x y yarn --cwd DIR remove x también se detectan. Una opción seguida de un argumento es una forma cotidiana; si se te escapa, la regla es decorativa.
Las pruebas vinieron de la mano. tests/tools/test_approval.py añade 6 casos parametrizados que agrupan seis formas de borrar bajo una misma clave. Esos casos fallaban contra el código anterior; tras el arreglo pasan 129 casos y la suite completa de tests/tools/ queda en verde con 9141.
Qué significa esto para ti
Si hay alguien mirando tu sesión de Hermes, es sencillo: el agente se detiene y pregunta antes de desinstalar un paquete, y tú confirmas o rechazas. Un clic de más a cambio de saber que lo borrado es lo que querías borrar.
El caso que sí conviene pensar con antelación es el trabajo desatendido: tareas de cron, agentes corriendo en segundo plano. No hay nadie para responder a un aviso, así que una desinstalación que debería haberse frenado se queda a medias. Si un flujo automatizado necesita de verdad desinstalar paquetes, no des por hecho que va a pasar: ensaya el comando contra los guardianes reales con hermes approvals test, mira en qué veredicto cae y luego decide si lo permites, si reformas el flujo o si directamente mantienes al agente lejos de ese paso. El comportamiento de las aprobaciones en cron se trata con más detalle en la guía de aprobaciones desatendidas.
Una distinción que conviene no mezclar: la aprobación de comandos peligrosos y approvals.deny son dos mecanismos distintos. La primera es la tabla de patrones integrada y funciona sin que configures nada; la segunda es una lista de denegación predefinida que mantienes tú. Este artículo solo habla de la primera. Para la segunda, mira la configuración de aprobaciones inteligentes: no hace falta repetirlo aquí.
Y por último, el estado de publicación, sin rodeos: esto entró en main el 2026-09-12, más tarde que la v0.21.2 (publicada el 2026-09-11). Por tanto todavía no está en ninguna versión publicada: está en la línea principal y te llegará con la próxima versión. Para saber qué haría tu compilación actual, hermes approvals test es la respuesta directa; las notas de la v0.21.2 son la última publicación estable anterior a este cambio.
En resumen
- Las desinstalaciones de gestores de paquetes pasan ahora por la aprobación de comandos peligrosos:
npm uninstall -g,pnpm remove,yarn remove,pip uninstallybrew uninstallestán cubiertas. - Instalaciones y actualizaciones siguen sin preguntar:
npm update -g,pip install,brew upgradeyyarn installno se ven afectadas. La aprobación se reserva para lo verdaderamente irreversible. - Las reglas están ancladas a la posición del comando, así que un
npm uninstalldentro de unas comillas no se marca por error, y una opción global seguida de un argumento no las esquiva. - El cambio está fusionado en
mainy todavía no ha salido en ninguna versión.