@saulwade/swl-ses 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (702) hide show
  1. package/CLAUDE.md +238 -0
  2. package/README.md +560 -0
  3. package/_userland/agentes/.gitkeep +0 -0
  4. package/_userland/habilidades/.gitkeep +0 -0
  5. package/agentes/.evolved.json +9 -0
  6. package/agentes/accesibilidad-wcag-swl.md +692 -0
  7. package/agentes/arquitecto-swl.md +238 -0
  8. package/agentes/auto-evolucion-swl.md +854 -0
  9. package/agentes/backend-api-swl.md +470 -0
  10. package/agentes/backend-csharp-swl.md +418 -0
  11. package/agentes/backend-go-swl.md +388 -0
  12. package/agentes/backend-java-swl.md +279 -0
  13. package/agentes/backend-node-swl.md +477 -0
  14. package/agentes/backend-python-swl.md +608 -0
  15. package/agentes/backend-rust-swl.md +362 -0
  16. package/agentes/backend-workers-swl.md +480 -0
  17. package/agentes/cloud-infra-swl.md +485 -0
  18. package/agentes/consolidador-swl.md +539 -0
  19. package/agentes/datos-swl.md +584 -0
  20. package/agentes/depurador-swl.md +349 -0
  21. package/agentes/devops-ci-swl.md +374 -0
  22. package/agentes/disenador-ui-swl.md +558 -0
  23. package/agentes/documentador-swl.md +343 -0
  24. package/agentes/evals/arquitecto-swl.evals.json +56 -0
  25. package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
  26. package/agentes/evals/implementador-swl.evals.json +56 -0
  27. package/agentes/evals/orquestador-swl.evals.json +60 -0
  28. package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
  29. package/agentes/evals/red-team-swl.evals.json +59 -0
  30. package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
  31. package/agentes/frontend-angular-swl.md +627 -0
  32. package/agentes/frontend-css-swl.md +720 -0
  33. package/agentes/frontend-react-swl.md +696 -0
  34. package/agentes/frontend-swl.md +500 -0
  35. package/agentes/frontend-tailwind-swl.md +830 -0
  36. package/agentes/implementador-swl.md +328 -0
  37. package/agentes/investigador-swl.md +430 -0
  38. package/agentes/investigador-ux-swl.md +500 -0
  39. package/agentes/llm-apps-swl.md +276 -0
  40. package/agentes/migrador-swl.md +417 -0
  41. package/agentes/mobile-android-swl.md +509 -0
  42. package/agentes/mobile-cross-swl.md +539 -0
  43. package/agentes/mobile-ios-swl.md +500 -0
  44. package/agentes/mobile-testing-swl.md +300 -0
  45. package/agentes/notificador-swl.md +916 -0
  46. package/agentes/observabilidad-swl.md +436 -0
  47. package/agentes/orquestador-swl.md +884 -0
  48. package/agentes/pagos-swl.md +283 -0
  49. package/agentes/perfilador-usuario-swl.md +306 -0
  50. package/agentes/planificador-swl.md +402 -0
  51. package/agentes/producto-prd-swl.md +587 -0
  52. package/agentes/red-team-swl.md +216 -0
  53. package/agentes/release-manager-swl.md +568 -0
  54. package/agentes/rendimiento-swl.md +714 -0
  55. package/agentes/resolutor-build-swl.md +243 -0
  56. package/agentes/revisor-angular-swl.md +276 -0
  57. package/agentes/revisor-codigo-swl.md +348 -0
  58. package/agentes/revisor-csharp-swl.md +262 -0
  59. package/agentes/revisor-go-swl.md +257 -0
  60. package/agentes/revisor-java-swl.md +255 -0
  61. package/agentes/revisor-kotlin-swl.md +271 -0
  62. package/agentes/revisor-nextjs-swl.md +279 -0
  63. package/agentes/revisor-php-swl.md +269 -0
  64. package/agentes/revisor-react-swl.md +276 -0
  65. package/agentes/revisor-rust-swl.md +344 -0
  66. package/agentes/revisor-seguridad-swl.md +390 -0
  67. package/agentes/revisor-swift-swl.md +266 -0
  68. package/agentes/revisor-typescript-swl.md +344 -0
  69. package/agentes/sre-swl.md +265 -0
  70. package/agentes/tdd-qa-swl.md +354 -0
  71. package/agentes/ux-disenador-swl.md +501 -0
  72. package/bin/lib/bot-comandos.js +1030 -0
  73. package/bin/lib/bot-discovery.js +182 -0
  74. package/bin/lib/bot-git.js +142 -0
  75. package/bin/swl-ses.js +325 -0
  76. package/bin/swl-telegram-bot.js +442 -0
  77. package/bin/swl-telegram-bot.plist +21 -0
  78. package/bin/swl-telegram-bot.service +14 -0
  79. package/comandos/swl/.evolved.json +23 -0
  80. package/comandos/swl/actualizar.md +174 -0
  81. package/comandos/swl/adoptar-proyecto.md +207 -0
  82. package/comandos/swl/aprender.md +701 -0
  83. package/comandos/swl/auditar-deps.md +134 -0
  84. package/comandos/swl/autoresearch.md +170 -0
  85. package/comandos/swl/ayuda.md +224 -0
  86. package/comandos/swl/brainstorm.md +50 -0
  87. package/comandos/swl/checkpoint.md +330 -0
  88. package/comandos/swl/compactar.md +283 -0
  89. package/comandos/swl/configurar-ci.md +227 -0
  90. package/comandos/swl/contexto.md +112 -0
  91. package/comandos/swl/contribuir.md +233 -0
  92. package/comandos/swl/crear-skill.md +292 -0
  93. package/comandos/swl/cron.md +196 -0
  94. package/comandos/swl/dashboard.md +146 -0
  95. package/comandos/swl/discutir-fase.md +230 -0
  96. package/comandos/swl/ejecutar-fase.md +135 -0
  97. package/comandos/swl/evaluar-skill.md +487 -0
  98. package/comandos/swl/evolucion-estado.md +142 -0
  99. package/comandos/swl/evolucionar.md +259 -0
  100. package/comandos/swl/exportar-vault.md +189 -0
  101. package/comandos/swl/gateway.md +158 -0
  102. package/comandos/swl/inbox.md +116 -0
  103. package/comandos/swl/instalar.md +220 -0
  104. package/comandos/swl/instintos.md +86 -0
  105. package/comandos/swl/mapear-codebase.md +312 -0
  106. package/comandos/swl/mcp-status.md +175 -0
  107. package/comandos/swl/metricas.md +270 -0
  108. package/comandos/swl/modelo.md +102 -0
  109. package/comandos/swl/notificaciones.md +396 -0
  110. package/comandos/swl/nuevo-proyecto.md +154 -0
  111. package/comandos/swl/planear-fase.md +221 -0
  112. package/comandos/swl/plugins.md +256 -0
  113. package/comandos/swl/reflect-skills.md +125 -0
  114. package/comandos/swl/release.md +217 -0
  115. package/comandos/swl/revisar-impacto.md +206 -0
  116. package/comandos/swl/revisar.md +330 -0
  117. package/comandos/swl/salud.md +363 -0
  118. package/comandos/swl/sesiones.md +200 -0
  119. package/comandos/swl/skill-search.md +113 -0
  120. package/comandos/swl/verificar.md +585 -0
  121. package/comandos/swl/wiki.md +620 -0
  122. package/contextos/dev.md +32 -0
  123. package/contextos/research.md +30 -0
  124. package/contextos/review.md +31 -0
  125. package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
  126. package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
  127. package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
  128. package/habilidades/agent-browser/SKILL.md +218 -0
  129. package/habilidades/agentes-como-servicio/SKILL.md +218 -0
  130. package/habilidades/ai-runtime-security/SKILL.md +273 -0
  131. package/habilidades/angular-avanzado/SKILL.md +164 -0
  132. package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
  133. package/habilidades/angular-moderno/SKILL.md +186 -0
  134. package/habilidades/angular-moderno/evals/evals.json +45 -0
  135. package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
  136. package/habilidades/api-rest-diseno/SKILL.md +191 -0
  137. package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
  138. package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
  139. package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
  140. package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
  141. package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
  142. package/habilidades/async-python/SKILL.md +149 -0
  143. package/habilidades/async-python/evals/evals.json +47 -0
  144. package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
  145. package/habilidades/auth-patrones/.evolved.json +9 -0
  146. package/habilidades/auth-patrones/SKILL.md +413 -0
  147. package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
  148. package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
  149. package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
  150. package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
  151. package/habilidades/autoresearch/SKILL.md +268 -0
  152. package/habilidades/autoresearch/evals/evals.json +41 -0
  153. package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
  154. package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
  155. package/habilidades/azure-cloud/SKILL.md +308 -0
  156. package/habilidades/azure-cloud/recursos/aks.md +327 -0
  157. package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
  158. package/habilidades/backend-production-resilience/SKILL.md +288 -0
  159. package/habilidades/brainstorming/SKILL.md +295 -0
  160. package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
  161. package/habilidades/build-errors-cpp/SKILL.md +270 -0
  162. package/habilidades/build-errors-csharp/SKILL.md +265 -0
  163. package/habilidades/build-errors-go/SKILL.md +306 -0
  164. package/habilidades/build-errors-java/SKILL.md +278 -0
  165. package/habilidades/build-errors-kotlin/SKILL.md +303 -0
  166. package/habilidades/build-errors-nextjs/SKILL.md +312 -0
  167. package/habilidades/build-errors-php/SKILL.md +270 -0
  168. package/habilidades/build-errors-python/SKILL.md +292 -0
  169. package/habilidades/build-errors-rust/SKILL.md +284 -0
  170. package/habilidades/build-errors-swift/SKILL.md +272 -0
  171. package/habilidades/build-errors-typescript/SKILL.md +369 -0
  172. package/habilidades/checklist-calidad/SKILL.md +271 -0
  173. package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
  174. package/habilidades/checklist-seguridad/SKILL.md +285 -0
  175. package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
  176. package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
  177. package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
  178. package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
  179. package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
  180. package/habilidades/cloud-aws/SKILL.md +142 -0
  181. package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
  182. package/habilidades/compactacion-contexto/SKILL.md +247 -0
  183. package/habilidades/contenedores-docker/SKILL.md +137 -0
  184. package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
  185. package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
  186. package/habilidades/context-builder/SKILL.md +170 -0
  187. package/habilidades/control-profundidad/SKILL.md +128 -0
  188. package/habilidades/csharp-experto/SKILL.md +322 -0
  189. package/habilidades/csharp-patrones/SKILL.md +316 -0
  190. package/habilidades/csharp-testing/SKILL.md +286 -0
  191. package/habilidades/css-moderno/SKILL.md +166 -0
  192. package/habilidades/css-moderno/evals/evals.json +43 -0
  193. package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
  194. package/habilidades/datos-etl/SKILL.md +129 -0
  195. package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
  196. package/habilidades/dbml-experto/SKILL.md +339 -0
  197. package/habilidades/dbml-experto/evals/evals.json +56 -0
  198. package/habilidades/dependencias-auditoria/SKILL.md +320 -0
  199. package/habilidades/deprecacion-migracion/SKILL.md +169 -0
  200. package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
  201. package/habilidades/design-tokens/SKILL.md +158 -0
  202. package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
  203. package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
  204. package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
  205. package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
  206. package/habilidades/discutir-fase/SKILL.md +188 -0
  207. package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
  208. package/habilidades/diseno-responsivo/SKILL.md +186 -0
  209. package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
  210. package/habilidades/django-experto/SKILL.md +205 -0
  211. package/habilidades/django-experto/recursos/async-django.md +390 -0
  212. package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
  213. package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
  214. package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
  215. package/habilidades/django-experto/recursos/testing-django.md +415 -0
  216. package/habilidades/doc-sync/SKILL.md +280 -0
  217. package/habilidades/drift-detection/SKILL.md +179 -0
  218. package/habilidades/ejecutar-fase/SKILL.md +468 -0
  219. package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
  220. package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
  221. package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
  222. package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
  223. package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
  224. package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
  225. package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
  226. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
  227. package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
  228. package/habilidades/evaluacion-agentes/SKILL.md +314 -0
  229. package/habilidades/event-driven/SKILL.md +153 -0
  230. package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
  231. package/habilidades/extraccion-documentos/SKILL.md +221 -0
  232. package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
  233. package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
  234. package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
  235. package/habilidades/fastapi-experto/SKILL.md +221 -0
  236. package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
  237. package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
  238. package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
  239. package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
  240. package/habilidades/filament-admin/SKILL.md +290 -0
  241. package/habilidades/frontend-avanzado/SKILL.md +257 -0
  242. package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
  243. package/habilidades/gcp-cloud/SKILL.md +260 -0
  244. package/habilidades/gcp-cloud/recursos/gke.md +234 -0
  245. package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
  246. package/habilidades/generacion-mermaid/SKILL.md +229 -0
  247. package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
  248. package/habilidades/go-experto/SKILL.md +305 -0
  249. package/habilidades/go-patrones/SKILL.md +299 -0
  250. package/habilidades/go-testing/SKILL.md +291 -0
  251. package/habilidades/graphql-experto/SKILL.md +323 -0
  252. package/habilidades/guardrail-semantico/SKILL.md +282 -0
  253. package/habilidades/harness-claude-code/SKILL.md +299 -0
  254. package/habilidades/iam-secretos/SKILL.md +265 -0
  255. package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
  256. package/habilidades/infra-github-actions/SKILL.md +166 -0
  257. package/habilidades/instalar-sistema/.evolved.json +9 -0
  258. package/habilidades/instalar-sistema/SKILL.md +221 -0
  259. package/habilidades/java-experto/SKILL.md +290 -0
  260. package/habilidades/java-patrones/SKILL.md +275 -0
  261. package/habilidades/java-testing/SKILL.md +288 -0
  262. package/habilidades/kotlin-compose/SKILL.md +278 -0
  263. package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
  264. package/habilidades/kotlin-experto/SKILL.md +318 -0
  265. package/habilidades/kotlin-testing/SKILL.md +267 -0
  266. package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
  267. package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
  268. package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
  269. package/habilidades/langchain-langraph/SKILL.md +386 -0
  270. package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
  271. package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
  272. package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
  273. package/habilidades/legacy-code-rescue/SKILL.md +267 -0
  274. package/habilidades/likec4-experto/SKILL.md +412 -0
  275. package/habilidades/likec4-experto/evals/evals.json +69 -0
  276. package/habilidades/manejo-errores/.evolved.json +9 -0
  277. package/habilidades/manejo-errores/SKILL.md +407 -0
  278. package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
  279. package/habilidades/mapear-codebase/SKILL.md +275 -0
  280. package/habilidades/memoria-busqueda/SKILL.md +194 -0
  281. package/habilidades/memoria-busqueda/evals/evals.json +44 -0
  282. package/habilidades/meta-skills-estandar/SKILL.md +298 -0
  283. package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
  284. package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
  285. package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
  286. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
  287. package/habilidades/microservicios/SKILL.md +155 -0
  288. package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
  289. package/habilidades/mobile-flutter/SKILL.md +199 -0
  290. package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
  291. package/habilidades/mobile-react-native/SKILL.md +176 -0
  292. package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
  293. package/habilidades/mongodb-experto/SKILL.md +302 -0
  294. package/habilidades/monitoring-alertas/SKILL.md +201 -0
  295. package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
  296. package/habilidades/nestjs-experto/SKILL.md +307 -0
  297. package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
  298. package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
  299. package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
  300. package/habilidades/nextjs-experto/SKILL.md +335 -0
  301. package/habilidades/nextjs-patrones/SKILL.md +303 -0
  302. package/habilidades/nextjs-testing/SKILL.md +331 -0
  303. package/habilidades/node-experto/.evolved.json +9 -0
  304. package/habilidades/node-experto/SKILL.md +266 -0
  305. package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
  306. package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
  307. package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
  308. package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
  309. package/habilidades/nuevo-proyecto/SKILL.md +204 -0
  310. package/habilidades/orquestacion-async/SKILL.md +303 -0
  311. package/habilidades/paid-media-tracking/SKILL.md +269 -0
  312. package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
  313. package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
  314. package/habilidades/patrones-python/SKILL.md +228 -0
  315. package/habilidades/patrones-python/evals/evals.json +56 -0
  316. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
  317. package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
  318. package/habilidades/perfil-usuario/SKILL.md +200 -0
  319. package/habilidades/perfil-usuario/evals/evals.json +55 -0
  320. package/habilidades/performance-baseline/SKILL.md +297 -0
  321. package/habilidades/php-experto/SKILL.md +291 -0
  322. package/habilidades/php-patrones/SKILL.md +306 -0
  323. package/habilidades/php-testing/SKILL.md +280 -0
  324. package/habilidades/planear-fase/SKILL.md +269 -0
  325. package/habilidades/postgresql-experto/SKILL.md +151 -0
  326. package/habilidades/postgresql-experto/evals/evals.json +53 -0
  327. package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
  328. package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
  329. package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
  330. package/habilidades/privacy-memoria/SKILL.md +141 -0
  331. package/habilidades/privacy-memoria/evals/evals.json +43 -0
  332. package/habilidades/prompt-engineering/SKILL.md +518 -0
  333. package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
  334. package/habilidades/rag-arquitectura/SKILL.md +338 -0
  335. package/habilidades/rails-experto/SKILL.md +237 -0
  336. package/habilidades/rails-experto/recursos/active-record.md +260 -0
  337. package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
  338. package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
  339. package/habilidades/react-experto/SKILL.md +209 -0
  340. package/habilidades/react-experto/evals/evals.json +55 -0
  341. package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
  342. package/habilidades/react-optimizacion/SKILL.md +174 -0
  343. package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
  344. package/habilidades/redis-experto/SKILL.md +305 -0
  345. package/habilidades/release-semver/.evolved.json +9 -0
  346. package/habilidades/release-semver/SKILL.md +248 -0
  347. package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
  348. package/habilidades/rust-experto/SKILL.md +400 -0
  349. package/habilidades/rust-patrones/SKILL.md +296 -0
  350. package/habilidades/rust-testing/SKILL.md +311 -0
  351. package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
  352. package/habilidades/sql-optimizacion/SKILL.md +200 -0
  353. package/habilidades/sql-optimizacion/evals/evals.json +54 -0
  354. package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
  355. package/habilidades/sre-patrones/SKILL.md +333 -0
  356. package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
  357. package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
  358. package/habilidades/stripe-pagos/SKILL.md +550 -0
  359. package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
  360. package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
  361. package/habilidades/structured-outputs/SKILL.md +343 -0
  362. package/habilidades/swift-experto/SKILL.md +320 -0
  363. package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
  364. package/habilidades/swift-patrones/SKILL.md +313 -0
  365. package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
  366. package/habilidades/swift-testing/SKILL.md +254 -0
  367. package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
  368. package/habilidades/swl-dashboard/SKILL.md +370 -0
  369. package/habilidades/swl-markitdown/SKILL.md +285 -0
  370. package/habilidades/swl-markitdown/evals/evals.json +52 -0
  371. package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
  372. package/habilidades/tailwind-experto/SKILL.md +240 -0
  373. package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
  374. package/habilidades/tdd-workflow/SKILL.md +293 -0
  375. package/habilidades/terraform-experto/SKILL.md +321 -0
  376. package/habilidades/testing-python/SKILL.md +340 -0
  377. package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
  378. package/habilidades/threat-model-lite/SKILL.md +246 -0
  379. package/habilidades/tracing-processor/SKILL.md +212 -0
  380. package/habilidades/tracking-measurement/SKILL.md +239 -0
  381. package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
  382. package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
  383. package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
  384. package/habilidades/typescript-avanzado/SKILL.md +144 -0
  385. package/habilidades/typescript-avanzado/evals/evals.json +55 -0
  386. package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
  387. package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
  388. package/habilidades/ux-diseno/SKILL.md +116 -0
  389. package/habilidades/ux-diseno/evals/evals.json +43 -0
  390. package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
  391. package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
  392. package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
  393. package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
  394. package/habilidades/verificacion-evidencia/SKILL.md +160 -0
  395. package/habilidades/verificar-trabajo/SKILL.md +303 -0
  396. package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
  397. package/habilidades/wiki-conocimiento/SKILL.md +276 -0
  398. package/habilidades/wireframes-flujos/SKILL.md +212 -0
  399. package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
  400. package/habilidades/workflow-claude-code/SKILL.md +260 -0
  401. package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
  402. package/hooks/_run-hook.sh +57 -0
  403. package/hooks/actualizar-perfil-usuario.js +364 -0
  404. package/hooks/agente-lifecycle.js +71 -0
  405. package/hooks/aiisms-detector.js +173 -0
  406. package/hooks/audit-trail.js +204 -0
  407. package/hooks/auto-background.js +97 -0
  408. package/hooks/auto-consolidacion.js +178 -0
  409. package/hooks/auto-evolucion.js +666 -0
  410. package/hooks/auto-restaurar-settings.js +360 -0
  411. package/hooks/calidad-pre-commit.js +929 -0
  412. package/hooks/calidad-typescript.js +511 -0
  413. package/hooks/captura-feedback-usuario.js +148 -0
  414. package/hooks/check-update.js +211 -0
  415. package/hooks/clasificador-mensajes.js +271 -0
  416. package/hooks/degradacion-instintos.js +272 -0
  417. package/hooks/escaneo-secretos.js +389 -0
  418. package/hooks/extraccion-aprendizajes.js +763 -0
  419. package/hooks/grafo-contexto.js +129 -0
  420. package/hooks/graph-update.js +67 -0
  421. package/hooks/guardrail-modelo.js +247 -0
  422. package/hooks/inbox-aviso.js +75 -0
  423. package/hooks/inyeccion-contexto.js +246 -0
  424. package/hooks/lib/abort-registry.js +214 -0
  425. package/hooks/lib/agent-backend.js +210 -0
  426. package/hooks/lib/agent-comms.js +263 -0
  427. package/hooks/lib/agent-issue-codes.js +284 -0
  428. package/hooks/lib/agent-matcher.js +189 -0
  429. package/hooks/lib/async-hook-registry.js +252 -0
  430. package/hooks/lib/atomic-write.js +130 -0
  431. package/hooks/lib/auto-consolidator.js +335 -0
  432. package/hooks/lib/canary-skills.js +187 -0
  433. package/hooks/lib/consolidation-lock.js +291 -0
  434. package/hooks/lib/context-builder.js +430 -0
  435. package/hooks/lib/context-compressor.js +657 -0
  436. package/hooks/lib/convergence-detector.js +105 -0
  437. package/hooks/lib/delegation-tracker.js +198 -0
  438. package/hooks/lib/detectar-package-manager.js +423 -0
  439. package/hooks/lib/edit-accumulator.js +171 -0
  440. package/hooks/lib/error-classifier.js +308 -0
  441. package/hooks/lib/event-bus.js +112 -0
  442. package/hooks/lib/evolution-tracker.js +442 -0
  443. package/hooks/lib/execution-state.js +316 -0
  444. package/hooks/lib/fingerprint-id.js +135 -0
  445. package/hooks/lib/gateway-notify.js +116 -0
  446. package/hooks/lib/graph-security.js +75 -0
  447. package/hooks/lib/guardrail-metrics.js +202 -0
  448. package/hooks/lib/hook-circuit-breaker.js +206 -0
  449. package/hooks/lib/loop-detector.js +267 -0
  450. package/hooks/lib/mcp-health.js +184 -0
  451. package/hooks/lib/mcp-pool.js +436 -0
  452. package/hooks/lib/memory-search.js +506 -0
  453. package/hooks/lib/merkle-audit.js +96 -0
  454. package/hooks/lib/model-router.js +222 -0
  455. package/hooks/lib/normalize-error.js +324 -0
  456. package/hooks/lib/normalize-input.js +65 -0
  457. package/hooks/lib/nudge-tracker.js +306 -0
  458. package/hooks/lib/otlp-exporter.js +365 -0
  459. package/hooks/lib/performance-marks.js +239 -0
  460. package/hooks/lib/privacy-filter.js +128 -0
  461. package/hooks/lib/prompt-injection-scanner.js +209 -0
  462. package/hooks/lib/provenance-tracker.js +183 -0
  463. package/hooks/lib/rate-limit-tracker.js +253 -0
  464. package/hooks/lib/reflect-classifier.js +164 -0
  465. package/hooks/lib/resource-quota.js +122 -0
  466. package/hooks/lib/retry-jitter.js +165 -0
  467. package/hooks/lib/risk-engine.js +368 -0
  468. package/hooks/lib/run-log.js +408 -0
  469. package/hooks/lib/session-fts.js +379 -0
  470. package/hooks/lib/session-store.js +293 -0
  471. package/hooks/lib/singleton-guard.js +159 -0
  472. package/hooks/lib/skill-auditor.js +588 -0
  473. package/hooks/lib/sync-status.js +228 -0
  474. package/hooks/lib/taint-tracker.js +107 -0
  475. package/hooks/lib/task-service.js +295 -0
  476. package/hooks/lib/tech-skills-map.js +146 -0
  477. package/hooks/lib/telegram-cliente.js +159 -0
  478. package/hooks/lib/telegram-config.js +170 -0
  479. package/hooks/lib/token-budget.js +156 -0
  480. package/hooks/lib/token-estimator.js +420 -0
  481. package/hooks/lib/toon-compressor.js +245 -0
  482. package/hooks/lib/usage-model.js +183 -0
  483. package/hooks/lib/variable-resolver.js +230 -0
  484. package/hooks/linea-estado.js +324 -0
  485. package/hooks/metricas-evolucion.js +209 -0
  486. package/hooks/monitor-contexto.js +325 -0
  487. package/hooks/notificacion-sesion-stop.js +198 -0
  488. package/hooks/notificacion-telegram-notification.js +4 -0
  489. package/hooks/notificacion-telegram-subagent.js +4 -0
  490. package/hooks/notificacion-telegram.js +267 -0
  491. package/hooks/preservar-estado-pre-compact.js +150 -0
  492. package/hooks/proteccion-rutas.js +366 -0
  493. package/hooks/registro-turnos.js +209 -0
  494. package/hooks/resumen-sesion.js +249 -0
  495. package/hooks/risk-scoring.js +323 -0
  496. package/hooks/rotar-audit-auto.js +122 -0
  497. package/hooks/sugerir-regenerar-inventario.js +170 -0
  498. package/hooks/telemetria-agentes.js +167 -0
  499. package/hooks/tracking-costos.js +688 -0
  500. package/instintos/global.yaml +8 -0
  501. package/instintos/perfil-usuario.yaml +53 -0
  502. package/instintos/prompt-appendices.yaml +57 -0
  503. package/instintos/proyecto.yaml +372 -0
  504. package/manifiestos/gateway-config.json +77 -0
  505. package/manifiestos/handoff-context.json +223 -0
  506. package/manifiestos/hook-profiles.json +44 -0
  507. package/manifiestos/hooks-config.json +360 -0
  508. package/manifiestos/modulos.json +1173 -0
  509. package/manifiestos/perfiles.json +404 -0
  510. package/package.json +86 -0
  511. package/plantillas/ESTADO.md +109 -0
  512. package/plantillas/HOJA-RUTA.md +143 -0
  513. package/plantillas/PROYECTO.md +122 -0
  514. package/plantillas/REQUISITOS.md +132 -0
  515. package/plantillas/auditor-veto-template.md +105 -0
  516. package/plantillas/github-workflows/README.md +47 -0
  517. package/plantillas/github-workflows/release-please.yml +44 -0
  518. package/plantillas/github-workflows/swl-ci.yml +107 -0
  519. package/plantillas/github-workflows/swl-security.yml +51 -0
  520. package/plantillas/mcp-mineru.json +13 -0
  521. package/plantillas/research/ARQUITECTURA.md +220 -0
  522. package/plantillas/research/FUNCIONALIDADES.md +175 -0
  523. package/plantillas/research/RESUMEN.md +165 -0
  524. package/plantillas/research/STACK.md +233 -0
  525. package/plantillas/research/TRAMPAS.md +299 -0
  526. package/plantillas/skill-evals-template.json +44 -0
  527. package/plugin.json +343 -0
  528. package/reglas/accesibilidad.md +269 -0
  529. package/reglas/api-diseno.md +400 -0
  530. package/reglas/arquitectura.md +352 -0
  531. package/reglas/brevedad-output.md +124 -0
  532. package/reglas/cloud-infra.md +247 -0
  533. package/reglas/docs.md +245 -0
  534. package/reglas/estilo-codigo.md +201 -0
  535. package/reglas/git-workflow.md +245 -0
  536. package/reglas/gobernanza.md +271 -0
  537. package/reglas/harness-claude-code.md +213 -0
  538. package/reglas/hooks.md +186 -0
  539. package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
  540. package/reglas/lenguajes/csharp/hooks.md +281 -0
  541. package/reglas/lenguajes/csharp/patrones.md +226 -0
  542. package/reglas/lenguajes/csharp/seguridad.md +258 -0
  543. package/reglas/lenguajes/csharp/testing.md +176 -0
  544. package/reglas/lenguajes/go/estilo-codigo.md +195 -0
  545. package/reglas/lenguajes/go/hooks.md +249 -0
  546. package/reglas/lenguajes/go/patrones.md +249 -0
  547. package/reglas/lenguajes/go/seguridad.md +225 -0
  548. package/reglas/lenguajes/go/testing.md +272 -0
  549. package/reglas/lenguajes/java/estilo-codigo.md +217 -0
  550. package/reglas/lenguajes/java/hooks.md +251 -0
  551. package/reglas/lenguajes/java/patrones.md +226 -0
  552. package/reglas/lenguajes/java/seguridad.md +233 -0
  553. package/reglas/lenguajes/java/testing.md +238 -0
  554. package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
  555. package/reglas/lenguajes/kotlin/hooks.md +245 -0
  556. package/reglas/lenguajes/kotlin/patrones.md +201 -0
  557. package/reglas/lenguajes/kotlin/seguridad.md +202 -0
  558. package/reglas/lenguajes/kotlin/testing.md +236 -0
  559. package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
  560. package/reglas/lenguajes/nextjs/hooks.md +186 -0
  561. package/reglas/lenguajes/nextjs/patrones.md +225 -0
  562. package/reglas/lenguajes/nextjs/seguridad.md +216 -0
  563. package/reglas/lenguajes/nextjs/testing.md +193 -0
  564. package/reglas/lenguajes/php/estilo-codigo.md +228 -0
  565. package/reglas/lenguajes/php/hooks.md +165 -0
  566. package/reglas/lenguajes/php/patrones.md +233 -0
  567. package/reglas/lenguajes/php/seguridad.md +186 -0
  568. package/reglas/lenguajes/php/testing.md +205 -0
  569. package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
  570. package/reglas/lenguajes/rust/hooks.md +240 -0
  571. package/reglas/lenguajes/rust/patrones.md +250 -0
  572. package/reglas/lenguajes/rust/seguridad.md +221 -0
  573. package/reglas/lenguajes/rust/testing.md +194 -0
  574. package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
  575. package/reglas/lenguajes/swift/hooks.md +257 -0
  576. package/reglas/lenguajes/swift/patrones.md +235 -0
  577. package/reglas/lenguajes/swift/seguridad.md +248 -0
  578. package/reglas/lenguajes/swift/testing.md +242 -0
  579. package/reglas/markitdown.md +60 -0
  580. package/reglas/memoria-consolidada.md +209 -0
  581. package/reglas/patrones.md +225 -0
  582. package/reglas/performance.md +195 -0
  583. package/reglas/pruebas.md +159 -0
  584. package/reglas/seguridad-agentes.md +351 -0
  585. package/reglas/seguridad.md +151 -0
  586. package/reglas/skills-estandar.md +373 -0
  587. package/reglas/testing.md +193 -0
  588. package/schemas/agent-contract.json +176 -0
  589. package/schemas/agent-frontmatter.schema.json +149 -0
  590. package/schemas/agent-message.schema.json +53 -0
  591. package/schemas/agent-output-implementacion.schema.json +85 -0
  592. package/schemas/agent-output-planificacion.schema.json +113 -0
  593. package/schemas/agent-output-review.schema.json +78 -0
  594. package/schemas/diary-entry.schema.json +80 -0
  595. package/schemas/hook-profiles.schema.json +39 -0
  596. package/schemas/hooks-config.schema.json +74 -0
  597. package/schemas/instinct.schema.json +115 -0
  598. package/schemas/modulos.schema.json +29 -0
  599. package/schemas/perfiles.schema.json +28 -0
  600. package/schemas/plugin.schema.json +64 -0
  601. package/schemas/skill-evals.schema.json +95 -0
  602. package/schemas/skill-frontmatter.schema.json +170 -0
  603. package/scripts/actualizar.js +145 -0
  604. package/scripts/audit-skills.sh +78 -0
  605. package/scripts/auditar-agentes-gaps.js +149 -0
  606. package/scripts/auditar-cobertura-frameworks.js +241 -0
  607. package/scripts/auditar-skills-gaps.js +206 -0
  608. package/scripts/bootstrap-instintos.js +259 -0
  609. package/scripts/check-update.js +109 -0
  610. package/scripts/comandos/agents.js +105 -0
  611. package/scripts/comandos/info.js +108 -0
  612. package/scripts/comandos/install-asistido.js +186 -0
  613. package/scripts/comandos/skills.js +211 -0
  614. package/scripts/configurar-branch-protection.js +418 -0
  615. package/scripts/daemon-swl.py +388 -0
  616. package/scripts/desinstalar.js +130 -0
  617. package/scripts/doctor.js +559 -0
  618. package/scripts/field-report.js +199 -0
  619. package/scripts/generar-inventario.js +317 -0
  620. package/scripts/inbox-tmux-inject.js +161 -0
  621. package/scripts/inferir-herramientas-permitidas.js +586 -0
  622. package/scripts/inicializar.js +133 -0
  623. package/scripts/instalador.js +1031 -0
  624. package/scripts/instalar-git-hook.js +122 -0
  625. package/scripts/lib/agp-frontmatter.js +222 -0
  626. package/scripts/lib/append-con-marcadores.js +199 -0
  627. package/scripts/lib/artefactos-python.js +43 -0
  628. package/scripts/lib/audit-query.js +221 -0
  629. package/scripts/lib/autostart-linux.js +347 -0
  630. package/scripts/lib/autostart-macos.js +360 -0
  631. package/scripts/lib/autostart-windows.js +307 -0
  632. package/scripts/lib/budget-enforcer.js +252 -0
  633. package/scripts/lib/claude-sessions.js +285 -0
  634. package/scripts/lib/configurar-ci.js +380 -0
  635. package/scripts/lib/console-span-exporter.js +92 -0
  636. package/scripts/lib/contadores-inventario.js +217 -0
  637. package/scripts/lib/dashboard-widgets.js +290 -0
  638. package/scripts/lib/detectar-runtime.js +279 -0
  639. package/scripts/lib/detectar-stack.js +187 -0
  640. package/scripts/lib/diary-entry.js +234 -0
  641. package/scripts/lib/drift-detector.js +545 -0
  642. package/scripts/lib/estado.js +124 -0
  643. package/scripts/lib/gestor-componentes.js +243 -0
  644. package/scripts/lib/gitignore-manifest.js +305 -0
  645. package/scripts/lib/graph-analyze.py +556 -0
  646. package/scripts/lib/graph-builder.py +485 -0
  647. package/scripts/lib/graph-cluster.py +259 -0
  648. package/scripts/lib/health-row.js +168 -0
  649. package/scripts/lib/hooks-settings.js +789 -0
  650. package/scripts/lib/manifiestos.js +138 -0
  651. package/scripts/lib/mc-client.js +137 -0
  652. package/scripts/lib/notificaciones-telegram.js +1107 -0
  653. package/scripts/lib/npm-version.js +261 -0
  654. package/scripts/lib/paquetes-conocidos.js +50 -0
  655. package/scripts/lib/preservar-usuario.js +586 -0
  656. package/scripts/lib/prompt-builder.js +264 -0
  657. package/scripts/lib/resolver-externo.js +332 -0
  658. package/scripts/lib/schedule-parser.js +305 -0
  659. package/scripts/lib/scoring-instintos.js +240 -0
  660. package/scripts/lib/seguridad.js +160 -0
  661. package/scripts/lib/selector-interactivo.js +152 -0
  662. package/scripts/lib/semantic-search.js +242 -0
  663. package/scripts/lib/skill-discovery.js +234 -0
  664. package/scripts/lib/skill-metrics.js +246 -0
  665. package/scripts/lib/skill-normalizer.js +112 -0
  666. package/scripts/lib/skills-hub.js +340 -0
  667. package/scripts/lib/span-schema.js +134 -0
  668. package/scripts/lib/tool-cost-analyzer.js +255 -0
  669. package/scripts/lib/tracing-processor-interface.js +286 -0
  670. package/scripts/lib/transformadores/base.js +80 -0
  671. package/scripts/lib/transformadores/claude.js +124 -0
  672. package/scripts/lib/transformadores/codex.js +115 -0
  673. package/scripts/lib/transformadores/copilot.js +106 -0
  674. package/scripts/lib/transformadores/gemini.js +74 -0
  675. package/scripts/lib/transformadores/index.js +35 -0
  676. package/scripts/lib/transformadores/opencode.js +75 -0
  677. package/scripts/lib/ui.js +259 -0
  678. package/scripts/limpiar-artefactos-python.js +131 -0
  679. package/scripts/mcp-orchestrator.py +386 -0
  680. package/scripts/mcp-pool-manager.py +352 -0
  681. package/scripts/mcp-telemetry.py +378 -0
  682. package/scripts/poblar-evolvable.js +226 -0
  683. package/scripts/publicar.js +287 -0
  684. package/scripts/reflect-skills.js +403 -0
  685. package/scripts/rotar-audit-logs.js +185 -0
  686. package/scripts/run-skill-evals.js +242 -0
  687. package/scripts/smoke-test.js +374 -0
  688. package/scripts/token-analysis.py +471 -0
  689. package/scripts/validar-manifest.js +195 -0
  690. package/scripts/validar-memoria.js +321 -0
  691. package/scripts/validar-tests-aislamiento.js +184 -0
  692. package/scripts/validar-tokens-test.js +208 -0
  693. package/scripts/validar.js +147 -0
  694. package/scripts/validate-markdown.py +339 -0
  695. package/scripts/validate-skills.py +385 -0
  696. package/scripts/vendor/claude-usage/README.md +116 -0
  697. package/scripts/vendor/claude-usage/cli.py +334 -0
  698. package/scripts/vendor/claude-usage/dashboard.py +795 -0
  699. package/scripts/vendor/claude-usage/scanner.py +467 -0
  700. package/scripts/vendor/markitdown/cli.py +194 -0
  701. package/scripts/verificar-evolucion.js +289 -0
  702. package/scripts/verificar-release.js +494 -0
