theus-cli-darwin-x64 0.2.84
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.
- package/LICENSE +42 -0
- package/README.md +295 -0
- package/RELEASE.json +18 -0
- package/assets/brand-official/v1.0/logo/theus-lockup-negative-official.png +0 -0
- package/assets/brand-official/v1.0/logo/theus-lockup-primary-dark-official.png +0 -0
- package/assets/fonts/satoshi/satoshi-300.woff2 +0 -0
- package/assets/fonts/satoshi/satoshi-400.woff2 +0 -0
- package/assets/fonts/satoshi/satoshi-500.woff2 +0 -0
- package/assets/fonts/satoshi/satoshi-700.woff2 +0 -0
- package/assets/fonts/satoshi/satoshi-900.woff2 +0 -0
- package/assets/windows-store/Square150x150Logo.png +0 -0
- package/assets/windows-store/Square44x44Logo.png +0 -0
- package/assets/windows-store/StoreLogo.png +0 -0
- package/assets/windows-store/theus-store-icon-master.png +0 -0
- package/bin/theus +0 -0
- package/package.json +18 -0
- package/vendor/theus-arsenal/.arsenal-nombres-ola2.json +6 -0
- package/vendor/theus-arsenal/.arsenal-nombres-ola3.json +72 -0
- package/vendor/theus-arsenal/.mailmap +2 -0
- package/vendor/theus-arsenal/.theus-plugin/marketplace.json +25 -0
- package/vendor/theus-arsenal/.theus-plugin/plugin.json +20 -0
- package/vendor/theus-arsenal/AUTHORS.md +8 -0
- package/vendor/theus-arsenal/CLEANROOM_REPLACEMENT_PLAN.md +11 -0
- package/vendor/theus-arsenal/LICENSE +26 -0
- package/vendor/theus-arsenal/PROVENANCE.md +9 -0
- package/vendor/theus-arsenal/README.md +41 -0
- package/vendor/theus-arsenal/THIRD_PARTY.md +80 -0
- package/vendor/theus-arsenal/agents/actualizador-docs.md +123 -0
- package/vendor/theus-arsenal/agents/analista-comentarios.md +53 -0
- package/vendor/theus-arsenal/agents/analista-conversaciones.md +60 -0
- package/vendor/theus-arsenal/agents/analista-tests-pr.md +53 -0
- package/vendor/theus-arsenal/agents/analista-tipos.md +49 -0
- package/vendor/theus-arsenal/agents/arquitecto-accesibilidad.md +148 -0
- package/vendor/theus-arsenal/agents/arquitecto-codigo.md +79 -0
- package/vendor/theus-arsenal/agents/arquitecto-homelab.md +90 -0
- package/vendor/theus-arsenal/agents/arquitecto-redes.md +116 -0
- package/vendor/theus-arsenal/agents/arquitecto-sistemas.md +219 -0
- package/vendor/theus-arsenal/agents/bifurcador-opensource.md +206 -0
- package/vendor/theus-arsenal/agents/cazador-fallos-silenciosos.md +58 -0
- package/vendor/theus-arsenal/agents/consultor-documentacion.md +76 -0
- package/vendor/theus-arsenal/agents/diagnosticador-redes.md +135 -0
- package/vendor/theus-arsenal/agents/ejecutor-e2e.md +96 -0
- package/vendor/theus-arsenal/agents/empaquetador-opensource.md +257 -0
- package/vendor/theus-arsenal/agents/escaner-secretos.md +196 -0
- package/vendor/theus-arsenal/agents/especialista-seo.md +70 -0
- package/vendor/theus-arsenal/agents/estratega-marketing.md +158 -0
- package/vendor/theus-arsenal/agents/evaluador-agentes.md +214 -0
- package/vendor/theus-arsenal/agents/evaluador-harness.md +217 -0
- package/vendor/theus-arsenal/agents/explorador-codigo.md +79 -0
- package/vendor/theus-arsenal/agents/extractor-specs.md +214 -0
- package/vendor/theus-arsenal/agents/generador-harness.md +139 -0
- package/vendor/theus-arsenal/agents/guia-tdd.md +99 -0
- package/vendor/theus-arsenal/agents/jefe-de-gabinete.md +162 -0
- package/vendor/theus-arsenal/agents/limpiador-refactors.md +93 -0
- package/vendor/theus-arsenal/agents/optimizador-rendimiento.md +454 -0
- package/vendor/theus-arsenal/agents/planificador-harness.md +107 -0
- package/vendor/theus-arsenal/agents/planificador.md +221 -0
- package/vendor/theus-arsenal/agents/resolutor-apps-harmonyos.md +181 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-cpp.md +98 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-dart.md +209 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-django.md +253 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-go.md +102 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-java.md +274 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-kotlin.md +128 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-pytorch.md +128 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-react.md +214 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-rust.md +156 -0
- package/vendor/theus-arsenal/agents/resolutor-builds-swift.md +169 -0
- package/vendor/theus-arsenal/agents/resolutor-builds.md +122 -0
- package/vendor/theus-arsenal/agents/revisor-bd.md +97 -0
- package/vendor/theus-arsenal/agents/revisor-codigo.md +291 -0
- package/vendor/theus-arsenal/agents/revisor-config-red.md +116 -0
- package/vendor/theus-arsenal/agents/revisor-cpp.md +80 -0
- package/vendor/theus-arsenal/agents/revisor-csharp.md +109 -0
- package/vendor/theus-arsenal/agents/revisor-django.md +168 -0
- package/vendor/theus-arsenal/agents/revisor-fastapi.md +82 -0
- package/vendor/theus-arsenal/agents/revisor-flutter.md +251 -0
- package/vendor/theus-arsenal/agents/revisor-go.md +84 -0
- package/vendor/theus-arsenal/agents/revisor-java.md +192 -0
- package/vendor/theus-arsenal/agents/revisor-kotlin.md +171 -0
- package/vendor/theus-arsenal/agents/revisor-ml.md +159 -0
- package/vendor/theus-arsenal/agents/revisor-php.md +108 -0
- package/vendor/theus-arsenal/agents/revisor-python.md +106 -0
- package/vendor/theus-arsenal/agents/revisor-react.md +166 -0
- package/vendor/theus-arsenal/agents/revisor-rust.md +102 -0
- package/vendor/theus-arsenal/agents/revisor-seguridad.md +116 -0
- package/vendor/theus-arsenal/agents/revisor-software-clinico.md +95 -0
- package/vendor/theus-arsenal/agents/revisor-swift.md +115 -0
- package/vendor/theus-arsenal/agents/revisor-typescript.md +123 -0
- package/vendor/theus-arsenal/agents/revisor-vue.md +205 -0
- package/vendor/theus-arsenal/agents/simplificador-codigo.md +55 -0
- package/vendor/theus-arsenal/commands/actualizar-docs.md +88 -0
- package/vendor/theus-arsenal/commands/actualizar-mapas-codigo.md +78 -0
- package/vendor/theus-arsenal/commands/aprender-evaluar.md +109 -0
- package/vendor/theus-arsenal/commands/aprender.md +74 -0
- package/vendor/theus-arsenal/commands/arreglar-build.md +66 -0
- package/vendor/theus-arsenal/commands/bucle-multiperspectiva.md +153 -0
- package/vendor/theus-arsenal/commands/build-cpp.md +173 -0
- package/vendor/theus-arsenal/commands/build-flutter.md +164 -0
- package/vendor/theus-arsenal/commands/build-go.md +183 -0
- package/vendor/theus-arsenal/commands/build-gradle.md +75 -0
- package/vendor/theus-arsenal/commands/build-kotlin.md +176 -0
- package/vendor/theus-arsenal/commands/build-react.md +187 -0
- package/vendor/theus-arsenal/commands/build-rust.md +187 -0
- package/vendor/theus-arsenal/commands/campana-marketing.md +125 -0
- package/vendor/theus-arsenal/commands/checkpoint.md +78 -0
- package/vendor/theus-arsenal/commands/cobertura-tests.md +73 -0
- package/vendor/theus-arsenal/commands/configurar-gestor-paquetes.md +86 -0
- package/vendor/theus-arsenal/commands/consulta.md +164 -0
- package/vendor/theus-arsenal/commands/control-calidad.md +50 -0
- package/vendor/theus-arsenal/commands/crear-skill.md +77 -0
- package/vendor/theus-arsenal/commands/enrutar-modelo.md +30 -0
- package/vendor/theus-arsenal/commands/epica-desbloquear.md +17 -0
- package/vendor/theus-arsenal/commands/epica-descomponer.md +22 -0
- package/vendor/theus-arsenal/commands/epica-publicar.md +21 -0
- package/vendor/theus-arsenal/commands/epica-reclamar.md +25 -0
- package/vendor/theus-arsenal/commands/epica-revisar.md +22 -0
- package/vendor/theus-arsenal/commands/epica-sincronizar.md +21 -0
- package/vendor/theus-arsenal/commands/epica-validar.md +21 -0
- package/vendor/theus-arsenal/commands/evolucionar.md +176 -0
- package/vendor/theus-arsenal/commands/funcionalidad.md +49 -0
- package/vendor/theus-arsenal/commands/guardar-sesion.md +278 -0
- package/vendor/theus-arsenal/commands/harness-build.md +111 -0
- package/vendor/theus-arsenal/commands/harness-diseno.md +46 -0
- package/vendor/theus-arsenal/commands/informe-costos.md +90 -0
- package/vendor/theus-arsenal/commands/iniciar-bucle.md +36 -0
- package/vendor/theus-arsenal/commands/instintos-estado.md +53 -0
- package/vendor/theus-arsenal/commands/instintos-exportar.md +69 -0
- package/vendor/theus-arsenal/commands/instintos-importar.md +120 -0
- package/vendor/theus-arsenal/commands/lienzo-planes.md +48 -0
- package/vendor/theus-arsenal/commands/limpiar-refactor.md +84 -0
- package/vendor/theus-arsenal/commands/modo-seguro.md +96 -0
- package/vendor/theus-arsenal/commands/orq-agregar-funcionalidad.md +36 -0
- package/vendor/theus-arsenal/commands/orq-cambiar-funcionalidad.md +38 -0
- package/vendor/theus-arsenal/commands/orq-construir-mvp.md +36 -0
- package/vendor/theus-arsenal/commands/orq-corregir-defecto.md +40 -0
- package/vendor/theus-arsenal/commands/orq-refinar-codigo.md +44 -0
- package/vendor/theus-arsenal/commands/orq-revisar.md +135 -0
- package/vendor/theus-arsenal/commands/plan-prd.md +160 -0
- package/vendor/theus-arsenal/commands/plan.md +198 -0
- package/vendor/theus-arsenal/commands/podar.md +31 -0
- package/vendor/theus-arsenal/commands/pr.md +181 -0
- package/vendor/theus-arsenal/commands/promover.md +41 -0
- package/vendor/theus-arsenal/commands/proyectos.md +33 -0
- package/vendor/theus-arsenal/commands/prp-commit.md +112 -0
- package/vendor/theus-arsenal/commands/prp-implementar.md +385 -0
- package/vendor/theus-arsenal/commands/prp-planificar.md +501 -0
- package/vendor/theus-arsenal/commands/reanudar-sesion.md +160 -0
- package/vendor/theus-arsenal/commands/revisar-codigo.md +289 -0
- package/vendor/theus-arsenal/commands/revisar-cpp.md +132 -0
- package/vendor/theus-arsenal/commands/revisar-fastapi.md +39 -0
- package/vendor/theus-arsenal/commands/revisar-flutter.md +115 -0
- package/vendor/theus-arsenal/commands/revisar-go.md +148 -0
- package/vendor/theus-arsenal/commands/revisar-kotlin.md +140 -0
- package/vendor/theus-arsenal/commands/revisar-pr.md +37 -0
- package/vendor/theus-arsenal/commands/revisar-python.md +297 -0
- package/vendor/theus-arsenal/commands/revisar-react.md +170 -0
- package/vendor/theus-arsenal/commands/revisar-rust.md +142 -0
- package/vendor/theus-arsenal/commands/revisar-vue.md +174 -0
- package/vendor/theus-arsenal/commands/salud-skills.md +52 -0
- package/vendor/theus-arsenal/commands/sesiones.md +345 -0
- package/vendor/theus-arsenal/commands/test-cpp.md +252 -0
- package/vendor/theus-arsenal/commands/test-flutter.md +143 -0
- package/vendor/theus-arsenal/commands/test-go.md +268 -0
- package/vendor/theus-arsenal/commands/test-kotlin.md +312 -0
- package/vendor/theus-arsenal/commands/test-react.md +265 -0
- package/vendor/theus-arsenal/commands/test-rust.md +309 -0
- package/vendor/theus-arsenal/commands/vigilancia-canary.md +43 -0
- package/vendor/theus-arsenal/hooks/hooks.json +274 -0
- package/vendor/theus-arsenal/package.json +6 -0
- package/vendor/theus-arsenal/rules/angular/coding-style.md +182 -0
- package/vendor/theus-arsenal/rules/angular/hooks.md +25 -0
- package/vendor/theus-arsenal/rules/angular/patterns.md +249 -0
- package/vendor/theus-arsenal/rules/angular/security.md +87 -0
- package/vendor/theus-arsenal/rules/angular/testing.md +164 -0
- package/vendor/theus-arsenal/rules/arkts/coding-style.md +153 -0
- package/vendor/theus-arsenal/rules/arkts/hooks.md +80 -0
- package/vendor/theus-arsenal/rules/arkts/patterns.md +236 -0
- package/vendor/theus-arsenal/rules/arkts/security.md +141 -0
- package/vendor/theus-arsenal/rules/arkts/testing.md +126 -0
- package/vendor/theus-arsenal/rules/common/agents.md +49 -0
- package/vendor/theus-arsenal/rules/common/code-review.md +123 -0
- package/vendor/theus-arsenal/rules/common/coding-style.md +90 -0
- package/vendor/theus-arsenal/rules/common/development-workflow.md +44 -0
- package/vendor/theus-arsenal/rules/common/git-workflow.md +24 -0
- package/vendor/theus-arsenal/rules/common/hooks.md +32 -0
- package/vendor/theus-arsenal/rules/common/patterns.md +31 -0
- package/vendor/theus-arsenal/rules/common/performance.md +53 -0
- package/vendor/theus-arsenal/rules/common/security.md +29 -0
- package/vendor/theus-arsenal/rules/common/testing.md +57 -0
- package/vendor/theus-arsenal/rules/cpp/coding-style.md +44 -0
- package/vendor/theus-arsenal/rules/cpp/hooks.md +39 -0
- package/vendor/theus-arsenal/rules/cpp/patterns.md +51 -0
- package/vendor/theus-arsenal/rules/cpp/security.md +51 -0
- package/vendor/theus-arsenal/rules/cpp/testing.md +44 -0
- package/vendor/theus-arsenal/rules/csharp/coding-style.md +72 -0
- package/vendor/theus-arsenal/rules/csharp/hooks.md +25 -0
- package/vendor/theus-arsenal/rules/csharp/patterns.md +50 -0
- package/vendor/theus-arsenal/rules/csharp/security.md +58 -0
- package/vendor/theus-arsenal/rules/csharp/testing.md +50 -0
- package/vendor/theus-arsenal/rules/dart/coding-style.md +159 -0
- package/vendor/theus-arsenal/rules/dart/hooks.md +68 -0
- package/vendor/theus-arsenal/rules/dart/patterns.md +261 -0
- package/vendor/theus-arsenal/rules/dart/security.md +135 -0
- package/vendor/theus-arsenal/rules/dart/testing.md +215 -0
- package/vendor/theus-arsenal/rules/fsharp/coding-style.md +112 -0
- package/vendor/theus-arsenal/rules/fsharp/hooks.md +26 -0
- package/vendor/theus-arsenal/rules/fsharp/patterns.md +111 -0
- package/vendor/theus-arsenal/rules/fsharp/security.md +76 -0
- package/vendor/theus-arsenal/rules/fsharp/testing.md +62 -0
- package/vendor/theus-arsenal/rules/golang/coding-style.md +32 -0
- package/vendor/theus-arsenal/rules/golang/hooks.md +17 -0
- package/vendor/theus-arsenal/rules/golang/patterns.md +45 -0
- package/vendor/theus-arsenal/rules/golang/security.md +34 -0
- package/vendor/theus-arsenal/rules/golang/testing.md +31 -0
- package/vendor/theus-arsenal/rules/java/coding-style.md +114 -0
- package/vendor/theus-arsenal/rules/java/hooks.md +18 -0
- package/vendor/theus-arsenal/rules/java/patterns.md +147 -0
- package/vendor/theus-arsenal/rules/java/security.md +101 -0
- package/vendor/theus-arsenal/rules/java/testing.md +133 -0
- package/vendor/theus-arsenal/rules/kotlin/coding-style.md +86 -0
- package/vendor/theus-arsenal/rules/kotlin/hooks.md +17 -0
- package/vendor/theus-arsenal/rules/kotlin/patterns.md +146 -0
- package/vendor/theus-arsenal/rules/kotlin/security.md +82 -0
- package/vendor/theus-arsenal/rules/kotlin/testing.md +128 -0
- package/vendor/theus-arsenal/rules/nuxt/coding-style.md +47 -0
- package/vendor/theus-arsenal/rules/nuxt/hooks.md +39 -0
- package/vendor/theus-arsenal/rules/nuxt/patterns.md +54 -0
- package/vendor/theus-arsenal/rules/nuxt/security.md +48 -0
- package/vendor/theus-arsenal/rules/nuxt/testing.md +49 -0
- package/vendor/theus-arsenal/rules/php/coding-style.md +40 -0
- package/vendor/theus-arsenal/rules/php/hooks.md +24 -0
- package/vendor/theus-arsenal/rules/php/patterns.md +33 -0
- package/vendor/theus-arsenal/rules/php/security.md +37 -0
- package/vendor/theus-arsenal/rules/php/testing.md +38 -0
- package/vendor/theus-arsenal/rules/python/coding-style.md +42 -0
- package/vendor/theus-arsenal/rules/python/fastapi.md +58 -0
- package/vendor/theus-arsenal/rules/python/hooks.md +19 -0
- package/vendor/theus-arsenal/rules/python/patterns.md +39 -0
- package/vendor/theus-arsenal/rules/python/security.md +30 -0
- package/vendor/theus-arsenal/rules/python/testing.md +38 -0
- package/vendor/theus-arsenal/rules/react/coding-style.md +109 -0
- package/vendor/theus-arsenal/rules/react/hooks.md +187 -0
- package/vendor/theus-arsenal/rules/react/patterns.md +194 -0
- package/vendor/theus-arsenal/rules/react/security.md +180 -0
- package/vendor/theus-arsenal/rules/react/testing.md +208 -0
- package/vendor/theus-arsenal/rules/react-native/accessibility.md +55 -0
- package/vendor/theus-arsenal/rules/react-native/coding-style.md +71 -0
- package/vendor/theus-arsenal/rules/react-native/hooks.md +28 -0
- package/vendor/theus-arsenal/rules/react-native/patterns.md +88 -0
- package/vendor/theus-arsenal/rules/react-native/performance.md +45 -0
- package/vendor/theus-arsenal/rules/react-native/production-readiness.md +51 -0
- package/vendor/theus-arsenal/rules/react-native/security.md +43 -0
- package/vendor/theus-arsenal/rules/react-native/testing.md +52 -0
- package/vendor/theus-arsenal/rules/ruby/coding-style.md +46 -0
- package/vendor/theus-arsenal/rules/ruby/hooks.md +37 -0
- package/vendor/theus-arsenal/rules/ruby/patterns.md +44 -0
- package/vendor/theus-arsenal/rules/ruby/security.md +51 -0
- package/vendor/theus-arsenal/rules/ruby/testing.md +51 -0
- package/vendor/theus-arsenal/rules/rust/coding-style.md +151 -0
- package/vendor/theus-arsenal/rules/rust/hooks.md +16 -0
- package/vendor/theus-arsenal/rules/rust/patterns.md +168 -0
- package/vendor/theus-arsenal/rules/rust/security.md +141 -0
- package/vendor/theus-arsenal/rules/rust/testing.md +154 -0
- package/vendor/theus-arsenal/rules/swift/coding-style.md +47 -0
- package/vendor/theus-arsenal/rules/swift/hooks.md +20 -0
- package/vendor/theus-arsenal/rules/swift/patterns.md +66 -0
- package/vendor/theus-arsenal/rules/swift/security.md +33 -0
- package/vendor/theus-arsenal/rules/swift/testing.md +45 -0
- package/vendor/theus-arsenal/rules/typescript/coding-style.md +199 -0
- package/vendor/theus-arsenal/rules/typescript/hooks.md +22 -0
- package/vendor/theus-arsenal/rules/typescript/patterns.md +52 -0
- package/vendor/theus-arsenal/rules/typescript/security.md +28 -0
- package/vendor/theus-arsenal/rules/typescript/testing.md +18 -0
- package/vendor/theus-arsenal/rules/vue/coding-style.md +54 -0
- package/vendor/theus-arsenal/rules/vue/hooks.md +45 -0
- package/vendor/theus-arsenal/rules/vue/patterns.md +56 -0
- package/vendor/theus-arsenal/rules/vue/security.md +46 -0
- package/vendor/theus-arsenal/rules/vue/testing.md +53 -0
- package/vendor/theus-arsenal/rules/web/coding-style.md +108 -0
- package/vendor/theus-arsenal/rules/web/design-quality.md +75 -0
- package/vendor/theus-arsenal/rules/web/hooks.md +141 -0
- package/vendor/theus-arsenal/rules/web/patterns.md +91 -0
- package/vendor/theus-arsenal/rules/web/performance.md +76 -0
- package/vendor/theus-arsenal/rules/web/security.md +69 -0
- package/vendor/theus-arsenal/rules/web/testing.md +67 -0
- package/vendor/theus-arsenal/scripts/hooks/bash-hook-dispatcher.js +192 -0
- package/vendor/theus-arsenal/scripts/hooks/block-no-verify.js +556 -0
- package/vendor/theus-arsenal/scripts/hooks/check-console-log.js +92 -0
- package/vendor/theus-arsenal/scripts/hooks/check-hook-enabled.js +16 -0
- package/vendor/theus-arsenal/scripts/hooks/config-protection.js +171 -0
- package/vendor/theus-arsenal/scripts/hooks/design-quality-check.js +132 -0
- package/vendor/theus-arsenal/scripts/hooks/doc-file-warning.js +110 -0
- package/vendor/theus-arsenal/scripts/hooks/modo-seguro.js +158 -0
- package/vendor/theus-arsenal/scripts/hooks/notificacion-escritorio.js +208 -0
- package/vendor/theus-arsenal/scripts/hooks/plugin-hook-bootstrap.js +280 -0
- package/vendor/theus-arsenal/scripts/hooks/post-bash-command-log.js +87 -0
- package/vendor/theus-arsenal/scripts/hooks/post-bash-dispatcher.js +24 -0
- package/vendor/theus-arsenal/scripts/hooks/post-bash-pr-created.js +60 -0
- package/vendor/theus-arsenal/scripts/hooks/post-edit-accumulator.js +94 -0
- package/vendor/theus-arsenal/scripts/hooks/post-edit-console-warn.js +54 -0
- package/vendor/theus-arsenal/scripts/hooks/post-edit-format.js +110 -0
- package/vendor/theus-arsenal/scripts/hooks/post-edit-typecheck.js +98 -0
- package/vendor/theus-arsenal/scripts/hooks/pre-bash-commit-quality.js +447 -0
- package/vendor/theus-arsenal/scripts/hooks/pre-bash-dev-server-block.js +232 -0
- package/vendor/theus-arsenal/scripts/hooks/pre-bash-dispatcher.js +27 -0
- package/vendor/theus-arsenal/scripts/hooks/pre-compact.js +101 -0
- package/vendor/theus-arsenal/scripts/hooks/pretooluse-visible-output.js +49 -0
- package/vendor/theus-arsenal/scripts/hooks/quality-gate.js +168 -0
- package/vendor/theus-arsenal/scripts/hooks/run-with-flags.js +271 -0
- package/vendor/theus-arsenal/scripts/hooks/salud-mcp.js +749 -0
- package/vendor/theus-arsenal/scripts/hooks/seguimiento-costos.js +161 -0
- package/vendor/theus-arsenal/scripts/hooks/session-end.js +340 -0
- package/vendor/theus-arsenal/scripts/hooks/session-start.js +906 -0
- package/vendor/theus-arsenal/scripts/hooks/stop-format-typecheck.js +263 -0
- package/vendor/theus-arsenal/scripts/hooks/suggest-compact.js +286 -0
- package/vendor/theus-arsenal/scripts/hooks/theus-context-monitor.js +289 -0
- package/vendor/theus-arsenal/scripts/hooks/verificacion-factual.js +1278 -0
- package/vendor/theus-arsenal/scripts/lib/agent-data-home.js +96 -0
- package/vendor/theus-arsenal/scripts/lib/cost-estimate.js +66 -0
- package/vendor/theus-arsenal/scripts/lib/hook-flags.js +79 -0
- package/vendor/theus-arsenal/scripts/lib/llm-summary.js +185 -0
- package/vendor/theus-arsenal/scripts/lib/loopback-guard.js +54 -0
- package/vendor/theus-arsenal/scripts/lib/observer-sessions.js +237 -0
- package/vendor/theus-arsenal/scripts/lib/package-manager.d.ts +120 -0
- package/vendor/theus-arsenal/scripts/lib/package-manager.js +434 -0
- package/vendor/theus-arsenal/scripts/lib/path-safety.js +86 -0
- package/vendor/theus-arsenal/scripts/lib/plan-canvas/markdown.js +285 -0
- package/vendor/theus-arsenal/scripts/lib/plan-canvas/sdk.js +238 -0
- package/vendor/theus-arsenal/scripts/lib/plan-canvas/server.js +534 -0
- package/vendor/theus-arsenal/scripts/lib/plan-canvas/sessions.js +274 -0
- package/vendor/theus-arsenal/scripts/lib/plan-canvas/ui.js +546 -0
- package/vendor/theus-arsenal/scripts/lib/project-detect.js +451 -0
- package/vendor/theus-arsenal/scripts/lib/resolve-formatter.js +193 -0
- package/vendor/theus-arsenal/scripts/lib/resolve-theus-root.js +101 -0
- package/vendor/theus-arsenal/scripts/lib/session-aliases.d.ts +138 -0
- package/vendor/theus-arsenal/scripts/lib/session-aliases.js +483 -0
- package/vendor/theus-arsenal/scripts/lib/session-bridge.js +155 -0
- package/vendor/theus-arsenal/scripts/lib/session-manager.d.ts +137 -0
- package/vendor/theus-arsenal/scripts/lib/session-manager.js +555 -0
- package/vendor/theus-arsenal/scripts/lib/shell-split.js +86 -0
- package/vendor/theus-arsenal/scripts/lib/shell-substitution.js +501 -0
- package/vendor/theus-arsenal/scripts/lib/skill-evolution/dashboard.js +414 -0
- package/vendor/theus-arsenal/scripts/lib/skill-evolution/health.js +285 -0
- package/vendor/theus-arsenal/scripts/lib/skill-evolution/index.js +22 -0
- package/vendor/theus-arsenal/scripts/lib/skill-evolution/provenance.js +200 -0
- package/vendor/theus-arsenal/scripts/lib/skill-evolution/tracker.js +157 -0
- package/vendor/theus-arsenal/scripts/lib/skill-evolution/versioning.js +246 -0
- package/vendor/theus-arsenal/scripts/lib/transcript-context.js +232 -0
- package/vendor/theus-arsenal/scripts/lib/utils.d.ts +205 -0
- package/vendor/theus-arsenal/scripts/lib/utils.js +658 -0
- package/vendor/theus-arsenal/scripts/plan-canvas.js +341 -0
- package/vendor/theus-arsenal/scripts/setup-package-manager.js +46 -0
- package/vendor/theus-arsenal/scripts/skills-health.js +143 -0
- package/vendor/theus-arsenal/skills/a11y-frontend/SKILL.md +444 -0
- package/vendor/theus-arsenal/skills/accesibilidad/SKILL.md +144 -0
- package/vendor/theus-arsenal/skills/acelerador-throughput-datos/SKILL.md +72 -0
- package/vendor/theus-arsenal/skills/agente-scraper-datos/SKILL.md +771 -0
- package/vendor/theus-arsenal/skills/analisis-plataformas-competencia/SKILL.md +137 -0
- package/vendor/theus-arsenal/skills/api-x/SKILL.md +233 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/SKILL.md +335 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/observer-loop.sh +374 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/observer.md +188 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/session-guardian.sh +153 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/start-observer.sh +253 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/config.json +8 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/hooks/observe.sh +594 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/detect-project.sh +325 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/instinct-cli.py +1918 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/lib/arsenal-dir.sh +23 -0
- package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/test_parse_instinct.py +1420 -0
- package/vendor/theus-arsenal/skills/arquitectura-hexagonal/SKILL.md +275 -0
- package/vendor/theus-arsenal/skills/arquitectura-limpia-android/SKILL.md +340 -0
- package/vendor/theus-arsenal/skills/arquitectura-pipelines-recomendacion/SKILL.md +112 -0
- package/vendor/theus-arsenal/skills/atlas-datos-prediccion/SKILL.md +53 -0
- package/vendor/theus-arsenal/skills/auditoria-arquitectura-agentes/SKILL.md +257 -0
- package/vendor/theus-arsenal/skills/auditoria-produccion/SKILL.md +180 -0
- package/vendor/theus-arsenal/skills/auditoria-rutas-clic/SKILL.md +243 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/SKILL.md +180 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/examples/high-score-example.md +89 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/examples/low-score-example.md +87 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/references/evaluation-criteria.md +71 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/references/hook-integration.md +90 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/scripts/evaluate.py +409 -0
- package/vendor/theus-arsenal/skills/autoevaluacion-agente/templates/evaluation-report.md +86 -0
- package/vendor/theus-arsenal/skills/automatizacion-ssh-netmiko/SKILL.md +176 -0
- package/vendor/theus-arsenal/skills/base-datos-pubmed/SKILL.md +174 -0
- package/vendor/theus-arsenal/skills/base-datos-uspto/SKILL.md +173 -0
- package/vendor/theus-arsenal/skills/benchmark/SKILL.md +92 -0
- package/vendor/theus-arsenal/skills/bitacora-crecimiento/SKILL.md +120 -0
- package/vendor/theus-arsenal/skills/bucle-verificacion/SKILL.md +125 -0
- package/vendor/theus-arsenal/skills/buscar-primero/SKILL.md +184 -0
- package/vendor/theus-arsenal/skills/busqueda-exa/SKILL.md +111 -0
- package/vendor/theus-arsenal/skills/cache-por-hash/SKILL.md +160 -0
- package/vendor/theus-arsenal/skills/campana-marketing/SKILL.md +118 -0
- package/vendor/theus-arsenal/skills/capacidad-producto/SKILL.md +138 -0
- package/vendor/theus-arsenal/skills/cazador-vulnerabilidades/SKILL.md +104 -0
- package/vendor/theus-arsenal/skills/compactacion-estrategica/SKILL.md +115 -0
- package/vendor/theus-arsenal/skills/comparador-baskets-prediccion/SKILL.md +69 -0
- package/vendor/theus-arsenal/skills/compras-energia/SKILL.md +206 -0
- package/vendor/theus-arsenal/skills/concurrencia-swift-6-2/SKILL.md +224 -0
- package/vendor/theus-arsenal/skills/consejo/SKILL.md +201 -0
- package/vendor/theus-arsenal/skills/construccion-harness-agentes/SKILL.md +78 -0
- package/vendor/theus-arsenal/skills/constructor-conectores/SKILL.md +119 -0
- package/vendor/theus-arsenal/skills/constructor-equipos/SKILL.md +169 -0
- package/vendor/theus-arsenal/skills/consulta-documentacion/SKILL.md +92 -0
- package/vendor/theus-arsenal/skills/consultas-genomicas-gget/SKILL.md +170 -0
- package/vendor/theus-arsenal/skills/contacto-inversores/SKILL.md +95 -0
- package/vendor/theus-arsenal/skills/corrutinas-flows-kotlin/SKILL.md +284 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/SKILL.md +46 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/3d.md +86 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/animations.md +29 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/charts-bar-chart.tsx +173 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/text-animations-typewriter.tsx +100 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/text-animations-word-highlight.tsx +108 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets.md +78 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/audio.md +172 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/calculate-metadata.md +104 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/can-decode.md +75 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/charts.md +58 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/compositions.md +146 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/display-captions.md +126 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/extract-frames.md +229 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/fonts.md +152 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-audio-duration.md +58 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-video-dimensions.md +68 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-video-duration.md +58 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/gifs.md +138 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/images.md +130 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/import-srt-captions.md +67 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/lottie.md +67 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/measuring-dom-nodes.md +34 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/measuring-text.md +143 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/sequencing.md +106 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/tailwind.md +11 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/text-animations.md +20 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/timing.md +179 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/transcribe-captions.md +19 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/transitions.md +122 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/trimming.md +52 -0
- package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/videos.md +171 -0
- package/vendor/theus-arsenal/skills/cumplimiento-aduanero/SKILL.md +270 -0
- package/vendor/theus-arsenal/skills/cumplimiento-hipaa/SKILL.md +78 -0
- package/vendor/theus-arsenal/skills/datos-sensibles-salud/SKILL.md +149 -0
- package/vendor/theus-arsenal/skills/decimales-tokens-evm/SKILL.md +128 -0
- package/vendor/theus-arsenal/skills/decisiones-arquitectura/SKILL.md +206 -0
- package/vendor/theus-arsenal/skills/demos-ui/SKILL.md +469 -0
- package/vendor/theus-arsenal/skills/desarrollo-por-intencion/SKILL.md +369 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/SKILL.md +149 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/10_proposito-porque.md +42 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/20_posicionamiento.md +47 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/30_audiencia-nicho.md +53 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/40_personalidad-arquetipo.md +61 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/50_voz-tono.md +62 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/60_narrativa-historia.md +54 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/70_tension-fundador.md +50 -0
- package/vendor/theus-arsenal/skills/descubrimiento-marca/references/90_SINTESIS.md +133 -0
- package/vendor/theus-arsenal/skills/descubrimiento-plugins-laravel/SKILL.md +230 -0
- package/vendor/theus-arsenal/skills/destilado-reglas/SKILL.md +263 -0
- package/vendor/theus-arsenal/skills/destilado-reglas/scripts/scan-rules.sh +58 -0
- package/vendor/theus-arsenal/skills/destilado-reglas/scripts/scan-skills.sh +129 -0
- package/vendor/theus-arsenal/skills/diagnostico-bgp/SKILL.md +170 -0
- package/vendor/theus-arsenal/skills/direccion-estetica/SKILL.md +220 -0
- package/vendor/theus-arsenal/skills/direccion-estetica/references/taxonomia-generos.md +89 -0
- package/vendor/theus-arsenal/skills/diseno-api/SKILL.md +522 -0
- package/vendor/theus-arsenal/skills/diseno-liquid-glass/SKILL.md +282 -0
- package/vendor/theus-arsenal/skills/e2e-escritorio-windows/SKILL.md +879 -0
- package/vendor/theus-arsenal/skills/edicion-video/SKILL.md +289 -0
- package/vendor/theus-arsenal/skills/enfoque-producto/SKILL.md +91 -0
- package/vendor/theus-arsenal/skills/entornos-flox/SKILL.md +493 -0
- package/vendor/theus-arsenal/skills/estandares-codigo/SKILL.md +548 -0
- package/vendor/theus-arsenal/skills/estandares-cpp/SKILL.md +727 -0
- package/vendor/theus-arsenal/skills/estandares-java/SKILL.md +389 -0
- package/vendor/theus-arsenal/skills/estilo-legado/SKILL.md +149 -0
- package/vendor/theus-arsenal/skills/estructura-informes-competencia/SKILL.md +95 -0
- package/vendor/theus-arsenal/skills/evaluacion-academica/SKILL.md +165 -0
- package/vendor/theus-arsenal/skills/explorador-skills/SKILL.md +129 -0
- package/vendor/theus-arsenal/skills/flujo-git/SKILL.md +714 -0
- package/vendor/theus-arsenal/skills/flujo-ingenieria-ml/SKILL.md +343 -0
- package/vendor/theus-arsenal/skills/flujo-tdd/SKILL.md +584 -0
- package/vendor/theus-arsenal/skills/forja-personas/SKILL.md +298 -0
- package/vendor/theus-arsenal/skills/forja-personas/gacha.py +224 -0
- package/vendor/theus-arsenal/skills/forja-personas/gacha.sh +5 -0
- package/vendor/theus-arsenal/skills/forja-personas/references/avatar-style.md +123 -0
- package/vendor/theus-arsenal/skills/forja-personas/references/boundary-rules.md +53 -0
- package/vendor/theus-arsenal/skills/forja-personas/references/error-handling.md +53 -0
- package/vendor/theus-arsenal/skills/forja-personas/references/identity-tension.md +48 -0
- package/vendor/theus-arsenal/skills/forja-personas/references/naming-system.md +39 -0
- package/vendor/theus-arsenal/skills/forja-personas/references/output-template.md +166 -0
- package/vendor/theus-arsenal/skills/fundamentos-animacion/SKILL.md +296 -0
- package/vendor/theus-arsenal/skills/generacion-iconos-ios/SKILL.md +156 -0
- package/vendor/theus-arsenal/skills/generacion-iconos-ios/scripts/generate_icons.swift +258 -0
- package/vendor/theus-arsenal/skills/generacion-iconos-ios/scripts/iconify_gen.sh +235 -0
- package/vendor/theus-arsenal/skills/gestion-excepciones-logisticas/SKILL.md +208 -0
- package/vendor/theus-arsenal/skills/gestion-transportistas/SKILL.md +204 -0
- package/vendor/theus-arsenal/skills/guia-adopcion-ml/SKILL.md +64 -0
- package/vendor/theus-arsenal/skills/harness-agente-autonomo/SKILL.md +252 -0
- package/vendor/theus-arsenal/skills/harness-eval-clinico/SKILL.md +212 -0
- package/vendor/theus-arsenal/skills/harness-evaluacion/SKILL.md +296 -0
- package/vendor/theus-arsenal/skills/harness-generador-evaluador/SKILL.md +254 -0
- package/vendor/theus-arsenal/skills/homelab-diseno-red/SKILL.md +120 -0
- package/vendor/theus-arsenal/skills/homelab-dns-pihole/SKILL.md +264 -0
- package/vendor/theus-arsenal/skills/homelab-preparacion-red/SKILL.md +144 -0
- package/vendor/theus-arsenal/skills/homelab-segmentacion-vlan/SKILL.md +307 -0
- package/vendor/theus-arsenal/skills/homelab-vpn-wireguard/SKILL.md +299 -0
- package/vendor/theus-arsenal/skills/ingenieria-agentica/SKILL.md +96 -0
- package/vendor/theus-arsenal/skills/inspeccion-animaciones-blender/SKILL.md +164 -0
- package/vendor/theus-arsenal/skills/instaladores-python/SKILL.md +820 -0
- package/vendor/theus-arsenal/skills/integracion-jira/SKILL.md +307 -0
- package/vendor/theus-arsenal/skills/inteligencia-leads/SKILL.md +312 -0
- package/vendor/theus-arsenal/skills/inteligencia-leads/agents/agente-enriquecimiento.md +87 -0
- package/vendor/theus-arsenal/skills/inteligencia-leads/agents/mapeador-mutuos.md +76 -0
- package/vendor/theus-arsenal/skills/inteligencia-leads/agents/puntuador-senales.md +60 -0
- package/vendor/theus-arsenal/skills/inteligencia-leads/agents/redactor-outreach.md +102 -0
- package/vendor/theus-arsenal/skills/inteligencia-mercados-prediccion/SKILL.md +53 -0
- package/vendor/theus-arsenal/skills/introspeccion-agente/SKILL.md +150 -0
- package/vendor/theus-arsenal/skills/inventario-skills/SKILL.md +194 -0
- package/vendor/theus-arsenal/skills/inventario-skills/scripts/quick-diff.sh +87 -0
- package/vendor/theus-arsenal/skills/inventario-skills/scripts/save-results.sh +57 -0
- package/vendor/theus-arsenal/skills/inventario-skills/scripts/scan.sh +170 -0
- package/vendor/theus-arsenal/skills/investigacion-mercado/SKILL.md +87 -0
- package/vendor/theus-arsenal/skills/investigacion-oraculos-prediccion/SKILL.md +59 -0
- package/vendor/theus-arsenal/skills/investigacion-profunda/SKILL.md +161 -0
- package/vendor/theus-arsenal/skills/keccak256-nodejs/SKILL.md +100 -0
- package/vendor/theus-arsenal/skills/libro-decisiones-recursivo/SKILL.md +82 -0
- package/vendor/theus-arsenal/skills/lienzo-planes/SKILL.md +111 -0
- package/vendor/theus-arsenal/skills/limpieza-configuracion/SKILL.md +116 -0
- package/vendor/theus-arsenal/skills/logistica-inversa-devoluciones/SKILL.md +241 -0
- package/vendor/theus-arsenal/skills/manejo-errores/SKILL.md +375 -0
- package/vendor/theus-arsenal/skills/materiales-inversores/SKILL.md +101 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/SKILL.md +170 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/forget.mjs +44 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/info.mjs +24 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/init.mjs +152 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/list.mjs +40 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/migrate.mjs +214 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/resume.mjs +36 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/save.mjs +210 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/shared.mjs +402 -0
- package/vendor/theus-arsenal/skills/memoria-por-proyecto/hooks/session-start.mjs +238 -0
- package/vendor/theus-arsenal/skills/metodologia-benchmarks/SKILL.md +131 -0
- package/vendor/theus-arsenal/skills/migraciones-bd/SKILL.md +430 -0
- package/vendor/theus-arsenal/skills/modelos-fundacionales-en-dispositivo/SKILL.md +244 -0
- package/vendor/theus-arsenal/skills/modo-seguro/SKILL.md +86 -0
- package/vendor/theus-arsenal/skills/motion-avanzado/SKILL.md +592 -0
- package/vendor/theus-arsenal/skills/motor-de-contenido/SKILL.md +136 -0
- package/vendor/theus-arsenal/skills/no-conformidades-calidad/SKILL.md +249 -0
- package/vendor/theus-arsenal/skills/onboarding-codigo/SKILL.md +244 -0
- package/vendor/theus-arsenal/skills/operaciones-agentes-empresariales/SKILL.md +51 -0
- package/vendor/theus-arsenal/skills/operaciones-conocimiento/SKILL.md +159 -0
- package/vendor/theus-arsenal/skills/operaciones-correo/SKILL.md +123 -0
- package/vendor/theus-arsenal/skills/operaciones-facturacion/SKILL.md +142 -0
- package/vendor/theus-arsenal/skills/operaciones-flujo-proyectos/SKILL.md +110 -0
- package/vendor/theus-arsenal/skills/operaciones-github/SKILL.md +143 -0
- package/vendor/theus-arsenal/skills/operaciones-google-workspace/SKILL.md +100 -0
- package/vendor/theus-arsenal/skills/operaciones-investigacion/SKILL.md +124 -0
- package/vendor/theus-arsenal/skills/operaciones-mensajes/SKILL.md +103 -0
- package/vendor/theus-arsenal/skills/operaciones-terminal/SKILL.md +110 -0
- package/vendor/theus-arsenal/skills/optimizacion-benchmark/SKILL.md +70 -0
- package/vendor/theus-arsenal/skills/optimizacion-costos-llm/SKILL.md +182 -0
- package/vendor/theus-arsenal/skills/optimizador-conexiones/SKILL.md +191 -0
- package/vendor/theus-arsenal/skills/optimizador-paralelismo/SKILL.md +75 -0
- package/vendor/theus-arsenal/skills/optimizador-prompts/SKILL.md +374 -0
- package/vendor/theus-arsenal/skills/orq-agregar-funcionalidad/SKILL.md +37 -0
- package/vendor/theus-arsenal/skills/orq-cambiar-funcionalidad/SKILL.md +36 -0
- package/vendor/theus-arsenal/skills/orq-construir-mvp/SKILL.md +38 -0
- package/vendor/theus-arsenal/skills/orq-corregir-defecto/SKILL.md +36 -0
- package/vendor/theus-arsenal/skills/orq-pipeline/SKILL.md +134 -0
- package/vendor/theus-arsenal/skills/orq-refinar-codigo/SKILL.md +49 -0
- package/vendor/theus-arsenal/skills/orquestacion-equipos-agentes/SKILL.md +117 -0
- package/vendor/theus-arsenal/skills/pagos-agentes-x402/SKILL.md +237 -0
- package/vendor/theus-arsenal/skills/patrones-angular/SKILL.md +153 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/angular-animations.md +160 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/angular-aria.md +410 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/cli.md +86 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/component-harnesses.md +59 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/component-styling.md +91 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/components.md +117 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/creating-services.md +97 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/data-resolvers.md +69 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/define-routes.md +67 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/defining-providers.md +72 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/di-fundamentals.md +120 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/e2e-testing.md +56 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/effects.md +83 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/hierarchical-injectors.md +43 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/host-elements.md +80 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/injection-context.md +63 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/inputs.md +101 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/linked-signal.md +59 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/loading-strategies.md +61 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/mcp.md +67 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/navigate-to-routes.md +69 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/outputs.md +86 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/reactive-forms.md +122 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/rendering-strategies.md +44 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/resource.md +77 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/route-animations.md +56 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/route-guards.md +52 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/router-lifecycle.md +45 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/router-testing.md +87 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/show-routes-with-outlets.md +68 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/signal-forms.md +795 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/signals-overview.md +94 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/tailwind-css.md +69 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/template-driven-forms.md +114 -0
- package/vendor/theus-arsenal/skills/patrones-angular/references/testing-fundamentals.md +65 -0
- package/vendor/theus-arsenal/skills/patrones-animacion/SKILL.md +432 -0
- package/vendor/theus-arsenal/skills/patrones-backend/SKILL.md +560 -0
- package/vendor/theus-arsenal/skills/patrones-cdss-clinico/SKILL.md +249 -0
- package/vendor/theus-arsenal/skills/patrones-cisco-ios/SKILL.md +148 -0
- package/vendor/theus-arsenal/skills/patrones-clickhouse/SKILL.md +443 -0
- package/vendor/theus-arsenal/skills/patrones-compose-multiplatform/SKILL.md +298 -0
- package/vendor/theus-arsenal/skills/patrones-dart-flutter/SKILL.md +566 -0
- package/vendor/theus-arsenal/skills/patrones-despliegue/SKILL.md +426 -0
- package/vendor/theus-arsenal/skills/patrones-django/SKILL.md +739 -0
- package/vendor/theus-arsenal/skills/patrones-django-celery/SKILL.md +456 -0
- package/vendor/theus-arsenal/skills/patrones-docker/SKILL.md +363 -0
- package/vendor/theus-arsenal/skills/patrones-dotnet/SKILL.md +321 -0
- package/vendor/theus-arsenal/skills/patrones-emr-clinico/SKILL.md +168 -0
- package/vendor/theus-arsenal/skills/patrones-fastapi/SKILL.md +513 -0
- package/vendor/theus-arsenal/skills/patrones-frontend/SKILL.md +655 -0
- package/vendor/theus-arsenal/skills/patrones-go/SKILL.md +674 -0
- package/vendor/theus-arsenal/skills/patrones-jpa/SKILL.md +156 -0
- package/vendor/theus-arsenal/skills/patrones-kotlin/SKILL.md +717 -0
- package/vendor/theus-arsenal/skills/patrones-kotlin-exposed/SKILL.md +724 -0
- package/vendor/theus-arsenal/skills/patrones-kotlin-ktor/SKILL.md +694 -0
- package/vendor/theus-arsenal/skills/patrones-kubernetes/SKILL.md +754 -0
- package/vendor/theus-arsenal/skills/patrones-laravel/SKILL.md +414 -0
- package/vendor/theus-arsenal/skills/patrones-mcp/SKILL.md +66 -0
- package/vendor/theus-arsenal/skills/patrones-mysql/SKILL.md +420 -0
- package/vendor/theus-arsenal/skills/patrones-nestjs/SKILL.md +229 -0
- package/vendor/theus-arsenal/skills/patrones-nextjs/SKILL.md +56 -0
- package/vendor/theus-arsenal/skills/patrones-nuxt4/SKILL.md +99 -0
- package/vendor/theus-arsenal/skills/patrones-perl/SKILL.md +508 -0
- package/vendor/theus-arsenal/skills/patrones-postgres/SKILL.md +141 -0
- package/vendor/theus-arsenal/skills/patrones-prisma/SKILL.md +399 -0
- package/vendor/theus-arsenal/skills/patrones-python/SKILL.md +750 -0
- package/vendor/theus-arsenal/skills/patrones-pytorch/SKILL.md +400 -0
- package/vendor/theus-arsenal/skills/patrones-quarkus/SKILL.md +729 -0
- package/vendor/theus-arsenal/skills/patrones-react/SKILL.md +339 -0
- package/vendor/theus-arsenal/skills/patrones-react-native/SKILL.md +325 -0
- package/vendor/theus-arsenal/skills/patrones-redis/SKILL.md +401 -0
- package/vendor/theus-arsenal/skills/patrones-rust/SKILL.md +504 -0
- package/vendor/theus-arsenal/skills/patrones-springboot/SKILL.md +314 -0
- package/vendor/theus-arsenal/skills/patrones-swiftui/SKILL.md +261 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/SKILL.md +281 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/references/architecture.md +90 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/references/data-handling.md +60 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/references/database.md +99 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/references/routing.md +64 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/references/system-usage.md +97 -0
- package/vendor/theus-arsenal/skills/patrones-tinystruct/references/testing.md +72 -0
- package/vendor/theus-arsenal/skills/patrones-vite/SKILL.md +449 -0
- package/vendor/theus-arsenal/skills/patrones-vue/SKILL.md +469 -0
- package/vendor/theus-arsenal/skills/persistencia-actores-swift/SKILL.md +148 -0
- package/vendor/theus-arsenal/skills/pipeline-opensource/SKILL.md +254 -0
- package/vendor/theus-arsenal/skills/planificacion-demanda-inventario/SKILL.md +236 -0
- package/vendor/theus-arsenal/skills/planificador-trades-prediccion/SKILL.md +60 -0
- package/vendor/theus-arsenal/skills/plano-tecnico/SKILL.md +102 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/SKILL.md +189 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/STYLE_PRESETS.md +330 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/animation-patterns.md +122 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/html-template.md +419 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/scripts/export-pdf.sh +418 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/scripts/extract-pptx.py +96 -0
- package/vendor/theus-arsenal/skills/presentaciones-html/viewport-base.css +153 -0
- package/vendor/theus-arsenal/skills/presupuesto-contexto/SKILL.md +263 -0
- package/vendor/theus-arsenal/skills/procesamiento-documentos-nutrient/SKILL.md +168 -0
- package/vendor/theus-arsenal/skills/programacion-produccion/SKILL.md +220 -0
- package/vendor/theus-arsenal/skills/publicacion-cruzada/SKILL.md +117 -0
- package/vendor/theus-arsenal/skills/publicador-social/SKILL.md +121 -0
- package/vendor/theus-arsenal/skills/puerta-de-entrega/SKILL.md +164 -0
- package/vendor/theus-arsenal/skills/puerta-de-entrega/hooks/puerta-entrega.py +242 -0
- package/vendor/theus-arsenal/skills/pulir-interfaces/SKILL.md +126 -0
- package/vendor/theus-arsenal/skills/qa-navegador/SKILL.md +103 -0
- package/vendor/theus-arsenal/skills/ranking-grafo-social/SKILL.md +153 -0
- package/vendor/theus-arsenal/skills/recuperacion-iterativa/SKILL.md +236 -0
- package/vendor/theus-arsenal/skills/redaccion-articulos/SKILL.md +81 -0
- package/vendor/theus-arsenal/skills/regex-vs-llm/SKILL.md +221 -0
- package/vendor/theus-arsenal/skills/regresion-codigo-ia/SKILL.md +388 -0
- package/vendor/theus-arsenal/skills/rendimiento-react/SKILL.md +567 -0
- package/vendor/theus-arsenal/skills/revision-codigo-flutter-dart/SKILL.md +442 -0
- package/vendor/theus-arsenal/skills/revision-literatura-cientifica/SKILL.md +191 -0
- package/vendor/theus-arsenal/skills/revision-multiperspectiva/SKILL.md +302 -0
- package/vendor/theus-arsenal/skills/revision-riesgo-prediccion/SKILL.md +56 -0
- package/vendor/theus-arsenal/skills/revision-seguridad/SKILL.md +505 -0
- package/vendor/theus-arsenal/skills/revision-seguridad/cloud-infrastructure-security.md +361 -0
- package/vendor/theus-arsenal/skills/runtime-bun/SKILL.md +83 -0
- package/vendor/theus-arsenal/skills/salud-codigo-codescene/SKILL.md +163 -0
- package/vendor/theus-arsenal/skills/salud-interfaces-red/SKILL.md +143 -0
- package/vendor/theus-arsenal/skills/seguimiento-costos/SKILL.md +122 -0
- package/vendor/theus-arsenal/skills/seguridad-agentes-trading/SKILL.md +145 -0
- package/vendor/theus-arsenal/skills/seguridad-amm-defi/SKILL.md +166 -0
- package/vendor/theus-arsenal/skills/seguridad-django/SKILL.md +648 -0
- package/vendor/theus-arsenal/skills/seguridad-laravel/SKILL.md +945 -0
- package/vendor/theus-arsenal/skills/seguridad-perl/SKILL.md +507 -0
- package/vendor/theus-arsenal/skills/seguridad-quarkus/SKILL.md +474 -0
- package/vendor/theus-arsenal/skills/seguridad-springboot/SKILL.md +279 -0
- package/vendor/theus-arsenal/skills/seo/SKILL.md +166 -0
- package/vendor/theus-arsenal/skills/sistema-diseno/SKILL.md +81 -0
- package/vendor/theus-arsenal/skills/sistema-operativo-agentico/SKILL.md +375 -0
- package/vendor/theus-arsenal/skills/sistemas-latencia-critica/SKILL.md +65 -0
- package/vendor/theus-arsenal/skills/tdd-django/SKILL.md +735 -0
- package/vendor/theus-arsenal/skills/tdd-laravel/SKILL.md +673 -0
- package/vendor/theus-arsenal/skills/tdd-quarkus/SKILL.md +817 -0
- package/vendor/theus-arsenal/skills/tdd-springboot/SKILL.md +165 -0
- package/vendor/theus-arsenal/skills/testing-cpp/SKILL.md +328 -0
- package/vendor/theus-arsenal/skills/testing-csharp/SKILL.md +321 -0
- package/vendor/theus-arsenal/skills/testing-e2e/SKILL.md +325 -0
- package/vendor/theus-arsenal/skills/testing-go/SKILL.md +719 -0
- package/vendor/theus-arsenal/skills/testing-kotlin/SKILL.md +829 -0
- package/vendor/theus-arsenal/skills/testing-perl/SKILL.md +479 -0
- package/vendor/theus-arsenal/skills/testing-protocolos-di-swift/SKILL.md +196 -0
- package/vendor/theus-arsenal/skills/testing-python/SKILL.md +815 -0
- package/vendor/theus-arsenal/skills/testing-react/SKILL.md +421 -0
- package/vendor/theus-arsenal/skills/testing-rust/SKILL.md +506 -0
- package/vendor/theus-arsenal/skills/tours-de-codigo/SKILL.md +252 -0
- package/vendor/theus-arsenal/skills/traduccion-documentos-visado/SKILL.md +121 -0
- package/vendor/theus-arsenal/skills/ui-a-vue/SKILL.md +141 -0
- package/vendor/theus-arsenal/skills/validacion-config-red/SKILL.md +211 -0
- package/vendor/theus-arsenal/skills/verificacion-django/SKILL.md +470 -0
- package/vendor/theus-arsenal/skills/verificacion-factual/SKILL.md +142 -0
- package/vendor/theus-arsenal/skills/verificacion-laravel/SKILL.md +184 -0
- package/vendor/theus-arsenal/skills/verificacion-quarkus/SKILL.md +485 -0
- package/vendor/theus-arsenal/skills/verificacion-springboot/SKILL.md +237 -0
- package/vendor/theus-arsenal/skills/videodb/SKILL.md +374 -0
- package/vendor/theus-arsenal/skills/videodb/reference/api-reference.md +550 -0
- package/vendor/theus-arsenal/skills/videodb/reference/capture-reference.md +407 -0
- package/vendor/theus-arsenal/skills/videodb/reference/capture.md +101 -0
- package/vendor/theus-arsenal/skills/videodb/reference/editor.md +443 -0
- package/vendor/theus-arsenal/skills/videodb/reference/generative.md +331 -0
- package/vendor/theus-arsenal/skills/videodb/reference/rtstream-reference.md +564 -0
- package/vendor/theus-arsenal/skills/videodb/reference/rtstream.md +65 -0
- package/vendor/theus-arsenal/skills/videodb/reference/search.md +230 -0
- package/vendor/theus-arsenal/skills/videodb/reference/streaming.md +406 -0
- package/vendor/theus-arsenal/skills/videodb/reference/use-cases.md +118 -0
- package/vendor/theus-arsenal/skills/videodb/scripts/ws_listener.py +279 -0
- package/vendor/theus-arsenal/skills/videos-manim/SKILL.md +91 -0
- package/vendor/theus-arsenal/skills/videos-manim/assets/network_graph_scene.py +52 -0
- package/vendor/theus-arsenal/skills/vigilancia-canary/SKILL.md +108 -0
- package/vendor/theus-arsenal/skills/voz-de-marca/SKILL.md +106 -0
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: e2e-escritorio-windows
|
|
3
|
+
description: Testing E2E de aplicaciones de escritorio nativas de Windows (WPF, WinForms, Win32/MFC, Qt) usando pywinauto y Windows UI Automation. Incluye Page Object Model, aislamiento por niveles, CI y fallback por capturas.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Testing E2E de escritorio en Windows
|
|
7
|
+
|
|
8
|
+
Testing end-to-end de aplicaciones de escritorio nativas de Windows usando **pywinauto** sobre Windows UI Automation (UIA). Cubre WPF, WinForms, Win32/MFC y Qt (5.x / 6.x) — con una sección dedicada a las particularidades de Qt.
|
|
9
|
+
|
|
10
|
+
## Cuándo activarla
|
|
11
|
+
|
|
12
|
+
- Escribir o ejecutar tests E2E para una aplicación de escritorio nativa de Windows
|
|
13
|
+
- Montar una suite de tests de GUI de escritorio desde cero
|
|
14
|
+
- Diagnosticar tests de automatización de escritorio inestables o fallidos
|
|
15
|
+
- Añadir testabilidad (AutomationId, nombres accesibles) a una app existente
|
|
16
|
+
- Integrar E2E de escritorio en un pipeline CI/CD (GitHub Actions `windows-latest`)
|
|
17
|
+
|
|
18
|
+
### Cuándo NO usarla
|
|
19
|
+
|
|
20
|
+
- Aplicaciones web → usa la skill `testing-e2e` (Playwright)
|
|
21
|
+
- Apps Electron / CEF / WebView2 → la capa HTML necesita automatización de navegador, no UIA
|
|
22
|
+
- Apps móviles → usa herramientas específicas de plataforma (UIAutomator, XCUITest)
|
|
23
|
+
- Tests unitarios o de integración puros que no necesitan una GUI en ejecución
|
|
24
|
+
|
|
25
|
+
## Conceptos centrales
|
|
26
|
+
|
|
27
|
+
Toda la automatización de escritorio en Windows se apoya en **UI Automation (UIA)**, una API de accesibilidad integrada en Windows. Cada framework soportado expone un árbol de elementos UIA con propiedades que el agente puede leer y sobre las que puede actuar:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Tu test (Python)
|
|
31
|
+
└── pywinauto (backend UIA)
|
|
32
|
+
└── API Windows UI Automation ← integrada en Windows, agnóstica del framework
|
|
33
|
+
└── Proveedor UIA de la app ← cada framework trae el suyo
|
|
34
|
+
└── .exe en ejecución
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Calidad de UIA por framework:**
|
|
38
|
+
|
|
39
|
+
| Framework | AutomationId | Fiabilidad | Notas |
|
|
40
|
+
|-----------|-------------|------------|-------|
|
|
41
|
+
| WPF | 5/5 | Excelente | `x:Name` se mapea directamente a AutomationId |
|
|
42
|
+
| WinForms | 4/5 | Buena | `AccessibleName` = AutomationId |
|
|
43
|
+
| UWP / WinUI 3 | 5/5 | Excelente | Soporte completo de Microsoft |
|
|
44
|
+
| Qt 6.x | 5/5 | Excelente | Accesibilidad habilitada por defecto; los nombres de clase cambian a `Qt6*` |
|
|
45
|
+
| Qt 5.15+ | 4/5 | Buena | Módulo de accesibilidad mejorado |
|
|
46
|
+
| Qt 5.7–5.14 | 3/5 | Regular | Necesita `QT_ACCESSIBILITY=1`; objectName manual |
|
|
47
|
+
| Win32 / MFC | 3/5 | Regular | IDs de controles accesibles; el matching por texto es común |
|
|
48
|
+
|
|
49
|
+
## Instalación y prerrequisitos
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Python 3.8+, solo Windows
|
|
53
|
+
pip install pywinauto pytest pytest-html Pillow pytest-timeout
|
|
54
|
+
# Opcional: grabación de pantalla
|
|
55
|
+
# Instala ffmpeg y añádelo al PATH: https://ffmpeg.org/download.html
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Verifica que UIA es alcanzable:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from pywinauto import Desktop
|
|
62
|
+
Desktop(backend="uia").windows() # lista todas las ventanas de nivel superior
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Instala **Accessibility Insights for Windows** (gratuito, de Microsoft) — tu equivalente a DevTools para inspeccionar el árbol de elementos UIA antes de escribir cualquier test.
|
|
66
|
+
|
|
67
|
+
## Preparar la testabilidad (por framework)
|
|
68
|
+
|
|
69
|
+
Lo más impactante que puedes hacer es **dar a cada control interactivo un AutomationId estable** antes de escribir tests.
|
|
70
|
+
|
|
71
|
+
### WPF
|
|
72
|
+
|
|
73
|
+
```xml
|
|
74
|
+
<!-- XAML: x:Name se convierte en AutomationId automáticamente -->
|
|
75
|
+
<TextBox x:Name="usernameInput" />
|
|
76
|
+
<PasswordBox x:Name="passwordInput" />
|
|
77
|
+
<Button x:Name="btnLogin" Content="Login" />
|
|
78
|
+
<TextBlock x:Name="lblError" />
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### WinForms
|
|
82
|
+
|
|
83
|
+
```csharp
|
|
84
|
+
// Se establece en el diseñador o en código
|
|
85
|
+
usernameInput.AccessibleName = "usernameInput";
|
|
86
|
+
passwordInput.AccessibleName = "passwordInput";
|
|
87
|
+
btnLogin.AccessibleName = "btnLogin";
|
|
88
|
+
lblError.AccessibleName = "lblError";
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Win32 / MFC
|
|
92
|
+
|
|
93
|
+
```cpp
|
|
94
|
+
// Los IDs de recurso de controles del archivo .rc se exponen como strings de AutomationId
|
|
95
|
+
// IDC_EDIT_USERNAME -> AutomationId "1001"
|
|
96
|
+
// Prefiere SetWindowText para Name; añade IAccessible para soporte más rico
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Qt — ver la sección dedicada más abajo
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Page Object Model
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
tests/
|
|
107
|
+
├── conftest.py # fixture de arranque de la app, captura en fallo
|
|
108
|
+
├── pytest.ini
|
|
109
|
+
├── config.py
|
|
110
|
+
├── pages/
|
|
111
|
+
│ ├── __init__.py # requerido para los imports
|
|
112
|
+
│ ├── base_page.py # localizadores, esperas, helpers de captura
|
|
113
|
+
│ ├── login_page.py
|
|
114
|
+
│ └── main_page.py
|
|
115
|
+
├── tests/
|
|
116
|
+
│ ├── __init__.py
|
|
117
|
+
│ ├── test_login.py
|
|
118
|
+
│ └── test_main_flow.py
|
|
119
|
+
└── artifacts/ # capturas, videos, logs
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### base_page.py
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import os, time
|
|
126
|
+
from pywinauto import Desktop
|
|
127
|
+
from config import ACTION_TIMEOUT, ARTIFACT_DIR
|
|
128
|
+
|
|
129
|
+
class BasePage:
|
|
130
|
+
def __init__(self, window):
|
|
131
|
+
self.window = window
|
|
132
|
+
|
|
133
|
+
# --- Localizadores (en orden de prioridad) ---
|
|
134
|
+
|
|
135
|
+
def by_id(self, auto_id, **kw):
|
|
136
|
+
"""AutomationId — el más estable. Úsalo como primera opción."""
|
|
137
|
+
return self.window.child_window(auto_id=auto_id, **kw)
|
|
138
|
+
|
|
139
|
+
def by_name(self, name, **kw):
|
|
140
|
+
"""Texto visible / nombre accesible."""
|
|
141
|
+
return self.window.child_window(title=name, **kw)
|
|
142
|
+
|
|
143
|
+
def by_class(self, cls, index=0, **kw):
|
|
144
|
+
"""Clase del control + índice — frágil, evítalo si es posible."""
|
|
145
|
+
return self.window.child_window(class_name=cls, found_index=index, **kw)
|
|
146
|
+
|
|
147
|
+
# --- Esperas ---
|
|
148
|
+
|
|
149
|
+
def wait_visible(self, spec, timeout=ACTION_TIMEOUT):
|
|
150
|
+
spec.wait("visible", timeout=timeout)
|
|
151
|
+
return spec
|
|
152
|
+
|
|
153
|
+
def wait_gone(self, spec, timeout=ACTION_TIMEOUT):
|
|
154
|
+
spec.wait_not("visible", timeout=timeout)
|
|
155
|
+
return spec
|
|
156
|
+
|
|
157
|
+
def wait_window(self, title, timeout=ACTION_TIMEOUT):
|
|
158
|
+
"""Espera una nueva ventana de nivel superior (diálogos, ventanas hijas)."""
|
|
159
|
+
dlg = Desktop(backend="uia").window(title=title)
|
|
160
|
+
dlg.wait("visible", timeout=timeout)
|
|
161
|
+
return dlg
|
|
162
|
+
|
|
163
|
+
def wait_until(self, fn, timeout=ACTION_TIMEOUT, interval=0.3):
|
|
164
|
+
"""Sondea una condición arbitraria — úsalo cuando los eventos UIA no son fiables."""
|
|
165
|
+
deadline = time.time() + timeout
|
|
166
|
+
while time.time() < deadline:
|
|
167
|
+
try:
|
|
168
|
+
if fn():
|
|
169
|
+
return True
|
|
170
|
+
except Exception:
|
|
171
|
+
pass
|
|
172
|
+
time.sleep(interval)
|
|
173
|
+
raise TimeoutError(f"Condición no cumplida en {timeout}s")
|
|
174
|
+
|
|
175
|
+
# --- Acciones ---
|
|
176
|
+
|
|
177
|
+
def click(self, spec):
|
|
178
|
+
self.wait_visible(spec)
|
|
179
|
+
spec.click_input()
|
|
180
|
+
|
|
181
|
+
def type_text(self, spec, text):
|
|
182
|
+
self.wait_visible(spec)
|
|
183
|
+
ctrl = spec.wrapper_object()
|
|
184
|
+
try:
|
|
185
|
+
ctrl.set_edit_text(text)
|
|
186
|
+
except Exception as e:
|
|
187
|
+
# Fallback para Qt 5.x: el Value Pattern de UIA puede estar incompleto
|
|
188
|
+
import sys, pywinauto.keyboard as kb
|
|
189
|
+
print(f"[e2e-escritorio-windows] set_edit_text falló ({e}), usando fallback de teclado", file=sys.stderr)
|
|
190
|
+
ctrl.click_input()
|
|
191
|
+
kb.send_keys("^a")
|
|
192
|
+
kb.send_keys(text, with_spaces=True)
|
|
193
|
+
|
|
194
|
+
def get_text(self, spec):
|
|
195
|
+
ctrl = spec.wrapper_object()
|
|
196
|
+
for attr in ("window_text", "get_value"):
|
|
197
|
+
try:
|
|
198
|
+
v = getattr(ctrl, attr)()
|
|
199
|
+
if v:
|
|
200
|
+
return v
|
|
201
|
+
except Exception:
|
|
202
|
+
pass
|
|
203
|
+
return ""
|
|
204
|
+
|
|
205
|
+
# --- Artefactos ---
|
|
206
|
+
|
|
207
|
+
def screenshot(self, name):
|
|
208
|
+
os.makedirs(ARTIFACT_DIR, exist_ok=True)
|
|
209
|
+
path = os.path.join(ARTIFACT_DIR, f"{name}.png")
|
|
210
|
+
self.window.capture_as_image().save(path)
|
|
211
|
+
return path
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### login_page.py
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from pages.base_page import BasePage
|
|
218
|
+
|
|
219
|
+
class LoginPage(BasePage):
|
|
220
|
+
@property
|
|
221
|
+
def username(self): return self.by_id("usernameInput")
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def password(self): return self.by_id("passwordInput")
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def btn_login(self): return self.by_id("btnLogin")
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def error_label(self): return self.by_id("lblError")
|
|
231
|
+
|
|
232
|
+
def login(self, user, pwd):
|
|
233
|
+
self.type_text(self.username, user)
|
|
234
|
+
self.type_text(self.password, pwd)
|
|
235
|
+
self.click(self.btn_login)
|
|
236
|
+
|
|
237
|
+
def login_ok(self, user, pwd, main_title="Main Window"):
|
|
238
|
+
self.login(user, pwd)
|
|
239
|
+
return self.wait_window(main_title)
|
|
240
|
+
|
|
241
|
+
def login_fail(self, user, pwd):
|
|
242
|
+
self.login(user, pwd)
|
|
243
|
+
self.wait_visible(self.error_label)
|
|
244
|
+
return self.get_text(self.error_label)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### conftest.py
|
|
248
|
+
|
|
249
|
+
> Para proyectos nuevos prefiere el **fixture sandbox de Nivel 1** (ver más abajo) — añade aislamiento de sistema de archivos a costo cero. Este fixture básico es solo para montajes mínimos o legados.
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
import os, pytest
|
|
253
|
+
os.environ["QT_ACCESSIBILITY"] = "1" # Requerido para soporte UIA en Qt 5.x
|
|
254
|
+
|
|
255
|
+
from pywinauto import Application
|
|
256
|
+
from config import APP_PATH, MAIN_WINDOW_TITLE, LAUNCH_TIMEOUT, ARTIFACT_DIR
|
|
257
|
+
|
|
258
|
+
@pytest.fixture
|
|
259
|
+
def app(request):
|
|
260
|
+
if not APP_PATH:
|
|
261
|
+
pytest.exit("La variable de entorno APP_PATH no está definida", returncode=1)
|
|
262
|
+
proc = Application(backend="uia").start(APP_PATH, timeout=LAUNCH_TIMEOUT)
|
|
263
|
+
win = proc.window(title=MAIN_WINDOW_TITLE)
|
|
264
|
+
win.wait("visible", timeout=LAUNCH_TIMEOUT)
|
|
265
|
+
yield win
|
|
266
|
+
# Captura de pantalla en caso de fallo
|
|
267
|
+
if getattr(getattr(request.node, "rep_call", None), "failed", False):
|
|
268
|
+
os.makedirs(ARTIFACT_DIR, exist_ok=True)
|
|
269
|
+
try:
|
|
270
|
+
win.capture_as_image().save(
|
|
271
|
+
os.path.join(ARTIFACT_DIR, f"FAIL_{request.node.name}.png")
|
|
272
|
+
)
|
|
273
|
+
except Exception:
|
|
274
|
+
pass
|
|
275
|
+
# Salida ordenada primero, kill forzado como respaldo
|
|
276
|
+
# proc es una Application de pywinauto — usa wait_for_process_exit(), no wait_for_process()
|
|
277
|
+
try:
|
|
278
|
+
win.close()
|
|
279
|
+
proc.wait_for_process_exit(timeout=5)
|
|
280
|
+
except Exception:
|
|
281
|
+
proc.kill()
|
|
282
|
+
|
|
283
|
+
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
|
284
|
+
def pytest_runtest_makereport(item, call):
|
|
285
|
+
outcome = yield
|
|
286
|
+
setattr(item, f"rep_{outcome.get_result().when}", outcome.get_result())
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### config.py
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
import os
|
|
293
|
+
APP_PATH = os.environ.get("APP_PATH", "") # se define por env — sin ruta por defecto
|
|
294
|
+
MAIN_WINDOW_TITLE = os.environ.get("APP_TITLE", "")
|
|
295
|
+
LAUNCH_TIMEOUT = int(os.environ.get("LAUNCH_TIMEOUT", "15"))
|
|
296
|
+
ACTION_TIMEOUT = int(os.environ.get("ACTION_TIMEOUT", "10"))
|
|
297
|
+
ARTIFACT_DIR = os.path.join(os.path.dirname(__file__), "artifacts")
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### pytest.ini
|
|
301
|
+
|
|
302
|
+
```ini
|
|
303
|
+
[pytest]
|
|
304
|
+
testpaths = tests
|
|
305
|
+
markers =
|
|
306
|
+
smoke: tests de humo rápidos para rutas críticas
|
|
307
|
+
flaky: tests conocidos como inestables
|
|
308
|
+
addopts = -v --tb=short --html=artifacts/report.html --self-contained-html
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Estrategia de localizadores
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
AutomationId > Name (texto) > ClassName + índice > XPath
|
|
315
|
+
(estable) (legible) (frágil) (último recurso)
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Inspecciona con Accessibility Insights → panel **Properties** → busca `AutomationId` primero.
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
# Inspección en tiempo de ejecución — pégalo en un REPL para explorar el árbol
|
|
322
|
+
win.print_control_identifiers()
|
|
323
|
+
# o acota el alcance:
|
|
324
|
+
win.child_window(auto_id="groupBox1").print_control_identifiers()
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Patrones de espera
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
# Esperar a que un control aparezca
|
|
331
|
+
page.wait_visible(page.by_id("statusLabel"))
|
|
332
|
+
|
|
333
|
+
# Esperar a que un control desaparezca (p. ej., spinner de carga)
|
|
334
|
+
page.wait_gone(page.by_id("spinnerOverlay"))
|
|
335
|
+
|
|
336
|
+
# Esperar a que aparezca un diálogo
|
|
337
|
+
dlg = page.wait_window("Confirm Delete")
|
|
338
|
+
|
|
339
|
+
# Condición personalizada (p. ej., cambio de texto)
|
|
340
|
+
page.wait_until(lambda: page.get_text(page.by_id("lblStatus")) == "Ready")
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
**Nunca uses `time.sleep()` como sincronización primaria** — usa `wait()` o `wait_until()`.
|
|
344
|
+
|
|
345
|
+
## Gestión de artefactos
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
# Captura bajo demanda
|
|
349
|
+
page.screenshot("after_login")
|
|
350
|
+
|
|
351
|
+
# Captura de pantalla completa (cuando la ventana está fuera de pantalla o minimizada)
|
|
352
|
+
import pyautogui
|
|
353
|
+
pyautogui.screenshot("artifacts/fullscreen.png")
|
|
354
|
+
|
|
355
|
+
# Grabación de pantalla con ffmpeg (inicia antes del test, detén después)
|
|
356
|
+
import subprocess
|
|
357
|
+
|
|
358
|
+
def start_recording(name):
|
|
359
|
+
return subprocess.Popen([
|
|
360
|
+
"ffmpeg", "-f", "gdigrab", "-framerate", "10",
|
|
361
|
+
"-i", "desktop", "-y", f"artifacts/videos/{name}.mp4"
|
|
362
|
+
], stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
363
|
+
|
|
364
|
+
def stop_recording(proc):
|
|
365
|
+
proc.stdin.write(b"q"); proc.stdin.flush(); proc.wait(timeout=10)
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Traza por paso (opt-in)
|
|
369
|
+
|
|
370
|
+
La captura por defecto al fallar suele ser insuficiente para diagnosticar tests inestables. La traza a nivel de paso está **desactivada por defecto** — habilítala solo al reproducir un caso flaky.
|
|
371
|
+
|
|
372
|
+
### Habilitar
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
E2E_TRACE=1 pytest tests/test_login.py -v
|
|
376
|
+
# Incluir el texto tecleado en el log JSONL (NO usar en tests que teclean credenciales/PII):
|
|
377
|
+
E2E_TRACE=1 E2E_TRACE_INCLUDE_TEXT=1 pytest ...
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Parche en BasePage
|
|
381
|
+
|
|
382
|
+
```python
|
|
383
|
+
import os, json, time
|
|
384
|
+
TRACE_ENABLED = os.environ.get("E2E_TRACE") == "1"
|
|
385
|
+
TRACE_INCLUDE_TEXT = os.environ.get("E2E_TRACE_INCLUDE_TEXT") == "1"
|
|
386
|
+
|
|
387
|
+
class BasePage:
|
|
388
|
+
_step = 0
|
|
389
|
+
|
|
390
|
+
def _trace(self, action, spec=None, text=None):
|
|
391
|
+
if not TRACE_ENABLED:
|
|
392
|
+
return
|
|
393
|
+
BasePage._step += 1
|
|
394
|
+
idx = f"{BasePage._step:03d}"
|
|
395
|
+
os.makedirs(ARTIFACT_DIR, exist_ok=True)
|
|
396
|
+
try:
|
|
397
|
+
self.window.capture_as_image().save(
|
|
398
|
+
os.path.join(ARTIFACT_DIR, f"step_{idx}_{action}.png"))
|
|
399
|
+
except Exception:
|
|
400
|
+
pass # un fallo de captura no debe romper el test
|
|
401
|
+
rec = {
|
|
402
|
+
"ts": time.time(), "step": BasePage._step, "action": action,
|
|
403
|
+
"locator": getattr(spec, "criteria", None),
|
|
404
|
+
"text": text if TRACE_INCLUDE_TEXT else ("<redactado>" if text else None),
|
|
405
|
+
}
|
|
406
|
+
with open(os.path.join(ARTIFACT_DIR, "trace.jsonl"), "a") as f:
|
|
407
|
+
f.write(json.dumps(rec) + "\n")
|
|
408
|
+
|
|
409
|
+
def click(self, spec):
|
|
410
|
+
self.wait_visible(spec); self._trace("click_before", spec)
|
|
411
|
+
spec.click_input(); self._trace("click_after", spec)
|
|
412
|
+
|
|
413
|
+
def type_text(self, spec, text):
|
|
414
|
+
self.wait_visible(spec); self._trace("type_before", spec, text)
|
|
415
|
+
# ... el set_edit_text / fallback de teclado existente ...
|
|
416
|
+
self._trace("type_after", spec)
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Advertencias
|
|
420
|
+
|
|
421
|
+
- **PII / credenciales**: el contenido de `type_text` queda `<redactado>` por defecto. Nunca actives `E2E_TRACE_INCLUDE_TEXT=1` en flujos de login o de pago.
|
|
422
|
+
- **Sobrecoste**: ~50–200 ms por acción + un PNG por paso en disco. No lo habilites en la matriz de CI por defecto — solo en un job dedicado a reproducir flakiness.
|
|
423
|
+
- **Inflado de artefactos**: un flujo largo produce decenas de MB; ajusta `retention-days` en consecuencia.
|
|
424
|
+
- **Higiene en paralelo/reintentos**: este ejemplo simple hace append a `trace.jsonl` y usa un contador a nivel de clase. Limpia el directorio de artefactos antes de reejecutar, y usa directorios de artefactos por worker para tests paralelos.
|
|
425
|
+
- **Hueco de cobertura**: las acciones realizadas fuera de `BasePage` (llamadas crudas a `pywinauto` en el código del test) no quedan trazadas.
|
|
426
|
+
|
|
427
|
+
## Manejo de tests inestables
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
# Cuarentena — equivalente a test.fixme() de Playwright
|
|
431
|
+
@pytest.mark.skip(reason="Flaky: carrera de animación en CI lento. Issue #42")
|
|
432
|
+
def test_animated_transition(self, app): ...
|
|
433
|
+
|
|
434
|
+
# Saltar solo en CI
|
|
435
|
+
@pytest.mark.skipif(os.environ.get("CI") == "true", reason="Flaky en CI #43")
|
|
436
|
+
def test_heavy_load(self, app): ...
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Causas comunes y soluciones:
|
|
440
|
+
|
|
441
|
+
| Causa | Solución |
|
|
442
|
+
|-------|----------|
|
|
443
|
+
| Control no listo | Reemplaza `time.sleep` por `wait_visible` |
|
|
444
|
+
| Ventana sin foco | Añade `win.set_focus()` antes de interactuar |
|
|
445
|
+
| Animación en curso | `wait_until(lambda: not loading_indicator.exists())` |
|
|
446
|
+
| Timing de diálogos | `wait_window(title, timeout=15)` |
|
|
447
|
+
| Pantalla de CI no lista | Define `DISPLAY` o usa escritorio virtual en CI |
|
|
448
|
+
| `set_edit_text` lanza NotImplementedError | Falta el ValuePattern de UIA (común en Qt 5.x) — `BasePage.type_text` ya cae a `keyboard.send_keys` |
|
|
449
|
+
| El control existe pero `wait_visible` expira | Ventana minimizada o fuera de pantalla — llama a `win.restore()` + `win.set_focus()` antes de esperar |
|
|
450
|
+
|
|
451
|
+
## Aislamiento de tests y sandbox
|
|
452
|
+
|
|
453
|
+
Tres niveles de aislamiento — usa el más ligero que satisfaga tus necesidades.
|
|
454
|
+
|
|
455
|
+
### Nivel 1 — Aislamiento de sistema de archivos (por defecto, úsalo siempre)
|
|
456
|
+
|
|
457
|
+
Cada test recibe su propio `APPDATA` / `LOCALAPPDATA` / `TEMP` vía `subprocess.Popen` y `Application.connect()`. El fixture `tmp_path` de pytest se encarga de la limpieza automáticamente.
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
# conftest.py — reemplaza el fixture `app` básico por este
|
|
461
|
+
import os, subprocess, pytest
|
|
462
|
+
from pywinauto import Application
|
|
463
|
+
from config import APP_PATH, APP_ARGS, APP_TITLE, LAUNCH_TIMEOUT, ACTION_TIMEOUT, ARTIFACT_DIR
|
|
464
|
+
|
|
465
|
+
@pytest.fixture(scope="function")
|
|
466
|
+
def app(request, tmp_path):
|
|
467
|
+
"""Proceso fresco + directorios de datos de usuario aislados por test."""
|
|
468
|
+
if not APP_PATH:
|
|
469
|
+
pytest.exit("APP_PATH no está definido", returncode=1)
|
|
470
|
+
|
|
471
|
+
# Redirige todo el almacenamiento por usuario a un directorio tmp aislado
|
|
472
|
+
sandbox_env = os.environ.copy()
|
|
473
|
+
sandbox_env["QT_ACCESSIBILITY"] = "1"
|
|
474
|
+
sandbox_env["APPDATA"] = str(tmp_path / "AppData" / "Roaming")
|
|
475
|
+
sandbox_env["LOCALAPPDATA"] = str(tmp_path / "AppData" / "Local")
|
|
476
|
+
sandbox_env["TEMP"] = sandbox_env["TMP"] = str(tmp_path / "Temp")
|
|
477
|
+
for p in (sandbox_env["APPDATA"], sandbox_env["LOCALAPPDATA"], sandbox_env["TEMP"]):
|
|
478
|
+
os.makedirs(p, exist_ok=True)
|
|
479
|
+
|
|
480
|
+
if not APP_TITLE:
|
|
481
|
+
pytest.exit("La variable de entorno APP_TITLE no está definida", returncode=1)
|
|
482
|
+
|
|
483
|
+
# shlex.split maneja argumentos entrecomillados con espacios; split() plano se rompe con ellos
|
|
484
|
+
import shlex
|
|
485
|
+
# Arranca vía subprocess para poder pasar env; conecta pywinauto por PID
|
|
486
|
+
proc = subprocess.Popen(
|
|
487
|
+
[APP_PATH] + shlex.split(APP_ARGS),
|
|
488
|
+
env=sandbox_env,
|
|
489
|
+
)
|
|
490
|
+
pw_app = Application(backend="uia").connect(process=proc.pid, timeout=LAUNCH_TIMEOUT)
|
|
491
|
+
win = pw_app.window(title=APP_TITLE)
|
|
492
|
+
win.wait("visible", timeout=LAUNCH_TIMEOUT)
|
|
493
|
+
yield win
|
|
494
|
+
|
|
495
|
+
if getattr(getattr(request.node, "rep_call", None), "failed", False):
|
|
496
|
+
os.makedirs(ARTIFACT_DIR, exist_ok=True)
|
|
497
|
+
try:
|
|
498
|
+
win.capture_as_image().save(
|
|
499
|
+
os.path.join(ARTIFACT_DIR, f"FAIL_{request.node.name}.png")
|
|
500
|
+
)
|
|
501
|
+
except Exception:
|
|
502
|
+
pass
|
|
503
|
+
try:
|
|
504
|
+
win.close()
|
|
505
|
+
proc.wait(timeout=5)
|
|
506
|
+
except Exception:
|
|
507
|
+
proc.kill()
|
|
508
|
+
# pytest limpia tmp_path automáticamente
|
|
509
|
+
|
|
510
|
+
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
|
511
|
+
def pytest_runtest_makereport(item, call):
|
|
512
|
+
outcome = yield
|
|
513
|
+
setattr(item, f"rep_{outcome.get_result().when}", outcome.get_result())
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Nivel 2 — Job Object de Windows (opcional: contención del ciclo de vida del proceso)
|
|
517
|
+
|
|
518
|
+
Adjunta el proceso a un Job Object para que sea **terminado automáticamente** cuando el handle del job del fixture sea recolectado por el GC. También evita que la app genere procesos hijos que escapen a la limpieza del fixture.
|
|
519
|
+
|
|
520
|
+
> **Alcance del aislamiento:** los Job Objects NO virtualizan el acceso al sistema de archivos ni bloquean el tráfico de red. El aislamiento de escritura de archivos y de red requiere AppContainer, reglas de Windows Firewall o el Nivel 3 (Windows Sandbox). Usa el Nivel 2 solo para contención del ciclo de vida del proceso y de procesos hijos.
|
|
521
|
+
|
|
522
|
+
No requiere dependencias adicionales.
|
|
523
|
+
|
|
524
|
+
```python
|
|
525
|
+
import ctypes, ctypes.wintypes as wt
|
|
526
|
+
|
|
527
|
+
def restrict_process(pid: int):
|
|
528
|
+
"""
|
|
529
|
+
Adjunta el proceso a un Job Object que le impide:
|
|
530
|
+
- generar procesos fuera del job (LIMIT_KILL_ON_JOB_CLOSE)
|
|
531
|
+
NO bloquea la red — usa reglas de Windows Firewall para eso.
|
|
532
|
+
"""
|
|
533
|
+
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000
|
|
534
|
+
# Derechos mínimos: SET_QUOTA (0x0100) | TERMINATE (0x0001)
|
|
535
|
+
PROCESS_SET_QUOTA_AND_TERMINATE = 0x0101
|
|
536
|
+
|
|
537
|
+
kernel32 = ctypes.windll.kernel32
|
|
538
|
+
job = kernel32.CreateJobObjectW(None, None)
|
|
539
|
+
hproc = kernel32.OpenProcess(PROCESS_SET_QUOTA_AND_TERMINATE, False, pid)
|
|
540
|
+
|
|
541
|
+
# Layout correcto de la estructura — LimitFlags está en el offset +16, no +44
|
|
542
|
+
class JOBOBJECT_BASIC_LIMIT_INFORMATION(ctypes.Structure):
|
|
543
|
+
_fields_ = [
|
|
544
|
+
("PerProcessUserTimeLimit", wt.LARGE_INTEGER),
|
|
545
|
+
("PerJobUserTimeLimit", wt.LARGE_INTEGER),
|
|
546
|
+
("LimitFlags", wt.DWORD),
|
|
547
|
+
("MinimumWorkingSetSize", ctypes.c_size_t),
|
|
548
|
+
("MaximumWorkingSetSize", ctypes.c_size_t),
|
|
549
|
+
("ActiveProcessLimit", wt.DWORD),
|
|
550
|
+
("Affinity", ctypes.c_size_t),
|
|
551
|
+
("PriorityClass", wt.DWORD),
|
|
552
|
+
("SchedulingClass", wt.DWORD),
|
|
553
|
+
]
|
|
554
|
+
|
|
555
|
+
info = JOBOBJECT_BASIC_LIMIT_INFORMATION()
|
|
556
|
+
info.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
|
557
|
+
ok = kernel32.SetInformationJobObject(job, 2, ctypes.byref(info), ctypes.sizeof(info))
|
|
558
|
+
if not ok:
|
|
559
|
+
raise ctypes.WinError()
|
|
560
|
+
kernel32.AssignProcessToJobObject(job, hproc)
|
|
561
|
+
kernel32.CloseHandle(hproc)
|
|
562
|
+
return job # mantenlo vivo — el job se cierra (mata el proceso) al ser recolectado
|
|
563
|
+
|
|
564
|
+
# Después de proc = subprocess.Popen(...): job = restrict_process(proc.pid)
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Nivel 3 — Windows Sandbox (aislamiento de SO completo en CI)
|
|
568
|
+
|
|
569
|
+
Cuando necesitas una imagen limpia de Windows por ejecución (sin claves de registro residuales, sin estado de GPU compartido, aislamiento real), ejecuta **la suite completa** dentro de [Windows Sandbox](https://learn.microsoft.com/windows/security/application-security/application-isolation/windows-sandbox/windows-sandbox-overview).
|
|
570
|
+
|
|
571
|
+
**Requisito:** Windows 10/11 Pro o Enterprise, con virtualización habilitada.
|
|
572
|
+
|
|
573
|
+
Crea `e2e-sandbox.wsb` en la raíz del proyecto:
|
|
574
|
+
|
|
575
|
+
```xml
|
|
576
|
+
<Configuration>
|
|
577
|
+
<MappedFolders>
|
|
578
|
+
<!-- Binario de la app (solo lectura) -->
|
|
579
|
+
<MappedFolder>
|
|
580
|
+
<HostFolder>C:\ruta\a\tu\build\Release</HostFolder>
|
|
581
|
+
<SandboxFolder>C:\app</SandboxFolder>
|
|
582
|
+
<ReadOnly>true</ReadOnly>
|
|
583
|
+
</MappedFolder>
|
|
584
|
+
<!-- Suite de tests (lectura-escritura para los artefactos) -->
|
|
585
|
+
<MappedFolder>
|
|
586
|
+
<HostFolder>C:\ruta\a\tu\e2e_test</HostFolder>
|
|
587
|
+
<SandboxFolder>C:\e2e_test</SandboxFolder>
|
|
588
|
+
<ReadOnly>false</ReadOnly>
|
|
589
|
+
</MappedFolder>
|
|
590
|
+
</MappedFolders>
|
|
591
|
+
<LogonCommand>
|
|
592
|
+
<!--
|
|
593
|
+
Windows Sandbox arranca sin Python. Instálalo en silencio primero,
|
|
594
|
+
luego instala las dependencias y ejecuta los tests. Los artefactos se
|
|
595
|
+
escriben de vuelta al host vía el MappedFolder de arriba.
|
|
596
|
+
-->
|
|
597
|
+
<Command>powershell -Command "
|
|
598
|
+
winget install --id Python.Python.3.11 --silent --accept-package-agreements;
|
|
599
|
+
$env:PATH += ';' + $env:LOCALAPPDATA + '\Programs\Python\Python311\Scripts';
|
|
600
|
+
cd C:\e2e_test;
|
|
601
|
+
pip install -r requirements.txt;
|
|
602
|
+
pytest tests\ -v
|
|
603
|
+
"</Command>
|
|
604
|
+
</LogonCommand>
|
|
605
|
+
</Configuration>
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
Lanzamiento: `WindowsSandbox.exe e2e-sandbox.wsb`
|
|
609
|
+
|
|
610
|
+
> pywinauto y la app corren ambos **dentro** del sandbox (se requiere la misma sesión).
|
|
611
|
+
> Los artefactos se escriben de vuelta al host vía la carpeta mapeada.
|
|
612
|
+
|
|
613
|
+
### Comparación de niveles
|
|
614
|
+
|
|
615
|
+
| Nivel | Aislamiento | Costo de montaje | Funciona en CI | Úsalo cuando |
|
|
616
|
+
|-------|-------------|------------------|----------------|--------------|
|
|
617
|
+
| 1 — Redirección env a `tmp_path` | Sistema de archivos | Cero | Siempre | Por defecto para todos los tests |
|
|
618
|
+
| 2 — Job Object | Árbol de procesos | Bajo | Siempre | Evitar fugas de procesos hijos |
|
|
619
|
+
| 3 — Windows Sandbox | SO completo | Medio | Necesita imagen Pro/Enterprise | Ejecuciones nocturnas en sala limpia |
|
|
620
|
+
|
|
621
|
+
### Prevenir tests colgados
|
|
622
|
+
|
|
623
|
+
Añade `pytest-timeout` para acotar cualquier test individual. En `pytest.ini` define `timeout = 60` y `timeout_method = thread`. Nota: el método `thread` no puede matar subprocesos de apps Qt en Windows — añade `atexit.register(lambda: [p.kill() for p in psutil.Process().children(recursive=True)])` en `conftest.py` para recoger huérfanos.
|
|
624
|
+
|
|
625
|
+
## Integración CI/CD
|
|
626
|
+
|
|
627
|
+
```yaml
|
|
628
|
+
# .github/workflows/e2e-desktop.yml
|
|
629
|
+
name: Desktop E2E
|
|
630
|
+
on: [push, pull_request]
|
|
631
|
+
|
|
632
|
+
jobs:
|
|
633
|
+
e2e:
|
|
634
|
+
runs-on: windows-latest # entorno GUI real, no hace falta Xvfb
|
|
635
|
+
steps:
|
|
636
|
+
- uses: actions/checkout@v4
|
|
637
|
+
|
|
638
|
+
- uses: actions/setup-python@v5
|
|
639
|
+
with: { python-version: "3.11" }
|
|
640
|
+
|
|
641
|
+
- name: Instalar dependencias
|
|
642
|
+
run: pip install pywinauto pytest pytest-html Pillow
|
|
643
|
+
|
|
644
|
+
- name: Compilar la app
|
|
645
|
+
run: cmake --build build --config Release # ajusta a tu sistema de build
|
|
646
|
+
|
|
647
|
+
- name: Ejecutar E2E
|
|
648
|
+
env:
|
|
649
|
+
APP_PATH: ${{ github.workspace }}\build\Release\MyApp.exe
|
|
650
|
+
APP_TITLE: "My Application"
|
|
651
|
+
CI: "true"
|
|
652
|
+
run: pytest tests/ --html=artifacts/report.html --self-contained-html --junitxml=artifacts/results.xml -v
|
|
653
|
+
|
|
654
|
+
- uses: actions/upload-artifact@v4
|
|
655
|
+
if: always()
|
|
656
|
+
with:
|
|
657
|
+
name: e2e-artifacts
|
|
658
|
+
path: artifacts/
|
|
659
|
+
retention-days: 14
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
## Particularidades de Qt
|
|
663
|
+
|
|
664
|
+
### Habilitar UIA en Qt 5.x
|
|
665
|
+
|
|
666
|
+
La accesibilidad de Qt 5.x está deshabilitada por defecto en algunos builds (especialmente 5.7–5.14). Define la variable de entorno **antes** de arrancar. Qt 6.x habilita la accesibilidad por defecto — omite este paso para Qt 6.
|
|
667
|
+
|
|
668
|
+
```python
|
|
669
|
+
# conftest.py — añadir al inicio del módulo
|
|
670
|
+
import os
|
|
671
|
+
os.environ["QT_ACCESSIBILITY"] = "1"
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
O expórtala en CI:
|
|
675
|
+
|
|
676
|
+
```yaml
|
|
677
|
+
env:
|
|
678
|
+
QT_ACCESSIBILITY: "1"
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### Añadir identificadores estables a widgets Qt
|
|
682
|
+
|
|
683
|
+
```cpp
|
|
684
|
+
// Preferido: tanto objectName como accessibleName
|
|
685
|
+
void setTestId(QWidget* w, const char* id) {
|
|
686
|
+
w->setObjectName(id);
|
|
687
|
+
w->setAccessibleName(id); // se convierte en la propiedad Name de UIA
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// En el constructor de tu diálogo:
|
|
691
|
+
setTestId(ui->usernameEdit, "usernameInput");
|
|
692
|
+
setTestId(ui->passwordEdit, "passwordInput");
|
|
693
|
+
setTestId(ui->loginButton, "btnLogin");
|
|
694
|
+
setTestId(ui->errorLabel, "lblError");
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
Centraliza todos los IDs en un header para evitar erratas:
|
|
698
|
+
|
|
699
|
+
```cpp
|
|
700
|
+
// test_ids.h
|
|
701
|
+
#define TID_USERNAME "usernameInput"
|
|
702
|
+
#define TID_PASSWORD "passwordInput"
|
|
703
|
+
#define TID_BTN_LOGIN "btnLogin"
|
|
704
|
+
#define TID_LBL_ERROR "lblError"
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Peculiaridades específicas de Qt
|
|
708
|
+
|
|
709
|
+
**QComboBox** — el desplegable es una ventana de nivel superior separada:
|
|
710
|
+
|
|
711
|
+
```python
|
|
712
|
+
from pywinauto import Desktop
|
|
713
|
+
|
|
714
|
+
def select_combo_item(page, combo_spec, item_text):
|
|
715
|
+
page.click(combo_spec)
|
|
716
|
+
# El desplegable aparece como una nueva ventana raíz
|
|
717
|
+
# class_name varía según la versión de Qt — verifica con Accessibility Insights
|
|
718
|
+
# Qt 5.x: "Qt5QWindowIcon" | Qt 6.x: "Qt6QWindowIcon" — verifica con Accessibility Insights
|
|
719
|
+
popup = Desktop(backend="uia").window(class_name_re="Qt[56]QWindowIcon")
|
|
720
|
+
popup.wait("visible", timeout=5)
|
|
721
|
+
popup.child_window(title=item_text).click_input()
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
**QMessageBox / QDialog** — también son ventanas de nivel superior separadas:
|
|
725
|
+
|
|
726
|
+
```python
|
|
727
|
+
dlg = page.wait_window("Confirm") # espera el título del diálogo
|
|
728
|
+
dlg.child_window(title="OK").click_input() # clic en el botón interior
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
**QTableWidget / QTableView** — acceso a filas/celdas:
|
|
732
|
+
|
|
733
|
+
```python
|
|
734
|
+
table = page.by_id("tblUsers").wrapper_object()
|
|
735
|
+
cell = table.cell(row=0, column=1)
|
|
736
|
+
print(cell.window_text())
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
**Controles autodibujados** (`paintEvent` puro, `QGraphicsView`, `QOpenGLWidget`) — UIA no puede ver su interior. Usa la sección de fallback más abajo.
|
|
740
|
+
|
|
741
|
+
## Fallback: modo de capturas
|
|
742
|
+
|
|
743
|
+
Cuando un control no es alcanzable vía UIA (autodibujado, de terceros, motor de juego):
|
|
744
|
+
|
|
745
|
+
```bash
|
|
746
|
+
pip install pyautogui Pillow opencv-python
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
```python
|
|
750
|
+
import pyautogui, cv2, numpy as np
|
|
751
|
+
from PIL import Image
|
|
752
|
+
|
|
753
|
+
def find_image_on_screen(template_path, confidence=0.85):
|
|
754
|
+
"""Localiza una imagen plantilla en pantalla. Devuelve el centro (x, y) o None."""
|
|
755
|
+
screen = np.array(pyautogui.screenshot())
|
|
756
|
+
template = np.array(Image.open(template_path))
|
|
757
|
+
result = cv2.matchTemplate(
|
|
758
|
+
cv2.cvtColor(screen, cv2.COLOR_RGB2BGR),
|
|
759
|
+
cv2.cvtColor(template, cv2.COLOR_RGB2BGR),
|
|
760
|
+
cv2.TM_CCOEFF_NORMED,
|
|
761
|
+
)
|
|
762
|
+
_, max_val, _, max_loc = cv2.minMaxLoc(result)
|
|
763
|
+
if max_val >= confidence:
|
|
764
|
+
h, w = template.shape[:2]
|
|
765
|
+
return max_loc[0] + w // 2, max_loc[1] + h // 2
|
|
766
|
+
return None
|
|
767
|
+
|
|
768
|
+
def click_image(template_path, confidence=0.85):
|
|
769
|
+
pos = find_image_on_screen(template_path, confidence)
|
|
770
|
+
if pos is None:
|
|
771
|
+
raise RuntimeError(f"Imagen no encontrada en pantalla: {template_path}")
|
|
772
|
+
pyautogui.click(*pos)
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Reglas de DPI / escalado (solo modo de capturas)
|
|
776
|
+
|
|
777
|
+
El matching por capturas es brutalmente sensible al escalado de pantalla de Windows (100 % / 125 % / 150 %). Tres reglas duras:
|
|
778
|
+
|
|
779
|
+
1. **Captura las plantillas a la misma escala que la máquina objetivo.** No intentes rescatar un desajuste con `PIL.Image.resize` — `cv2.matchTemplate` es muy frágil frente a artefactos de remuestreo.
|
|
780
|
+
2. **Fija el escalado de pantalla en CI.** En `windows-latest` añade un paso como `Set-DisplayResolution 1920 1080 -Force` y deshabilita el escalado DPI por monitor, para que las dimensiones de las capturas sean reproducibles.
|
|
781
|
+
3. **Registra la escala junto a cada artefacto.** Al capturar, escribe `GetDpiForWindow(hwnd) / 96` en `artifacts/<test>/metadata.json` — los postmortems se vuelven obvios en lugar de adivinanzas.
|
|
782
|
+
|
|
783
|
+
> La conciencia de DPI a nivel de proceso (`SetProcessDpiAwarenessContext`) **puede entrar en conflicto con la gestión de DPI propia de Qt** cuando la app bajo prueba es Qt. Prefiere "plantillas a la misma escala + fijar CI" antes que cambiar el modo DPI de todo el proceso en los fixtures.
|
|
784
|
+
|
|
785
|
+
### Depurar la confianza del match
|
|
786
|
+
|
|
787
|
+
Al ajustar el umbral de `confidence`, el único flujo sensato es **ver** dónde cayó el match. El helper de abajo es solo para diagnóstico — no lo llames desde código de tests.
|
|
788
|
+
|
|
789
|
+
```python
|
|
790
|
+
def debug_match(template_path, out="artifacts/match_debug.png", confidence=0.85):
|
|
791
|
+
"""Solo diagnóstico. Dibuja el rectángulo del mejor match + puntuación sobre la pantalla actual.
|
|
792
|
+
|
|
793
|
+
NO es para tests de producción — úsalo al calibrar la confianza o al perseguir falsos matches.
|
|
794
|
+
"""
|
|
795
|
+
import os, cv2, pyautogui, numpy as np
|
|
796
|
+
screen = np.array(pyautogui.screenshot())[:, :, ::-1]
|
|
797
|
+
tpl = cv2.imread(template_path)
|
|
798
|
+
if tpl is None:
|
|
799
|
+
raise RuntimeError(f"Plantilla ilegible: {template_path}")
|
|
800
|
+
res = cv2.matchTemplate(screen, tpl, cv2.TM_CCOEFF_NORMED)
|
|
801
|
+
_, mv, _, ml = cv2.minMaxLoc(res)
|
|
802
|
+
h, w = tpl.shape[:2]
|
|
803
|
+
colour = (0, 255, 0) if mv >= confidence else (0, 0, 255) # verde pasa / rojo falla
|
|
804
|
+
cv2.rectangle(screen, ml, (ml[0]+w, ml[1]+h), colour, 2)
|
|
805
|
+
cv2.putText(screen, f"score={mv:.3f} thr={confidence}",
|
|
806
|
+
(ml[0], max(20, ml[1]-6)),
|
|
807
|
+
cv2.FONT_HERSHEY_SIMPLEX, 0.7, colour, 2)
|
|
808
|
+
os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
|
|
809
|
+
cv2.imwrite(out, screen)
|
|
810
|
+
return mv
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
**Úsalo con moderación** — el matching de imágenes se rompe con cambios de DPI, cambios de tema y oclusión parcial.
|
|
814
|
+
Intenta siempre UIA primero; cae a capturas solo para controles genuinamente inalcanzables.
|
|
815
|
+
|
|
816
|
+
## Antipatrones
|
|
817
|
+
|
|
818
|
+
```python
|
|
819
|
+
# MAL: sleep fijo
|
|
820
|
+
time.sleep(3)
|
|
821
|
+
page.click(page.by_id("btnSubmit"))
|
|
822
|
+
|
|
823
|
+
# BIEN: espera por condición
|
|
824
|
+
page.wait_visible(page.by_id("btnSubmit"))
|
|
825
|
+
page.click(page.by_id("btnSubmit"))
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
```python
|
|
829
|
+
# MAL: localizador frágil clase+índice como estrategia primaria
|
|
830
|
+
page.by_class("Edit", index=2).type_keys("hola")
|
|
831
|
+
|
|
832
|
+
# BIEN: AutomationId
|
|
833
|
+
page.by_id("usernameInput").set_edit_text("hola")
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
```python
|
|
837
|
+
# MAL: aserciones sobre coordenadas de píxeles
|
|
838
|
+
assert btn.rectangle().left == 120
|
|
839
|
+
|
|
840
|
+
# BIEN: aserciones sobre contenido / estado
|
|
841
|
+
assert page.get_text(page.by_id("lblStatus")) == "Logged in"
|
|
842
|
+
assert page.by_id("btnLogout").is_enabled()
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
```python
|
|
846
|
+
# MAL: compartir la instancia de la app entre todos los tests (fugas de estado)
|
|
847
|
+
@pytest.fixture(scope="session")
|
|
848
|
+
def app(): ...
|
|
849
|
+
|
|
850
|
+
# BIEN: proceso fresco por test (o por clase como máximo)
|
|
851
|
+
@pytest.fixture(scope="function")
|
|
852
|
+
def app(): ...
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
## Ejecutar los tests
|
|
856
|
+
|
|
857
|
+
```bash
|
|
858
|
+
# Todos los tests
|
|
859
|
+
pytest tests/ -v
|
|
860
|
+
|
|
861
|
+
# Solo smoke
|
|
862
|
+
pytest tests/ -m smoke -v
|
|
863
|
+
|
|
864
|
+
# Un archivo específico
|
|
865
|
+
pytest tests/test_login.py -v
|
|
866
|
+
|
|
867
|
+
# Con ruta de app personalizada
|
|
868
|
+
APP_PATH="C:\build\Release\MyApp.exe" APP_TITLE="MyApp" pytest tests/ -v
|
|
869
|
+
|
|
870
|
+
# Detectar tests inestables (repetir cada uno 5 veces)
|
|
871
|
+
pip install pytest-repeat
|
|
872
|
+
pytest tests/test_login.py --count=5 -v
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
## Skills relacionadas
|
|
876
|
+
|
|
877
|
+
- `testing-e2e` — E2E con Playwright para aplicaciones web
|
|
878
|
+
- `testing-cpp` — testing unitario/de integración en C++ con GoogleTest
|
|
879
|
+
- `estandares-cpp` — estilo y patrones de código C++
|