theus-cli-linux-arm64 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (758) hide show
  1. package/RELEASE.json +6 -6
  2. package/bin/theus +0 -0
  3. package/package.json +1 -1
  4. package/vendor/higiene-motor/PARCHES.md +244 -0
  5. package/vendor/higiene-motor/audit_dir.py +166 -0
  6. package/vendor/higiene-motor/audit_lib.py +333 -0
  7. package/vendor/higiene-motor/audit_website.py +635 -0
  8. package/vendor/higiene-motor/av_meta.py +498 -0
  9. package/vendor/higiene-motor/check_staged.py +71 -0
  10. package/vendor/higiene-motor/clean_ctrlregen.py +212 -0
  11. package/vendor/higiene-motor/clean_file.py +237 -0
  12. package/vendor/higiene-motor/clean_image.py +218 -0
  13. package/vendor/higiene-motor/clean_staged.py +143 -0
  14. package/vendor/higiene-motor/clean_text.py +108 -0
  15. package/vendor/higiene-motor/common.py +486 -0
  16. package/vendor/higiene-motor/container_meta.py +2522 -0
  17. package/vendor/higiene-motor/detect_gumbel.py +308 -0
  18. package/vendor/higiene-motor/detect_text_watermark.py +613 -0
  19. package/vendor/higiene-motor/format_dispatch.py +157 -0
  20. package/vendor/higiene-motor/hook_written_file.py +253 -0
  21. package/vendor/higiene-motor/image_meta.py +2171 -0
  22. package/vendor/higiene-motor/inspect_file.py +138 -0
  23. package/vendor/higiene-motor/inspect_image.py +72 -0
  24. package/vendor/higiene-motor/inspect_text.py +86 -0
  25. package/vendor/higiene-motor/markdiffusion_harness.py +533 -0
  26. package/vendor/higiene-motor/rewrite_text.py +737 -0
  27. package/vendor/higiene-motor/score_stylometry.py +460 -0
  28. package/vendor/higiene-motor/score_synthid.py +165 -0
  29. package/vendor/higiene-motor/server.py +1059 -0
  30. package/vendor/higiene-motor/synthid_score_server.py +176 -0
  31. package/vendor/higiene-motor/text_detectors.py +433 -0
  32. package/vendor/higiene-motor/text_unicode.py +730 -0
  33. package/vendor/theus-arsenal/.arsenal-nombres-ola2.json +0 -6
  34. package/vendor/theus-arsenal/.arsenal-nombres-ola3.json +0 -72
  35. package/vendor/theus-arsenal/.mailmap +0 -2
  36. package/vendor/theus-arsenal/.theus-plugin/marketplace.json +0 -25
  37. package/vendor/theus-arsenal/.theus-plugin/plugin.json +0 -20
  38. package/vendor/theus-arsenal/AUTHORS.md +0 -8
  39. package/vendor/theus-arsenal/CLEANROOM_REPLACEMENT_PLAN.md +0 -11
  40. package/vendor/theus-arsenal/LICENSE +0 -26
  41. package/vendor/theus-arsenal/PROVENANCE.md +0 -9
  42. package/vendor/theus-arsenal/README.md +0 -41
  43. package/vendor/theus-arsenal/THIRD_PARTY.md +0 -80
  44. package/vendor/theus-arsenal/agents/actualizador-docs.md +0 -123
  45. package/vendor/theus-arsenal/agents/analista-comentarios.md +0 -53
  46. package/vendor/theus-arsenal/agents/analista-conversaciones.md +0 -60
  47. package/vendor/theus-arsenal/agents/analista-tests-pr.md +0 -53
  48. package/vendor/theus-arsenal/agents/analista-tipos.md +0 -49
  49. package/vendor/theus-arsenal/agents/arquitecto-accesibilidad.md +0 -148
  50. package/vendor/theus-arsenal/agents/arquitecto-codigo.md +0 -79
  51. package/vendor/theus-arsenal/agents/arquitecto-homelab.md +0 -90
  52. package/vendor/theus-arsenal/agents/arquitecto-redes.md +0 -116
  53. package/vendor/theus-arsenal/agents/arquitecto-sistemas.md +0 -219
  54. package/vendor/theus-arsenal/agents/bifurcador-opensource.md +0 -206
  55. package/vendor/theus-arsenal/agents/cazador-fallos-silenciosos.md +0 -58
  56. package/vendor/theus-arsenal/agents/consultor-documentacion.md +0 -76
  57. package/vendor/theus-arsenal/agents/diagnosticador-redes.md +0 -135
  58. package/vendor/theus-arsenal/agents/ejecutor-e2e.md +0 -96
  59. package/vendor/theus-arsenal/agents/empaquetador-opensource.md +0 -257
  60. package/vendor/theus-arsenal/agents/escaner-secretos.md +0 -196
  61. package/vendor/theus-arsenal/agents/especialista-seo.md +0 -70
  62. package/vendor/theus-arsenal/agents/estratega-marketing.md +0 -158
  63. package/vendor/theus-arsenal/agents/evaluador-agentes.md +0 -214
  64. package/vendor/theus-arsenal/agents/evaluador-harness.md +0 -217
  65. package/vendor/theus-arsenal/agents/explorador-codigo.md +0 -79
  66. package/vendor/theus-arsenal/agents/extractor-specs.md +0 -214
  67. package/vendor/theus-arsenal/agents/generador-harness.md +0 -139
  68. package/vendor/theus-arsenal/agents/guia-tdd.md +0 -99
  69. package/vendor/theus-arsenal/agents/jefe-de-gabinete.md +0 -162
  70. package/vendor/theus-arsenal/agents/limpiador-refactors.md +0 -93
  71. package/vendor/theus-arsenal/agents/optimizador-rendimiento.md +0 -454
  72. package/vendor/theus-arsenal/agents/planificador-harness.md +0 -107
  73. package/vendor/theus-arsenal/agents/planificador.md +0 -221
  74. package/vendor/theus-arsenal/agents/resolutor-apps-harmonyos.md +0 -181
  75. package/vendor/theus-arsenal/agents/resolutor-builds-cpp.md +0 -98
  76. package/vendor/theus-arsenal/agents/resolutor-builds-dart.md +0 -209
  77. package/vendor/theus-arsenal/agents/resolutor-builds-django.md +0 -253
  78. package/vendor/theus-arsenal/agents/resolutor-builds-go.md +0 -102
  79. package/vendor/theus-arsenal/agents/resolutor-builds-java.md +0 -274
  80. package/vendor/theus-arsenal/agents/resolutor-builds-kotlin.md +0 -128
  81. package/vendor/theus-arsenal/agents/resolutor-builds-pytorch.md +0 -128
  82. package/vendor/theus-arsenal/agents/resolutor-builds-react.md +0 -214
  83. package/vendor/theus-arsenal/agents/resolutor-builds-rust.md +0 -156
  84. package/vendor/theus-arsenal/agents/resolutor-builds-swift.md +0 -169
  85. package/vendor/theus-arsenal/agents/resolutor-builds.md +0 -122
  86. package/vendor/theus-arsenal/agents/revisor-bd.md +0 -97
  87. package/vendor/theus-arsenal/agents/revisor-codigo.md +0 -291
  88. package/vendor/theus-arsenal/agents/revisor-config-red.md +0 -116
  89. package/vendor/theus-arsenal/agents/revisor-cpp.md +0 -80
  90. package/vendor/theus-arsenal/agents/revisor-csharp.md +0 -109
  91. package/vendor/theus-arsenal/agents/revisor-django.md +0 -168
  92. package/vendor/theus-arsenal/agents/revisor-fastapi.md +0 -82
  93. package/vendor/theus-arsenal/agents/revisor-flutter.md +0 -251
  94. package/vendor/theus-arsenal/agents/revisor-go.md +0 -84
  95. package/vendor/theus-arsenal/agents/revisor-java.md +0 -192
  96. package/vendor/theus-arsenal/agents/revisor-kotlin.md +0 -171
  97. package/vendor/theus-arsenal/agents/revisor-ml.md +0 -159
  98. package/vendor/theus-arsenal/agents/revisor-php.md +0 -108
  99. package/vendor/theus-arsenal/agents/revisor-python.md +0 -106
  100. package/vendor/theus-arsenal/agents/revisor-react.md +0 -166
  101. package/vendor/theus-arsenal/agents/revisor-rust.md +0 -102
  102. package/vendor/theus-arsenal/agents/revisor-seguridad.md +0 -116
  103. package/vendor/theus-arsenal/agents/revisor-software-clinico.md +0 -95
  104. package/vendor/theus-arsenal/agents/revisor-swift.md +0 -115
  105. package/vendor/theus-arsenal/agents/revisor-typescript.md +0 -123
  106. package/vendor/theus-arsenal/agents/revisor-vue.md +0 -205
  107. package/vendor/theus-arsenal/agents/simplificador-codigo.md +0 -55
  108. package/vendor/theus-arsenal/commands/actualizar-docs.md +0 -88
  109. package/vendor/theus-arsenal/commands/actualizar-mapas-codigo.md +0 -78
  110. package/vendor/theus-arsenal/commands/aprender-evaluar.md +0 -109
  111. package/vendor/theus-arsenal/commands/aprender.md +0 -74
  112. package/vendor/theus-arsenal/commands/arreglar-build.md +0 -66
  113. package/vendor/theus-arsenal/commands/bucle-multiperspectiva.md +0 -153
  114. package/vendor/theus-arsenal/commands/build-cpp.md +0 -173
  115. package/vendor/theus-arsenal/commands/build-flutter.md +0 -164
  116. package/vendor/theus-arsenal/commands/build-go.md +0 -183
  117. package/vendor/theus-arsenal/commands/build-gradle.md +0 -75
  118. package/vendor/theus-arsenal/commands/build-kotlin.md +0 -176
  119. package/vendor/theus-arsenal/commands/build-react.md +0 -187
  120. package/vendor/theus-arsenal/commands/build-rust.md +0 -187
  121. package/vendor/theus-arsenal/commands/campana-marketing.md +0 -125
  122. package/vendor/theus-arsenal/commands/checkpoint.md +0 -78
  123. package/vendor/theus-arsenal/commands/cobertura-tests.md +0 -73
  124. package/vendor/theus-arsenal/commands/configurar-gestor-paquetes.md +0 -86
  125. package/vendor/theus-arsenal/commands/consulta.md +0 -164
  126. package/vendor/theus-arsenal/commands/control-calidad.md +0 -50
  127. package/vendor/theus-arsenal/commands/crear-skill.md +0 -77
  128. package/vendor/theus-arsenal/commands/enrutar-modelo.md +0 -30
  129. package/vendor/theus-arsenal/commands/epica-desbloquear.md +0 -17
  130. package/vendor/theus-arsenal/commands/epica-descomponer.md +0 -22
  131. package/vendor/theus-arsenal/commands/epica-publicar.md +0 -21
  132. package/vendor/theus-arsenal/commands/epica-reclamar.md +0 -25
  133. package/vendor/theus-arsenal/commands/epica-revisar.md +0 -22
  134. package/vendor/theus-arsenal/commands/epica-sincronizar.md +0 -21
  135. package/vendor/theus-arsenal/commands/epica-validar.md +0 -21
  136. package/vendor/theus-arsenal/commands/evolucionar.md +0 -176
  137. package/vendor/theus-arsenal/commands/funcionalidad.md +0 -49
  138. package/vendor/theus-arsenal/commands/guardar-sesion.md +0 -278
  139. package/vendor/theus-arsenal/commands/harness-build.md +0 -111
  140. package/vendor/theus-arsenal/commands/harness-diseno.md +0 -46
  141. package/vendor/theus-arsenal/commands/informe-costos.md +0 -90
  142. package/vendor/theus-arsenal/commands/iniciar-bucle.md +0 -36
  143. package/vendor/theus-arsenal/commands/instintos-estado.md +0 -53
  144. package/vendor/theus-arsenal/commands/instintos-exportar.md +0 -69
  145. package/vendor/theus-arsenal/commands/instintos-importar.md +0 -120
  146. package/vendor/theus-arsenal/commands/lienzo-planes.md +0 -48
  147. package/vendor/theus-arsenal/commands/limpiar-refactor.md +0 -84
  148. package/vendor/theus-arsenal/commands/modo-seguro.md +0 -96
  149. package/vendor/theus-arsenal/commands/orq-agregar-funcionalidad.md +0 -36
  150. package/vendor/theus-arsenal/commands/orq-cambiar-funcionalidad.md +0 -38
  151. package/vendor/theus-arsenal/commands/orq-construir-mvp.md +0 -36
  152. package/vendor/theus-arsenal/commands/orq-corregir-defecto.md +0 -40
  153. package/vendor/theus-arsenal/commands/orq-refinar-codigo.md +0 -44
  154. package/vendor/theus-arsenal/commands/orq-revisar.md +0 -135
  155. package/vendor/theus-arsenal/commands/plan-prd.md +0 -160
  156. package/vendor/theus-arsenal/commands/plan.md +0 -198
  157. package/vendor/theus-arsenal/commands/podar.md +0 -31
  158. package/vendor/theus-arsenal/commands/pr.md +0 -181
  159. package/vendor/theus-arsenal/commands/promover.md +0 -41
  160. package/vendor/theus-arsenal/commands/proyectos.md +0 -33
  161. package/vendor/theus-arsenal/commands/prp-commit.md +0 -112
  162. package/vendor/theus-arsenal/commands/prp-implementar.md +0 -385
  163. package/vendor/theus-arsenal/commands/prp-planificar.md +0 -501
  164. package/vendor/theus-arsenal/commands/reanudar-sesion.md +0 -160
  165. package/vendor/theus-arsenal/commands/revisar-codigo.md +0 -289
  166. package/vendor/theus-arsenal/commands/revisar-cpp.md +0 -132
  167. package/vendor/theus-arsenal/commands/revisar-fastapi.md +0 -39
  168. package/vendor/theus-arsenal/commands/revisar-flutter.md +0 -115
  169. package/vendor/theus-arsenal/commands/revisar-go.md +0 -148
  170. package/vendor/theus-arsenal/commands/revisar-kotlin.md +0 -140
  171. package/vendor/theus-arsenal/commands/revisar-pr.md +0 -37
  172. package/vendor/theus-arsenal/commands/revisar-python.md +0 -297
  173. package/vendor/theus-arsenal/commands/revisar-react.md +0 -170
  174. package/vendor/theus-arsenal/commands/revisar-rust.md +0 -142
  175. package/vendor/theus-arsenal/commands/revisar-vue.md +0 -174
  176. package/vendor/theus-arsenal/commands/salud-skills.md +0 -52
  177. package/vendor/theus-arsenal/commands/sesiones.md +0 -345
  178. package/vendor/theus-arsenal/commands/test-cpp.md +0 -252
  179. package/vendor/theus-arsenal/commands/test-flutter.md +0 -143
  180. package/vendor/theus-arsenal/commands/test-go.md +0 -268
  181. package/vendor/theus-arsenal/commands/test-kotlin.md +0 -312
  182. package/vendor/theus-arsenal/commands/test-react.md +0 -265
  183. package/vendor/theus-arsenal/commands/test-rust.md +0 -309
  184. package/vendor/theus-arsenal/commands/vigilancia-canary.md +0 -43
  185. package/vendor/theus-arsenal/hooks/hooks.json +0 -274
  186. package/vendor/theus-arsenal/package.json +0 -6
  187. package/vendor/theus-arsenal/rules/angular/coding-style.md +0 -182
  188. package/vendor/theus-arsenal/rules/angular/hooks.md +0 -25
  189. package/vendor/theus-arsenal/rules/angular/patterns.md +0 -249
  190. package/vendor/theus-arsenal/rules/angular/security.md +0 -87
  191. package/vendor/theus-arsenal/rules/angular/testing.md +0 -164
  192. package/vendor/theus-arsenal/rules/arkts/coding-style.md +0 -153
  193. package/vendor/theus-arsenal/rules/arkts/hooks.md +0 -80
  194. package/vendor/theus-arsenal/rules/arkts/patterns.md +0 -236
  195. package/vendor/theus-arsenal/rules/arkts/security.md +0 -141
  196. package/vendor/theus-arsenal/rules/arkts/testing.md +0 -126
  197. package/vendor/theus-arsenal/rules/common/agents.md +0 -49
  198. package/vendor/theus-arsenal/rules/common/code-review.md +0 -123
  199. package/vendor/theus-arsenal/rules/common/coding-style.md +0 -90
  200. package/vendor/theus-arsenal/rules/common/development-workflow.md +0 -44
  201. package/vendor/theus-arsenal/rules/common/git-workflow.md +0 -24
  202. package/vendor/theus-arsenal/rules/common/hooks.md +0 -32
  203. package/vendor/theus-arsenal/rules/common/patterns.md +0 -31
  204. package/vendor/theus-arsenal/rules/common/performance.md +0 -53
  205. package/vendor/theus-arsenal/rules/common/security.md +0 -29
  206. package/vendor/theus-arsenal/rules/common/testing.md +0 -57
  207. package/vendor/theus-arsenal/rules/cpp/coding-style.md +0 -44
  208. package/vendor/theus-arsenal/rules/cpp/hooks.md +0 -39
  209. package/vendor/theus-arsenal/rules/cpp/patterns.md +0 -51
  210. package/vendor/theus-arsenal/rules/cpp/security.md +0 -51
  211. package/vendor/theus-arsenal/rules/cpp/testing.md +0 -44
  212. package/vendor/theus-arsenal/rules/csharp/coding-style.md +0 -72
  213. package/vendor/theus-arsenal/rules/csharp/hooks.md +0 -25
  214. package/vendor/theus-arsenal/rules/csharp/patterns.md +0 -50
  215. package/vendor/theus-arsenal/rules/csharp/security.md +0 -58
  216. package/vendor/theus-arsenal/rules/csharp/testing.md +0 -50
  217. package/vendor/theus-arsenal/rules/dart/coding-style.md +0 -159
  218. package/vendor/theus-arsenal/rules/dart/hooks.md +0 -68
  219. package/vendor/theus-arsenal/rules/dart/patterns.md +0 -261
  220. package/vendor/theus-arsenal/rules/dart/security.md +0 -135
  221. package/vendor/theus-arsenal/rules/dart/testing.md +0 -215
  222. package/vendor/theus-arsenal/rules/fsharp/coding-style.md +0 -112
  223. package/vendor/theus-arsenal/rules/fsharp/hooks.md +0 -26
  224. package/vendor/theus-arsenal/rules/fsharp/patterns.md +0 -111
  225. package/vendor/theus-arsenal/rules/fsharp/security.md +0 -76
  226. package/vendor/theus-arsenal/rules/fsharp/testing.md +0 -62
  227. package/vendor/theus-arsenal/rules/golang/coding-style.md +0 -32
  228. package/vendor/theus-arsenal/rules/golang/hooks.md +0 -17
  229. package/vendor/theus-arsenal/rules/golang/patterns.md +0 -45
  230. package/vendor/theus-arsenal/rules/golang/security.md +0 -34
  231. package/vendor/theus-arsenal/rules/golang/testing.md +0 -31
  232. package/vendor/theus-arsenal/rules/java/coding-style.md +0 -114
  233. package/vendor/theus-arsenal/rules/java/hooks.md +0 -18
  234. package/vendor/theus-arsenal/rules/java/patterns.md +0 -147
  235. package/vendor/theus-arsenal/rules/java/security.md +0 -101
  236. package/vendor/theus-arsenal/rules/java/testing.md +0 -133
  237. package/vendor/theus-arsenal/rules/kotlin/coding-style.md +0 -86
  238. package/vendor/theus-arsenal/rules/kotlin/hooks.md +0 -17
  239. package/vendor/theus-arsenal/rules/kotlin/patterns.md +0 -146
  240. package/vendor/theus-arsenal/rules/kotlin/security.md +0 -82
  241. package/vendor/theus-arsenal/rules/kotlin/testing.md +0 -128
  242. package/vendor/theus-arsenal/rules/nuxt/coding-style.md +0 -47
  243. package/vendor/theus-arsenal/rules/nuxt/hooks.md +0 -39
  244. package/vendor/theus-arsenal/rules/nuxt/patterns.md +0 -54
  245. package/vendor/theus-arsenal/rules/nuxt/security.md +0 -48
  246. package/vendor/theus-arsenal/rules/nuxt/testing.md +0 -49
  247. package/vendor/theus-arsenal/rules/php/coding-style.md +0 -40
  248. package/vendor/theus-arsenal/rules/php/hooks.md +0 -24
  249. package/vendor/theus-arsenal/rules/php/patterns.md +0 -33
  250. package/vendor/theus-arsenal/rules/php/security.md +0 -37
  251. package/vendor/theus-arsenal/rules/php/testing.md +0 -38
  252. package/vendor/theus-arsenal/rules/python/coding-style.md +0 -42
  253. package/vendor/theus-arsenal/rules/python/fastapi.md +0 -58
  254. package/vendor/theus-arsenal/rules/python/hooks.md +0 -19
  255. package/vendor/theus-arsenal/rules/python/patterns.md +0 -39
  256. package/vendor/theus-arsenal/rules/python/security.md +0 -30
  257. package/vendor/theus-arsenal/rules/python/testing.md +0 -38
  258. package/vendor/theus-arsenal/rules/react/coding-style.md +0 -109
  259. package/vendor/theus-arsenal/rules/react/hooks.md +0 -187
  260. package/vendor/theus-arsenal/rules/react/patterns.md +0 -194
  261. package/vendor/theus-arsenal/rules/react/security.md +0 -180
  262. package/vendor/theus-arsenal/rules/react/testing.md +0 -208
  263. package/vendor/theus-arsenal/rules/react-native/accessibility.md +0 -55
  264. package/vendor/theus-arsenal/rules/react-native/coding-style.md +0 -71
  265. package/vendor/theus-arsenal/rules/react-native/hooks.md +0 -28
  266. package/vendor/theus-arsenal/rules/react-native/patterns.md +0 -88
  267. package/vendor/theus-arsenal/rules/react-native/performance.md +0 -45
  268. package/vendor/theus-arsenal/rules/react-native/production-readiness.md +0 -51
  269. package/vendor/theus-arsenal/rules/react-native/security.md +0 -43
  270. package/vendor/theus-arsenal/rules/react-native/testing.md +0 -52
  271. package/vendor/theus-arsenal/rules/ruby/coding-style.md +0 -46
  272. package/vendor/theus-arsenal/rules/ruby/hooks.md +0 -37
  273. package/vendor/theus-arsenal/rules/ruby/patterns.md +0 -44
  274. package/vendor/theus-arsenal/rules/ruby/security.md +0 -51
  275. package/vendor/theus-arsenal/rules/ruby/testing.md +0 -51
  276. package/vendor/theus-arsenal/rules/rust/coding-style.md +0 -151
  277. package/vendor/theus-arsenal/rules/rust/hooks.md +0 -16
  278. package/vendor/theus-arsenal/rules/rust/patterns.md +0 -168
  279. package/vendor/theus-arsenal/rules/rust/security.md +0 -141
  280. package/vendor/theus-arsenal/rules/rust/testing.md +0 -154
  281. package/vendor/theus-arsenal/rules/swift/coding-style.md +0 -47
  282. package/vendor/theus-arsenal/rules/swift/hooks.md +0 -20
  283. package/vendor/theus-arsenal/rules/swift/patterns.md +0 -66
  284. package/vendor/theus-arsenal/rules/swift/security.md +0 -33
  285. package/vendor/theus-arsenal/rules/swift/testing.md +0 -45
  286. package/vendor/theus-arsenal/rules/typescript/coding-style.md +0 -199
  287. package/vendor/theus-arsenal/rules/typescript/hooks.md +0 -22
  288. package/vendor/theus-arsenal/rules/typescript/patterns.md +0 -52
  289. package/vendor/theus-arsenal/rules/typescript/security.md +0 -28
  290. package/vendor/theus-arsenal/rules/typescript/testing.md +0 -18
  291. package/vendor/theus-arsenal/rules/vue/coding-style.md +0 -54
  292. package/vendor/theus-arsenal/rules/vue/hooks.md +0 -45
  293. package/vendor/theus-arsenal/rules/vue/patterns.md +0 -56
  294. package/vendor/theus-arsenal/rules/vue/security.md +0 -46
  295. package/vendor/theus-arsenal/rules/vue/testing.md +0 -53
  296. package/vendor/theus-arsenal/rules/web/coding-style.md +0 -108
  297. package/vendor/theus-arsenal/rules/web/design-quality.md +0 -75
  298. package/vendor/theus-arsenal/rules/web/hooks.md +0 -141
  299. package/vendor/theus-arsenal/rules/web/patterns.md +0 -91
  300. package/vendor/theus-arsenal/rules/web/performance.md +0 -76
  301. package/vendor/theus-arsenal/rules/web/security.md +0 -69
  302. package/vendor/theus-arsenal/rules/web/testing.md +0 -67
  303. package/vendor/theus-arsenal/scripts/hooks/bash-hook-dispatcher.js +0 -192
  304. package/vendor/theus-arsenal/scripts/hooks/block-no-verify.js +0 -556
  305. package/vendor/theus-arsenal/scripts/hooks/check-console-log.js +0 -92
  306. package/vendor/theus-arsenal/scripts/hooks/check-hook-enabled.js +0 -16
  307. package/vendor/theus-arsenal/scripts/hooks/config-protection.js +0 -171
  308. package/vendor/theus-arsenal/scripts/hooks/design-quality-check.js +0 -132
  309. package/vendor/theus-arsenal/scripts/hooks/doc-file-warning.js +0 -110
  310. package/vendor/theus-arsenal/scripts/hooks/modo-seguro.js +0 -158
  311. package/vendor/theus-arsenal/scripts/hooks/notificacion-escritorio.js +0 -208
  312. package/vendor/theus-arsenal/scripts/hooks/plugin-hook-bootstrap.js +0 -280
  313. package/vendor/theus-arsenal/scripts/hooks/post-bash-command-log.js +0 -87
  314. package/vendor/theus-arsenal/scripts/hooks/post-bash-dispatcher.js +0 -24
  315. package/vendor/theus-arsenal/scripts/hooks/post-bash-pr-created.js +0 -60
  316. package/vendor/theus-arsenal/scripts/hooks/post-edit-accumulator.js +0 -94
  317. package/vendor/theus-arsenal/scripts/hooks/post-edit-console-warn.js +0 -54
  318. package/vendor/theus-arsenal/scripts/hooks/post-edit-format.js +0 -110
  319. package/vendor/theus-arsenal/scripts/hooks/post-edit-typecheck.js +0 -98
  320. package/vendor/theus-arsenal/scripts/hooks/pre-bash-commit-quality.js +0 -447
  321. package/vendor/theus-arsenal/scripts/hooks/pre-bash-dev-server-block.js +0 -232
  322. package/vendor/theus-arsenal/scripts/hooks/pre-bash-dispatcher.js +0 -27
  323. package/vendor/theus-arsenal/scripts/hooks/pre-compact.js +0 -101
  324. package/vendor/theus-arsenal/scripts/hooks/pretooluse-visible-output.js +0 -49
  325. package/vendor/theus-arsenal/scripts/hooks/quality-gate.js +0 -168
  326. package/vendor/theus-arsenal/scripts/hooks/run-with-flags.js +0 -271
  327. package/vendor/theus-arsenal/scripts/hooks/salud-mcp.js +0 -749
  328. package/vendor/theus-arsenal/scripts/hooks/seguimiento-costos.js +0 -161
  329. package/vendor/theus-arsenal/scripts/hooks/session-end.js +0 -340
  330. package/vendor/theus-arsenal/scripts/hooks/session-start.js +0 -906
  331. package/vendor/theus-arsenal/scripts/hooks/stop-format-typecheck.js +0 -263
  332. package/vendor/theus-arsenal/scripts/hooks/suggest-compact.js +0 -286
  333. package/vendor/theus-arsenal/scripts/hooks/theus-context-monitor.js +0 -289
  334. package/vendor/theus-arsenal/scripts/hooks/verificacion-factual.js +0 -1278
  335. package/vendor/theus-arsenal/scripts/lib/agent-data-home.js +0 -96
  336. package/vendor/theus-arsenal/scripts/lib/cost-estimate.js +0 -66
  337. package/vendor/theus-arsenal/scripts/lib/hook-flags.js +0 -79
  338. package/vendor/theus-arsenal/scripts/lib/llm-summary.js +0 -185
  339. package/vendor/theus-arsenal/scripts/lib/loopback-guard.js +0 -54
  340. package/vendor/theus-arsenal/scripts/lib/observer-sessions.js +0 -237
  341. package/vendor/theus-arsenal/scripts/lib/package-manager.d.ts +0 -120
  342. package/vendor/theus-arsenal/scripts/lib/package-manager.js +0 -434
  343. package/vendor/theus-arsenal/scripts/lib/path-safety.js +0 -86
  344. package/vendor/theus-arsenal/scripts/lib/plan-canvas/markdown.js +0 -285
  345. package/vendor/theus-arsenal/scripts/lib/plan-canvas/sdk.js +0 -238
  346. package/vendor/theus-arsenal/scripts/lib/plan-canvas/server.js +0 -534
  347. package/vendor/theus-arsenal/scripts/lib/plan-canvas/sessions.js +0 -274
  348. package/vendor/theus-arsenal/scripts/lib/plan-canvas/ui.js +0 -546
  349. package/vendor/theus-arsenal/scripts/lib/project-detect.js +0 -451
  350. package/vendor/theus-arsenal/scripts/lib/resolve-formatter.js +0 -193
  351. package/vendor/theus-arsenal/scripts/lib/resolve-theus-root.js +0 -101
  352. package/vendor/theus-arsenal/scripts/lib/session-aliases.d.ts +0 -138
  353. package/vendor/theus-arsenal/scripts/lib/session-aliases.js +0 -483
  354. package/vendor/theus-arsenal/scripts/lib/session-bridge.js +0 -155
  355. package/vendor/theus-arsenal/scripts/lib/session-manager.d.ts +0 -137
  356. package/vendor/theus-arsenal/scripts/lib/session-manager.js +0 -555
  357. package/vendor/theus-arsenal/scripts/lib/shell-split.js +0 -86
  358. package/vendor/theus-arsenal/scripts/lib/shell-substitution.js +0 -501
  359. package/vendor/theus-arsenal/scripts/lib/skill-evolution/dashboard.js +0 -414
  360. package/vendor/theus-arsenal/scripts/lib/skill-evolution/health.js +0 -285
  361. package/vendor/theus-arsenal/scripts/lib/skill-evolution/index.js +0 -22
  362. package/vendor/theus-arsenal/scripts/lib/skill-evolution/provenance.js +0 -200
  363. package/vendor/theus-arsenal/scripts/lib/skill-evolution/tracker.js +0 -157
  364. package/vendor/theus-arsenal/scripts/lib/skill-evolution/versioning.js +0 -246
  365. package/vendor/theus-arsenal/scripts/lib/transcript-context.js +0 -232
  366. package/vendor/theus-arsenal/scripts/lib/utils.d.ts +0 -205
  367. package/vendor/theus-arsenal/scripts/lib/utils.js +0 -658
  368. package/vendor/theus-arsenal/scripts/plan-canvas.js +0 -341
  369. package/vendor/theus-arsenal/scripts/setup-package-manager.js +0 -46
  370. package/vendor/theus-arsenal/scripts/skills-health.js +0 -143
  371. package/vendor/theus-arsenal/skills/a11y-frontend/SKILL.md +0 -444
  372. package/vendor/theus-arsenal/skills/accesibilidad/SKILL.md +0 -144
  373. package/vendor/theus-arsenal/skills/acelerador-throughput-datos/SKILL.md +0 -72
  374. package/vendor/theus-arsenal/skills/agente-scraper-datos/SKILL.md +0 -771
  375. package/vendor/theus-arsenal/skills/analisis-plataformas-competencia/SKILL.md +0 -137
  376. package/vendor/theus-arsenal/skills/api-x/SKILL.md +0 -233
  377. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/SKILL.md +0 -335
  378. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/observer-loop.sh +0 -374
  379. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/observer.md +0 -188
  380. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/session-guardian.sh +0 -153
  381. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/start-observer.sh +0 -253
  382. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/config.json +0 -8
  383. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/hooks/observe.sh +0 -594
  384. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/detect-project.sh +0 -325
  385. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/instinct-cli.py +0 -1918
  386. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/lib/arsenal-dir.sh +0 -23
  387. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/test_parse_instinct.py +0 -1420
  388. package/vendor/theus-arsenal/skills/arquitectura-hexagonal/SKILL.md +0 -275
  389. package/vendor/theus-arsenal/skills/arquitectura-limpia-android/SKILL.md +0 -340
  390. package/vendor/theus-arsenal/skills/arquitectura-pipelines-recomendacion/SKILL.md +0 -112
  391. package/vendor/theus-arsenal/skills/atlas-datos-prediccion/SKILL.md +0 -53
  392. package/vendor/theus-arsenal/skills/auditoria-arquitectura-agentes/SKILL.md +0 -257
  393. package/vendor/theus-arsenal/skills/auditoria-produccion/SKILL.md +0 -180
  394. package/vendor/theus-arsenal/skills/auditoria-rutas-clic/SKILL.md +0 -243
  395. package/vendor/theus-arsenal/skills/autoevaluacion-agente/SKILL.md +0 -180
  396. package/vendor/theus-arsenal/skills/autoevaluacion-agente/examples/high-score-example.md +0 -89
  397. package/vendor/theus-arsenal/skills/autoevaluacion-agente/examples/low-score-example.md +0 -87
  398. package/vendor/theus-arsenal/skills/autoevaluacion-agente/references/evaluation-criteria.md +0 -71
  399. package/vendor/theus-arsenal/skills/autoevaluacion-agente/references/hook-integration.md +0 -90
  400. package/vendor/theus-arsenal/skills/autoevaluacion-agente/scripts/evaluate.py +0 -409
  401. package/vendor/theus-arsenal/skills/autoevaluacion-agente/templates/evaluation-report.md +0 -86
  402. package/vendor/theus-arsenal/skills/automatizacion-ssh-netmiko/SKILL.md +0 -176
  403. package/vendor/theus-arsenal/skills/base-datos-pubmed/SKILL.md +0 -174
  404. package/vendor/theus-arsenal/skills/base-datos-uspto/SKILL.md +0 -173
  405. package/vendor/theus-arsenal/skills/benchmark/SKILL.md +0 -92
  406. package/vendor/theus-arsenal/skills/bitacora-crecimiento/SKILL.md +0 -120
  407. package/vendor/theus-arsenal/skills/bucle-verificacion/SKILL.md +0 -125
  408. package/vendor/theus-arsenal/skills/buscar-primero/SKILL.md +0 -184
  409. package/vendor/theus-arsenal/skills/busqueda-exa/SKILL.md +0 -111
  410. package/vendor/theus-arsenal/skills/cache-por-hash/SKILL.md +0 -160
  411. package/vendor/theus-arsenal/skills/campana-marketing/SKILL.md +0 -118
  412. package/vendor/theus-arsenal/skills/capacidad-producto/SKILL.md +0 -138
  413. package/vendor/theus-arsenal/skills/cazador-vulnerabilidades/SKILL.md +0 -104
  414. package/vendor/theus-arsenal/skills/compactacion-estrategica/SKILL.md +0 -115
  415. package/vendor/theus-arsenal/skills/comparador-baskets-prediccion/SKILL.md +0 -69
  416. package/vendor/theus-arsenal/skills/compras-energia/SKILL.md +0 -206
  417. package/vendor/theus-arsenal/skills/concurrencia-swift-6-2/SKILL.md +0 -224
  418. package/vendor/theus-arsenal/skills/consejo/SKILL.md +0 -201
  419. package/vendor/theus-arsenal/skills/construccion-harness-agentes/SKILL.md +0 -78
  420. package/vendor/theus-arsenal/skills/constructor-conectores/SKILL.md +0 -119
  421. package/vendor/theus-arsenal/skills/constructor-equipos/SKILL.md +0 -169
  422. package/vendor/theus-arsenal/skills/consulta-documentacion/SKILL.md +0 -92
  423. package/vendor/theus-arsenal/skills/consultas-genomicas-gget/SKILL.md +0 -170
  424. package/vendor/theus-arsenal/skills/contacto-inversores/SKILL.md +0 -95
  425. package/vendor/theus-arsenal/skills/corrutinas-flows-kotlin/SKILL.md +0 -284
  426. package/vendor/theus-arsenal/skills/creacion-video-remotion/SKILL.md +0 -46
  427. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/3d.md +0 -86
  428. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/animations.md +0 -29
  429. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/charts-bar-chart.tsx +0 -173
  430. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/text-animations-typewriter.tsx +0 -100
  431. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/text-animations-word-highlight.tsx +0 -108
  432. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets.md +0 -78
  433. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/audio.md +0 -172
  434. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/calculate-metadata.md +0 -104
  435. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/can-decode.md +0 -75
  436. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/charts.md +0 -58
  437. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/compositions.md +0 -146
  438. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/display-captions.md +0 -126
  439. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/extract-frames.md +0 -229
  440. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/fonts.md +0 -152
  441. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-audio-duration.md +0 -58
  442. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-video-dimensions.md +0 -68
  443. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-video-duration.md +0 -58
  444. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/gifs.md +0 -138
  445. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/images.md +0 -130
  446. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/import-srt-captions.md +0 -67
  447. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/lottie.md +0 -67
  448. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/measuring-dom-nodes.md +0 -34
  449. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/measuring-text.md +0 -143
  450. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/sequencing.md +0 -106
  451. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/tailwind.md +0 -11
  452. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/text-animations.md +0 -20
  453. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/timing.md +0 -179
  454. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/transcribe-captions.md +0 -19
  455. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/transitions.md +0 -122
  456. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/trimming.md +0 -52
  457. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/videos.md +0 -171
  458. package/vendor/theus-arsenal/skills/cumplimiento-aduanero/SKILL.md +0 -270
  459. package/vendor/theus-arsenal/skills/cumplimiento-hipaa/SKILL.md +0 -78
  460. package/vendor/theus-arsenal/skills/datos-sensibles-salud/SKILL.md +0 -149
  461. package/vendor/theus-arsenal/skills/decimales-tokens-evm/SKILL.md +0 -128
  462. package/vendor/theus-arsenal/skills/decisiones-arquitectura/SKILL.md +0 -206
  463. package/vendor/theus-arsenal/skills/demos-ui/SKILL.md +0 -469
  464. package/vendor/theus-arsenal/skills/desarrollo-por-intencion/SKILL.md +0 -369
  465. package/vendor/theus-arsenal/skills/descubrimiento-marca/SKILL.md +0 -149
  466. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/10_proposito-porque.md +0 -42
  467. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/20_posicionamiento.md +0 -47
  468. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/30_audiencia-nicho.md +0 -53
  469. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/40_personalidad-arquetipo.md +0 -61
  470. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/50_voz-tono.md +0 -62
  471. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/60_narrativa-historia.md +0 -54
  472. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/70_tension-fundador.md +0 -50
  473. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/90_SINTESIS.md +0 -133
  474. package/vendor/theus-arsenal/skills/descubrimiento-plugins-laravel/SKILL.md +0 -230
  475. package/vendor/theus-arsenal/skills/destilado-reglas/SKILL.md +0 -263
  476. package/vendor/theus-arsenal/skills/destilado-reglas/scripts/scan-rules.sh +0 -58
  477. package/vendor/theus-arsenal/skills/destilado-reglas/scripts/scan-skills.sh +0 -129
  478. package/vendor/theus-arsenal/skills/diagnostico-bgp/SKILL.md +0 -170
  479. package/vendor/theus-arsenal/skills/direccion-estetica/SKILL.md +0 -220
  480. package/vendor/theus-arsenal/skills/direccion-estetica/references/taxonomia-generos.md +0 -89
  481. package/vendor/theus-arsenal/skills/diseno-api/SKILL.md +0 -522
  482. package/vendor/theus-arsenal/skills/diseno-liquid-glass/SKILL.md +0 -282
  483. package/vendor/theus-arsenal/skills/e2e-escritorio-windows/SKILL.md +0 -879
  484. package/vendor/theus-arsenal/skills/edicion-video/SKILL.md +0 -289
  485. package/vendor/theus-arsenal/skills/enfoque-producto/SKILL.md +0 -91
  486. package/vendor/theus-arsenal/skills/entornos-flox/SKILL.md +0 -493
  487. package/vendor/theus-arsenal/skills/estandares-codigo/SKILL.md +0 -548
  488. package/vendor/theus-arsenal/skills/estandares-cpp/SKILL.md +0 -727
  489. package/vendor/theus-arsenal/skills/estandares-java/SKILL.md +0 -389
  490. package/vendor/theus-arsenal/skills/estilo-legado/SKILL.md +0 -149
  491. package/vendor/theus-arsenal/skills/estructura-informes-competencia/SKILL.md +0 -95
  492. package/vendor/theus-arsenal/skills/evaluacion-academica/SKILL.md +0 -165
  493. package/vendor/theus-arsenal/skills/explorador-skills/SKILL.md +0 -129
  494. package/vendor/theus-arsenal/skills/flujo-git/SKILL.md +0 -714
  495. package/vendor/theus-arsenal/skills/flujo-ingenieria-ml/SKILL.md +0 -343
  496. package/vendor/theus-arsenal/skills/flujo-tdd/SKILL.md +0 -584
  497. package/vendor/theus-arsenal/skills/forja-personas/SKILL.md +0 -298
  498. package/vendor/theus-arsenal/skills/forja-personas/gacha.py +0 -224
  499. package/vendor/theus-arsenal/skills/forja-personas/gacha.sh +0 -5
  500. package/vendor/theus-arsenal/skills/forja-personas/references/avatar-style.md +0 -123
  501. package/vendor/theus-arsenal/skills/forja-personas/references/boundary-rules.md +0 -53
  502. package/vendor/theus-arsenal/skills/forja-personas/references/error-handling.md +0 -53
  503. package/vendor/theus-arsenal/skills/forja-personas/references/identity-tension.md +0 -48
  504. package/vendor/theus-arsenal/skills/forja-personas/references/naming-system.md +0 -39
  505. package/vendor/theus-arsenal/skills/forja-personas/references/output-template.md +0 -166
  506. package/vendor/theus-arsenal/skills/fundamentos-animacion/SKILL.md +0 -296
  507. package/vendor/theus-arsenal/skills/generacion-iconos-ios/SKILL.md +0 -156
  508. package/vendor/theus-arsenal/skills/generacion-iconos-ios/scripts/generate_icons.swift +0 -258
  509. package/vendor/theus-arsenal/skills/generacion-iconos-ios/scripts/iconify_gen.sh +0 -235
  510. package/vendor/theus-arsenal/skills/gestion-excepciones-logisticas/SKILL.md +0 -208
  511. package/vendor/theus-arsenal/skills/gestion-transportistas/SKILL.md +0 -204
  512. package/vendor/theus-arsenal/skills/guia-adopcion-ml/SKILL.md +0 -64
  513. package/vendor/theus-arsenal/skills/harness-agente-autonomo/SKILL.md +0 -252
  514. package/vendor/theus-arsenal/skills/harness-eval-clinico/SKILL.md +0 -212
  515. package/vendor/theus-arsenal/skills/harness-evaluacion/SKILL.md +0 -296
  516. package/vendor/theus-arsenal/skills/harness-generador-evaluador/SKILL.md +0 -254
  517. package/vendor/theus-arsenal/skills/homelab-diseno-red/SKILL.md +0 -120
  518. package/vendor/theus-arsenal/skills/homelab-dns-pihole/SKILL.md +0 -264
  519. package/vendor/theus-arsenal/skills/homelab-preparacion-red/SKILL.md +0 -144
  520. package/vendor/theus-arsenal/skills/homelab-segmentacion-vlan/SKILL.md +0 -307
  521. package/vendor/theus-arsenal/skills/homelab-vpn-wireguard/SKILL.md +0 -299
  522. package/vendor/theus-arsenal/skills/ingenieria-agentica/SKILL.md +0 -96
  523. package/vendor/theus-arsenal/skills/inspeccion-animaciones-blender/SKILL.md +0 -164
  524. package/vendor/theus-arsenal/skills/instaladores-python/SKILL.md +0 -820
  525. package/vendor/theus-arsenal/skills/integracion-jira/SKILL.md +0 -307
  526. package/vendor/theus-arsenal/skills/inteligencia-leads/SKILL.md +0 -312
  527. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/agente-enriquecimiento.md +0 -87
  528. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/mapeador-mutuos.md +0 -76
  529. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/puntuador-senales.md +0 -60
  530. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/redactor-outreach.md +0 -102
  531. package/vendor/theus-arsenal/skills/inteligencia-mercados-prediccion/SKILL.md +0 -53
  532. package/vendor/theus-arsenal/skills/introspeccion-agente/SKILL.md +0 -150
  533. package/vendor/theus-arsenal/skills/inventario-skills/SKILL.md +0 -194
  534. package/vendor/theus-arsenal/skills/inventario-skills/scripts/quick-diff.sh +0 -87
  535. package/vendor/theus-arsenal/skills/inventario-skills/scripts/save-results.sh +0 -57
  536. package/vendor/theus-arsenal/skills/inventario-skills/scripts/scan.sh +0 -170
  537. package/vendor/theus-arsenal/skills/investigacion-mercado/SKILL.md +0 -87
  538. package/vendor/theus-arsenal/skills/investigacion-oraculos-prediccion/SKILL.md +0 -59
  539. package/vendor/theus-arsenal/skills/investigacion-profunda/SKILL.md +0 -161
  540. package/vendor/theus-arsenal/skills/keccak256-nodejs/SKILL.md +0 -100
  541. package/vendor/theus-arsenal/skills/libro-decisiones-recursivo/SKILL.md +0 -82
  542. package/vendor/theus-arsenal/skills/lienzo-planes/SKILL.md +0 -111
  543. package/vendor/theus-arsenal/skills/limpieza-configuracion/SKILL.md +0 -116
  544. package/vendor/theus-arsenal/skills/logistica-inversa-devoluciones/SKILL.md +0 -241
  545. package/vendor/theus-arsenal/skills/manejo-errores/SKILL.md +0 -375
  546. package/vendor/theus-arsenal/skills/materiales-inversores/SKILL.md +0 -101
  547. package/vendor/theus-arsenal/skills/memoria-por-proyecto/SKILL.md +0 -170
  548. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/forget.mjs +0 -44
  549. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/info.mjs +0 -24
  550. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/init.mjs +0 -152
  551. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/list.mjs +0 -40
  552. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/migrate.mjs +0 -214
  553. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/resume.mjs +0 -36
  554. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/save.mjs +0 -210
  555. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/shared.mjs +0 -402
  556. package/vendor/theus-arsenal/skills/memoria-por-proyecto/hooks/session-start.mjs +0 -238
  557. package/vendor/theus-arsenal/skills/metodologia-benchmarks/SKILL.md +0 -131
  558. package/vendor/theus-arsenal/skills/migraciones-bd/SKILL.md +0 -430
  559. package/vendor/theus-arsenal/skills/modelos-fundacionales-en-dispositivo/SKILL.md +0 -244
  560. package/vendor/theus-arsenal/skills/modo-seguro/SKILL.md +0 -86
  561. package/vendor/theus-arsenal/skills/motion-avanzado/SKILL.md +0 -592
  562. package/vendor/theus-arsenal/skills/motor-de-contenido/SKILL.md +0 -136
  563. package/vendor/theus-arsenal/skills/no-conformidades-calidad/SKILL.md +0 -249
  564. package/vendor/theus-arsenal/skills/onboarding-codigo/SKILL.md +0 -244
  565. package/vendor/theus-arsenal/skills/operaciones-agentes-empresariales/SKILL.md +0 -51
  566. package/vendor/theus-arsenal/skills/operaciones-conocimiento/SKILL.md +0 -159
  567. package/vendor/theus-arsenal/skills/operaciones-correo/SKILL.md +0 -123
  568. package/vendor/theus-arsenal/skills/operaciones-facturacion/SKILL.md +0 -142
  569. package/vendor/theus-arsenal/skills/operaciones-flujo-proyectos/SKILL.md +0 -110
  570. package/vendor/theus-arsenal/skills/operaciones-github/SKILL.md +0 -143
  571. package/vendor/theus-arsenal/skills/operaciones-google-workspace/SKILL.md +0 -100
  572. package/vendor/theus-arsenal/skills/operaciones-investigacion/SKILL.md +0 -124
  573. package/vendor/theus-arsenal/skills/operaciones-mensajes/SKILL.md +0 -103
  574. package/vendor/theus-arsenal/skills/operaciones-terminal/SKILL.md +0 -110
  575. package/vendor/theus-arsenal/skills/optimizacion-benchmark/SKILL.md +0 -70
  576. package/vendor/theus-arsenal/skills/optimizacion-costos-llm/SKILL.md +0 -182
  577. package/vendor/theus-arsenal/skills/optimizador-conexiones/SKILL.md +0 -191
  578. package/vendor/theus-arsenal/skills/optimizador-paralelismo/SKILL.md +0 -75
  579. package/vendor/theus-arsenal/skills/optimizador-prompts/SKILL.md +0 -374
  580. package/vendor/theus-arsenal/skills/orq-agregar-funcionalidad/SKILL.md +0 -37
  581. package/vendor/theus-arsenal/skills/orq-cambiar-funcionalidad/SKILL.md +0 -36
  582. package/vendor/theus-arsenal/skills/orq-construir-mvp/SKILL.md +0 -38
  583. package/vendor/theus-arsenal/skills/orq-corregir-defecto/SKILL.md +0 -36
  584. package/vendor/theus-arsenal/skills/orq-pipeline/SKILL.md +0 -134
  585. package/vendor/theus-arsenal/skills/orq-refinar-codigo/SKILL.md +0 -49
  586. package/vendor/theus-arsenal/skills/orquestacion-equipos-agentes/SKILL.md +0 -117
  587. package/vendor/theus-arsenal/skills/pagos-agentes-x402/SKILL.md +0 -237
  588. package/vendor/theus-arsenal/skills/patrones-angular/SKILL.md +0 -153
  589. package/vendor/theus-arsenal/skills/patrones-angular/references/angular-animations.md +0 -160
  590. package/vendor/theus-arsenal/skills/patrones-angular/references/angular-aria.md +0 -410
  591. package/vendor/theus-arsenal/skills/patrones-angular/references/cli.md +0 -86
  592. package/vendor/theus-arsenal/skills/patrones-angular/references/component-harnesses.md +0 -59
  593. package/vendor/theus-arsenal/skills/patrones-angular/references/component-styling.md +0 -91
  594. package/vendor/theus-arsenal/skills/patrones-angular/references/components.md +0 -117
  595. package/vendor/theus-arsenal/skills/patrones-angular/references/creating-services.md +0 -97
  596. package/vendor/theus-arsenal/skills/patrones-angular/references/data-resolvers.md +0 -69
  597. package/vendor/theus-arsenal/skills/patrones-angular/references/define-routes.md +0 -67
  598. package/vendor/theus-arsenal/skills/patrones-angular/references/defining-providers.md +0 -72
  599. package/vendor/theus-arsenal/skills/patrones-angular/references/di-fundamentals.md +0 -120
  600. package/vendor/theus-arsenal/skills/patrones-angular/references/e2e-testing.md +0 -56
  601. package/vendor/theus-arsenal/skills/patrones-angular/references/effects.md +0 -83
  602. package/vendor/theus-arsenal/skills/patrones-angular/references/hierarchical-injectors.md +0 -43
  603. package/vendor/theus-arsenal/skills/patrones-angular/references/host-elements.md +0 -80
  604. package/vendor/theus-arsenal/skills/patrones-angular/references/injection-context.md +0 -63
  605. package/vendor/theus-arsenal/skills/patrones-angular/references/inputs.md +0 -101
  606. package/vendor/theus-arsenal/skills/patrones-angular/references/linked-signal.md +0 -59
  607. package/vendor/theus-arsenal/skills/patrones-angular/references/loading-strategies.md +0 -61
  608. package/vendor/theus-arsenal/skills/patrones-angular/references/mcp.md +0 -67
  609. package/vendor/theus-arsenal/skills/patrones-angular/references/navigate-to-routes.md +0 -69
  610. package/vendor/theus-arsenal/skills/patrones-angular/references/outputs.md +0 -86
  611. package/vendor/theus-arsenal/skills/patrones-angular/references/reactive-forms.md +0 -122
  612. package/vendor/theus-arsenal/skills/patrones-angular/references/rendering-strategies.md +0 -44
  613. package/vendor/theus-arsenal/skills/patrones-angular/references/resource.md +0 -77
  614. package/vendor/theus-arsenal/skills/patrones-angular/references/route-animations.md +0 -56
  615. package/vendor/theus-arsenal/skills/patrones-angular/references/route-guards.md +0 -52
  616. package/vendor/theus-arsenal/skills/patrones-angular/references/router-lifecycle.md +0 -45
  617. package/vendor/theus-arsenal/skills/patrones-angular/references/router-testing.md +0 -87
  618. package/vendor/theus-arsenal/skills/patrones-angular/references/show-routes-with-outlets.md +0 -68
  619. package/vendor/theus-arsenal/skills/patrones-angular/references/signal-forms.md +0 -795
  620. package/vendor/theus-arsenal/skills/patrones-angular/references/signals-overview.md +0 -94
  621. package/vendor/theus-arsenal/skills/patrones-angular/references/tailwind-css.md +0 -69
  622. package/vendor/theus-arsenal/skills/patrones-angular/references/template-driven-forms.md +0 -114
  623. package/vendor/theus-arsenal/skills/patrones-angular/references/testing-fundamentals.md +0 -65
  624. package/vendor/theus-arsenal/skills/patrones-animacion/SKILL.md +0 -432
  625. package/vendor/theus-arsenal/skills/patrones-backend/SKILL.md +0 -560
  626. package/vendor/theus-arsenal/skills/patrones-cdss-clinico/SKILL.md +0 -249
  627. package/vendor/theus-arsenal/skills/patrones-cisco-ios/SKILL.md +0 -148
  628. package/vendor/theus-arsenal/skills/patrones-clickhouse/SKILL.md +0 -443
  629. package/vendor/theus-arsenal/skills/patrones-compose-multiplatform/SKILL.md +0 -298
  630. package/vendor/theus-arsenal/skills/patrones-dart-flutter/SKILL.md +0 -566
  631. package/vendor/theus-arsenal/skills/patrones-despliegue/SKILL.md +0 -426
  632. package/vendor/theus-arsenal/skills/patrones-django/SKILL.md +0 -739
  633. package/vendor/theus-arsenal/skills/patrones-django-celery/SKILL.md +0 -456
  634. package/vendor/theus-arsenal/skills/patrones-docker/SKILL.md +0 -363
  635. package/vendor/theus-arsenal/skills/patrones-dotnet/SKILL.md +0 -321
  636. package/vendor/theus-arsenal/skills/patrones-emr-clinico/SKILL.md +0 -168
  637. package/vendor/theus-arsenal/skills/patrones-fastapi/SKILL.md +0 -513
  638. package/vendor/theus-arsenal/skills/patrones-frontend/SKILL.md +0 -655
  639. package/vendor/theus-arsenal/skills/patrones-go/SKILL.md +0 -674
  640. package/vendor/theus-arsenal/skills/patrones-jpa/SKILL.md +0 -156
  641. package/vendor/theus-arsenal/skills/patrones-kotlin/SKILL.md +0 -717
  642. package/vendor/theus-arsenal/skills/patrones-kotlin-exposed/SKILL.md +0 -724
  643. package/vendor/theus-arsenal/skills/patrones-kotlin-ktor/SKILL.md +0 -694
  644. package/vendor/theus-arsenal/skills/patrones-kubernetes/SKILL.md +0 -754
  645. package/vendor/theus-arsenal/skills/patrones-laravel/SKILL.md +0 -414
  646. package/vendor/theus-arsenal/skills/patrones-mcp/SKILL.md +0 -66
  647. package/vendor/theus-arsenal/skills/patrones-mysql/SKILL.md +0 -420
  648. package/vendor/theus-arsenal/skills/patrones-nestjs/SKILL.md +0 -229
  649. package/vendor/theus-arsenal/skills/patrones-nextjs/SKILL.md +0 -56
  650. package/vendor/theus-arsenal/skills/patrones-nuxt4/SKILL.md +0 -99
  651. package/vendor/theus-arsenal/skills/patrones-perl/SKILL.md +0 -508
  652. package/vendor/theus-arsenal/skills/patrones-postgres/SKILL.md +0 -141
  653. package/vendor/theus-arsenal/skills/patrones-prisma/SKILL.md +0 -399
  654. package/vendor/theus-arsenal/skills/patrones-python/SKILL.md +0 -750
  655. package/vendor/theus-arsenal/skills/patrones-pytorch/SKILL.md +0 -400
  656. package/vendor/theus-arsenal/skills/patrones-quarkus/SKILL.md +0 -729
  657. package/vendor/theus-arsenal/skills/patrones-react/SKILL.md +0 -339
  658. package/vendor/theus-arsenal/skills/patrones-react-native/SKILL.md +0 -325
  659. package/vendor/theus-arsenal/skills/patrones-redis/SKILL.md +0 -401
  660. package/vendor/theus-arsenal/skills/patrones-rust/SKILL.md +0 -504
  661. package/vendor/theus-arsenal/skills/patrones-springboot/SKILL.md +0 -314
  662. package/vendor/theus-arsenal/skills/patrones-swiftui/SKILL.md +0 -261
  663. package/vendor/theus-arsenal/skills/patrones-tinystruct/SKILL.md +0 -281
  664. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/architecture.md +0 -90
  665. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/data-handling.md +0 -60
  666. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/database.md +0 -99
  667. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/routing.md +0 -64
  668. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/system-usage.md +0 -97
  669. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/testing.md +0 -72
  670. package/vendor/theus-arsenal/skills/patrones-vite/SKILL.md +0 -449
  671. package/vendor/theus-arsenal/skills/patrones-vue/SKILL.md +0 -469
  672. package/vendor/theus-arsenal/skills/persistencia-actores-swift/SKILL.md +0 -148
  673. package/vendor/theus-arsenal/skills/pipeline-opensource/SKILL.md +0 -254
  674. package/vendor/theus-arsenal/skills/planificacion-demanda-inventario/SKILL.md +0 -236
  675. package/vendor/theus-arsenal/skills/planificador-trades-prediccion/SKILL.md +0 -60
  676. package/vendor/theus-arsenal/skills/plano-tecnico/SKILL.md +0 -102
  677. package/vendor/theus-arsenal/skills/presentaciones-html/SKILL.md +0 -189
  678. package/vendor/theus-arsenal/skills/presentaciones-html/STYLE_PRESETS.md +0 -330
  679. package/vendor/theus-arsenal/skills/presentaciones-html/animation-patterns.md +0 -122
  680. package/vendor/theus-arsenal/skills/presentaciones-html/html-template.md +0 -419
  681. package/vendor/theus-arsenal/skills/presentaciones-html/scripts/export-pdf.sh +0 -418
  682. package/vendor/theus-arsenal/skills/presentaciones-html/scripts/extract-pptx.py +0 -96
  683. package/vendor/theus-arsenal/skills/presentaciones-html/viewport-base.css +0 -153
  684. package/vendor/theus-arsenal/skills/presupuesto-contexto/SKILL.md +0 -263
  685. package/vendor/theus-arsenal/skills/procesamiento-documentos-nutrient/SKILL.md +0 -168
  686. package/vendor/theus-arsenal/skills/programacion-produccion/SKILL.md +0 -220
  687. package/vendor/theus-arsenal/skills/publicacion-cruzada/SKILL.md +0 -117
  688. package/vendor/theus-arsenal/skills/publicador-social/SKILL.md +0 -121
  689. package/vendor/theus-arsenal/skills/puerta-de-entrega/SKILL.md +0 -164
  690. package/vendor/theus-arsenal/skills/puerta-de-entrega/hooks/puerta-entrega.py +0 -242
  691. package/vendor/theus-arsenal/skills/pulir-interfaces/SKILL.md +0 -126
  692. package/vendor/theus-arsenal/skills/qa-navegador/SKILL.md +0 -103
  693. package/vendor/theus-arsenal/skills/ranking-grafo-social/SKILL.md +0 -153
  694. package/vendor/theus-arsenal/skills/recuperacion-iterativa/SKILL.md +0 -236
  695. package/vendor/theus-arsenal/skills/redaccion-articulos/SKILL.md +0 -81
  696. package/vendor/theus-arsenal/skills/regex-vs-llm/SKILL.md +0 -221
  697. package/vendor/theus-arsenal/skills/regresion-codigo-ia/SKILL.md +0 -388
  698. package/vendor/theus-arsenal/skills/rendimiento-react/SKILL.md +0 -567
  699. package/vendor/theus-arsenal/skills/revision-codigo-flutter-dart/SKILL.md +0 -442
  700. package/vendor/theus-arsenal/skills/revision-literatura-cientifica/SKILL.md +0 -191
  701. package/vendor/theus-arsenal/skills/revision-multiperspectiva/SKILL.md +0 -302
  702. package/vendor/theus-arsenal/skills/revision-riesgo-prediccion/SKILL.md +0 -56
  703. package/vendor/theus-arsenal/skills/revision-seguridad/SKILL.md +0 -505
  704. package/vendor/theus-arsenal/skills/revision-seguridad/cloud-infrastructure-security.md +0 -361
  705. package/vendor/theus-arsenal/skills/runtime-bun/SKILL.md +0 -83
  706. package/vendor/theus-arsenal/skills/salud-codigo-codescene/SKILL.md +0 -163
  707. package/vendor/theus-arsenal/skills/salud-interfaces-red/SKILL.md +0 -143
  708. package/vendor/theus-arsenal/skills/seguimiento-costos/SKILL.md +0 -122
  709. package/vendor/theus-arsenal/skills/seguridad-agentes-trading/SKILL.md +0 -145
  710. package/vendor/theus-arsenal/skills/seguridad-amm-defi/SKILL.md +0 -166
  711. package/vendor/theus-arsenal/skills/seguridad-django/SKILL.md +0 -648
  712. package/vendor/theus-arsenal/skills/seguridad-laravel/SKILL.md +0 -945
  713. package/vendor/theus-arsenal/skills/seguridad-perl/SKILL.md +0 -507
  714. package/vendor/theus-arsenal/skills/seguridad-quarkus/SKILL.md +0 -474
  715. package/vendor/theus-arsenal/skills/seguridad-springboot/SKILL.md +0 -279
  716. package/vendor/theus-arsenal/skills/seo/SKILL.md +0 -166
  717. package/vendor/theus-arsenal/skills/sistema-diseno/SKILL.md +0 -81
  718. package/vendor/theus-arsenal/skills/sistema-operativo-agentico/SKILL.md +0 -375
  719. package/vendor/theus-arsenal/skills/sistemas-latencia-critica/SKILL.md +0 -65
  720. package/vendor/theus-arsenal/skills/tdd-django/SKILL.md +0 -735
  721. package/vendor/theus-arsenal/skills/tdd-laravel/SKILL.md +0 -673
  722. package/vendor/theus-arsenal/skills/tdd-quarkus/SKILL.md +0 -817
  723. package/vendor/theus-arsenal/skills/tdd-springboot/SKILL.md +0 -165
  724. package/vendor/theus-arsenal/skills/testing-cpp/SKILL.md +0 -328
  725. package/vendor/theus-arsenal/skills/testing-csharp/SKILL.md +0 -321
  726. package/vendor/theus-arsenal/skills/testing-e2e/SKILL.md +0 -325
  727. package/vendor/theus-arsenal/skills/testing-go/SKILL.md +0 -719
  728. package/vendor/theus-arsenal/skills/testing-kotlin/SKILL.md +0 -829
  729. package/vendor/theus-arsenal/skills/testing-perl/SKILL.md +0 -479
  730. package/vendor/theus-arsenal/skills/testing-protocolos-di-swift/SKILL.md +0 -196
  731. package/vendor/theus-arsenal/skills/testing-python/SKILL.md +0 -815
  732. package/vendor/theus-arsenal/skills/testing-react/SKILL.md +0 -421
  733. package/vendor/theus-arsenal/skills/testing-rust/SKILL.md +0 -506
  734. package/vendor/theus-arsenal/skills/tours-de-codigo/SKILL.md +0 -252
  735. package/vendor/theus-arsenal/skills/traduccion-documentos-visado/SKILL.md +0 -121
  736. package/vendor/theus-arsenal/skills/ui-a-vue/SKILL.md +0 -141
  737. package/vendor/theus-arsenal/skills/validacion-config-red/SKILL.md +0 -211
  738. package/vendor/theus-arsenal/skills/verificacion-django/SKILL.md +0 -470
  739. package/vendor/theus-arsenal/skills/verificacion-factual/SKILL.md +0 -142
  740. package/vendor/theus-arsenal/skills/verificacion-laravel/SKILL.md +0 -184
  741. package/vendor/theus-arsenal/skills/verificacion-quarkus/SKILL.md +0 -485
  742. package/vendor/theus-arsenal/skills/verificacion-springboot/SKILL.md +0 -237
  743. package/vendor/theus-arsenal/skills/videodb/SKILL.md +0 -374
  744. package/vendor/theus-arsenal/skills/videodb/reference/api-reference.md +0 -550
  745. package/vendor/theus-arsenal/skills/videodb/reference/capture-reference.md +0 -407
  746. package/vendor/theus-arsenal/skills/videodb/reference/capture.md +0 -101
  747. package/vendor/theus-arsenal/skills/videodb/reference/editor.md +0 -443
  748. package/vendor/theus-arsenal/skills/videodb/reference/generative.md +0 -331
  749. package/vendor/theus-arsenal/skills/videodb/reference/rtstream-reference.md +0 -564
  750. package/vendor/theus-arsenal/skills/videodb/reference/rtstream.md +0 -65
  751. package/vendor/theus-arsenal/skills/videodb/reference/search.md +0 -230
  752. package/vendor/theus-arsenal/skills/videodb/reference/streaming.md +0 -406
  753. package/vendor/theus-arsenal/skills/videodb/reference/use-cases.md +0 -118
  754. package/vendor/theus-arsenal/skills/videodb/scripts/ws_listener.py +0 -279
  755. package/vendor/theus-arsenal/skills/videos-manim/SKILL.md +0 -91
  756. package/vendor/theus-arsenal/skills/videos-manim/assets/network_graph_scene.py +0 -52
  757. package/vendor/theus-arsenal/skills/vigilancia-canary/SKILL.md +0 -108
  758. package/vendor/theus-arsenal/skills/voz-de-marca/SKILL.md +0 -106