@@ -0,0 +1,208 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * validar-tokens-test.js
5
+ *
6
+ * Análisis estático: detecta literales con apariencia de token Telegram real
7
+ * (TELEGRAM_BOT_TOKEN=<valor> o TELEGRAM_CHAT_ID=<valor>) en archivos de test.
8
+ *
9
+ * Un token Telegram real tiene formato: <bot_id>:<hash_40chars>
10
+ * Un chat ID real tiene formato: [-]<número de 10+ dígitos>
11
+ *
12
+ * Este script NO bloquea por tokens con sufijo _test, _fake, _mock, ni por
13
+ * valores de longitud claramente inválida. Bloquea cuando el valor tiene
14
+ * apariencia estructuralmente válida de credencial real.
15
+ *
16
+ * Propósito: prevenir que fixtures de test con credenciales de apariencia real
17
+ * lleguen a commits y contaminen el .env del usuario o el historial de git.
18
+ * Introducido en v5.12.2 como Fix E.
19
+ *
20
+ * Uso:
21
+ * node scripts/validar-tokens-test.js
22
+ * node scripts/validar-tokens-test.js [directorio]
23
+ *
24
+ * Salida:
25
+ * 0 — ningún problema encontrado
26
+ * 1 — se encontraron literales de credencial con apariencia real
27
+ */
28
+
29
+ const fs = require('node:fs');
30
+ const path = require('node:path');
31
+
32
+ // ─── Configuración ─────────────────────────────────────────────────────────
33
+
34
+ const DIRECTORIO_DEFAULT = path.join(__dirname, '..', 'tests');
35
+ const EXTENSION = '.test.js';
36
+
37
+ // Comentario de exención explícita — úsalo cuando el valor es intencionalmente
38
+ // similar a un token real (ej: test de validación del formato del token).
39
+ // Ejemplo: const token = '1234567890:AABBCCxyz'; // swl-token-test:ok
40
+ const EXENCION_COMENTARIO = 'swl-token-test:ok';
41
+
42
+ // Regex para detectar un token de bot Telegram con apariencia real:
43
+ // Formato: <dígitos>:<letras_y_símbolos_de_40+chars>
44
+ // Se considera "apariencia real" si la parte hash tiene ≥ 25 caracteres alfanuméricos/guiones/guiones_bajos
45
+ const RX_BOT_TOKEN = /TELEGRAM_BOT_TOKEN\s*=\s*['"]?(\d{8,12}:[A-Za-z0-9_\-]{25,})['"]?/;
46
+
47
+ // Regex para detectar chat ID con apariencia real:
48
+ // Los IDs reales tienen entre 9 y 14 dígitos, con posible prefijo -100 para grupos/canales
49
+ // Un valor de test "real" como -100999888777 tiene 12 dígitos — apariencia válida.
50
+ // Exentar si el valor es claramente sintético (todos los mismos dígitos, ej: -100111111111)
51
+ const RX_CHAT_ID_REAL = /TELEGRAM_CHAT_ID\s*=\s*['"]?(-?[1-9]\d{8,13})['"]?/;
52
+
53
+ // Sufijos que indican que el valor es intencionalmente sintético — no reportar
54
+ // Estos patrones en el token hash indican uso de prueba sin ambigüedad
55
+ const SUFIJOS_SINTETICOS = [
56
+ /^[0-9]+$/, // solo dígitos — no es un token real (que mezcla alfa + guiones)
57
+ /test/i,
58
+ /fake/i,
59
+ /mock/i,
60
+ /dummy/i,
61
+ /placeholder/i,
62
+ /example/i,
63
+ /invalid/i,
64
+ ];
65
+
66
+ // IDs de bot conocidos como fixtures de test del sistema SWL — no son credenciales reales
67
+ // Estos IDs se usan en tests internos y están documentados como fixtures sintéticos.
68
+ const BOT_IDS_SINTETICOS = new Set([
69
+ '7123456789', // ID de fixture SWL-test (introducido en Slice 004, v5.12.0)
70
+ ]);
71
+
72
+ // Chat IDs que son claramente sintéticos por su patrón repetitivo
73
+ const RX_CHAT_ID_SINTETICO = /^-?1+$|^-?0+$|^-?1+0+$|^-?10+$|(\d)\1{4,}/;
74
+
75
+ // Archivos explícitamente exentos (ninguno por ahora)
76
+ const EXENTOS = new Set([]);
77
+
78
+ // ─── Utilidades ────────────────────────────────────────────────────────────
79
+
80
+ /**
81
+ * Recorre un directorio recursivamente y devuelve todos los archivos .test.js
82
+ * @param {string} dir
83
+ * @returns {string[]}
84
+ */
85
+ function obtenerArchivosTest(dir) {
86
+ const resultado = [];
87
+ if (!fs.existsSync(dir)) return resultado;
88
+
89
+ for (const entrada of fs.readdirSync(dir, { withFileTypes: true })) {
90
+ const ruta = path.join(dir, entrada.name);
91
+ if (entrada.isDirectory()) {
92
+ resultado.push(...obtenerArchivosTest(ruta));
93
+ } else if (entrada.isFile() && entrada.name.endsWith(EXTENSION)) {
94
+ resultado.push(ruta);
95
+ }
96
+ }
97
+ return resultado;
98
+ }
99
+
100
+ /**
101
+ * Verifica si el hash de un token parece sintético (no credencial real).
102
+ * @param {string} hash - Parte después de ":" en el token
103
+ * @returns {boolean}
104
+ */
105
+ function esHashSintetico(hash) {
106
+ return SUFIJOS_SINTETICOS.some(rx => rx.test(hash));
107
+ }
108
+
109
+ /**
110
+ * Analiza un archivo de test línea por línea.
111
+ * Devuelve la lista de alertas encontradas.
112
+ *
113
+ * @param {string} rutaArchivo
114
+ * @returns {{ archivo: string, linea: number, tipo: string, valor: string }[]}
115
+ */
116
+ function analizarArchivo(rutaArchivo) {
117
+ const alertas = [];
118
+ const lineas = fs.readFileSync(rutaArchivo, 'utf8').split('\n');
119
+
120
+ for (let i = 0; i < lineas.length; i++) {
121
+ const lineaActual = lineas[i];
122
+
123
+ // Ignorar líneas de comentario puro
124
+ const lineaTrimmed = lineaActual.trim();
125
+ if (lineaTrimmed.startsWith('//') || lineaTrimmed.startsWith('*')) continue;
126
+
127
+ // Verificar exención explícita
128
+ const lineaAnterior = i > 0 ? lineas[i - 1] : '';
129
+ const tieneExencion =
130
+ lineaActual.includes(EXENCION_COMENTARIO) ||
131
+ lineaAnterior.includes(EXENCION_COMENTARIO);
132
+ if (tieneExencion) continue;
133
+
134
+ // Verificar token de bot
135
+ const matchToken = lineaActual.match(RX_BOT_TOKEN);
136
+ if (matchToken) {
137
+ const valorCompleto = matchToken[1]; // <id>:<hash>
138
+ const partesToken = valorCompleto.split(':');
139
+ const botId = partesToken[0] || '';
140
+ const hash = partesToken[1] || '';
141
+ if (!esHashSintetico(hash) && !BOT_IDS_SINTETICOS.has(botId)) {
142
+ alertas.push({
143
+ archivo: rutaArchivo,
144
+ linea: i + 1,
145
+ tipo: 'TELEGRAM_BOT_TOKEN',
146
+ valor: valorCompleto.substring(0, 20) + '...',
147
+ });
148
+ }
149
+ }
150
+
151
+ // Verificar chat ID
152
+ const matchChatId = lineaActual.match(RX_CHAT_ID_REAL);
153
+ if (matchChatId) {
154
+ const valorChatId = matchChatId[1];
155
+ if (!RX_CHAT_ID_SINTETICO.test(valorChatId)) {
156
+ alertas.push({
157
+ archivo: rutaArchivo,
158
+ linea: i + 1,
159
+ tipo: 'TELEGRAM_CHAT_ID',
160
+ valor: valorChatId,
161
+ });
162
+ }
163
+ }
164
+ }
165
+
166
+ return alertas;
167
+ }
168
+
169
+ // ─── Main ───────────────────────────────────────────────────────────────────
170
+
171
+ function main() {
172
+ const args = process.argv.slice(2);
173
+ const directorio = args[0] ? path.resolve(args[0]) : DIRECTORIO_DEFAULT;
174
+
175
+ console.log(`Validando tokens en archivos de test: ${directorio}`);
176
+ console.log(`Buscando literales TELEGRAM_BOT_TOKEN/CHAT_ID con apariencia real...\n`);
177
+
178
+ const archivos = obtenerArchivosTest(directorio);
179
+ const todasAlertas = [];
180
+
181
+ for (const archivo of archivos) {
182
+ if (EXENTOS.has(path.basename(archivo))) continue;
183
+ const alertas = analizarArchivo(archivo);
184
+ todasAlertas.push(...alertas);
185
+ }
186
+
187
+ if (todasAlertas.length === 0) {
188
+ console.log(`OK: ${archivos.length} archivo(s) analizados — ningún token de apariencia real encontrado.`);
189
+ process.exit(0);
190
+ }
191
+
192
+ console.error(`ERROR: Se encontraron ${todasAlertas.length} literal(es) de credencial con apariencia real:\n`);
193
+ for (const a of todasAlertas) {
194
+ const rutaRelativa = path.relative(process.cwd(), a.archivo);
195
+ console.error(` ${rutaRelativa}:${a.linea}`);
196
+ console.error(` → ${a.tipo} = ${a.valor}`);
197
+ console.error('');
198
+ }
199
+ console.error(
200
+ 'Si el valor es intencionalmente sintético, agregar comentario en la misma línea:\n' +
201
+ ` // ${EXENCION_COMENTARIO}\n` +
202
+ 'Ver scripts/lib/notificaciones-telegram.js para referencia de fixtures de test seguros.\n' +
203
+ 'Si es una credencial real filtrada: rotar el token en BotFather INMEDIATAMENTE.'
204
+ );
205
+ process.exit(1);
206
+ }
207
+
208
+ main();
@@ -0,0 +1,147 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Validación básica de la estructura del paquete SWL.
5
+ * Ejecuta con: npm test
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const RAIZ = path.resolve(__dirname, '..');
12
+ let errores = 0;
13
+
14
+ function verificar(condicion, mensaje) {
15
+ if (condicion) {
16
+ console.log(` [OK] ${mensaje}`);
17
+ } else {
18
+ console.log(` [FALLA] ${mensaje}`);
19
+ errores++;
20
+ }
21
+ }
22
+
23
+ console.log('Validando estructura SWL...\n');
24
+
25
+ // 1. package.json
26
+ const pkg = require('../package.json');
27
+ const { NOMBRES_VALIDOS } = require('./lib/paquetes-conocidos');
28
+ verificar(
29
+ NOMBRES_VALIDOS.includes(pkg.name),
30
+ `package.json: nombre correcto (esperado uno de ${JSON.stringify(NOMBRES_VALIDOS)}; actual: ${pkg.name})`
31
+ );
32
+ verificar(pkg.bin && pkg.bin['swl-ses'], 'package.json: bin swl-ses definido');
33
+ verificar(pkg.engines && pkg.engines.node, 'package.json: engine de node definido');
34
+
35
+ // 2. CLI
36
+ verificar(fs.existsSync(path.join(RAIZ, 'bin', 'swl-ses.js')), 'bin/swl-ses.js existe');
37
+
38
+ // 3. Scripts
39
+ const scriptsRequeridos = ['inicializar.js', 'instalador.js', 'doctor.js', 'actualizar.js', 'desinstalar.js'];
40
+ for (const s of scriptsRequeridos) {
41
+ verificar(fs.existsSync(path.join(RAIZ, 'scripts', s)), `scripts/${s} existe`);
42
+ }
43
+
44
+ // 4. Manifiestos
45
+ const manifiestosRequeridos = ['perfiles.json', 'modulos.json', 'hooks-config.json'];
46
+ for (const m of manifiestosRequeridos) {
47
+ verificar(fs.existsSync(path.join(RAIZ, 'manifiestos', m)), `manifiestos/${m} existe`);
48
+ }
49
+
50
+ // 4b. Validar hooks-config.json tiene entradas para cada hook
51
+ const hooksConfigPath = path.join(RAIZ, 'manifiestos', 'hooks-config.json');
52
+ if (fs.existsSync(hooksConfigPath)) {
53
+ const hooksConfig = JSON.parse(fs.readFileSync(hooksConfigPath, 'utf-8'));
54
+ const hooksEnConfig = Object.keys(hooksConfig.hooks || {});
55
+ verificar(hooksEnConfig.length >= 4, `hooks-config.json: ${hooksEnConfig.length} hooks definidos (mínimo 4)`);
56
+ for (const hookName of hooksEnConfig) {
57
+ const hc = hooksConfig.hooks[hookName];
58
+ const eventosValidos = ['PreToolUse', 'PostToolUse', 'Stop', 'Notification', 'SubagentStop', 'UserPromptSubmit', 'PreCompact', 'SessionStart'];
59
+ verificar(
60
+ eventosValidos.includes(hc.event),
61
+ `hooks-config.json: ${hookName} tiene event válido (${hc.event})`
62
+ );
63
+ }
64
+ }
65
+
66
+ // 5. Agentes (mínimo 12)
67
+ const agentes = fs.readdirSync(path.join(RAIZ, 'agentes')).filter(f => f.endsWith('.md'));
68
+ verificar(agentes.length >= 12, `Agentes: ${agentes.length} (mínimo 12)`);
69
+
70
+ // Verificar frontmatter en agentes
71
+ for (const agente of agentes) {
72
+ const contenido = fs.readFileSync(path.join(RAIZ, 'agentes', agente), 'utf-8');
73
+ verificar(contenido.startsWith('---'), `${agente}: tiene frontmatter YAML`);
74
+ verificar(contenido.includes('name:'), `${agente}: tiene campo name`);
75
+ verificar(contenido.includes('description:'), `${agente}: tiene campo description`);
76
+ }
77
+
78
+ // 6. Habilidades (mínimo 25)
79
+ const habilidades = fs.readdirSync(path.join(RAIZ, 'habilidades'))
80
+ .filter(h => {
81
+ const skillPath = path.join(RAIZ, 'habilidades', h, 'SKILL.md');
82
+ return fs.existsSync(skillPath);
83
+ });
84
+ verificar(habilidades.length >= 25, `Habilidades: ${habilidades.length} (mínimo 25)`);
85
+
86
+ // 7. Comandos
87
+ const comandos = fs.readdirSync(path.join(RAIZ, 'comandos', 'swl')).filter(f => f.endsWith('.md'));
88
+ verificar(comandos.length >= 9, `Comandos: ${comandos.length} (mínimo 9)`);
89
+
90
+ // 8. Reglas
91
+ const reglas = fs.readdirSync(path.join(RAIZ, 'reglas')).filter(f => f.endsWith('.md'));
92
+ verificar(reglas.length >= 7, `Reglas: ${reglas.length} (mínimo 7)`);
93
+
94
+ // 9. Hooks
95
+ const hooks = fs.readdirSync(path.join(RAIZ, 'hooks')).filter(f => f.endsWith('.js'));
96
+ verificar(hooks.length >= 4, `Hooks: ${hooks.length} (mínimo 4)`);
97
+
98
+ // 10. Plantillas
99
+ verificar(fs.existsSync(path.join(RAIZ, 'plantillas', 'PROYECTO.md')), 'plantillas/PROYECTO.md existe');
100
+ verificar(fs.existsSync(path.join(RAIZ, 'plantillas', 'ESTADO.md')), 'plantillas/ESTADO.md existe');
101
+
102
+ // 11. plugin.json
103
+ const pluginPath = path.join(RAIZ, 'plugin.json');
104
+ verificar(fs.existsSync(pluginPath), 'plugin.json existe');
105
+ if (fs.existsSync(pluginPath)) {
106
+ const plugin = JSON.parse(fs.readFileSync(pluginPath, 'utf-8'));
107
+ verificar(plugin.skills && plugin.skills.length >= 25, `plugin.json: ${(plugin.skills || []).length} skills registrados`);
108
+ verificar(plugin.agents && plugin.agents.length >= 12, `plugin.json: ${(plugin.agents || []).length} agentes registrados`);
109
+ verificar(plugin.hooks && plugin.hooks.PreToolUse, 'plugin.json: tiene hooks PreToolUse');
110
+ verificar(plugin.hooks && plugin.hooks.PostToolUse, 'plugin.json: tiene hooks PostToolUse');
111
+ }
112
+
113
+ // 12. CLAUDE.md
114
+ verificar(fs.existsSync(path.join(RAIZ, 'CLAUDE.md')), 'CLAUDE.md existe');
115
+
116
+ // 13. Memoria consolidada
117
+ const memRule = path.join(RAIZ, 'reglas', 'memoria-consolidada.md');
118
+ verificar(fs.existsSync(memRule), 'reglas/memoria-consolidada.md existe');
119
+
120
+ // 14. Validación de memoria: ejecuta validar-memoria.js
121
+ try {
122
+ const { execSync } = require('child_process');
123
+ const memoria = path.join(RAIZ, 'scripts', 'validar-memoria.js');
124
+ if (fs.existsSync(memoria)) {
125
+ try {
126
+ execSync(`node "${memoria}" --json`, { stdio: 'pipe' });
127
+ verificar(true, 'Memoria consolidada: sin violaciones');
128
+ } catch (e) {
129
+ const exitCode = e.status;
130
+ if (exitCode === 2) {
131
+ verificar(false, 'Memoria consolidada: violaciones CRÍTICAS (posibles secretos)');
132
+ } else if (exitCode === 1) {
133
+ verificar(true, "Memoria consolidada: warnings no críticos — ver 'node scripts/validar-memoria.js'");
134
+ } else {
135
+ verificar(true, 'Memoria consolidada: sin violaciones');
136
+ }
137
+ }
138
+ }
139
+ } catch { /* ignore */ }
140
+
141
+ console.log('\n' + '='.repeat(40));
142
+ if (errores === 0) {
143
+ console.log('Todas las validaciones pasaron.');
144
+ } else {
145
+ console.log(`${errores} validaciones fallaron.`);
146
+ process.exit(1);
147
+ }
@@ -0,0 +1,339 @@
1
+ """
2
+ validate-markdown.py — Validador de sintaxis Markdown para skills del sistema SWL
3
+
4
+ Uso:
5
+ python scripts/validate-markdown.py # valida todos los .md
6
+ python scripts/validate-markdown.py --path habilidades/django-experto/SKILL.md
7
+ python scripts/validate-markdown.py --check # modo CI: exit 1 si hay errores
8
+
9
+ Valida SKILL.md y recursos/*.md de todas las habilidades en ../habilidades.
10
+ Exit code 0 = éxito o solo advertencias; 1 = hay errores.
11
+ """
12
+
13
+ import argparse
14
+ import re
15
+ import sys
16
+ from pathlib import Path
17
+
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Constantes
21
+ # ---------------------------------------------------------------------------
22
+ REGEX_APERTURA_BLOQUE = re.compile(r"^```(\w*)\s*$")
23
+ REGEX_CIERRE_BLOQUE = re.compile(r"^```\s*$")
24
+ REGEX_FILA_TABLA = re.compile(r"^\s*\|.*\|\s*$")
25
+ REGEX_SEPARADOR_TABLA = re.compile(r"^\s*\|[\s|:\-]+\|\s*$")
26
+ REGEX_COMENTARIO_HTML = re.compile(r"<!--.*?-->", re.DOTALL)
27
+ REGEX_ENCABEZADO = re.compile(r"^(#{1,6})\s+\S")
28
+
29
+
30
+ # ---------------------------------------------------------------------------
31
+ # Tipos de resultado
32
+ # ---------------------------------------------------------------------------
33
+ def _problema(tipo: str, codigo: str, linea: int | None, mensaje: str) -> dict:
34
+ return {"type": tipo, "code": codigo, "line": linea, "message": mensaje}
35
+
36
+
37
+ def _error(codigo: str, linea: int | None, mensaje: str) -> dict:
38
+ return _problema("error", codigo, linea, mensaje)
39
+
40
+
41
+ def _advertencia(codigo: str, linea: int | None, mensaje: str) -> dict:
42
+ return _problema("warning", codigo, linea, mensaje)
43
+
44
+
45
+ # ---------------------------------------------------------------------------
46
+ # Validación de bloques de código
47
+ # ---------------------------------------------------------------------------
48
+ def _validar_bloques_codigo(lineas: list[str]) -> list[dict]:
49
+ issues: list[dict] = []
50
+ dentro_bloque = False
51
+ linea_apertura = 0
52
+
53
+ for i, linea in enumerate(lineas, start=1):
54
+ if not dentro_bloque:
55
+ if REGEX_APERTURA_BLOQUE.match(linea):
56
+ dentro_bloque = True
57
+ linea_apertura = i
58
+ else:
59
+ if REGEX_CIERRE_BLOQUE.match(linea):
60
+ dentro_bloque = False
61
+
62
+ if dentro_bloque:
63
+ issues.append(_error(
64
+ "UNCLOSED_CODE_BLOCK",
65
+ linea_apertura,
66
+ f"Bloque de codigo abierto en linea {linea_apertura} nunca se cierra"
67
+ ))
68
+
69
+ return issues
70
+
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Validación de tablas
74
+ # ---------------------------------------------------------------------------
75
+ def _contar_columnas(fila: str) -> int:
76
+ """Cuenta el número de columnas en una fila de tabla Markdown."""
77
+ fila = fila.strip()
78
+ if fila.startswith("|"):
79
+ fila = fila[1:]
80
+ if fila.endswith("|"):
81
+ fila = fila[:-1]
82
+ return len(fila.split("|"))
83
+
84
+
85
+ def _validar_tablas(lineas: list[str]) -> list[dict]:
86
+ issues: list[dict] = []
87
+ dentro_bloque = False
88
+ i = 0
89
+
90
+ while i < len(lineas):
91
+ linea = lineas[i]
92
+ num_linea = i + 1
93
+
94
+ # No validar tablas dentro de bloques de código
95
+ if not dentro_bloque and REGEX_APERTURA_BLOQUE.match(linea):
96
+ dentro_bloque = True
97
+ elif dentro_bloque and REGEX_CIERRE_BLOQUE.match(linea):
98
+ dentro_bloque = False
99
+ elif not dentro_bloque and REGEX_FILA_TABLA.match(linea):
100
+ # Inicio potencial de tabla: fila de encabezado
101
+ fila_encabezado = linea
102
+ num_cols_encabezado = _contar_columnas(fila_encabezado)
103
+ num_linea_encabezado = num_linea
104
+
105
+ # Verificar si la siguiente línea es el separador
106
+ if i + 1 < len(lineas):
107
+ linea_siguiente = lineas[i + 1]
108
+ if not REGEX_SEPARADOR_TABLA.match(linea_siguiente):
109
+ # Puede ser tabla sin separador solo si la línea siguiente también es fila de tabla
110
+ if REGEX_FILA_TABLA.match(linea_siguiente):
111
+ issues.append(_error(
112
+ "TABLE_MISSING_SEPARATOR",
113
+ num_linea,
114
+ f"Tabla en linea {num_linea} no tiene separador (segunda fila debe tener |---|)"
115
+ ))
116
+ else:
117
+ # Tiene separador: avanzar y validar columnas del resto
118
+ i += 2 # saltar encabezado y separador
119
+ while i < len(lineas) and REGEX_FILA_TABLA.match(lineas[i]):
120
+ num_cols_fila = _contar_columnas(lineas[i])
121
+ if num_cols_fila != num_cols_encabezado:
122
+ issues.append(_error(
123
+ "TABLE_INCONSISTENT_COLUMNS",
124
+ i + 1,
125
+ f"Fila {i + 1} de tabla tiene {num_cols_fila} columna(s) "
126
+ f"pero el encabezado (linea {num_linea_encabezado}) define {num_cols_encabezado}"
127
+ ))
128
+ # Advertencia: comentarios HTML dentro de celdas de tabla
129
+ if REGEX_COMENTARIO_HTML.search(lineas[i]):
130
+ issues.append(_advertencia(
131
+ "HTML_COMMENT_IN_TABLE",
132
+ i + 1,
133
+ f"Comentario HTML en fila {i + 1} de tabla; puede romper el parsing en algunas herramientas"
134
+ ))
135
+ i += 1
136
+ continue # ya avanzamos manualmente
137
+
138
+ i += 1
139
+
140
+ return issues
141
+
142
+
143
+ # ---------------------------------------------------------------------------
144
+ # Validación de encabezados (salto de nivel)
145
+ # ---------------------------------------------------------------------------
146
+ def _validar_encabezados(lineas: list[str]) -> list[dict]:
147
+ issues: list[dict] = []
148
+ dentro_bloque = False
149
+ nivel_anterior = 0
150
+
151
+ for i, linea in enumerate(lineas, start=1):
152
+ if not dentro_bloque and REGEX_APERTURA_BLOQUE.match(linea):
153
+ dentro_bloque = True
154
+ continue
155
+ if dentro_bloque and REGEX_CIERRE_BLOQUE.match(linea):
156
+ dentro_bloque = False
157
+ continue
158
+ if dentro_bloque:
159
+ continue
160
+
161
+ m = REGEX_ENCABEZADO.match(linea)
162
+ if m:
163
+ nivel_actual = len(m.group(1))
164
+ if nivel_anterior > 0 and nivel_actual > nivel_anterior + 1:
165
+ issues.append(_advertencia(
166
+ "HEADING_LEVEL_SKIP",
167
+ i,
168
+ f"Encabezado salta de H{nivel_anterior} a H{nivel_actual} en linea {i} "
169
+ f"(se omite H{nivel_anterior + 1})"
170
+ ))
171
+ nivel_anterior = nivel_actual
172
+
173
+ return issues
174
+
175
+
176
+ # ---------------------------------------------------------------------------
177
+ # Validación de un archivo individual
178
+ # ---------------------------------------------------------------------------
179
+ def validar_archivo(ruta: Path) -> dict:
180
+ """
181
+ Valida un archivo Markdown.
182
+ Devuelve dict con claves: archivo, status, issues.
183
+ """
184
+ issues: list[dict] = []
185
+
186
+ if not ruta.exists():
187
+ return {
188
+ "archivo": str(ruta),
189
+ "status": "error",
190
+ "issues": [_error("FILE_NOT_FOUND", None, f"Archivo no encontrado: {ruta}")]
191
+ }
192
+
193
+ contenido = ruta.read_text(encoding="utf-8", errors="replace")
194
+ lineas = contenido.splitlines()
195
+
196
+ issues.extend(_validar_bloques_codigo(lineas))
197
+ issues.extend(_validar_tablas(lineas))
198
+ issues.extend(_validar_encabezados(lineas))
199
+
200
+ tiene_error = any(i["type"] == "error" for i in issues)
201
+ tiene_advertencia = any(i["type"] == "warning" for i in issues)
202
+
203
+ if tiene_error:
204
+ estado = "error"
205
+ elif tiene_advertencia:
206
+ estado = "warning"
207
+ else:
208
+ estado = "ok"
209
+
210
+ return {"archivo": str(ruta), "status": estado, "issues": issues}
211
+
212
+
213
+ # ---------------------------------------------------------------------------
214
+ # Recolección de archivos a validar
215
+ # ---------------------------------------------------------------------------
216
+ def recolectar_archivos_markdown(dir_habilidades: Path) -> list[Path]:
217
+ """Devuelve todos los SKILL.md y recursos/*.md bajo dir_habilidades."""
218
+ archivos: list[Path] = []
219
+
220
+ for skill_dir in sorted(dir_habilidades.iterdir()):
221
+ if not skill_dir.is_dir():
222
+ continue
223
+
224
+ skill_md = skill_dir / "SKILL.md"
225
+ if skill_md.exists():
226
+ archivos.append(skill_md)
227
+
228
+ recursos_dir = skill_dir / "recursos"
229
+ if recursos_dir.is_dir():
230
+ for archivo in sorted(recursos_dir.iterdir()):
231
+ if archivo.suffix.lower() == ".md":
232
+ archivos.append(archivo)
233
+
234
+ return archivos
235
+
236
+
237
+ # ---------------------------------------------------------------------------
238
+ # Presentación de resultados
239
+ # ---------------------------------------------------------------------------
240
+ def _iconos() -> dict[str, str]:
241
+ """Devuelve iconos Unicode si el terminal los soporta, ASCII en caso contrario."""
242
+ enc = getattr(sys.stdout, "encoding", "") or ""
243
+ if enc.lower().replace("-", "") in ("utf8", "utf16", "utf32"):
244
+ return {"ok": "\u2713", "warning": "\u26a0", "error": "\u2717"}
245
+ return {"ok": "[OK]", "warning": "[WARN]", "error": "[ERR]"}
246
+
247
+
248
+ def imprimir_resultado_normal(resultado: dict, raiz: Path, iconos: dict[str, str]) -> None:
249
+ """Imprime el resultado de un archivo, mostrando la ruta relativa a raiz."""
250
+ ruta_abs = Path(resultado["archivo"])
251
+ try:
252
+ ruta_mostrar = ruta_abs.relative_to(raiz)
253
+ except ValueError:
254
+ ruta_mostrar = ruta_abs
255
+
256
+ estado = resultado["status"]
257
+ icono = iconos.get(estado, "?")
258
+ issues = resultado["issues"]
259
+
260
+ if estado == "ok":
261
+ print(f"{icono} {ruta_mostrar} - OK")
262
+ else:
263
+ for issue in issues:
264
+ prefijo = "ERROR" if issue["type"] == "error" else "ADVERTENCIA"
265
+ ref_linea = f" (linea {issue['line']})" if issue.get("line") else ""
266
+ print(f"{icono} {ruta_mostrar}{ref_linea} - {prefijo}: {issue['message']}")
267
+
268
+
269
+ # ---------------------------------------------------------------------------
270
+ # Punto de entrada
271
+ # ---------------------------------------------------------------------------
272
+ def main() -> int:
273
+ parser = argparse.ArgumentParser(
274
+ description="Validador de sintaxis Markdown para skills del sistema SWL"
275
+ )
276
+ parser.add_argument(
277
+ "--path",
278
+ metavar="RUTA",
279
+ help="Validar un archivo Markdown específico"
280
+ )
281
+ parser.add_argument(
282
+ "--check",
283
+ action="store_true",
284
+ help="Modo CI: exit 1 si hay errores"
285
+ )
286
+ args = parser.parse_args()
287
+
288
+ raiz = Path(__file__).parent.parent
289
+ dir_habilidades = raiz / "habilidades"
290
+
291
+ if args.path:
292
+ # Ruta puede ser relativa a la raíz del proyecto o absoluta
293
+ ruta_archivo = Path(args.path)
294
+ if not ruta_archivo.is_absolute():
295
+ ruta_archivo = raiz / ruta_archivo
296
+ archivos = [ruta_archivo]
297
+ else:
298
+ if not dir_habilidades.is_dir():
299
+ print(
300
+ f"ERROR: Directorio de habilidades no encontrado: {dir_habilidades}",
301
+ file=sys.stderr
302
+ )
303
+ return 1
304
+ archivos = recolectar_archivos_markdown(dir_habilidades)
305
+
306
+ if not archivos:
307
+ print("No se encontraron archivos Markdown para validar.")
308
+ return 0
309
+
310
+ resultados: list[dict] = []
311
+ for ruta in archivos:
312
+ resultado = validar_archivo(ruta)
313
+ resultados.append(resultado)
314
+
315
+ # Contadores
316
+ n_ok = sum(1 for r in resultados if r["status"] == "ok")
317
+ n_warnings = sum(1 for r in resultados if r["status"] == "warning")
318
+ n_errors = sum(1 for r in resultados if r["status"] == "error")
319
+
320
+ iconos = _iconos()
321
+ for resultado in resultados:
322
+ imprimir_resultado_normal(resultado, raiz, iconos)
323
+
324
+ total = len(resultados)
325
+ partes = [f"{total} archivo(s) validado(s)", f"{n_ok} OK"]
326
+ if n_warnings:
327
+ partes.append(f"{n_warnings} advertencia(s)")
328
+ if n_errors:
329
+ partes.append(f"{n_errors} error(es)")
330
+ print(f"\nResumen: {', '.join(partes)}")
331
+
332
+ if args.check and n_errors > 0:
333
+ return 1
334
+
335
+ return 0
336
+
337
+
338
+ if __name__ == "__main__":
339
+ sys.exit(main())