lint-drupal-module — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited lint-drupal-module (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Primera línea del informe generado: "Español confirmado."
Combina 4 fuentes de análisis (PHPStan, PHPCS, agente drupal-qa, agente drupal-security) en una sola invocación paralelizada, y consolida los hallazgos en un informe accionable. A mano son ~12 pasos y ~30 minutos; con la skill, lo que tarda la fuente más lenta (~2-5 min en completo, ~30s-1min en diff).
1. Identificar módulo (nombre/ruta del usuario, o Glob si no especifica)
2. Detectar modo: completo (default) | diff (si dice "diff", "rápido", "vs develop")
3. Detectar entorno: ddev describe → ejecutar via "ddev exec"
4. Verificar herramientas (vendor/bin/phpstan, vendor/bin/phpcs); instalar si faltan PREGUNTANDO
5. Verificar agentes drupal-qa y drupal-security disponibles (si no, ver "Recovery")
6. Leer references/prompts-agentes.md (necesario para el paso 7)
7. Ejecutar las 4 fuentes EN PARALELO en el mismo mensaje:
a) Agent drupal-qa — prompt literal de references/prompts-agentes.md
b) Agent drupal-security — prompt literal de references/prompts-agentes.md
c) PHPStan level 5 vía Bash (ver "Ejecución en paralelo")
d) PHPCS Drupal,DrupalPractice vía Bash
8. Leer references/plantilla-informe.md y consolidar las 4 salidas en un informe markdown
9. Detectar IDE → escribir en <carpeta-IDE>/Lint reviews/<nombre-modo-rama>.md
10. Resumir top bloqueantes en chat; preguntar "arregla todo" / "solo crítico" / "déjalo así"Si cualquier paso falla, detente y consulta references/edge-cases.md. No improvises.
Tres archivos en references/, cargados solo cuando los necesitas (progressive disclosure):
| Archivo | Cuándo cargarlo | Por qué |
|---|---|---|
references/prompts-agentes.md | Antes del paso 7 (invocar agentes) | Contiene los prompts literales para drupal-qa y drupal-security. Son largos a propósito — sin brief explícito los agentes devuelven reviews superficiales. Cópialos literales, solo sustituye <ruta-absoluta>, <modo>, <lista-archivos>. |
references/plantilla-informe.md | Antes del paso 8 (redactar informe) | Plantilla fija. La consistencia entre informes de distintos módulos es lo que hace que el equipo los lea rápido. |
references/edge-cases.md | Cuando algo falle | Síntoma → causa → solución para los problemas más comunes (DDEV, PHPStan, services.yml, OAuth, modo diff). |
Si ya leíste un archivo en esta sesión, no recargues — el contexto lo conserva.
Analiza TODOS los archivos del módulo. Más exhaustivo (~2-5 min). Úsalo:
Analiza SOLO los archivos cambiados en la rama actual respecto a origin/develop. Más rápido (~30s-1min). Úsalo:
Obtener la lista de archivos analizables del módulo (filtrando extensiones que PHPStan/PHPCS pueden procesar):
cd drupal
git fetch origin develop --quiet
git diff --name-only origin/develop...HEAD \
| grep "^web/modules/custom/<nombre>/" \
| grep -E '\.(php|module|inc|install|profile|theme|yml|twig)$'El segundo grep es importante: sin él recibirás .css, .md o imágenes que PHPStan rechaza con "no PHP files found". Para PHPStan específicamente, restringe aún más a \.(php|module|inc|install|profile|theme)$ (sin yml/twig).
Si el resultado está vacío o estás en develop → ver references/edge-cases.md, sección "Modo diff".
| Lo que dice el usuario | Acción |
|---|---|
Nombre exacto (chat_soporte_tecnico_ia) | Glob: "**/web/modules/custom/<nombre>/*.info.yml" |
Ruta (web/modules/custom/foo) | Validar que existe <ruta>/<basename>.info.yml |
| Sin especificar | Glob: "**/web/modules/custom/*/*.info.yml". Si hay 1 → usar; si >1 → listar y preguntar; si 0 → parar |
ddev describe (silencioso) → si OK, todo dentro de DDEV con ddev exec.vendor/bin/phpstan directo.Path en contenedor DDEV: verifica con ddev exec "ls /var/www/html". Suele ser /var/www/html/drupal o /var/www/html según el docroot del .ddev/config.yaml.
Si vendor/bin/phpstan no existe:
ddev composer require --dev phpstan/phpstan mglaman/phpstan-drupal phpstan/phpstan-deprecation-rulesPedir confirmación antes de instalar. PHPCS suele venir con drupal/coder (verificar con ddev exec "vendor/bin/phpcs -i" | grep -i drupal).
Crea phpstan.lint-review.neon en la raíz del proyecto Drupal (no en el módulo):
parameters:
level: 5
paths:
- web/modules/custom/<nombre>
excludePaths:
- web/modules/custom/<nombre>/js/vendor/*
- web/modules/custom/<nombre>/tests/fixtures/*
reportUnmatchedIgnoredErrors: false
includes:
- vendor/mglaman/phpstan-drupal/extension.neon
- vendor/mglaman/phpstan-drupal/rules.neon
- vendor/phpstan/phpstan-deprecation-rules/rules.neonNo uses drupal_root (deprecated en phpstan-drupal 2.x — ver edge-cases).
Crítico: lanza las 4 fuentes en el MISMO mensaje (mismo bloque de tool calls). Sin paralelización pierdes el principal valor de la skill.
# PHPStan — usa el bloque paths: del .neon
ddev exec "cd /var/www/html/drupal && vendor/bin/phpstan analyse -c phpstan.lint-review.neon --no-progress --error-format=raw"
# PHPCS — apunta al directorio del módulo. Restringido a archivos PHP con --extensions.
# ⚠️ NUNCA incluir `js` en --extensions: el standard Drupal aplica reglas PHP al JS
# y phpcbf puede convertir null/true/false → NULL/TRUE/FALSE, rompiendo el JS en runtime.
# Los archivos JS se analizan con ESLint/prettier, no con PHPCS (ver edge-cases.md).
ddev exec "cd /var/www/html/drupal && vendor/bin/phpcs --standard=Drupal,DrupalPractice --report=full --extensions=php,module,inc,install,profile,theme --ignore='*/vendor/*,*/js/*' web/modules/custom/<nombre>"Tras obtener la lista de archivos cambiados (ver sección "Modo diff"), pásalos como argumentos posicionales — sobreescriben el bloque paths: del .neon:
# PHPStan — solo archivos PHP cambiados
ddev exec "cd /var/www/html/drupal && vendor/bin/phpstan analyse -c phpstan.lint-review.neon --no-progress --error-format=raw \
web/modules/custom/<nombre>/src/Foo.php \
web/modules/custom/<nombre>/src/Bar.php"
# PHPCS — filtra archivos PHP y YAML (no JS) antes de pasarlos como positional args.
# Pasa SOLO archivos cuya extensión esté en --extensions; si pasas un .js posicional,
# phpcbf lo procesa igualmente aunque no esté en --extensions, rompiendo el JS.
ddev exec "cd /var/www/html/drupal && vendor/bin/phpcs --standard=Drupal,DrupalPractice --report=full --extensions=php,module,inc,install,profile,theme --ignore='*/vendor/*' \
web/modules/custom/<nombre>/src/Foo.php \
web/modules/custom/<nombre>/src/Bar.php \
web/modules/custom/<nombre>/<modulo>.routing.yml"Nota sobre `phpcbf`: PHPCS a menudo reporta "PHPCBF CAN FIX N OF THESE SNIFF VIOLATIONS AUTOMATICALLY". Si el número es alto (>50% de los ERRORS de PHP, no cuentes los de JS), merece la pena ofrecerle al usuariophpcbfcomo acción rápida tras el informe (ver "Después del informe"). Los JS NUNCA deben ir a phpcbf — ver el edge case "phpcbf rompe JavaScript" enreferences/edge-cases.md.
references/prompts-agentes.md, sección "Prompt para drupal-qa".drupal-security".En modo diff, pasa la lista de archivos a los agentes con la ruta completa relativa al repo (web/modules/custom/<nombre>/src/Foo.php), no la subruta del módulo. Los agentes hacen Read sobre esas rutas.
Sigue la plantilla literal de references/plantilla-informe.md. La estructura es fija: cabecera, resumen ejecutivo, una sección por fuente (PHPStan/PHPCS/QA/Security), acciones priorizadas P0/P1/P2, cobertura buenas prácticas, comandos de verificación.
Reglas críticas (todas detalladas en la plantilla):
archivo:línea siempre clickable, ruta relativa al proyecto.SEC-ALTO-1, QA-ROUTING, etc.)._csrf_request_header_token en las 9 rutas POST", no "mejorar la seguridad".Paso 1 — IDE por env var (PRIORITARIO). Ejecuta printenv CLAUDE_CODE_ENTRYPOINT:
CLAUDE_CODE_ENTRYPOINT | Carpeta |
|---|---|
claude-antigravity | .antigravity/Lint reviews/ |
claude-cursor | .cursor/Lint reviews/ |
claude-vscode | .vscode/Lint reviews/ |
otros (cli, vacío) | continuar al Paso 2 |
Paso 2 — fallback por existencia: .antigravity/ > .cursor/ > .vscode/ > docs/lint-reviews/.
Nombre: lint-review-<nombre-modulo>-<modo>-<rama>.md. Sobrescribir si existe (es la versión más reciente). NUNCA caigas a detección por carpeta cuando el env var es claro — eso causa el bug de elegir .cursor/ solo porque sobrevive de un uso anterior del IDE.
drupal-backend con la lista P0 estructurada (archivo:línea + acción)ddev exec "cd /var/www/html/drupal && vendor/bin/phpcbf --standard=Drupal,DrupalPractice --extensions=php,module,inc,install,profile,theme --ignore='*/vendor/*,*/js/*' web/modules/custom/<nombre>". OBLIGATORIO el flag --extensions para excluir .js — sin él, phpcbf convierte null/true/false → NULL/TRUE/FALSE en JavaScript y rompe el código en runtime (ver edge-cases.md). Avisa al usuario de que phpcbf modifica archivos in-place y pídele que revise el diff antes de commitear.routing.yml o services.yml → drush cr obligatorio + tests del módulo + re-ejecutar la skill para verificar.Estas son las trampas que he visto romper la skill en sesiones reales. Cada una incluye el porqué, no solo la regla.
prompts-agentes.md. Por qué: sin la checklist explícita los agentes devuelven reviews superficiales (ver el docu del propio prompts-agentes.md).'@servicio') es necesaria para el autowiring del Hook OOP. Eliminarla rompe drush cr. Ver edge-cases.getClient(), post() sobre interfaces) en el directorio tests/, el test depende del driver actual y romperá silenciosamente en CI cuando cambie. Reportarlo como bloqueante.Drupal.Semantics.ConstantName a cualquier archivo que pilla, incluyendo .js. Phpcbf convierte null/true/false → NULL/TRUE/FALSE en JavaScript, lo que rompe el código en runtime con ReferenceError. Usa siempre --extensions=php,module,inc,install,profile,theme y --ignore='*/js/*' al llamar a phpcbf (y a phpcs por consistencia). Los JS se analizan/arreglan con ESLint, no con PHPCS. Ver el edge case completo en references/edge-cases.md.Verifica cada item leyendo el informe que has generado. Si algo falta, vuelve atrás antes de entregárselo al usuario.
Español confirmado.<carpeta-IDE>/Lint reviews/lint-review-<nombre>-<modo>-<rama>.md (verifica con ls)❌ no ejecutada — <razón>, no omitida silenciosamente.archivo:línea con ruta relativa al proyecto (no rutas absolutas del contenedor DDEV).archivo:línea".APTO, APTO con correcciones menores, APTO con correcciones críticas, NO APTO). Nada de "depende".git status sobre la carpeta del módulo no muestra cambios atribuibles a esta skill.arregla todo/solo crítico/déjalo así), no un asume "ahora arreglo todo".| Síntoma | Acción |
|---|---|
references/*.md no existe | Avisar al usuario, no inventar plantillas |
| DDEV no levantado | Pedir al usuario antes de ddev start |
| PHPStan/PHPCS no instalados | Pedir confirmación para instalar (ddev composer require --dev ...) |
Agentes drupal-qa o drupal-security no disponibles | Continuar con las otras fuentes (PHPStan + PHPCS) y pedir al usuario que confirme si quiere review manual del modelo (más lento, menos rigor) |
| Una de las 4 fuentes falla en runtime | Continuar con las otras 3, marcar la fallida en el informe |
| No se puede crear la carpeta del IDE | Crear con mkdir -p; si falla, usar docs/lint-reviews/ |
| Modo diff sin cambios en el módulo | Ofrecer cambiar a completo |
Estás en develop (no hay rama feature) | Abortar con mensaje claro |
| Cliente no soporta tool calls paralelas | Avisar al usuario al inicio: la skill será 4x más lenta, ¿continuar? |
| Síntoma no listado | Consulta references/edge-cases.md. Si tu síntoma no aparece, añádelo después de resolverlo |
lint-drupal-module (esta skill) → fixes mecánicoscodex-diff-develop → fixes de lógicacodex-pr-review → revisión final antes de mergear~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.