@@ -1,1420 +0,0 @@
1
- """Tests del instinct-cli.py de aprendizaje-continuo-v2
2
-
3
- Cubre:
4
- - parse_instinct_file() — preservación de contenido, casos límite
5
- - _validate_file_path() — bloqueo de path traversal
6
- - detect_project() — detección de proyecto con git/env simulados
7
- - load_all_instincts() — carga desde dirs de proyecto + globales, dedup
8
- - _load_instincts_from_dir() — recorrido de directorios
9
- - cmd_projects() — listado de proyectos desde el registro
10
- - cmd_status() — presentación del estado
11
- - _promote_specific() — promoción de un instinto individual
12
- - _promote_auto() — autopromoción entre proyectos
13
- """
14
-
15
- import importlib.util
16
- import io
17
- import json
18
- import os
19
- import sys
20
- from pathlib import Path
21
- from types import SimpleNamespace
22
-
23
- import pytest
24
-
25
- # Cargar instinct-cli.py (el nombre con guion requiere importlib)
26
- _spec = importlib.util.spec_from_file_location(
27
- "instinct_cli",
28
- os.path.join(os.path.dirname(__file__), "instinct-cli.py"),
29
- )
30
- _mod = importlib.util.module_from_spec(_spec)
31
- _spec.loader.exec_module(_mod)
32
-
33
- parse_instinct_file = _mod.parse_instinct_file
34
- _validate_file_path = _mod._validate_file_path
35
- detect_project = _mod.detect_project
36
- load_all_instincts = _mod.load_all_instincts
37
- load_project_only_instincts = _mod.load_project_only_instincts
38
- _load_instincts_from_dir = _mod._load_instincts_from_dir
39
- cmd_status = _mod.cmd_status
40
- cmd_projects = _mod.cmd_projects
41
- _promote_specific = _mod._promote_specific
42
- _promote_auto = _mod._promote_auto
43
- _find_cross_project_instincts = _mod._find_cross_project_instincts
44
- load_registry = _mod.load_registry
45
- _validate_instinct_id = _mod._validate_instinct_id
46
- _validate_import_url = _mod._validate_import_url
47
- _update_registry = _mod._update_registry
48
- _write_registry = _mod._write_registry
49
- _remove_project_storage = _mod._remove_project_storage
50
- _confidence_bar = _mod._confidence_bar
51
-
52
-
53
- # ─────────────────────────────────────────────
54
- # Fixtures
55
- # ─────────────────────────────────────────────
56
-
57
- SAMPLE_INSTINCT_YAML = """\
58
- ---
59
- id: test-instinct
60
- trigger: "when writing tests"
61
- confidence: 0.8
62
- domain: testing
63
- scope: project
64
- ---
65
-
66
- ## Action
67
- Always write tests first.
68
-
69
- ## Evidence
70
- TDD leads to better design.
71
- """
72
-
73
- SAMPLE_GLOBAL_INSTINCT_YAML = """\
74
- ---
75
- id: global-instinct
76
- trigger: "always"
77
- confidence: 0.9
78
- domain: security
79
- scope: global
80
- ---
81
-
82
- ## Action
83
- Validate all user input.
84
- """
85
-
86
-
87
- @pytest.fixture
88
- def project_tree(tmp_path):
89
- """Create a realistic project directory tree for testing."""
90
- arsenal = tmp_path / ".theus" / "arsenal"
91
- projects_dir = arsenal / "projects"
92
- global_personal = arsenal / "instincts" / "personal"
93
- global_inherited = arsenal / "instincts" / "inherited"
94
- global_evolved = arsenal / "evolved"
95
-
96
- for d in [
97
- global_personal, global_inherited,
98
- global_evolved / "skills", global_evolved / "commands", global_evolved / "agents",
99
- projects_dir,
100
- ]:
101
- d.mkdir(parents=True, exist_ok=True)
102
-
103
- return {
104
- "root": tmp_path,
105
- "arsenal": arsenal,
106
- "projects_dir": projects_dir,
107
- "global_personal": global_personal,
108
- "global_inherited": global_inherited,
109
- "global_evolved": global_evolved,
110
- "registry_file": arsenal / "projects.json",
111
- }
112
-
113
-
114
- @pytest.fixture
115
- def patch_globals(project_tree, monkeypatch):
116
- """Patch module-level globals to use tmp_path-based directories."""
117
- monkeypatch.setattr(_mod, "ARSENAL_DIR", project_tree["arsenal"])
118
- monkeypatch.setattr(_mod, "PROJECTS_DIR", project_tree["projects_dir"])
119
- monkeypatch.setattr(_mod, "REGISTRY_FILE", project_tree["registry_file"])
120
- monkeypatch.setattr(_mod, "GLOBAL_PERSONAL_DIR", project_tree["global_personal"])
121
- monkeypatch.setattr(_mod, "GLOBAL_INHERITED_DIR", project_tree["global_inherited"])
122
- monkeypatch.setattr(_mod, "GLOBAL_EVOLVED_DIR", project_tree["global_evolved"])
123
- monkeypatch.setattr(_mod, "GLOBAL_OBSERVATIONS_FILE", project_tree["arsenal"] / "observations.jsonl")
124
- return project_tree
125
-
126
-
127
- def _make_project(tree, pid="abc123", pname="test-project"):
128
- """Create project directory structure and return a project dict."""
129
- project_dir = tree["projects_dir"] / pid
130
- personal_dir = project_dir / "instincts" / "personal"
131
- inherited_dir = project_dir / "instincts" / "inherited"
132
- for d in [personal_dir, inherited_dir,
133
- project_dir / "evolved" / "skills",
134
- project_dir / "evolved" / "commands",
135
- project_dir / "evolved" / "agents",
136
- project_dir / "observations.archive"]:
137
- d.mkdir(parents=True, exist_ok=True)
138
-
139
- return {
140
- "id": pid,
141
- "name": pname,
142
- "root": str(tree["root"] / "fake-repo"),
143
- "remote": "https://github.com/test/test-project.git",
144
- "project_dir": project_dir,
145
- "instincts_personal": personal_dir,
146
- "instincts_inherited": inherited_dir,
147
- "evolved_dir": project_dir / "evolved",
148
- "observations_file": project_dir / "observations.jsonl",
149
- }
150
-
151
-
152
- # ─────────────────────────────────────────────
153
- # parse_instinct_file tests
154
- # ─────────────────────────────────────────────
155
-
156
- MULTI_SECTION = """\
157
- ---
158
- id: instinct-a
159
- trigger: "when coding"
160
- confidence: 0.9
161
- domain: general
162
- ---
163
-
164
- ## Action
165
- Do thing A.
166
-
167
- ## Examples
168
- - Example A1
169
-
170
- ---
171
- id: instinct-b
172
- trigger: "when testing"
173
- confidence: 0.7
174
- domain: testing
175
- ---
176
-
177
- ## Action
178
- Do thing B.
179
- """
180
-
181
-
182
- def test_multiple_instincts_preserve_content():
183
- result = parse_instinct_file(MULTI_SECTION)
184
- assert len(result) == 2
185
- assert "Do thing A." in result[0]["content"]
186
- assert "Example A1" in result[0]["content"]
187
- assert "Do thing B." in result[1]["content"]
188
-
189
-
190
- def test_single_instinct_preserves_content():
191
- content = """\
192
- ---
193
- id: solo
194
- trigger: "when reviewing"
195
- confidence: 0.8
196
- domain: review
197
- ---
198
-
199
- ## Action
200
- Check for security issues.
201
-
202
- ## Evidence
203
- Prevents vulnerabilities.
204
- """
205
- result = parse_instinct_file(content)
206
- assert len(result) == 1
207
- assert "Check for security issues." in result[0]["content"]
208
- assert "Prevents vulnerabilities." in result[0]["content"]
209
-
210
-
211
- def test_empty_content_no_error():
212
- content = """\
213
- ---
214
- id: empty
215
- trigger: "placeholder"
216
- confidence: 0.5
217
- domain: general
218
- ---
219
- """
220
- result = parse_instinct_file(content)
221
- assert len(result) == 1
222
- assert result[0]["content"] == ""
223
-
224
-
225
- def test_parse_no_id_skipped():
226
- """Instincts without an 'id' field should be silently dropped."""
227
- content = """\
228
- ---
229
- trigger: "when doing nothing"
230
- confidence: 0.5
231
- ---
232
-
233
- No id here.
234
- """
235
- result = parse_instinct_file(content)
236
- assert len(result) == 0
237
-
238
-
239
- def test_parse_confidence_is_float():
240
- content = """\
241
- ---
242
- id: float-check
243
- trigger: "when parsing"
244
- confidence: 0.42
245
- domain: general
246
- ---
247
-
248
- Body.
249
- """
250
- result = parse_instinct_file(content)
251
- assert isinstance(result[0]["confidence"], float)
252
- assert result[0]["confidence"] == pytest.approx(0.42)
253
-
254
-
255
- def test_parse_trigger_strips_quotes():
256
- content = """\
257
- ---
258
- id: quote-check
259
- trigger: "when quoting"
260
- confidence: 0.5
261
- domain: general
262
- ---
263
-
264
- Body.
265
- """
266
- result = parse_instinct_file(content)
267
- assert result[0]["trigger"] == "when quoting"
268
-
269
-
270
- def test_parse_empty_string():
271
- result = parse_instinct_file("")
272
- assert result == []
273
-
274
-
275
- def test_parse_garbage_input():
276
- result = parse_instinct_file("this is not yaml at all\nno frontmatter here")
277
- assert result == []
278
-
279
-
280
- # ─────────────────────────────────────────────
281
- # _validate_file_path tests
282
- # ─────────────────────────────────────────────
283
-
284
- def test_validate_normal_path(tmp_path):
285
- test_file = tmp_path / "test.yaml"
286
- test_file.write_text("hello")
287
- result = _validate_file_path(str(test_file), must_exist=True)
288
- assert result == test_file.resolve()
289
-
290
-
291
- def test_validate_rejects_etc():
292
- with pytest.raises(ValueError, match="system directory"):
293
- _validate_file_path("/etc/passwd")
294
-
295
-
296
- def test_validate_rejects_var_log():
297
- with pytest.raises(ValueError, match="system directory"):
298
- _validate_file_path("/var/log/syslog")
299
-
300
-
301
- def test_validate_rejects_usr():
302
- with pytest.raises(ValueError, match="system directory"):
303
- _validate_file_path("/usr/local/bin/foo")
304
-
305
-
306
- def test_validate_rejects_proc():
307
- with pytest.raises(ValueError, match="system directory"):
308
- _validate_file_path("/proc/self/status")
309
-
310
-
311
- def test_validate_must_exist_fails(tmp_path):
312
- with pytest.raises(ValueError, match="does not exist"):
313
- _validate_file_path(str(tmp_path / "nonexistent.yaml"), must_exist=True)
314
-
315
-
316
- def test_validate_home_expansion(tmp_path):
317
- """Tilde expansion should work."""
318
- result = _validate_file_path("~/test.yaml")
319
- assert str(result).startswith(str(Path.home()))
320
-
321
-
322
- def test_validate_relative_path(tmp_path, monkeypatch):
323
- """Relative paths should be resolved."""
324
- monkeypatch.chdir(tmp_path)
325
- test_file = tmp_path / "rel.yaml"
326
- test_file.write_text("content")
327
- result = _validate_file_path("rel.yaml", must_exist=True)
328
- assert result == test_file.resolve()
329
-
330
-
331
- def test_validate_import_url_rejects_http():
332
- """Remote imports should not downgrade to plaintext HTTP."""
333
- with pytest.raises(ValueError, match="require https"):
334
- _validate_import_url("http://example.com/instincts.yaml")
335
-
336
-
337
- def test_validate_import_url_rejects_private_hosts(monkeypatch):
338
- """Remote imports should not resolve to private or loopback addresses."""
339
- monkeypatch.setattr(
340
- _mod.socket,
341
- "getaddrinfo",
342
- lambda *args, **kwargs: [(None, None, None, None, ("127.0.0.1", 443))],
343
- )
344
- with pytest.raises(ValueError, match="non-public address"):
345
- _validate_import_url("https://example.com/instincts.yaml")
346
-
347
-
348
- def test_validate_import_url_allows_public_https(monkeypatch):
349
- monkeypatch.setattr(
350
- _mod.socket,
351
- "getaddrinfo",
352
- lambda *args, **kwargs: [(None, None, None, None, ("93.184.216.34", 443))],
353
- )
354
- assert _validate_import_url("https://example.com/instincts.yaml") == "https://example.com/instincts.yaml"
355
-
356
-
357
- # ─────────────────────────────────────────────
358
- # detect_project tests
359
- # ─────────────────────────────────────────────
360
-
361
- def test_detect_project_global_fallback(patch_globals, monkeypatch):
362
- """When no git and no env var, should return global project."""
363
- monkeypatch.delenv("THEUS_PROJECT_DIR", raising=False)
364
-
365
- # Mock subprocess.run to simulate git not available
366
- def mock_run(*args, **kwargs):
367
- raise FileNotFoundError("git not found")
368
-
369
- monkeypatch.setattr("subprocess.run", mock_run)
370
-
371
- project = detect_project()
372
- assert project["id"] == "global"
373
- assert project["name"] == "global"
374
-
375
-
376
- def test_detect_project_from_env(patch_globals, monkeypatch, tmp_path):
377
- """THEUS_PROJECT_DIR env var should be used as project root."""
378
- fake_repo = tmp_path / "my-repo"
379
- fake_repo.mkdir()
380
- monkeypatch.setenv("THEUS_PROJECT_DIR", str(fake_repo))
381
-
382
- # Mock git remote to return a URL
383
- def mock_run(cmd, **kwargs):
384
- if "rev-parse" in cmd:
385
- return SimpleNamespace(returncode=0, stdout=str(fake_repo) + "\n", stderr="")
386
- if "get-url" in cmd:
387
- return SimpleNamespace(returncode=0, stdout="https://github.com/test/my-repo.git\n", stderr="")
388
- return SimpleNamespace(returncode=1, stdout="", stderr="")
389
-
390
- monkeypatch.setattr("subprocess.run", mock_run)
391
-
392
- project = detect_project()
393
- assert project["id"] != "global"
394
- assert project["name"] == "my-repo"
395
-
396
-
397
- def test_detect_project_git_timeout(patch_globals, monkeypatch):
398
- """Git timeout should fall through to global."""
399
- monkeypatch.delenv("THEUS_PROJECT_DIR", raising=False)
400
- import subprocess as sp
401
-
402
- def mock_run(cmd, **kwargs):
403
- raise sp.TimeoutExpired(cmd, 5)
404
-
405
- monkeypatch.setattr("subprocess.run", mock_run)
406
-
407
- project = detect_project()
408
- assert project["id"] == "global"
409
-
410
-
411
- def test_detect_project_creates_directories(patch_globals, monkeypatch, tmp_path):
412
- """detect_project should create the project dir structure."""
413
- fake_repo = tmp_path / "structured-repo"
414
- fake_repo.mkdir()
415
- monkeypatch.setenv("THEUS_PROJECT_DIR", str(fake_repo))
416
-
417
- def mock_run(cmd, **kwargs):
418
- if "rev-parse" in cmd:
419
- return SimpleNamespace(returncode=0, stdout=str(fake_repo) + "\n", stderr="")
420
- if "get-url" in cmd:
421
- return SimpleNamespace(returncode=1, stdout="", stderr="no remote")
422
- return SimpleNamespace(returncode=1, stdout="", stderr="")
423
-
424
- monkeypatch.setattr("subprocess.run", mock_run)
425
-
426
- project = detect_project()
427
- assert project["instincts_personal"].exists()
428
- assert project["instincts_inherited"].exists()
429
- assert (project["evolved_dir"] / "skills").exists()
430
-
431
-
432
- # ─────────────────────────────────────────────
433
- # _load_instincts_from_dir tests
434
- # ─────────────────────────────────────────────
435
-
436
- def test_load_from_empty_dir(tmp_path):
437
- result = _load_instincts_from_dir(tmp_path, "personal", "project")
438
- assert result == []
439
-
440
-
441
- def test_load_from_nonexistent_dir(tmp_path):
442
- result = _load_instincts_from_dir(tmp_path / "does-not-exist", "personal", "project")
443
- assert result == []
444
-
445
-
446
- def test_load_annotates_metadata(tmp_path):
447
- """Loaded instincts should have _source_file, _source_type, _scope_label."""
448
- yaml_file = tmp_path / "test.yaml"
449
- yaml_file.write_text(SAMPLE_INSTINCT_YAML)
450
-
451
- result = _load_instincts_from_dir(tmp_path, "personal", "project")
452
- assert len(result) == 1
453
- assert result[0]["_source_file"] == str(yaml_file)
454
- assert result[0]["_source_type"] == "personal"
455
- assert result[0]["_scope_label"] == "project"
456
-
457
-
458
- def test_load_defaults_scope_from_label(tmp_path):
459
- """If an instinct has no 'scope' in frontmatter, it should default to scope_label."""
460
- no_scope_yaml = """\
461
- ---
462
- id: no-scope
463
- trigger: "test"
464
- confidence: 0.5
465
- domain: general
466
- ---
467
-
468
- Body.
469
- """
470
- (tmp_path / "no-scope.yaml").write_text(no_scope_yaml)
471
- result = _load_instincts_from_dir(tmp_path, "inherited", "global")
472
- assert result[0]["scope"] == "global"
473
-
474
-
475
- def test_load_preserves_explicit_scope(tmp_path):
476
- """If frontmatter has explicit scope, it should be preserved."""
477
- yaml_file = tmp_path / "test.yaml"
478
- yaml_file.write_text(SAMPLE_INSTINCT_YAML)
479
-
480
- result = _load_instincts_from_dir(tmp_path, "personal", "global")
481
- # Frontmatter says scope: project, scope_label is global
482
- # The explicit scope should be preserved (not overwritten)
483
- assert result[0]["scope"] == "project"
484
-
485
-
486
- def test_load_handles_corrupt_file(tmp_path, capsys):
487
- """Corrupt YAML files should be warned about but not crash."""
488
- # A file that will cause parse_instinct_file to return empty
489
- (tmp_path / "good.yaml").write_text(SAMPLE_INSTINCT_YAML)
490
- (tmp_path / "bad.yaml").write_text("not yaml\nno frontmatter")
491
-
492
- result = _load_instincts_from_dir(tmp_path, "personal", "project")
493
- # bad.yaml has no valid instincts (no id), so only good.yaml contributes
494
- assert len(result) == 1
495
- assert result[0]["id"] == "test-instinct"
496
-
497
-
498
- def test_load_supports_yml_extension(tmp_path):
499
- yml_file = tmp_path / "test.yml"
500
- yml_file.write_text(SAMPLE_INSTINCT_YAML)
501
-
502
- result = _load_instincts_from_dir(tmp_path, "personal", "project")
503
- ids = {i["id"] for i in result}
504
- assert "test-instinct" in ids
505
-
506
-
507
- def test_load_supports_md_extension(tmp_path):
508
- md_file = tmp_path / "legacy-instinct.md"
509
- md_file.write_text(SAMPLE_INSTINCT_YAML)
510
-
511
- result = _load_instincts_from_dir(tmp_path, "personal", "project")
512
- ids = {i["id"] for i in result}
513
- assert "test-instinct" in ids
514
-
515
-
516
- def test_load_instincts_from_dir_uses_utf8_encoding(tmp_path, monkeypatch):
517
- yaml_file = tmp_path / "test.yaml"
518
- yaml_file.write_text("placeholder")
519
- calls = []
520
-
521
- def fake_read_text(self, *args, **kwargs):
522
- calls.append(kwargs.get("encoding"))
523
- return SAMPLE_INSTINCT_YAML
524
-
525
- monkeypatch.setattr(Path, "read_text", fake_read_text)
526
- result = _load_instincts_from_dir(tmp_path, "personal", "project")
527
- assert result[0]["id"] == "test-instinct"
528
- assert calls == ["utf-8"]
529
-
530
-
531
- # ─────────────────────────────────────────────
532
- # load_all_instincts tests
533
- # ─────────────────────────────────────────────
534
-
535
- def test_load_all_project_and_global(patch_globals):
536
- """Should load from both project and global directories."""
537
- tree = patch_globals
538
- project = _make_project(tree)
539
-
540
- # Write a project instinct
541
- (project["instincts_personal"] / "proj.yaml").write_text(SAMPLE_INSTINCT_YAML)
542
- # Write a global instinct
543
- (tree["global_personal"] / "glob.yaml").write_text(SAMPLE_GLOBAL_INSTINCT_YAML)
544
-
545
- result = load_all_instincts(project)
546
- ids = {i["id"] for i in result}
547
- assert "test-instinct" in ids
548
- assert "global-instinct" in ids
549
-
550
-
551
- def test_load_all_project_overrides_global(patch_globals):
552
- """When project and global have same ID, project wins."""
553
- tree = patch_globals
554
- project = _make_project(tree)
555
-
556
- # Same ID but different confidence
557
- proj_yaml = SAMPLE_INSTINCT_YAML.replace("id: test-instinct", "id: shared-id")
558
- proj_yaml = proj_yaml.replace("confidence: 0.8", "confidence: 0.9")
559
- glob_yaml = SAMPLE_GLOBAL_INSTINCT_YAML.replace("id: global-instinct", "id: shared-id")
560
- glob_yaml = glob_yaml.replace("confidence: 0.9", "confidence: 0.3")
561
-
562
- (project["instincts_personal"] / "shared.yaml").write_text(proj_yaml)
563
- (tree["global_personal"] / "shared.yaml").write_text(glob_yaml)
564
-
565
- result = load_all_instincts(project)
566
- shared = [i for i in result if i["id"] == "shared-id"]
567
- assert len(shared) == 1
568
- assert shared[0]["_scope_label"] == "project"
569
- assert shared[0]["confidence"] == 0.9
570
-
571
-
572
- def test_load_all_global_only(patch_globals):
573
- """Global project should only load global instincts."""
574
- tree = patch_globals
575
- (tree["global_personal"] / "glob.yaml").write_text(SAMPLE_GLOBAL_INSTINCT_YAML)
576
-
577
- global_project = {
578
- "id": "global",
579
- "name": "global",
580
- "root": "",
581
- "project_dir": tree["arsenal"],
582
- "instincts_personal": tree["global_personal"],
583
- "instincts_inherited": tree["global_inherited"],
584
- "evolved_dir": tree["global_evolved"],
585
- "observations_file": tree["arsenal"] / "observations.jsonl",
586
- }
587
-
588
- result = load_all_instincts(global_project)
589
- assert len(result) == 1
590
- assert result[0]["id"] == "global-instinct"
591
-
592
-
593
- def test_load_project_only_excludes_global(patch_globals):
594
- """load_project_only_instincts should NOT include global instincts."""
595
- tree = patch_globals
596
- project = _make_project(tree)
597
-
598
- (project["instincts_personal"] / "proj.yaml").write_text(SAMPLE_INSTINCT_YAML)
599
- (tree["global_personal"] / "glob.yaml").write_text(SAMPLE_GLOBAL_INSTINCT_YAML)
600
-
601
- result = load_project_only_instincts(project)
602
- ids = {i["id"] for i in result}
603
- assert "test-instinct" in ids
604
- assert "global-instinct" not in ids
605
-
606
-
607
- def test_load_project_only_global_fallback_loads_global(patch_globals):
608
- """Global fallback should return global instincts for project-only queries."""
609
- tree = patch_globals
610
- (tree["global_personal"] / "glob.yaml").write_text(SAMPLE_GLOBAL_INSTINCT_YAML)
611
-
612
- global_project = {
613
- "id": "global",
614
- "name": "global",
615
- "root": "",
616
- "project_dir": tree["arsenal"],
617
- "instincts_personal": tree["global_personal"],
618
- "instincts_inherited": tree["global_inherited"],
619
- "evolved_dir": tree["global_evolved"],
620
- "observations_file": tree["arsenal"] / "observations.jsonl",
621
- }
622
-
623
- result = load_project_only_instincts(global_project)
624
- assert len(result) == 1
625
- assert result[0]["id"] == "global-instinct"
626
-
627
-
628
- def test_load_all_empty(patch_globals):
629
- """No instincts at all should return empty list."""
630
- tree = patch_globals
631
- project = _make_project(tree)
632
-
633
- result = load_all_instincts(project)
634
- assert result == []
635
-
636
-
637
- # ─────────────────────────────────────────────
638
- # cmd_status tests
639
- # ─────────────────────────────────────────────
640
-
641
- def test_cmd_status_no_instincts(patch_globals, monkeypatch, capsys):
642
- """Status with no instincts should print fallback message."""
643
- tree = patch_globals
644
- project = _make_project(tree)
645
- monkeypatch.setattr(_mod, "detect_project", lambda: project)
646
-
647
- args = SimpleNamespace()
648
- ret = cmd_status(args)
649
- assert ret == 0
650
- out = capsys.readouterr().out
651
- assert "No se encontraron instintos." in out
652
-
653
-
654
- def test_cmd_status_with_instincts(patch_globals, monkeypatch, capsys):
655
- """Status should show project and global instinct counts."""
656
- tree = patch_globals
657
- project = _make_project(tree)
658
- monkeypatch.setattr(_mod, "detect_project", lambda: project)
659
-
660
- (project["instincts_personal"] / "proj.yaml").write_text(SAMPLE_INSTINCT_YAML)
661
- (tree["global_personal"] / "glob.yaml").write_text(SAMPLE_GLOBAL_INSTINCT_YAML)
662
-
663
- args = SimpleNamespace()
664
- ret = cmd_status(args)
665
- assert ret == 0
666
- out = capsys.readouterr().out
667
- assert "ESTADO DE INSTINTOS" in out
668
- assert "Instintos del proyecto: 1" in out
669
- assert "Instintos globales: 1" in out
670
- assert "ÁMBITO DE PROYECTO" in out
671
- assert "GLOBALES" in out
672
-
673
-
674
- def test_confidence_bar_uses_unicode_when_supported():
675
- """Confidence bars should retain block glyphs on UTF-8 streams."""
676
- stream = SimpleNamespace(encoding="utf-8")
677
- assert _confidence_bar(0.8, stream=stream) == "\u2588" * 8 + "\u2591" * 2
678
-
679
-
680
- def test_confidence_bar_uses_ascii_when_stream_rejects_block_glyphs():
681
- """Windows cp1252 streams cannot encode block glyphs."""
682
- stream = SimpleNamespace(encoding="cp1252")
683
- assert _confidence_bar(0.8, stream=stream) == "########.."
684
-
685
-
686
- def test_print_instincts_by_domain_is_cp1252_safe(monkeypatch):
687
- """Status rendering should not crash on Windows cp1252 stdout."""
688
- raw = io.BytesIO()
689
- stream = io.TextIOWrapper(raw, encoding="cp1252")
690
- monkeypatch.setattr(_mod.sys, "stdout", stream)
691
-
692
- _mod._print_instincts_by_domain([{
693
- "id": "windows-safe",
694
- "trigger": "when stdout uses cp1252",
695
- "confidence": 0.8,
696
- "domain": "platform",
697
- "scope": "project",
698
- }])
699
-
700
- stream.flush()
701
- out = raw.getvalue().decode("cp1252")
702
- assert "########.." in out
703
- assert "\u2588" not in out
704
- assert "\u2591" not in out
705
-
706
-
707
- def test_cmd_status_returns_int(patch_globals, monkeypatch):
708
- """cmd_status should always return an int."""
709
- tree = patch_globals
710
- project = _make_project(tree)
711
- monkeypatch.setattr(_mod, "detect_project", lambda: project)
712
-
713
- args = SimpleNamespace()
714
- ret = cmd_status(args)
715
- assert isinstance(ret, int)
716
-
717
-
718
- # ─────────────────────────────────────────────
719
- # cmd_projects tests
720
- # ─────────────────────────────────────────────
721
-
722
- def test_cmd_projects_empty_registry(patch_globals, capsys):
723
- """No projects should print helpful message."""
724
- args = SimpleNamespace()
725
- ret = cmd_projects(args)
726
- assert ret == 0
727
- out = capsys.readouterr().out
728
- assert "Aún no hay proyectos registrados." in out
729
-
730
-
731
- def test_cmd_projects_with_registry(patch_globals, capsys):
732
- """Should list projects from registry."""
733
- tree = patch_globals
734
-
735
- # Create a project dir with instincts
736
- pid = "test123abc"
737
- project = _make_project(tree, pid=pid, pname="my-app")
738
- (project["instincts_personal"] / "inst.yaml").write_text(SAMPLE_INSTINCT_YAML)
739
-
740
- # Write registry
741
- registry = {
742
- pid: {
743
- "name": "my-app",
744
- "root": "/home/user/my-app",
745
- "remote": "https://github.com/user/my-app.git",
746
- "last_seen": "2025-01-15T12:00:00Z",
747
- }
748
- }
749
- tree["registry_file"].write_text(json.dumps(registry))
750
-
751
- args = SimpleNamespace()
752
- ret = cmd_projects(args)
753
- assert ret == 0
754
- out = capsys.readouterr().out
755
- assert "my-app" in out
756
- assert pid in out
757
- assert "1 personales" in out
758
-
759
-
760
- # ─────────────────────────────────────────────
761
- # _promote_specific tests
762
- # ─────────────────────────────────────────────
763
-
764
- def test_promote_specific_not_found(patch_globals, capsys):
765
- """Promoting nonexistent instinct should fail."""
766
- tree = patch_globals
767
- project = _make_project(tree)
768
-
769
- ret = _promote_specific(project, "nonexistent", force=True)
770
- assert ret == 1
771
- out = capsys.readouterr().out
772
- assert "No se encontró" in out
773
-
774
-
775
- def test_promote_specific_rejects_invalid_id(patch_globals, capsys):
776
- """Path-like instinct IDs should be rejected before file writes."""
777
- tree = patch_globals
778
- project = _make_project(tree)
779
-
780
- ret = _promote_specific(project, "../escape", force=True)
781
- assert ret == 1
782
- err = capsys.readouterr().err
783
- assert "ID de instinto inválido" in err
784
-
785
-
786
- def test_promote_specific_already_global(patch_globals, capsys):
787
- """Promoting an instinct that already exists globally should fail."""
788
- tree = patch_globals
789
- project = _make_project(tree)
790
-
791
- # Write same-id instinct in both project and global
792
- (project["instincts_personal"] / "shared.yaml").write_text(SAMPLE_INSTINCT_YAML)
793
- global_yaml = SAMPLE_INSTINCT_YAML # same id: test-instinct
794
- (tree["global_personal"] / "shared.yaml").write_text(global_yaml)
795
-
796
- ret = _promote_specific(project, "test-instinct", force=True)
797
- assert ret == 1
798
- out = capsys.readouterr().out
799
- assert "ya existe en el ámbito global" in out
800
-
801
-
802
- def test_promote_specific_success(patch_globals, capsys):
803
- """Promote a project instinct to global with --force."""
804
- tree = patch_globals
805
- project = _make_project(tree)
806
-
807
- (project["instincts_personal"] / "inst.yaml").write_text(SAMPLE_INSTINCT_YAML)
808
-
809
- ret = _promote_specific(project, "test-instinct", force=True)
810
- assert ret == 0
811
- out = capsys.readouterr().out
812
- assert "promovido" in out
813
-
814
- # Verify file was created in global dir
815
- promoted_file = tree["global_personal"] / "test-instinct.yaml"
816
- assert promoted_file.exists()
817
- content = promoted_file.read_text()
818
- assert "scope: global" in content
819
- assert "promoted_from: abc123" in content
820
-
821
-
822
- # ─────────────────────────────────────────────
823
- # _promote_auto tests
824
- # ─────────────────────────────────────────────
825
-
826
- def test_promote_auto_no_candidates(patch_globals, capsys):
827
- """Auto-promote with no cross-project instincts should say so."""
828
- tree = patch_globals
829
- project = _make_project(tree)
830
-
831
- # Empty registry
832
- tree["registry_file"].write_text("{}")
833
-
834
- ret = _promote_auto(project, force=True, dry_run=False)
835
- assert ret == 0
836
- out = capsys.readouterr().out
837
- assert "Ningún instinto califica" in out
838
-
839
-
840
- def test_promote_auto_dry_run(patch_globals, capsys):
841
- """Dry run should list candidates but not write files."""
842
- tree = patch_globals
843
-
844
- # Create two projects with the same high-confidence instinct
845
- p1 = _make_project(tree, pid="proj1", pname="project-one")
846
- p2 = _make_project(tree, pid="proj2", pname="project-two")
847
-
848
- high_conf_yaml = """\
849
- ---
850
- id: cross-project-instinct
851
- trigger: "when reviewing"
852
- confidence: 0.95
853
- domain: security
854
- scope: project
855
- ---
856
-
857
- ## Action
858
- Always review for injection.
859
- """
860
- (p1["instincts_personal"] / "cross.yaml").write_text(high_conf_yaml)
861
- (p2["instincts_personal"] / "cross.yaml").write_text(high_conf_yaml)
862
-
863
- # Write registry
864
- registry = {
865
- "proj1": {"name": "project-one", "root": "/a", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
866
- "proj2": {"name": "project-two", "root": "/b", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
867
- }
868
- tree["registry_file"].write_text(json.dumps(registry))
869
-
870
- project = p1
871
- ret = _promote_auto(project, force=True, dry_run=True)
872
- assert ret == 0
873
- out = capsys.readouterr().out
874
- assert "DRY RUN" in out
875
- assert "cross-project-instinct" in out
876
-
877
- # Verify no file was created
878
- assert not (tree["global_personal"] / "cross-project-instinct.yaml").exists()
879
-
880
-
881
- def test_promote_auto_writes_file(patch_globals, capsys):
882
- """Auto-promote with force should write global instinct file."""
883
- tree = patch_globals
884
-
885
- p1 = _make_project(tree, pid="proj1", pname="project-one")
886
- p2 = _make_project(tree, pid="proj2", pname="project-two")
887
-
888
- high_conf_yaml = """\
889
- ---
890
- id: universal-pattern
891
- trigger: "when coding"
892
- confidence: 0.85
893
- domain: general
894
- scope: project
895
- ---
896
-
897
- ## Action
898
- Use descriptive variable names.
899
- """
900
- (p1["instincts_personal"] / "uni.yaml").write_text(high_conf_yaml)
901
- (p2["instincts_personal"] / "uni.yaml").write_text(high_conf_yaml)
902
-
903
- registry = {
904
- "proj1": {"name": "project-one", "root": "/a", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
905
- "proj2": {"name": "project-two", "root": "/b", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
906
- }
907
- tree["registry_file"].write_text(json.dumps(registry))
908
-
909
- ret = _promote_auto(p1, force=True, dry_run=False)
910
- assert ret == 0
911
-
912
- promoted = tree["global_personal"] / "universal-pattern.yaml"
913
- assert promoted.exists()
914
- content = promoted.read_text()
915
- assert "scope: global" in content
916
- assert "auto-promoted" in content
917
-
918
-
919
- def test_promote_auto_skips_invalid_id(patch_globals, capsys):
920
- tree = patch_globals
921
-
922
- p1 = _make_project(tree, pid="proj1", pname="project-one")
923
- p2 = _make_project(tree, pid="proj2", pname="project-two")
924
-
925
- bad_id_yaml = """\
926
- ---
927
- id: ../escape
928
- trigger: "when coding"
929
- confidence: 0.9
930
- domain: general
931
- scope: project
932
- ---
933
-
934
- ## Action
935
- Invalid id should be skipped.
936
- """
937
- (p1["instincts_personal"] / "bad.yaml").write_text(bad_id_yaml)
938
- (p2["instincts_personal"] / "bad.yaml").write_text(bad_id_yaml)
939
-
940
- registry = {
941
- "proj1": {"name": "project-one", "root": "/a", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
942
- "proj2": {"name": "project-two", "root": "/b", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
943
- }
944
- tree["registry_file"].write_text(json.dumps(registry))
945
-
946
- ret = _promote_auto(p1, force=True, dry_run=False)
947
- assert ret == 0
948
- err = capsys.readouterr().err
949
- assert "Se omite un ID de instinto inválido" in err
950
- assert not (tree["global_personal"] / "../escape.yaml").exists()
951
-
952
-
953
- # ─────────────────────────────────────────────
954
- # _find_cross_project_instincts tests
955
- # ─────────────────────────────────────────────
956
-
957
- def test_find_cross_project_empty_registry(patch_globals):
958
- tree = patch_globals
959
- tree["registry_file"].write_text("{}")
960
- result = _find_cross_project_instincts()
961
- assert result == {}
962
-
963
-
964
- def test_find_cross_project_single_project(patch_globals):
965
- """Single project should return nothing (need 2+)."""
966
- tree = patch_globals
967
- p1 = _make_project(tree, pid="proj1", pname="project-one")
968
- (p1["instincts_personal"] / "inst.yaml").write_text(SAMPLE_INSTINCT_YAML)
969
-
970
- registry = {"proj1": {"name": "project-one", "root": "/a", "remote": "", "last_seen": "2025-01-01T00:00:00Z"}}
971
- tree["registry_file"].write_text(json.dumps(registry))
972
-
973
- result = _find_cross_project_instincts()
974
- assert result == {}
975
-
976
-
977
- def test_find_cross_project_shared_instinct(patch_globals):
978
- """Same instinct ID in 2 projects should be found."""
979
- tree = patch_globals
980
- p1 = _make_project(tree, pid="proj1", pname="project-one")
981
- p2 = _make_project(tree, pid="proj2", pname="project-two")
982
-
983
- (p1["instincts_personal"] / "shared.yaml").write_text(SAMPLE_INSTINCT_YAML)
984
- (p2["instincts_personal"] / "shared.yaml").write_text(SAMPLE_INSTINCT_YAML)
985
-
986
- registry = {
987
- "proj1": {"name": "project-one", "root": "/a", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
988
- "proj2": {"name": "project-two", "root": "/b", "remote": "", "last_seen": "2025-01-01T00:00:00Z"},
989
- }
990
- tree["registry_file"].write_text(json.dumps(registry))
991
-
992
- result = _find_cross_project_instincts()
993
- assert "test-instinct" in result
994
- assert len(result["test-instinct"]) == 2
995
-
996
-
997
- # ─────────────────────────────────────────────
998
- # load_registry tests
999
- # ─────────────────────────────────────────────
1000
-
1001
- def test_load_registry_missing_file(patch_globals):
1002
- result = load_registry()
1003
- assert result == {}
1004
-
1005
-
1006
- def test_load_registry_corrupt_json(patch_globals):
1007
- tree = patch_globals
1008
- tree["registry_file"].write_text("not json at all {{{")
1009
- result = load_registry()
1010
- assert result == {}
1011
-
1012
-
1013
- def test_load_registry_valid(patch_globals):
1014
- tree = patch_globals
1015
- data = {"abc": {"name": "test", "root": "/test"}}
1016
- tree["registry_file"].write_text(json.dumps(data))
1017
- result = load_registry()
1018
- assert result == data
1019
-
1020
-
1021
- def test_load_registry_uses_utf8_encoding(monkeypatch):
1022
- calls = []
1023
-
1024
- def fake_open(path, mode="r", *args, **kwargs):
1025
- calls.append(kwargs.get("encoding"))
1026
- return io.StringIO("{}")
1027
-
1028
- monkeypatch.setattr(_mod, "open", fake_open, raising=False)
1029
- assert load_registry() == {}
1030
- assert calls == ["utf-8"]
1031
-
1032
-
1033
- def test_validate_instinct_id():
1034
- assert _validate_instinct_id("good-id_1.0")
1035
- assert not _validate_instinct_id("../bad")
1036
- assert not _validate_instinct_id("bad/name")
1037
- assert not _validate_instinct_id(".hidden")
1038
-
1039
-
1040
- def test_update_registry_atomic_replaces_file(patch_globals):
1041
- tree = patch_globals
1042
- _update_registry("abc123", "demo", "/repo", "https://example.com/repo.git")
1043
- data = json.loads(tree["registry_file"].read_text())
1044
- assert "abc123" in data
1045
- leftovers = list(tree["registry_file"].parent.glob(".projects.json.tmp.*"))
1046
- assert leftovers == []
1047
-
1048
-
1049
- def test_update_registry_matches_shell_schema(patch_globals):
1050
- # Issue #2299: the Python writer must emit the same field set as the shell
1051
- # counterpart in detect-project.sh (id, name, root, remote, created_at,
1052
- # last_seen) so a projects.json entry has a consistent shape regardless of
1053
- # which path wrote it.
1054
- tree = patch_globals
1055
- _update_registry("abc123", "demo", "/repo", "https://example.com/repo.git")
1056
- entry = json.loads(tree["registry_file"].read_text())["abc123"]
1057
- assert set(entry) == {"id", "name", "root", "remote", "created_at", "last_seen"}
1058
- assert entry["id"] == "abc123"
1059
- assert entry["name"] == "demo"
1060
- assert entry["root"] == "/repo"
1061
- assert entry["remote"] == "https://example.com/repo.git"
1062
- # On the initial write both timestamps come from the same `now`, so the
1063
- # first-write contract is created_at == last_seen.
1064
- assert entry["created_at"]
1065
- assert entry["created_at"] == entry["last_seen"]
1066
-
1067
-
1068
- def test_update_registry_preserves_created_at(patch_globals):
1069
- # created_at is stamped on first write and preserved on subsequent updates,
1070
- # while last_seen advances — matching entry.get("created_at", now) in the
1071
- # shell counterpart.
1072
- tree = patch_globals
1073
- _update_registry("abc123", "demo", "/repo", "https://example.com/repo.git")
1074
- first = json.loads(tree["registry_file"].read_text())["abc123"]
1075
-
1076
- _update_registry("abc123", "demo-renamed", "/repo", "https://example.com/repo.git")
1077
- second = json.loads(tree["registry_file"].read_text())["abc123"]
1078
-
1079
- assert second["created_at"] == first["created_at"]
1080
- assert second["name"] == "demo-renamed"
1081
- assert second["last_seen"] >= first["last_seen"]
1082
-
1083
-
1084
- def test_update_registry_heals_malformed_entry(patch_globals):
1085
- # Issue #2299 follow-up: a non-dict value for the project id (e.g. a
1086
- # corrupt registry) must not crash _update_registry. The entry is healed by
1087
- # the rewrite, preserving the old unconditional-overwrite behavior.
1088
- tree = patch_globals
1089
- tree["registry_file"].write_text(json.dumps({"abc123": None}), encoding="utf-8")
1090
- _update_registry("abc123", "demo", "/repo", "https://example.com/repo.git")
1091
- entry = json.loads(tree["registry_file"].read_text())["abc123"]
1092
- assert isinstance(entry, dict)
1093
- assert entry["id"] == "abc123"
1094
- assert entry["created_at"]
1095
- assert entry["created_at"] == entry["last_seen"]
1096
-
1097
-
1098
- def test_update_registry_heals_non_dict_registry(patch_globals):
1099
- # Issue #2299 follow-up: a top-level registry that is valid JSON but not a
1100
- # mapping (e.g. a list or string from a corrupt projects.json) must not
1101
- # crash _update_registry before the per-entry guard runs. The whole file is
1102
- # healed by the rewrite, preserving the old unconditional-overwrite behavior.
1103
- tree = patch_globals
1104
- tree["registry_file"].write_text(json.dumps(["oops"]), encoding="utf-8")
1105
- _update_registry("abc123", "demo", "/repo", "https://example.com/repo.git")
1106
- registry = json.loads(tree["registry_file"].read_text())
1107
- assert isinstance(registry, dict)
1108
- entry = registry["abc123"]
1109
- assert entry["id"] == "abc123"
1110
- assert entry["created_at"] == entry["last_seen"]
1111
-
1112
-
1113
- def test_write_registry_atomic_no_tmp_leftovers(patch_globals):
1114
- # Issue #2294: _write_registry now holds the registry lock like
1115
- # _update_registry. It must still write atomically with no stray tmp files.
1116
- tree = patch_globals
1117
- _write_registry({"keep": {"name": "demo", "root": "/repo", "remote": ""}})
1118
- data = json.loads(tree["registry_file"].read_text())
1119
- assert data == {"keep": {"name": "demo", "root": "/repo", "remote": ""}}
1120
- leftovers = list(tree["registry_file"].parent.glob(".projects.json.tmp.*"))
1121
- assert leftovers == []
1122
-
1123
-
1124
- def test_remove_project_storage_deletes_contained_dir(patch_globals):
1125
- tree = patch_globals
1126
- target = tree["projects_dir"] / "proj-1"
1127
- (target / "instincts").mkdir(parents=True)
1128
- (target / "instincts" / "x.md").write_text("hi", encoding="utf-8")
1129
- _remove_project_storage("proj-1")
1130
- assert not target.exists()
1131
-
1132
-
1133
- def test_remove_project_storage_missing_dir_is_noop(patch_globals):
1134
- # No raise when the contained dir simply does not exist.
1135
- _remove_project_storage("never-created")
1136
-
1137
-
1138
- def test_remove_project_storage_blocks_traversal(patch_globals):
1139
- # Issue #2297: defense-in-depth — a traversal id must be refused even when a
1140
- # caller skips _validate_project_id, so this can never delete outside
1141
- # PROJECTS_DIR.
1142
- with pytest.raises(ValueError):
1143
- _remove_project_storage("../../etc")
1144
-
1145
-
1146
- def test_remove_project_storage_blocks_root_itself(patch_globals):
1147
- with pytest.raises(ValueError):
1148
- _remove_project_storage(".")
1149
-
1150
-
1151
- # ─────────────────────────────────────────────
1152
- # Issue #2302 coverage:
1153
- # _normalize_remote_url, _promote_specific dry-run,
1154
- # projects delete/gc/merge, cmd_prune
1155
- # ─────────────────────────────────────────────
1156
-
1157
- _normalize_remote_url = _mod._normalize_remote_url
1158
- _cmd_projects_delete = _mod._cmd_projects_delete
1159
- _cmd_projects_gc = _mod._cmd_projects_gc
1160
- _cmd_projects_merge = _mod._cmd_projects_merge
1161
- cmd_prune = _mod.cmd_prune
1162
-
1163
-
1164
- # ── _normalize_remote_url ────────────────────
1165
-
1166
- def test_normalize_remote_url_empty_returns_empty():
1167
- assert _normalize_remote_url("") == ""
1168
- assert _normalize_remote_url(None) == ""
1169
-
1170
-
1171
- def test_normalize_remote_url_scp_form():
1172
- # scp-style host:path -> host/path, credentials/.git stripped, lowercased
1173
- assert _normalize_remote_url("git@github.com:Test/Repo.git") == "github.com/test/repo"
1174
-
1175
-
1176
- def test_normalize_remote_url_https_strips_credentials_and_scheme():
1177
- assert (
1178
- _normalize_remote_url("https://user:token@github.com/test/repo.git")
1179
- == "github.com/test/repo"
1180
- )
1181
-
1182
-
1183
- def test_normalize_remote_url_network_is_lowercased():
1184
- assert _normalize_remote_url("https://GitHub.com/Owner/Project") == "github.com/owner/project"
1185
-
1186
-
1187
- def test_normalize_remote_url_trailing_slash_and_dotgit_stripped():
1188
- assert _normalize_remote_url("https://github.com/a/b.git/") == "github.com/a/b"
1189
-
1190
-
1191
- def test_normalize_remote_url_file_scheme_preserves_case():
1192
- # Local file paths are not network URLs: scheme is stripped but case is preserved.
1193
- assert _normalize_remote_url("file:///srv/Repos/My-Repo/") == "/srv/Repos/My-Repo"
1194
-
1195
-
1196
- def test_normalize_remote_url_idempotent():
1197
- once = _normalize_remote_url("https://user@github.com/Test/Repo.git")
1198
- assert _normalize_remote_url(once) == once
1199
-
1200
-
1201
- # ── _promote_specific dry-run ────────────────
1202
-
1203
- def test_promote_specific_dry_run_writes_nothing(patch_globals, capsys):
1204
- """dry_run returns 0, prints [DRY RUN], and writes no global file."""
1205
- tree = patch_globals
1206
- project = _make_project(tree)
1207
- (project["instincts_personal"] / "inst.yaml").write_text(SAMPLE_INSTINCT_YAML)
1208
-
1209
- ret = _promote_specific(project, "test-instinct", force=True, dry_run=True)
1210
- assert ret == 0
1211
- out = capsys.readouterr().out
1212
- assert "[DRY RUN]" in out
1213
- assert not (tree["global_personal"] / "test-instinct.yaml").exists()
1214
- assert list(tree["global_personal"].iterdir()) == []
1215
-
1216
-
1217
- # ── projects delete ──────────────────────────
1218
-
1219
- def test_projects_delete_rejects_invalid_id(patch_globals, capsys):
1220
- args = SimpleNamespace(project_id="../escape", dry_run=False, force=True)
1221
- assert _cmd_projects_delete(args) == 1
1222
- assert "ID de proyecto inválido" in capsys.readouterr().err
1223
-
1224
-
1225
- def test_projects_delete_not_found(patch_globals, capsys):
1226
- args = SimpleNamespace(project_id="ghost123", dry_run=False, force=True)
1227
- assert _cmd_projects_delete(args) == 1
1228
- assert "No se encontró" in capsys.readouterr().err
1229
-
1230
-
1231
- def test_projects_delete_dry_run_keeps_registry_and_storage(patch_globals, capsys):
1232
- tree = patch_globals
1233
- _make_project(tree, pid="proj1", pname="p1")
1234
- tree["registry_file"].write_text(json.dumps({"proj1": {"name": "p1"}}))
1235
-
1236
- args = SimpleNamespace(project_id="proj1", dry_run=True, force=False)
1237
- assert _cmd_projects_delete(args) == 0
1238
- assert "[DRY RUN]" in capsys.readouterr().out
1239
- assert (tree["projects_dir"] / "proj1").exists()
1240
- assert "proj1" in json.loads(tree["registry_file"].read_text())
1241
-
1242
-
1243
- def test_projects_delete_force_removes_registry_and_storage(patch_globals, capsys):
1244
- tree = patch_globals
1245
- _make_project(tree, pid="proj1", pname="p1")
1246
- tree["registry_file"].write_text(json.dumps({"proj1": {"name": "p1"}}))
1247
-
1248
- args = SimpleNamespace(project_id="proj1", dry_run=False, force=True)
1249
- assert _cmd_projects_delete(args) == 0
1250
- assert "eliminado" in capsys.readouterr().out
1251
- assert not (tree["projects_dir"] / "proj1").exists()
1252
- assert "proj1" not in json.loads(tree["registry_file"].read_text())
1253
-
1254
-
1255
- # ── projects gc ──────────────────────────────
1256
-
1257
- def test_projects_gc_no_candidates(patch_globals, capsys):
1258
- tree = patch_globals
1259
- tree["registry_file"].write_text("{}")
1260
- args = SimpleNamespace(dry_run=False, force=True)
1261
- assert _cmd_projects_gc(args) == 0
1262
- assert "No se encontraron entradas de proyecto vacías" in capsys.readouterr().out
1263
-
1264
-
1265
- def test_projects_gc_dry_run_keeps_entry(patch_globals, capsys):
1266
- tree = patch_globals
1267
- _make_project(tree, pid="empty1", pname="e1") # zero instincts/observations
1268
- tree["registry_file"].write_text(json.dumps({"empty1": {"name": "e1"}}))
1269
-
1270
- args = SimpleNamespace(dry_run=True, force=False)
1271
- assert _cmd_projects_gc(args) == 0
1272
- assert "[DRY RUN]" in capsys.readouterr().out
1273
- assert "empty1" in json.loads(tree["registry_file"].read_text())
1274
- # dry-run must not touch storage on disk
1275
- assert (tree["projects_dir"] / "empty1").exists()
1276
-
1277
-
1278
- def test_projects_gc_force_removes_only_zero_value(patch_globals, capsys):
1279
- tree = patch_globals
1280
- _make_project(tree, pid="empty1", pname="e1")
1281
- full = _make_project(tree, pid="full1", pname="f1")
1282
- (full["instincts_personal"] / "inst.yaml").write_text(SAMPLE_INSTINCT_YAML)
1283
- tree["registry_file"].write_text(
1284
- json.dumps({"empty1": {"name": "e1"}, "full1": {"name": "f1"}})
1285
- )
1286
-
1287
- args = SimpleNamespace(dry_run=False, force=True)
1288
- assert _cmd_projects_gc(args) == 0
1289
- reg = json.loads(tree["registry_file"].read_text())
1290
- assert "empty1" not in reg
1291
- assert "full1" in reg
1292
- assert not (tree["projects_dir"] / "empty1").exists()
1293
- assert (tree["projects_dir"] / "full1").exists()
1294
-
1295
-
1296
- # ── projects merge ───────────────────────────
1297
-
1298
- def test_projects_merge_rejects_same_id(patch_globals, capsys):
1299
- args = SimpleNamespace(from_id="dup", into_id="dup", dry_run=False, force=True)
1300
- assert _cmd_projects_merge(args) == 1
1301
- assert "consigo mismo" in capsys.readouterr().err
1302
-
1303
-
1304
- def test_projects_merge_missing_source(patch_globals, capsys):
1305
- tree = patch_globals
1306
- tree["registry_file"].write_text(json.dumps({"dest": {"name": "d"}}))
1307
- args = SimpleNamespace(from_id="src", into_id="dest", dry_run=False, force=True)
1308
- assert _cmd_projects_merge(args) == 1
1309
- assert "proyecto de origen" in capsys.readouterr().err
1310
-
1311
-
1312
- def test_projects_merge_missing_destination(patch_globals, capsys):
1313
- tree = patch_globals
1314
- # Source present, destination absent — exercises the symmetric error branch.
1315
- tree["registry_file"].write_text(json.dumps({"src": {"name": "s"}}))
1316
- args = SimpleNamespace(from_id="src", into_id="dest", dry_run=False, force=True)
1317
- assert _cmd_projects_merge(args) == 1
1318
- assert "proyecto de destino" in capsys.readouterr().err
1319
-
1320
-
1321
- def test_projects_merge_dry_run_no_changes(patch_globals, capsys):
1322
- tree = patch_globals
1323
- src = _make_project(tree, pid="src", pname="s")
1324
- _make_project(tree, pid="dest", pname="d")
1325
- (src["instincts_personal"] / "i.yaml").write_text(SAMPLE_INSTINCT_YAML)
1326
- tree["registry_file"].write_text(json.dumps({"src": {"name": "s"}, "dest": {"name": "d"}}))
1327
-
1328
- args = SimpleNamespace(from_id="src", into_id="dest", dry_run=True, force=False)
1329
- assert _cmd_projects_merge(args) == 0
1330
- assert "[DRY RUN]" in capsys.readouterr().out
1331
- reg = json.loads(tree["registry_file"].read_text())
1332
- assert "src" in reg and "dest" in reg
1333
- assert (tree["projects_dir"] / "src").exists()
1334
- # dry-run must not copy any instinct into the destination storage
1335
- assert not list((tree["projects_dir"] / "dest" / "instincts" / "personal").glob("*.yaml"))
1336
-
1337
-
1338
- def test_projects_merge_force_moves_and_removes_source(patch_globals, capsys):
1339
- tree = patch_globals
1340
- src = _make_project(tree, pid="src", pname="s")
1341
- _make_project(tree, pid="dest", pname="d")
1342
- (src["instincts_personal"] / "i.yaml").write_text(SAMPLE_INSTINCT_YAML)
1343
- tree["registry_file"].write_text(json.dumps({"src": {"name": "s"}, "dest": {"name": "d"}}))
1344
-
1345
- args = SimpleNamespace(from_id="src", into_id="dest", dry_run=False, force=True)
1346
- assert _cmd_projects_merge(args) == 0
1347
- reg = json.loads(tree["registry_file"].read_text())
1348
- assert "src" not in reg
1349
- assert "dest" in reg
1350
- assert not (tree["projects_dir"] / "src").exists()
1351
- moved = list((tree["projects_dir"] / "dest" / "instincts" / "personal").glob("*.yaml"))
1352
- assert len(moved) >= 1
1353
-
1354
-
1355
- # ── cmd_prune ────────────────────────────────
1356
-
1357
- def _pending_item(path, age_days):
1358
- return {
1359
- "path": path,
1360
- "created": None,
1361
- "age_days": age_days,
1362
- "name": path.stem,
1363
- "parent_dir": str(path.parent),
1364
- }
1365
-
1366
-
1367
- def test_cmd_prune_dry_run_keeps_files(monkeypatch, tmp_path, capsys):
1368
- f_old = tmp_path / "old.yaml"
1369
- f_old.write_text("x", encoding="utf-8")
1370
- f_new = tmp_path / "new.yaml"
1371
- f_new.write_text("y", encoding="utf-8")
1372
- items = [_pending_item(f_old, 40), _pending_item(f_new, 5)]
1373
- monkeypatch.setattr(_mod, "_collect_pending_instincts", lambda: items)
1374
-
1375
- args = SimpleNamespace(max_age=30, dry_run=True, quiet=False)
1376
- assert cmd_prune(args) == 0
1377
- assert "[DRY RUN]" in capsys.readouterr().out
1378
- assert f_old.exists()
1379
- assert f_new.exists()
1380
-
1381
-
1382
- def test_cmd_prune_deletes_only_expired(monkeypatch, tmp_path, capsys):
1383
- f_old = tmp_path / "old.yaml"
1384
- f_old.write_text("x", encoding="utf-8")
1385
- f_new = tmp_path / "new.yaml"
1386
- f_new.write_text("y", encoding="utf-8")
1387
- items = [_pending_item(f_old, 40), _pending_item(f_new, 5)]
1388
- monkeypatch.setattr(_mod, "_collect_pending_instincts", lambda: items)
1389
-
1390
- args = SimpleNamespace(max_age=30, dry_run=False, quiet=False)
1391
- assert cmd_prune(args) == 0
1392
- assert not f_old.exists()
1393
- assert f_new.exists()
1394
- assert "Se podaron 1" in capsys.readouterr().out
1395
-
1396
-
1397
- def test_cmd_prune_quiet_suppresses_output(monkeypatch, tmp_path, capsys):
1398
- f_old = tmp_path / "old.yaml"
1399
- f_old.write_text("x", encoding="utf-8")
1400
- items = [_pending_item(f_old, 99)]
1401
- monkeypatch.setattr(_mod, "_collect_pending_instincts", lambda: items)
1402
-
1403
- args = SimpleNamespace(max_age=30, dry_run=False, quiet=True)
1404
- assert cmd_prune(args) == 0
1405
- assert not f_old.exists()
1406
- captured = capsys.readouterr()
1407
- assert captured.out == ""
1408
- assert captured.err == ""
1409
-
1410
-
1411
- def test_cmd_prune_empty_pending_nothing_to_do(monkeypatch, capsys):
1412
- # Nothing pending at all: the non-dry-run, non-quiet branch must report
1413
- # "nothing to do" (not "[DRY RUN]"), return 0, and not crash.
1414
- monkeypatch.setattr(_mod, "_collect_pending_instincts", lambda: [])
1415
-
1416
- args = SimpleNamespace(max_age=30, dry_run=False, quiet=False)
1417
- assert cmd_prune(args) == 0
1418
- out = capsys.readouterr().out
1419
- assert "No hay instintos pendientes con más de 30 días." in out
1420
- assert "[DRY RUN]" not in out