@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,360 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Generador de LaunchAgent plist para el daemon swl-telegram-bot en macOS.
5
+ *
6
+ * SEGURIDAD:
7
+ * - NUNCA escribe en ~/Library/LaunchDaemons — eso requiere root.
8
+ * Solo LaunchAgents (nivel usuario, sin privilegios de sistema).
9
+ * - NUNCA hardcodea rutas absolutas. Resuelve bin/ con __dirname en runtime.
10
+ * - NUNCA incluye credenciales en el plist — las credenciales viven en .env.
11
+ * - Solo opera en process.platform === 'darwin'. Otros OS reciben error explícito.
12
+ *
13
+ * Rollback manual (si algo sale mal):
14
+ * launchctl unload -w ~/Library/LaunchAgents/com.swl.telegram-bot.plist
15
+ * rm ~/Library/LaunchAgents/com.swl.telegram-bot.plist
16
+ *
17
+ * @module scripts/lib/autostart-macos
18
+ */
19
+
20
+ const { execFileSync } = require('node:child_process');
21
+ const path = require('node:path');
22
+ const fs = require('node:fs');
23
+ const os = require('node:os');
24
+
25
+ const LABEL_PLIST = 'com.swl.telegram-bot';
26
+ const NOMBRE_PLIST = `${LABEL_PLIST}.plist`;
27
+
28
+ // Ruta del log de autostart — diagnóstico humano sin secrets
29
+ const RUTA_LOG_AUTOSTART = path.join(
30
+ os.homedir(), '.claude', 'notifications', 'autostart.log'
31
+ );
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Helpers
35
+ // ---------------------------------------------------------------------------
36
+
37
+ /**
38
+ * Escribe una línea al log de autostart.
39
+ * @param {string} nivel
40
+ * @param {string} mensaje
41
+ */
42
+ function _log(nivel, mensaje) {
43
+ const linea = `[${new Date().toISOString()}] [${nivel}] [macos] ${mensaje}\n`;
44
+ try {
45
+ const dir = path.dirname(RUTA_LOG_AUTOSTART);
46
+ if (!fs.existsSync(dir)) {
47
+ fs.mkdirSync(dir, { recursive: true });
48
+ }
49
+ fs.appendFileSync(RUTA_LOG_AUTOSTART, linea, 'utf8');
50
+ } catch (_) {}
51
+ process.stderr.write(linea);
52
+ }
53
+
54
+ /**
55
+ * REM-6: Valida que una ruta no contiene caracteres peligrosos que podrían
56
+ * inyectarse en el contenido del plist XML (caracteres de control, XML especiales,
57
+ * nuevas líneas).
58
+ *
59
+ * Previene que un path manipulado rompa el XML del plist o inyecte etiquetas.
60
+ *
61
+ * @param {string} ruta - Ruta a validar.
62
+ * @returns {boolean} true si la ruta es segura para incluir en el plist.
63
+ */
64
+ function _validarRutaSegura(ruta) {
65
+ if (typeof ruta !== 'string' || ruta.trim() === '') return false;
66
+ // Rechazar caracteres de control (incluye \n, \r, \t) y caracteres XML especiales
67
+ // que podrían romper el formato INI del unit o el XML de un plist.
68
+ // eslint-disable-next-line no-control-regex
69
+ const RX_PELIGROSOS = /[\x00-\x1F\x7F<>&"']/;
70
+ return !RX_PELIGROSOS.test(ruta);
71
+ }
72
+
73
+ /**
74
+ * Construye la ruta absoluta al daemon bin/swl-telegram-bot.js
75
+ * a partir de __dirname (scripts/lib/), NO hardcodeada.
76
+ *
77
+ * @returns {string} Ruta absoluta resuelta con path.resolve.
78
+ */
79
+ function _rutaDaemon() {
80
+ return path.resolve(__dirname, '..', '..', 'bin', 'swl-telegram-bot.js');
81
+ }
82
+
83
+ /**
84
+ * Ruta del directorio ~/Library/LaunchAgents.
85
+ * @returns {string}
86
+ */
87
+ function _dirLaunchAgents() {
88
+ return path.join(os.homedir(), 'Library', 'LaunchAgents');
89
+ }
90
+
91
+ /**
92
+ * Ruta del archivo plist instalado.
93
+ * @returns {string}
94
+ */
95
+ function _rutaPlistInstalado() {
96
+ return path.join(_dirLaunchAgents(), NOMBRE_PLIST);
97
+ }
98
+
99
+ /**
100
+ * Valida que estamos en macOS.
101
+ * @returns {{ ok: false, error: string } | null} null si OK, error si no.
102
+ */
103
+ function _validarPlatform() {
104
+ if (process.platform !== 'darwin') {
105
+ return {
106
+ ok: false,
107
+ error: `autostart-macos solo aplica en macOS (plataforma detectada: ${process.platform})`,
108
+ };
109
+ }
110
+ return null;
111
+ }
112
+
113
+ /**
114
+ * Ejecuta launchctl de forma segura (sin shell).
115
+ *
116
+ * @param {string[]} args - Argumentos para launchctl.
117
+ * @returns {{ ok: boolean, stdout?: string, error?: string }}
118
+ */
119
+ function _ejecutarLaunchctl(...args) {
120
+ try {
121
+ const stdout = execFileSync(
122
+ 'launchctl',
123
+ args,
124
+ {
125
+ encoding: 'utf8',
126
+ timeout: 30_000,
127
+ // NUNCA shell: true
128
+ }
129
+ );
130
+ return { ok: true, stdout: (stdout || '').trim() };
131
+ } catch (err) {
132
+ return { ok: false, error: (err.stderr || err.message || '').trim() };
133
+ }
134
+ }
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // Generador de template
138
+ // ---------------------------------------------------------------------------
139
+
140
+ /**
141
+ * Genera el contenido del plist con los paths resueltos en runtime.
142
+ *
143
+ * El XML resultante es válido para launchd:
144
+ * - RunAtLoad: arranca al cargar el agent (login)
145
+ * - KeepAlive: relanza si el proceso muere
146
+ * - ProgramArguments: [nodePath, binPath]
147
+ * - Stdout/Stderr a archivos de log separados
148
+ *
149
+ * @param {string} nodePath - Ruta absoluta al ejecutable node.
150
+ * @param {string} binPath - Ruta absoluta al daemon.
151
+ * @param {string} homeDir - Directorio home del usuario.
152
+ * @returns {string} Contenido XML del plist.
153
+ */
154
+ function generarContenidoPlist(nodePath, binPath, homeDir) {
155
+ const logDir = path.join(homeDir, '.claude', 'notifications');
156
+ return [
157
+ '<?xml version="1.0" encoding="UTF-8"?>',
158
+ '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
159
+ '<plist version="1.0">',
160
+ '<dict>',
161
+ ' <key>Label</key>',
162
+ ` <string>${LABEL_PLIST}</string>`,
163
+ ' <key>ProgramArguments</key>',
164
+ ' <array>',
165
+ ` <string>${nodePath}</string>`,
166
+ ` <string>${binPath}</string>`,
167
+ ' </array>',
168
+ ' <key>RunAtLoad</key>',
169
+ ' <true/>',
170
+ ' <key>KeepAlive</key>',
171
+ ' <true/>',
172
+ ' <key>StandardOutPath</key>',
173
+ ` <string>${logDir}/bot.stdout.log</string>`,
174
+ ' <key>StandardErrorPath</key>',
175
+ ` <string>${logDir}/bot.stderr.log</string>`,
176
+ '</dict>',
177
+ '</plist>',
178
+ '',
179
+ ].join('\n');
180
+ }
181
+
182
+ // ---------------------------------------------------------------------------
183
+ // API pública
184
+ // ---------------------------------------------------------------------------
185
+
186
+ /**
187
+ * Instala el LaunchAgent plist y lo carga con launchctl.
188
+ *
189
+ * Idempotente: si el plist ya existe, lo reemplaza y recarga.
190
+ *
191
+ * @returns {{ ok: boolean, mensaje?: string, error?: string }}
192
+ */
193
+ function install() {
194
+ const platErr = _validarPlatform();
195
+ if (platErr) return platErr;
196
+
197
+ const rutaDaemon = _rutaDaemon();
198
+ _log('INFO', `Instalando LaunchAgent "${LABEL_PLIST}" → ${rutaDaemon}`);
199
+
200
+ // Verificar que el daemon existe
201
+ if (!fs.existsSync(rutaDaemon)) {
202
+ const error = `El daemon no existe: ${rutaDaemon}. Verifica la instalación de swl-ses.`;
203
+ _log('ERROR', error);
204
+ return { ok: false, error };
205
+ }
206
+
207
+ // Resolver el ejecutable de node
208
+ let nodePath;
209
+ try {
210
+ nodePath = execFileSync('which', ['node'], { encoding: 'utf8', timeout: 5000 }).trim();
211
+ } catch (_) {
212
+ nodePath = process.execPath;
213
+ }
214
+
215
+ if (!nodePath || !fs.existsSync(nodePath)) {
216
+ const error = `node no encontrado en PATH. Instala Node.js antes de activar el autostart. Intentado: ${nodePath}`;
217
+ _log('ERROR', error);
218
+ return { ok: false, error };
219
+ }
220
+
221
+ // REM-6: validar que los paths no tienen caracteres peligrosos antes de
222
+ // incluirlos en el plist XML. Previene inyección de etiquetas XML.
223
+ if (!_validarRutaSegura(nodePath) || !_validarRutaSegura(rutaDaemon)) {
224
+ const error = 'Ruta con caracteres no permitidos — abortando generación del plist.';
225
+ _log('ERROR', error);
226
+ return { ok: false, error };
227
+ }
228
+
229
+ // Generar contenido del plist
230
+ const homeDir = os.homedir();
231
+ const contenido = generarContenidoPlist(nodePath, rutaDaemon, homeDir);
232
+ const dirAgents = _dirLaunchAgents();
233
+ const rutaPlist = _rutaPlistInstalado();
234
+
235
+ // Crear directorio si no existe (puede no existir en instalaciones limpias)
236
+ if (!fs.existsSync(dirAgents)) {
237
+ try {
238
+ fs.mkdirSync(dirAgents, { recursive: true });
239
+ } catch (err) {
240
+ const error = `No se pudo crear ${dirAgents}: ${err.message}`;
241
+ _log('ERROR', error);
242
+ return { ok: false, error };
243
+ }
244
+ }
245
+
246
+ // Si ya existe un plist cargado, descargarlo primero para evitar conflicto
247
+ const estadoPrev = status();
248
+ if (estadoPrev.cargado) {
249
+ _log('INFO', 'Descargando LaunchAgent previo antes de reemplazarlo...');
250
+ _ejecutarLaunchctl('unload', '-w', rutaPlist);
251
+ }
252
+
253
+ // Escribir el plist
254
+ try {
255
+ fs.writeFileSync(rutaPlist, contenido, 'utf8');
256
+ _log('INFO', `Plist escrito en: ${rutaPlist}`);
257
+ } catch (err) {
258
+ const error = `No se pudo escribir el plist: ${err.message}`;
259
+ _log('ERROR', error);
260
+ return { ok: false, error };
261
+ }
262
+
263
+ // Cargar con launchctl load -w
264
+ _log('INFO', 'Ejecutando launchctl load -w...');
265
+ const loadRes = _ejecutarLaunchctl('load', '-w', rutaPlist);
266
+ if (!loadRes.ok) {
267
+ const error = `launchctl load -w falló: ${loadRes.error}`;
268
+ _log('ERROR', error);
269
+ return { ok: false, error };
270
+ }
271
+
272
+ // Verificar estado
273
+ const estadoActual = status();
274
+ _log('INFO', `LaunchAgent cargado — instalado: ${estadoActual.instalado}, cargado: ${estadoActual.cargado}`);
275
+
276
+ return {
277
+ ok: true,
278
+ mensaje: `LaunchAgent "${LABEL_PLIST}" instalado y cargado. Arrancará al próximo login. Cargado ahora: ${estadoActual.cargado}.`,
279
+ };
280
+ }
281
+
282
+ /**
283
+ * Descarga y elimina el LaunchAgent.
284
+ *
285
+ * Idempotente: si el plist no existe, devuelve ok:true con mensaje informativo.
286
+ *
287
+ * @returns {{ ok: boolean, mensaje?: string, error?: string }}
288
+ */
289
+ function uninstall() {
290
+ const platErr = _validarPlatform();
291
+ if (platErr) return platErr;
292
+
293
+ _log('INFO', `Desinstalando LaunchAgent "${LABEL_PLIST}"...`);
294
+
295
+ const rutaPlist = _rutaPlistInstalado();
296
+
297
+ // Si no hay plist instalado, idempotente
298
+ if (!fs.existsSync(rutaPlist)) {
299
+ _log('INFO', `El plist "${NOMBRE_PLIST}" no estaba instalado — nada que hacer.`);
300
+ return { ok: true, mensaje: `no había LaunchAgent "${LABEL_PLIST}" instalado` };
301
+ }
302
+
303
+ // Descargar con launchctl unload -w
304
+ _log('INFO', 'Ejecutando launchctl unload -w...');
305
+ const unloadRes = _ejecutarLaunchctl('unload', '-w', rutaPlist);
306
+ if (!unloadRes.ok) {
307
+ _log('WARN', `launchctl unload -w reportó: ${unloadRes.error} (continuando con eliminación del archivo)`);
308
+ }
309
+
310
+ // Eliminar el archivo
311
+ try {
312
+ fs.unlinkSync(rutaPlist);
313
+ _log('INFO', `Plist eliminado: ${rutaPlist}`);
314
+ } catch (err) {
315
+ const error = `No se pudo eliminar el plist: ${err.message}`;
316
+ _log('ERROR', error);
317
+ return { ok: false, error };
318
+ }
319
+
320
+ return { ok: true, mensaje: `LaunchAgent "${LABEL_PLIST}" descargado y eliminado.` };
321
+ }
322
+
323
+ /**
324
+ * Consulta el estado del LaunchAgent.
325
+ *
326
+ * @returns {{ instalado: boolean, cargado: boolean, error?: string }}
327
+ */
328
+ function status() {
329
+ const platErr = _validarPlatform();
330
+ if (platErr) return { instalado: false, cargado: false, error: platErr.error };
331
+
332
+ const rutaPlist = _rutaPlistInstalado();
333
+ const instalado = fs.existsSync(rutaPlist);
334
+
335
+ // Verificar si está cargado en launchd con list | grep
336
+ let cargado = false;
337
+ try {
338
+ const stdout = execFileSync(
339
+ 'launchctl',
340
+ ['list'],
341
+ { encoding: 'utf8', timeout: 10_000 }
342
+ );
343
+ cargado = stdout.includes(LABEL_PLIST);
344
+ } catch (_) {
345
+ cargado = false;
346
+ }
347
+
348
+ return { instalado, cargado };
349
+ }
350
+
351
+ module.exports = {
352
+ install,
353
+ uninstall,
354
+ status,
355
+ // Exportar para tests
356
+ generarContenidoPlist,
357
+ _rutaDaemon,
358
+ _dirLaunchAgents,
359
+ _validarRutaSegura,
360
+ };
@@ -0,0 +1,307 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Generador de Scheduled Task de Windows para el daemon swl-telegram-bot.
5
+ *
6
+ * SEGURIDAD:
7
+ * - NUNCA usa shell:true ni execSync con string. Solo execFileSync con array.
8
+ * - NUNCA incluye credenciales en el task — las credenciales viven en .env.
9
+ * - RunLevel Limited (sin elevación). Si el usuario necesita admin, que lo
10
+ * gestione él; el daño de un task con privilegios elevados es irreversible.
11
+ * - Solo opera en process.platform === 'win32'. Otros OS reciben error explícito.
12
+ *
13
+ * Rollback manual (si algo sale mal):
14
+ * powershell.exe -NoProfile -Command "Unregister-ScheduledTask -TaskName SWL-Telegram-Bot -Confirm:$false"
15
+ *
16
+ * @module scripts/lib/autostart-windows
17
+ */
18
+
19
+ const { execFileSync } = require('node:child_process');
20
+ const path = require('node:path');
21
+ const fs = require('node:fs');
22
+ const os = require('node:os');
23
+
24
+ // Nombre canónico del Scheduled Task
25
+ const TASK_NAME = 'SWL-Telegram-Bot';
26
+
27
+ // Ruta del log de autostart — diagnóstico humano sin secrets
28
+ const RUTA_LOG_AUTOSTART = path.join(
29
+ os.homedir(), '.claude', 'notifications', 'autostart.log'
30
+ );
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Helpers
34
+ // ---------------------------------------------------------------------------
35
+
36
+ /**
37
+ * Escribe una línea al log de autostart.
38
+ * @param {string} nivel
39
+ * @param {string} mensaje
40
+ */
41
+ function _log(nivel, mensaje) {
42
+ const linea = `[${new Date().toISOString()}] [${nivel}] [windows] ${mensaje}\n`;
43
+ try {
44
+ const dir = path.dirname(RUTA_LOG_AUTOSTART);
45
+ if (!fs.existsSync(dir)) {
46
+ fs.mkdirSync(dir, { recursive: true });
47
+ }
48
+ fs.appendFileSync(RUTA_LOG_AUTOSTART, linea, 'utf8');
49
+ } catch (_) {}
50
+ process.stderr.write(linea);
51
+ }
52
+
53
+ // Regex para validar USERNAME seguro — solo caracteres alfanuméricos y separadores comunes.
54
+ // Exportada para tests unitarios de REM-3.
55
+ const _RX_USUARIO_SEGURO = /^[A-Za-z0-9._\-\\$ ]+$/;
56
+
57
+ /**
58
+ * REM-3: Resuelve el nombre de usuario para el trigger AtLogOn del Scheduled Task.
59
+ *
60
+ * Valida el valor de las variables de entorno USERNAME/USER contra un regex seguro.
61
+ * Si el valor contiene caracteres peligrosos (que podrían inyectarse en el script
62
+ * de PowerShell), usa '$env:USERNAME' como fallback — PowerShell resuelve la variable
63
+ * en tiempo de ejecución sin concatenación en el código generado.
64
+ *
65
+ * @param {string|undefined} [username] - Valor de USERNAME (por defecto process.env.USERNAME).
66
+ * @param {string|undefined} [user] - Valor de USER (por defecto process.env.USER).
67
+ * @returns {string} Nombre de usuario validado o '$env:USERNAME'.
68
+ */
69
+ function _resolverUsuario(username, user) {
70
+ const raw = (username !== undefined ? username : process.env.USERNAME)
71
+ || (user !== undefined ? user : process.env.USER);
72
+ return (raw && _RX_USUARIO_SEGURO.test(raw)) ? raw : '$env:USERNAME';
73
+ }
74
+
75
+ /**
76
+ * Construye la ruta absoluta al daemon bin/swl-telegram-bot.js
77
+ * a partir de __dirname (scripts/lib/), NO hardcodeada.
78
+ *
79
+ * @returns {string} Ruta absoluta resuelta con path.resolve.
80
+ */
81
+ function _rutaDaemon() {
82
+ return path.resolve(__dirname, '..', '..', 'bin', 'swl-telegram-bot.js');
83
+ }
84
+
85
+ /**
86
+ * Valida que estamos en Windows.
87
+ * @returns {{ ok: false, error: string } | null} null si OK, error si no.
88
+ */
89
+ function _validarPlatform() {
90
+ if (process.platform !== 'win32') {
91
+ return {
92
+ ok: false,
93
+ error: `autostart-windows solo aplica en Windows (plataforma detectada: ${process.platform})`,
94
+ };
95
+ }
96
+ return null;
97
+ }
98
+
99
+ /**
100
+ * Ejecuta un comando de PowerShell de forma segura:
101
+ * - Sin shell:true
102
+ * - Con array de argumentos (sin concatenación de strings)
103
+ * - Timeout de 30s
104
+ *
105
+ * @param {string} scriptBlock - Script PowerShell a ejecutar.
106
+ * @returns {{ ok: boolean, stdout?: string, error?: string }}
107
+ */
108
+ function _ejecutarPowerShell(scriptBlock) {
109
+ try {
110
+ const stdout = execFileSync(
111
+ 'powershell.exe',
112
+ [
113
+ '-NoProfile',
114
+ '-NonInteractive',
115
+ '-ExecutionPolicy', 'Bypass',
116
+ '-Command', scriptBlock,
117
+ ],
118
+ {
119
+ encoding: 'utf8',
120
+ timeout: 30_000,
121
+ // NUNCA shell: true — previene inyección de comandos
122
+ }
123
+ );
124
+ return { ok: true, stdout: (stdout || '').trim() };
125
+ } catch (err) {
126
+ return { ok: false, error: (err.stderr || err.message || '').trim() };
127
+ }
128
+ }
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // API pública
132
+ // ---------------------------------------------------------------------------
133
+
134
+ /**
135
+ * Instala el Scheduled Task de Windows para arrancar el daemon al logon.
136
+ *
137
+ * Parámetros del task:
138
+ * - Name: SWL-Telegram-Bot
139
+ * - Trigger: AtLogOn del usuario actual
140
+ * - Action: node.exe <ruta-absoluta-a-bin/swl-telegram-bot.js>
141
+ * - Principal: Interactive, RunLevel Limited (sin elevación)
142
+ * - StartWhenAvailable, RestartCount=3, RestartInterval=PT2M
143
+ * - AllowStartIfOnBatteries, sin timeout de idle
144
+ *
145
+ * Idempotente: si el task ya existe, lo reemplaza silenciosamente.
146
+ *
147
+ * @returns {{ ok: boolean, mensaje?: string, error?: string }}
148
+ */
149
+ function install() {
150
+ const platErr = _validarPlatform();
151
+ if (platErr) return platErr;
152
+
153
+ const rutaDaemon = _rutaDaemon();
154
+ _log('INFO', `Instalando Scheduled Task "${TASK_NAME}" → ${rutaDaemon}`);
155
+
156
+ // Verificar que node está disponible
157
+ let nodeExe;
158
+ try {
159
+ nodeExe = execFileSync('where.exe', ['node'], { encoding: 'utf8', timeout: 5000 }).trim().split('\n')[0].trim();
160
+ } catch (_) {
161
+ const error = 'node.exe no encontrado en PATH. Instala Node.js antes de activar el autostart.';
162
+ _log('ERROR', error);
163
+ return { ok: false, error };
164
+ }
165
+
166
+ if (!nodeExe) {
167
+ const error = 'node.exe no encontrado en PATH. Instala Node.js antes de activar el autostart.';
168
+ _log('ERROR', error);
169
+ return { ok: false, error };
170
+ }
171
+
172
+ // Verificar que el daemon existe
173
+ if (!fs.existsSync(rutaDaemon)) {
174
+ const error = `El daemon no existe: ${rutaDaemon}. Verifica la instalación de swl-ses.`;
175
+ _log('ERROR', error);
176
+ return { ok: false, error };
177
+ }
178
+
179
+ // Construir el script de PowerShell con parámetros en variables separadas
180
+ // Nunca concatenar dentro del script — los valores ya están en variables escapadas
181
+ const nodePath = nodeExe.replace(/'/g, "''"); // Escape de comillas simples en PS
182
+ const daemonPath = rutaDaemon.replace(/'/g, "''");
183
+
184
+ // REM-3: validar USERNAME antes de interpolarlo en el script de PowerShell.
185
+ // _resolverUsuario usa un regex para rechazar caracteres peligrosos y cae a
186
+ // '$env:USERNAME' si el valor es sospechoso.
187
+ const usuario = _resolverUsuario();
188
+
189
+ const psScript = `
190
+ $action = New-ScheduledTaskAction -Execute '${nodePath}' -Argument '"${daemonPath}"'
191
+ $trigger = New-ScheduledTaskTrigger -AtLogOn -User '${usuario}'
192
+ $settings = New-ScheduledTaskSettingsSet \`
193
+ -StartWhenAvailable \`
194
+ -RestartCount 3 \`
195
+ -RestartInterval (New-TimeSpan -Minutes 2) \`
196
+ -AllowStartIfOnBatteries \`
197
+ -DontStopIfGoingOnBatteries \`
198
+ -ExecutionTimeLimit ([TimeSpan]::Zero)
199
+ $principal = New-ScheduledTaskPrincipal -LogonType Interactive -RunLevel Limited
200
+ Register-ScheduledTask \`
201
+ -TaskName '${TASK_NAME}' \`
202
+ -Action $action \`
203
+ -Trigger $trigger \`
204
+ -Settings $settings \`
205
+ -Principal $principal \`
206
+ -Force
207
+ `.trim();
208
+
209
+ _log('INFO', 'Registrando Scheduled Task vía PowerShell (RunLevel: Limited, sin elevación)...');
210
+ const resultado = _ejecutarPowerShell(psScript);
211
+
212
+ if (!resultado.ok) {
213
+ _log('ERROR', `Register-ScheduledTask falló: ${resultado.error}`);
214
+ return { ok: false, error: `Register-ScheduledTask falló: ${resultado.error}` };
215
+ }
216
+
217
+ // Verificar que quedó registrado
218
+ const verificacion = status();
219
+ if (!verificacion.instalado) {
220
+ const error = 'El task fue registrado pero status() no lo detecta. Verifica manualmente en Programador de tareas.';
221
+ _log('WARN', error);
222
+ return { ok: false, error };
223
+ }
224
+
225
+ _log('INFO', `Scheduled Task "${TASK_NAME}" instalado — estado: ${verificacion.estado}`);
226
+ return {
227
+ ok: true,
228
+ mensaje: `Scheduled Task "${TASK_NAME}" registrado. Arrancará al próximo logon. Estado actual: ${verificacion.estado}.`,
229
+ };
230
+ }
231
+
232
+ /**
233
+ * Desinstala el Scheduled Task de Windows.
234
+ *
235
+ * Idempotente: si el task no existe, devuelve ok:true con mensaje informativo.
236
+ *
237
+ * @returns {{ ok: boolean, mensaje?: string, error?: string }}
238
+ */
239
+ function uninstall() {
240
+ const platErr = _validarPlatform();
241
+ if (platErr) return platErr;
242
+
243
+ _log('INFO', `Desinstalando Scheduled Task "${TASK_NAME}"...`);
244
+
245
+ // Verificar si existe primero para mensaje idempotente
246
+ const estadoActual = status();
247
+ if (!estadoActual.instalado) {
248
+ _log('INFO', `El task "${TASK_NAME}" no estaba instalado — nada que hacer.`);
249
+ return { ok: true, mensaje: `no había task "${TASK_NAME}" instalado` };
250
+ }
251
+
252
+ const psScript = `
253
+ Unregister-ScheduledTask -TaskName '${TASK_NAME}' -Confirm:$false -ErrorAction SilentlyContinue
254
+ `.trim();
255
+
256
+ const resultado = _ejecutarPowerShell(psScript);
257
+
258
+ if (!resultado.ok) {
259
+ // Algunos errores de Unregister son falsos positivos (el task ya se borró)
260
+ // Verificar el estado real antes de reportar error
261
+ const estadoPost = status();
262
+ if (!estadoPost.instalado) {
263
+ _log('INFO', `Task eliminado (PowerShell reportó: ${resultado.error})`);
264
+ return { ok: true, mensaje: `Scheduled Task "${TASK_NAME}" eliminado.` };
265
+ }
266
+ _log('ERROR', `Unregister-ScheduledTask falló: ${resultado.error}`);
267
+ return { ok: false, error: `Unregister-ScheduledTask falló: ${resultado.error}` };
268
+ }
269
+
270
+ _log('INFO', `Scheduled Task "${TASK_NAME}" eliminado correctamente.`);
271
+ return { ok: true, mensaje: `Scheduled Task "${TASK_NAME}" eliminado.` };
272
+ }
273
+
274
+ /**
275
+ * Consulta el estado del Scheduled Task de Windows.
276
+ *
277
+ * @returns {{ instalado: boolean, estado: 'Ready'|'Running'|'Disabled'|null, error?: string }}
278
+ */
279
+ function status() {
280
+ const platErr = _validarPlatform();
281
+ if (platErr) return { instalado: false, estado: null, error: platErr.error };
282
+
283
+ const psScript = `
284
+ $task = Get-ScheduledTask -TaskName '${TASK_NAME}' -ErrorAction SilentlyContinue
285
+ if ($task) { $task.State } else { 'NOT_FOUND' }
286
+ `.trim();
287
+
288
+ const resultado = _ejecutarPowerShell(psScript);
289
+
290
+ if (!resultado.ok) {
291
+ return { instalado: false, estado: null, error: resultado.error };
292
+ }
293
+
294
+ const estado = resultado.stdout;
295
+
296
+ if (estado === 'NOT_FOUND' || estado === '') {
297
+ return { instalado: false, estado: null };
298
+ }
299
+
300
+ // Mapear estados de Windows a los esperados
301
+ const estadosValidos = ['Ready', 'Running', 'Disabled'];
302
+ const estadoNorm = estadosValidos.find(e => e.toLowerCase() === estado.toLowerCase()) || estado;
303
+
304
+ return { instalado: true, estado: estadoNorm };
305
+ }
306
+
307
+ module.exports = { install, uninstall, status, _resolverUsuario };