theus-cli-linux-x64 1.2.2 → 1.4.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 (759) hide show
  1. package/README.md +50 -11
  2. package/RELEASE.json +6 -6
  3. package/bin/theus +0 -0
  4. package/package.json +1 -1
  5. package/vendor/higiene-motor/PARCHES.md +244 -0
  6. package/vendor/higiene-motor/audit_dir.py +166 -0
  7. package/vendor/higiene-motor/audit_lib.py +333 -0
  8. package/vendor/higiene-motor/audit_website.py +635 -0
  9. package/vendor/higiene-motor/av_meta.py +498 -0
  10. package/vendor/higiene-motor/check_staged.py +71 -0
  11. package/vendor/higiene-motor/clean_ctrlregen.py +212 -0
  12. package/vendor/higiene-motor/clean_file.py +237 -0
  13. package/vendor/higiene-motor/clean_image.py +218 -0
  14. package/vendor/higiene-motor/clean_staged.py +143 -0
  15. package/vendor/higiene-motor/clean_text.py +108 -0
  16. package/vendor/higiene-motor/common.py +486 -0
  17. package/vendor/higiene-motor/container_meta.py +2522 -0
  18. package/vendor/higiene-motor/detect_gumbel.py +308 -0
  19. package/vendor/higiene-motor/detect_text_watermark.py +613 -0
  20. package/vendor/higiene-motor/format_dispatch.py +157 -0
  21. package/vendor/higiene-motor/hook_written_file.py +253 -0
  22. package/vendor/higiene-motor/image_meta.py +2171 -0
  23. package/vendor/higiene-motor/inspect_file.py +138 -0
  24. package/vendor/higiene-motor/inspect_image.py +72 -0
  25. package/vendor/higiene-motor/inspect_text.py +86 -0
  26. package/vendor/higiene-motor/markdiffusion_harness.py +533 -0
  27. package/vendor/higiene-motor/rewrite_text.py +737 -0
  28. package/vendor/higiene-motor/score_stylometry.py +460 -0
  29. package/vendor/higiene-motor/score_synthid.py +165 -0
  30. package/vendor/higiene-motor/server.py +1059 -0
  31. package/vendor/higiene-motor/synthid_score_server.py +176 -0
  32. package/vendor/higiene-motor/text_detectors.py +433 -0
  33. package/vendor/higiene-motor/text_unicode.py +730 -0
  34. package/vendor/theus-arsenal/.arsenal-nombres-ola2.json +0 -6
  35. package/vendor/theus-arsenal/.arsenal-nombres-ola3.json +0 -72
  36. package/vendor/theus-arsenal/.mailmap +0 -2
  37. package/vendor/theus-arsenal/.theus-plugin/marketplace.json +0 -25
  38. package/vendor/theus-arsenal/.theus-plugin/plugin.json +0 -20
  39. package/vendor/theus-arsenal/AUTHORS.md +0 -8
  40. package/vendor/theus-arsenal/CLEANROOM_REPLACEMENT_PLAN.md +0 -11
  41. package/vendor/theus-arsenal/LICENSE +0 -26
  42. package/vendor/theus-arsenal/PROVENANCE.md +0 -9
  43. package/vendor/theus-arsenal/README.md +0 -41
  44. package/vendor/theus-arsenal/THIRD_PARTY.md +0 -80
  45. package/vendor/theus-arsenal/agents/actualizador-docs.md +0 -123
  46. package/vendor/theus-arsenal/agents/analista-comentarios.md +0 -53
  47. package/vendor/theus-arsenal/agents/analista-conversaciones.md +0 -60
  48. package/vendor/theus-arsenal/agents/analista-tests-pr.md +0 -53
  49. package/vendor/theus-arsenal/agents/analista-tipos.md +0 -49
  50. package/vendor/theus-arsenal/agents/arquitecto-accesibilidad.md +0 -148
  51. package/vendor/theus-arsenal/agents/arquitecto-codigo.md +0 -79
  52. package/vendor/theus-arsenal/agents/arquitecto-homelab.md +0 -90
  53. package/vendor/theus-arsenal/agents/arquitecto-redes.md +0 -116
  54. package/vendor/theus-arsenal/agents/arquitecto-sistemas.md +0 -219
  55. package/vendor/theus-arsenal/agents/bifurcador-opensource.md +0 -206
  56. package/vendor/theus-arsenal/agents/cazador-fallos-silenciosos.md +0 -58
  57. package/vendor/theus-arsenal/agents/consultor-documentacion.md +0 -76
  58. package/vendor/theus-arsenal/agents/diagnosticador-redes.md +0 -135
  59. package/vendor/theus-arsenal/agents/ejecutor-e2e.md +0 -96
  60. package/vendor/theus-arsenal/agents/empaquetador-opensource.md +0 -257
  61. package/vendor/theus-arsenal/agents/escaner-secretos.md +0 -196
  62. package/vendor/theus-arsenal/agents/especialista-seo.md +0 -70
  63. package/vendor/theus-arsenal/agents/estratega-marketing.md +0 -158
  64. package/vendor/theus-arsenal/agents/evaluador-agentes.md +0 -214
  65. package/vendor/theus-arsenal/agents/evaluador-harness.md +0 -217
  66. package/vendor/theus-arsenal/agents/explorador-codigo.md +0 -79
  67. package/vendor/theus-arsenal/agents/extractor-specs.md +0 -214
  68. package/vendor/theus-arsenal/agents/generador-harness.md +0 -139
  69. package/vendor/theus-arsenal/agents/guia-tdd.md +0 -99
  70. package/vendor/theus-arsenal/agents/jefe-de-gabinete.md +0 -162
  71. package/vendor/theus-arsenal/agents/limpiador-refactors.md +0 -93
  72. package/vendor/theus-arsenal/agents/optimizador-rendimiento.md +0 -454
  73. package/vendor/theus-arsenal/agents/planificador-harness.md +0 -107
  74. package/vendor/theus-arsenal/agents/planificador.md +0 -221
  75. package/vendor/theus-arsenal/agents/resolutor-apps-harmonyos.md +0 -181
  76. package/vendor/theus-arsenal/agents/resolutor-builds-cpp.md +0 -98
  77. package/vendor/theus-arsenal/agents/resolutor-builds-dart.md +0 -209
  78. package/vendor/theus-arsenal/agents/resolutor-builds-django.md +0 -253
  79. package/vendor/theus-arsenal/agents/resolutor-builds-go.md +0 -102
  80. package/vendor/theus-arsenal/agents/resolutor-builds-java.md +0 -274
  81. package/vendor/theus-arsenal/agents/resolutor-builds-kotlin.md +0 -128
  82. package/vendor/theus-arsenal/agents/resolutor-builds-pytorch.md +0 -128
  83. package/vendor/theus-arsenal/agents/resolutor-builds-react.md +0 -214
  84. package/vendor/theus-arsenal/agents/resolutor-builds-rust.md +0 -156
  85. package/vendor/theus-arsenal/agents/resolutor-builds-swift.md +0 -169
  86. package/vendor/theus-arsenal/agents/resolutor-builds.md +0 -122
  87. package/vendor/theus-arsenal/agents/revisor-bd.md +0 -97
  88. package/vendor/theus-arsenal/agents/revisor-codigo.md +0 -291
  89. package/vendor/theus-arsenal/agents/revisor-config-red.md +0 -116
  90. package/vendor/theus-arsenal/agents/revisor-cpp.md +0 -80
  91. package/vendor/theus-arsenal/agents/revisor-csharp.md +0 -109
  92. package/vendor/theus-arsenal/agents/revisor-django.md +0 -168
  93. package/vendor/theus-arsenal/agents/revisor-fastapi.md +0 -82
  94. package/vendor/theus-arsenal/agents/revisor-flutter.md +0 -251
  95. package/vendor/theus-arsenal/agents/revisor-go.md +0 -84
  96. package/vendor/theus-arsenal/agents/revisor-java.md +0 -192
  97. package/vendor/theus-arsenal/agents/revisor-kotlin.md +0 -171
  98. package/vendor/theus-arsenal/agents/revisor-ml.md +0 -159
  99. package/vendor/theus-arsenal/agents/revisor-php.md +0 -108
  100. package/vendor/theus-arsenal/agents/revisor-python.md +0 -106
  101. package/vendor/theus-arsenal/agents/revisor-react.md +0 -166
  102. package/vendor/theus-arsenal/agents/revisor-rust.md +0 -102
  103. package/vendor/theus-arsenal/agents/revisor-seguridad.md +0 -116
  104. package/vendor/theus-arsenal/agents/revisor-software-clinico.md +0 -95
  105. package/vendor/theus-arsenal/agents/revisor-swift.md +0 -115
  106. package/vendor/theus-arsenal/agents/revisor-typescript.md +0 -123
  107. package/vendor/theus-arsenal/agents/revisor-vue.md +0 -205
  108. package/vendor/theus-arsenal/agents/simplificador-codigo.md +0 -55
  109. package/vendor/theus-arsenal/commands/actualizar-docs.md +0 -88
  110. package/vendor/theus-arsenal/commands/actualizar-mapas-codigo.md +0 -78
  111. package/vendor/theus-arsenal/commands/aprender-evaluar.md +0 -109
  112. package/vendor/theus-arsenal/commands/aprender.md +0 -74
  113. package/vendor/theus-arsenal/commands/arreglar-build.md +0 -66
  114. package/vendor/theus-arsenal/commands/bucle-multiperspectiva.md +0 -153
  115. package/vendor/theus-arsenal/commands/build-cpp.md +0 -173
  116. package/vendor/theus-arsenal/commands/build-flutter.md +0 -164
  117. package/vendor/theus-arsenal/commands/build-go.md +0 -183
  118. package/vendor/theus-arsenal/commands/build-gradle.md +0 -75
  119. package/vendor/theus-arsenal/commands/build-kotlin.md +0 -176
  120. package/vendor/theus-arsenal/commands/build-react.md +0 -187
  121. package/vendor/theus-arsenal/commands/build-rust.md +0 -187
  122. package/vendor/theus-arsenal/commands/campana-marketing.md +0 -125
  123. package/vendor/theus-arsenal/commands/checkpoint.md +0 -78
  124. package/vendor/theus-arsenal/commands/cobertura-tests.md +0 -73
  125. package/vendor/theus-arsenal/commands/configurar-gestor-paquetes.md +0 -86
  126. package/vendor/theus-arsenal/commands/consulta.md +0 -164
  127. package/vendor/theus-arsenal/commands/control-calidad.md +0 -50
  128. package/vendor/theus-arsenal/commands/crear-skill.md +0 -77
  129. package/vendor/theus-arsenal/commands/enrutar-modelo.md +0 -30
  130. package/vendor/theus-arsenal/commands/epica-desbloquear.md +0 -17
  131. package/vendor/theus-arsenal/commands/epica-descomponer.md +0 -22
  132. package/vendor/theus-arsenal/commands/epica-publicar.md +0 -21
  133. package/vendor/theus-arsenal/commands/epica-reclamar.md +0 -25
  134. package/vendor/theus-arsenal/commands/epica-revisar.md +0 -22
  135. package/vendor/theus-arsenal/commands/epica-sincronizar.md +0 -21
  136. package/vendor/theus-arsenal/commands/epica-validar.md +0 -21
  137. package/vendor/theus-arsenal/commands/evolucionar.md +0 -176
  138. package/vendor/theus-arsenal/commands/funcionalidad.md +0 -49
  139. package/vendor/theus-arsenal/commands/guardar-sesion.md +0 -278
  140. package/vendor/theus-arsenal/commands/harness-build.md +0 -111
  141. package/vendor/theus-arsenal/commands/harness-diseno.md +0 -46
  142. package/vendor/theus-arsenal/commands/informe-costos.md +0 -90
  143. package/vendor/theus-arsenal/commands/iniciar-bucle.md +0 -36
  144. package/vendor/theus-arsenal/commands/instintos-estado.md +0 -53
  145. package/vendor/theus-arsenal/commands/instintos-exportar.md +0 -69
  146. package/vendor/theus-arsenal/commands/instintos-importar.md +0 -120
  147. package/vendor/theus-arsenal/commands/lienzo-planes.md +0 -48
  148. package/vendor/theus-arsenal/commands/limpiar-refactor.md +0 -84
  149. package/vendor/theus-arsenal/commands/modo-seguro.md +0 -96
  150. package/vendor/theus-arsenal/commands/orq-agregar-funcionalidad.md +0 -36
  151. package/vendor/theus-arsenal/commands/orq-cambiar-funcionalidad.md +0 -38
  152. package/vendor/theus-arsenal/commands/orq-construir-mvp.md +0 -36
  153. package/vendor/theus-arsenal/commands/orq-corregir-defecto.md +0 -40
  154. package/vendor/theus-arsenal/commands/orq-refinar-codigo.md +0 -44
  155. package/vendor/theus-arsenal/commands/orq-revisar.md +0 -135
  156. package/vendor/theus-arsenal/commands/plan-prd.md +0 -160
  157. package/vendor/theus-arsenal/commands/plan.md +0 -198
  158. package/vendor/theus-arsenal/commands/podar.md +0 -31
  159. package/vendor/theus-arsenal/commands/pr.md +0 -181
  160. package/vendor/theus-arsenal/commands/promover.md +0 -41
  161. package/vendor/theus-arsenal/commands/proyectos.md +0 -33
  162. package/vendor/theus-arsenal/commands/prp-commit.md +0 -112
  163. package/vendor/theus-arsenal/commands/prp-implementar.md +0 -385
  164. package/vendor/theus-arsenal/commands/prp-planificar.md +0 -501
  165. package/vendor/theus-arsenal/commands/reanudar-sesion.md +0 -160
  166. package/vendor/theus-arsenal/commands/revisar-codigo.md +0 -289
  167. package/vendor/theus-arsenal/commands/revisar-cpp.md +0 -132
  168. package/vendor/theus-arsenal/commands/revisar-fastapi.md +0 -39
  169. package/vendor/theus-arsenal/commands/revisar-flutter.md +0 -115
  170. package/vendor/theus-arsenal/commands/revisar-go.md +0 -148
  171. package/vendor/theus-arsenal/commands/revisar-kotlin.md +0 -140
  172. package/vendor/theus-arsenal/commands/revisar-pr.md +0 -37
  173. package/vendor/theus-arsenal/commands/revisar-python.md +0 -297
  174. package/vendor/theus-arsenal/commands/revisar-react.md +0 -170
  175. package/vendor/theus-arsenal/commands/revisar-rust.md +0 -142
  176. package/vendor/theus-arsenal/commands/revisar-vue.md +0 -174
  177. package/vendor/theus-arsenal/commands/salud-skills.md +0 -52
  178. package/vendor/theus-arsenal/commands/sesiones.md +0 -345
  179. package/vendor/theus-arsenal/commands/test-cpp.md +0 -252
  180. package/vendor/theus-arsenal/commands/test-flutter.md +0 -143
  181. package/vendor/theus-arsenal/commands/test-go.md +0 -268
  182. package/vendor/theus-arsenal/commands/test-kotlin.md +0 -312
  183. package/vendor/theus-arsenal/commands/test-react.md +0 -265
  184. package/vendor/theus-arsenal/commands/test-rust.md +0 -309
  185. package/vendor/theus-arsenal/commands/vigilancia-canary.md +0 -43
  186. package/vendor/theus-arsenal/hooks/hooks.json +0 -274
  187. package/vendor/theus-arsenal/package.json +0 -6
  188. package/vendor/theus-arsenal/rules/angular/coding-style.md +0 -182
  189. package/vendor/theus-arsenal/rules/angular/hooks.md +0 -25
  190. package/vendor/theus-arsenal/rules/angular/patterns.md +0 -249
  191. package/vendor/theus-arsenal/rules/angular/security.md +0 -87
  192. package/vendor/theus-arsenal/rules/angular/testing.md +0 -164
  193. package/vendor/theus-arsenal/rules/arkts/coding-style.md +0 -153
  194. package/vendor/theus-arsenal/rules/arkts/hooks.md +0 -80
  195. package/vendor/theus-arsenal/rules/arkts/patterns.md +0 -236
  196. package/vendor/theus-arsenal/rules/arkts/security.md +0 -141
  197. package/vendor/theus-arsenal/rules/arkts/testing.md +0 -126
  198. package/vendor/theus-arsenal/rules/common/agents.md +0 -49
  199. package/vendor/theus-arsenal/rules/common/code-review.md +0 -123
  200. package/vendor/theus-arsenal/rules/common/coding-style.md +0 -90
  201. package/vendor/theus-arsenal/rules/common/development-workflow.md +0 -44
  202. package/vendor/theus-arsenal/rules/common/git-workflow.md +0 -24
  203. package/vendor/theus-arsenal/rules/common/hooks.md +0 -32
  204. package/vendor/theus-arsenal/rules/common/patterns.md +0 -31
  205. package/vendor/theus-arsenal/rules/common/performance.md +0 -53
  206. package/vendor/theus-arsenal/rules/common/security.md +0 -29
  207. package/vendor/theus-arsenal/rules/common/testing.md +0 -57
  208. package/vendor/theus-arsenal/rules/cpp/coding-style.md +0 -44
  209. package/vendor/theus-arsenal/rules/cpp/hooks.md +0 -39
  210. package/vendor/theus-arsenal/rules/cpp/patterns.md +0 -51
  211. package/vendor/theus-arsenal/rules/cpp/security.md +0 -51
  212. package/vendor/theus-arsenal/rules/cpp/testing.md +0 -44
  213. package/vendor/theus-arsenal/rules/csharp/coding-style.md +0 -72
  214. package/vendor/theus-arsenal/rules/csharp/hooks.md +0 -25
  215. package/vendor/theus-arsenal/rules/csharp/patterns.md +0 -50
  216. package/vendor/theus-arsenal/rules/csharp/security.md +0 -58
  217. package/vendor/theus-arsenal/rules/csharp/testing.md +0 -50
  218. package/vendor/theus-arsenal/rules/dart/coding-style.md +0 -159
  219. package/vendor/theus-arsenal/rules/dart/hooks.md +0 -68
  220. package/vendor/theus-arsenal/rules/dart/patterns.md +0 -261
  221. package/vendor/theus-arsenal/rules/dart/security.md +0 -135
  222. package/vendor/theus-arsenal/rules/dart/testing.md +0 -215
  223. package/vendor/theus-arsenal/rules/fsharp/coding-style.md +0 -112
  224. package/vendor/theus-arsenal/rules/fsharp/hooks.md +0 -26
  225. package/vendor/theus-arsenal/rules/fsharp/patterns.md +0 -111
  226. package/vendor/theus-arsenal/rules/fsharp/security.md +0 -76
  227. package/vendor/theus-arsenal/rules/fsharp/testing.md +0 -62
  228. package/vendor/theus-arsenal/rules/golang/coding-style.md +0 -32
  229. package/vendor/theus-arsenal/rules/golang/hooks.md +0 -17
  230. package/vendor/theus-arsenal/rules/golang/patterns.md +0 -45
  231. package/vendor/theus-arsenal/rules/golang/security.md +0 -34
  232. package/vendor/theus-arsenal/rules/golang/testing.md +0 -31
  233. package/vendor/theus-arsenal/rules/java/coding-style.md +0 -114
  234. package/vendor/theus-arsenal/rules/java/hooks.md +0 -18
  235. package/vendor/theus-arsenal/rules/java/patterns.md +0 -147
  236. package/vendor/theus-arsenal/rules/java/security.md +0 -101
  237. package/vendor/theus-arsenal/rules/java/testing.md +0 -133
  238. package/vendor/theus-arsenal/rules/kotlin/coding-style.md +0 -86
  239. package/vendor/theus-arsenal/rules/kotlin/hooks.md +0 -17
  240. package/vendor/theus-arsenal/rules/kotlin/patterns.md +0 -146
  241. package/vendor/theus-arsenal/rules/kotlin/security.md +0 -82
  242. package/vendor/theus-arsenal/rules/kotlin/testing.md +0 -128
  243. package/vendor/theus-arsenal/rules/nuxt/coding-style.md +0 -47
  244. package/vendor/theus-arsenal/rules/nuxt/hooks.md +0 -39
  245. package/vendor/theus-arsenal/rules/nuxt/patterns.md +0 -54
  246. package/vendor/theus-arsenal/rules/nuxt/security.md +0 -48
  247. package/vendor/theus-arsenal/rules/nuxt/testing.md +0 -49
  248. package/vendor/theus-arsenal/rules/php/coding-style.md +0 -40
  249. package/vendor/theus-arsenal/rules/php/hooks.md +0 -24
  250. package/vendor/theus-arsenal/rules/php/patterns.md +0 -33
  251. package/vendor/theus-arsenal/rules/php/security.md +0 -37
  252. package/vendor/theus-arsenal/rules/php/testing.md +0 -38
  253. package/vendor/theus-arsenal/rules/python/coding-style.md +0 -42
  254. package/vendor/theus-arsenal/rules/python/fastapi.md +0 -58
  255. package/vendor/theus-arsenal/rules/python/hooks.md +0 -19
  256. package/vendor/theus-arsenal/rules/python/patterns.md +0 -39
  257. package/vendor/theus-arsenal/rules/python/security.md +0 -30
  258. package/vendor/theus-arsenal/rules/python/testing.md +0 -38
  259. package/vendor/theus-arsenal/rules/react/coding-style.md +0 -109
  260. package/vendor/theus-arsenal/rules/react/hooks.md +0 -187
  261. package/vendor/theus-arsenal/rules/react/patterns.md +0 -194
  262. package/vendor/theus-arsenal/rules/react/security.md +0 -180
  263. package/vendor/theus-arsenal/rules/react/testing.md +0 -208
  264. package/vendor/theus-arsenal/rules/react-native/accessibility.md +0 -55
  265. package/vendor/theus-arsenal/rules/react-native/coding-style.md +0 -71
  266. package/vendor/theus-arsenal/rules/react-native/hooks.md +0 -28
  267. package/vendor/theus-arsenal/rules/react-native/patterns.md +0 -88
  268. package/vendor/theus-arsenal/rules/react-native/performance.md +0 -45
  269. package/vendor/theus-arsenal/rules/react-native/production-readiness.md +0 -51
  270. package/vendor/theus-arsenal/rules/react-native/security.md +0 -43
  271. package/vendor/theus-arsenal/rules/react-native/testing.md +0 -52
  272. package/vendor/theus-arsenal/rules/ruby/coding-style.md +0 -46
  273. package/vendor/theus-arsenal/rules/ruby/hooks.md +0 -37
  274. package/vendor/theus-arsenal/rules/ruby/patterns.md +0 -44
  275. package/vendor/theus-arsenal/rules/ruby/security.md +0 -51
  276. package/vendor/theus-arsenal/rules/ruby/testing.md +0 -51
  277. package/vendor/theus-arsenal/rules/rust/coding-style.md +0 -151
  278. package/vendor/theus-arsenal/rules/rust/hooks.md +0 -16
  279. package/vendor/theus-arsenal/rules/rust/patterns.md +0 -168
  280. package/vendor/theus-arsenal/rules/rust/security.md +0 -141
  281. package/vendor/theus-arsenal/rules/rust/testing.md +0 -154
  282. package/vendor/theus-arsenal/rules/swift/coding-style.md +0 -47
  283. package/vendor/theus-arsenal/rules/swift/hooks.md +0 -20
  284. package/vendor/theus-arsenal/rules/swift/patterns.md +0 -66
  285. package/vendor/theus-arsenal/rules/swift/security.md +0 -33
  286. package/vendor/theus-arsenal/rules/swift/testing.md +0 -45
  287. package/vendor/theus-arsenal/rules/typescript/coding-style.md +0 -199
  288. package/vendor/theus-arsenal/rules/typescript/hooks.md +0 -22
  289. package/vendor/theus-arsenal/rules/typescript/patterns.md +0 -52
  290. package/vendor/theus-arsenal/rules/typescript/security.md +0 -28
  291. package/vendor/theus-arsenal/rules/typescript/testing.md +0 -18
  292. package/vendor/theus-arsenal/rules/vue/coding-style.md +0 -54
  293. package/vendor/theus-arsenal/rules/vue/hooks.md +0 -45
  294. package/vendor/theus-arsenal/rules/vue/patterns.md +0 -56
  295. package/vendor/theus-arsenal/rules/vue/security.md +0 -46
  296. package/vendor/theus-arsenal/rules/vue/testing.md +0 -53
  297. package/vendor/theus-arsenal/rules/web/coding-style.md +0 -108
  298. package/vendor/theus-arsenal/rules/web/design-quality.md +0 -75
  299. package/vendor/theus-arsenal/rules/web/hooks.md +0 -141
  300. package/vendor/theus-arsenal/rules/web/patterns.md +0 -91
  301. package/vendor/theus-arsenal/rules/web/performance.md +0 -76
  302. package/vendor/theus-arsenal/rules/web/security.md +0 -69
  303. package/vendor/theus-arsenal/rules/web/testing.md +0 -67
  304. package/vendor/theus-arsenal/scripts/hooks/bash-hook-dispatcher.js +0 -192
  305. package/vendor/theus-arsenal/scripts/hooks/block-no-verify.js +0 -556
  306. package/vendor/theus-arsenal/scripts/hooks/check-console-log.js +0 -92
  307. package/vendor/theus-arsenal/scripts/hooks/check-hook-enabled.js +0 -16
  308. package/vendor/theus-arsenal/scripts/hooks/config-protection.js +0 -171
  309. package/vendor/theus-arsenal/scripts/hooks/design-quality-check.js +0 -132
  310. package/vendor/theus-arsenal/scripts/hooks/doc-file-warning.js +0 -110
  311. package/vendor/theus-arsenal/scripts/hooks/modo-seguro.js +0 -158
  312. package/vendor/theus-arsenal/scripts/hooks/notificacion-escritorio.js +0 -208
  313. package/vendor/theus-arsenal/scripts/hooks/plugin-hook-bootstrap.js +0 -280
  314. package/vendor/theus-arsenal/scripts/hooks/post-bash-command-log.js +0 -87
  315. package/vendor/theus-arsenal/scripts/hooks/post-bash-dispatcher.js +0 -24
  316. package/vendor/theus-arsenal/scripts/hooks/post-bash-pr-created.js +0 -60
  317. package/vendor/theus-arsenal/scripts/hooks/post-edit-accumulator.js +0 -94
  318. package/vendor/theus-arsenal/scripts/hooks/post-edit-console-warn.js +0 -54
  319. package/vendor/theus-arsenal/scripts/hooks/post-edit-format.js +0 -110
  320. package/vendor/theus-arsenal/scripts/hooks/post-edit-typecheck.js +0 -98
  321. package/vendor/theus-arsenal/scripts/hooks/pre-bash-commit-quality.js +0 -447
  322. package/vendor/theus-arsenal/scripts/hooks/pre-bash-dev-server-block.js +0 -232
  323. package/vendor/theus-arsenal/scripts/hooks/pre-bash-dispatcher.js +0 -27
  324. package/vendor/theus-arsenal/scripts/hooks/pre-compact.js +0 -101
  325. package/vendor/theus-arsenal/scripts/hooks/pretooluse-visible-output.js +0 -49
  326. package/vendor/theus-arsenal/scripts/hooks/quality-gate.js +0 -168
  327. package/vendor/theus-arsenal/scripts/hooks/run-with-flags.js +0 -271
  328. package/vendor/theus-arsenal/scripts/hooks/salud-mcp.js +0 -749
  329. package/vendor/theus-arsenal/scripts/hooks/seguimiento-costos.js +0 -161
  330. package/vendor/theus-arsenal/scripts/hooks/session-end.js +0 -340
  331. package/vendor/theus-arsenal/scripts/hooks/session-start.js +0 -906
  332. package/vendor/theus-arsenal/scripts/hooks/stop-format-typecheck.js +0 -263
  333. package/vendor/theus-arsenal/scripts/hooks/suggest-compact.js +0 -286
  334. package/vendor/theus-arsenal/scripts/hooks/theus-context-monitor.js +0 -289
  335. package/vendor/theus-arsenal/scripts/hooks/verificacion-factual.js +0 -1278
  336. package/vendor/theus-arsenal/scripts/lib/agent-data-home.js +0 -96
  337. package/vendor/theus-arsenal/scripts/lib/cost-estimate.js +0 -66
  338. package/vendor/theus-arsenal/scripts/lib/hook-flags.js +0 -79
  339. package/vendor/theus-arsenal/scripts/lib/llm-summary.js +0 -185
  340. package/vendor/theus-arsenal/scripts/lib/loopback-guard.js +0 -54
  341. package/vendor/theus-arsenal/scripts/lib/observer-sessions.js +0 -237
  342. package/vendor/theus-arsenal/scripts/lib/package-manager.d.ts +0 -120
  343. package/vendor/theus-arsenal/scripts/lib/package-manager.js +0 -434
  344. package/vendor/theus-arsenal/scripts/lib/path-safety.js +0 -86
  345. package/vendor/theus-arsenal/scripts/lib/plan-canvas/markdown.js +0 -285
  346. package/vendor/theus-arsenal/scripts/lib/plan-canvas/sdk.js +0 -238
  347. package/vendor/theus-arsenal/scripts/lib/plan-canvas/server.js +0 -534
  348. package/vendor/theus-arsenal/scripts/lib/plan-canvas/sessions.js +0 -274
  349. package/vendor/theus-arsenal/scripts/lib/plan-canvas/ui.js +0 -546
  350. package/vendor/theus-arsenal/scripts/lib/project-detect.js +0 -451
  351. package/vendor/theus-arsenal/scripts/lib/resolve-formatter.js +0 -193
  352. package/vendor/theus-arsenal/scripts/lib/resolve-theus-root.js +0 -101
  353. package/vendor/theus-arsenal/scripts/lib/session-aliases.d.ts +0 -138
  354. package/vendor/theus-arsenal/scripts/lib/session-aliases.js +0 -483
  355. package/vendor/theus-arsenal/scripts/lib/session-bridge.js +0 -155
  356. package/vendor/theus-arsenal/scripts/lib/session-manager.d.ts +0 -137
  357. package/vendor/theus-arsenal/scripts/lib/session-manager.js +0 -555
  358. package/vendor/theus-arsenal/scripts/lib/shell-split.js +0 -86
  359. package/vendor/theus-arsenal/scripts/lib/shell-substitution.js +0 -501
  360. package/vendor/theus-arsenal/scripts/lib/skill-evolution/dashboard.js +0 -414
  361. package/vendor/theus-arsenal/scripts/lib/skill-evolution/health.js +0 -285
  362. package/vendor/theus-arsenal/scripts/lib/skill-evolution/index.js +0 -22
  363. package/vendor/theus-arsenal/scripts/lib/skill-evolution/provenance.js +0 -200
  364. package/vendor/theus-arsenal/scripts/lib/skill-evolution/tracker.js +0 -157
  365. package/vendor/theus-arsenal/scripts/lib/skill-evolution/versioning.js +0 -246
  366. package/vendor/theus-arsenal/scripts/lib/transcript-context.js +0 -232
  367. package/vendor/theus-arsenal/scripts/lib/utils.d.ts +0 -205
  368. package/vendor/theus-arsenal/scripts/lib/utils.js +0 -658
  369. package/vendor/theus-arsenal/scripts/plan-canvas.js +0 -341
  370. package/vendor/theus-arsenal/scripts/setup-package-manager.js +0 -46
  371. package/vendor/theus-arsenal/scripts/skills-health.js +0 -143
  372. package/vendor/theus-arsenal/skills/a11y-frontend/SKILL.md +0 -444
  373. package/vendor/theus-arsenal/skills/accesibilidad/SKILL.md +0 -144
  374. package/vendor/theus-arsenal/skills/acelerador-throughput-datos/SKILL.md +0 -72
  375. package/vendor/theus-arsenal/skills/agente-scraper-datos/SKILL.md +0 -771
  376. package/vendor/theus-arsenal/skills/analisis-plataformas-competencia/SKILL.md +0 -137
  377. package/vendor/theus-arsenal/skills/api-x/SKILL.md +0 -233
  378. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/SKILL.md +0 -335
  379. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/observer-loop.sh +0 -374
  380. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/observer.md +0 -188
  381. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/session-guardian.sh +0 -153
  382. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/agents/start-observer.sh +0 -253
  383. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/config.json +0 -8
  384. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/hooks/observe.sh +0 -594
  385. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/detect-project.sh +0 -325
  386. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/instinct-cli.py +0 -1918
  387. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/lib/arsenal-dir.sh +0 -23
  388. package/vendor/theus-arsenal/skills/aprendizaje-continuo-v2/scripts/test_parse_instinct.py +0 -1420
  389. package/vendor/theus-arsenal/skills/arquitectura-hexagonal/SKILL.md +0 -275
  390. package/vendor/theus-arsenal/skills/arquitectura-limpia-android/SKILL.md +0 -340
  391. package/vendor/theus-arsenal/skills/arquitectura-pipelines-recomendacion/SKILL.md +0 -112
  392. package/vendor/theus-arsenal/skills/atlas-datos-prediccion/SKILL.md +0 -53
  393. package/vendor/theus-arsenal/skills/auditoria-arquitectura-agentes/SKILL.md +0 -257
  394. package/vendor/theus-arsenal/skills/auditoria-produccion/SKILL.md +0 -180
  395. package/vendor/theus-arsenal/skills/auditoria-rutas-clic/SKILL.md +0 -243
  396. package/vendor/theus-arsenal/skills/autoevaluacion-agente/SKILL.md +0 -180
  397. package/vendor/theus-arsenal/skills/autoevaluacion-agente/examples/high-score-example.md +0 -89
  398. package/vendor/theus-arsenal/skills/autoevaluacion-agente/examples/low-score-example.md +0 -87
  399. package/vendor/theus-arsenal/skills/autoevaluacion-agente/references/evaluation-criteria.md +0 -71
  400. package/vendor/theus-arsenal/skills/autoevaluacion-agente/references/hook-integration.md +0 -90
  401. package/vendor/theus-arsenal/skills/autoevaluacion-agente/scripts/evaluate.py +0 -409
  402. package/vendor/theus-arsenal/skills/autoevaluacion-agente/templates/evaluation-report.md +0 -86
  403. package/vendor/theus-arsenal/skills/automatizacion-ssh-netmiko/SKILL.md +0 -176
  404. package/vendor/theus-arsenal/skills/base-datos-pubmed/SKILL.md +0 -174
  405. package/vendor/theus-arsenal/skills/base-datos-uspto/SKILL.md +0 -173
  406. package/vendor/theus-arsenal/skills/benchmark/SKILL.md +0 -92
  407. package/vendor/theus-arsenal/skills/bitacora-crecimiento/SKILL.md +0 -120
  408. package/vendor/theus-arsenal/skills/bucle-verificacion/SKILL.md +0 -125
  409. package/vendor/theus-arsenal/skills/buscar-primero/SKILL.md +0 -184
  410. package/vendor/theus-arsenal/skills/busqueda-exa/SKILL.md +0 -111
  411. package/vendor/theus-arsenal/skills/cache-por-hash/SKILL.md +0 -160
  412. package/vendor/theus-arsenal/skills/campana-marketing/SKILL.md +0 -118
  413. package/vendor/theus-arsenal/skills/capacidad-producto/SKILL.md +0 -138
  414. package/vendor/theus-arsenal/skills/cazador-vulnerabilidades/SKILL.md +0 -104
  415. package/vendor/theus-arsenal/skills/compactacion-estrategica/SKILL.md +0 -115
  416. package/vendor/theus-arsenal/skills/comparador-baskets-prediccion/SKILL.md +0 -69
  417. package/vendor/theus-arsenal/skills/compras-energia/SKILL.md +0 -206
  418. package/vendor/theus-arsenal/skills/concurrencia-swift-6-2/SKILL.md +0 -224
  419. package/vendor/theus-arsenal/skills/consejo/SKILL.md +0 -201
  420. package/vendor/theus-arsenal/skills/construccion-harness-agentes/SKILL.md +0 -78
  421. package/vendor/theus-arsenal/skills/constructor-conectores/SKILL.md +0 -119
  422. package/vendor/theus-arsenal/skills/constructor-equipos/SKILL.md +0 -169
  423. package/vendor/theus-arsenal/skills/consulta-documentacion/SKILL.md +0 -92
  424. package/vendor/theus-arsenal/skills/consultas-genomicas-gget/SKILL.md +0 -170
  425. package/vendor/theus-arsenal/skills/contacto-inversores/SKILL.md +0 -95
  426. package/vendor/theus-arsenal/skills/corrutinas-flows-kotlin/SKILL.md +0 -284
  427. package/vendor/theus-arsenal/skills/creacion-video-remotion/SKILL.md +0 -46
  428. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/3d.md +0 -86
  429. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/animations.md +0 -29
  430. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/charts-bar-chart.tsx +0 -173
  431. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/text-animations-typewriter.tsx +0 -100
  432. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets/text-animations-word-highlight.tsx +0 -108
  433. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/assets.md +0 -78
  434. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/audio.md +0 -172
  435. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/calculate-metadata.md +0 -104
  436. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/can-decode.md +0 -75
  437. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/charts.md +0 -58
  438. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/compositions.md +0 -146
  439. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/display-captions.md +0 -126
  440. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/extract-frames.md +0 -229
  441. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/fonts.md +0 -152
  442. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-audio-duration.md +0 -58
  443. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-video-dimensions.md +0 -68
  444. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/get-video-duration.md +0 -58
  445. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/gifs.md +0 -138
  446. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/images.md +0 -130
  447. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/import-srt-captions.md +0 -67
  448. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/lottie.md +0 -67
  449. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/measuring-dom-nodes.md +0 -34
  450. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/measuring-text.md +0 -143
  451. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/sequencing.md +0 -106
  452. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/tailwind.md +0 -11
  453. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/text-animations.md +0 -20
  454. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/timing.md +0 -179
  455. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/transcribe-captions.md +0 -19
  456. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/transitions.md +0 -122
  457. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/trimming.md +0 -52
  458. package/vendor/theus-arsenal/skills/creacion-video-remotion/rules/videos.md +0 -171
  459. package/vendor/theus-arsenal/skills/cumplimiento-aduanero/SKILL.md +0 -270
  460. package/vendor/theus-arsenal/skills/cumplimiento-hipaa/SKILL.md +0 -78
  461. package/vendor/theus-arsenal/skills/datos-sensibles-salud/SKILL.md +0 -149
  462. package/vendor/theus-arsenal/skills/decimales-tokens-evm/SKILL.md +0 -128
  463. package/vendor/theus-arsenal/skills/decisiones-arquitectura/SKILL.md +0 -206
  464. package/vendor/theus-arsenal/skills/demos-ui/SKILL.md +0 -469
  465. package/vendor/theus-arsenal/skills/desarrollo-por-intencion/SKILL.md +0 -369
  466. package/vendor/theus-arsenal/skills/descubrimiento-marca/SKILL.md +0 -149
  467. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/10_proposito-porque.md +0 -42
  468. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/20_posicionamiento.md +0 -47
  469. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/30_audiencia-nicho.md +0 -53
  470. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/40_personalidad-arquetipo.md +0 -61
  471. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/50_voz-tono.md +0 -62
  472. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/60_narrativa-historia.md +0 -54
  473. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/70_tension-fundador.md +0 -50
  474. package/vendor/theus-arsenal/skills/descubrimiento-marca/references/90_SINTESIS.md +0 -133
  475. package/vendor/theus-arsenal/skills/descubrimiento-plugins-laravel/SKILL.md +0 -230
  476. package/vendor/theus-arsenal/skills/destilado-reglas/SKILL.md +0 -263
  477. package/vendor/theus-arsenal/skills/destilado-reglas/scripts/scan-rules.sh +0 -58
  478. package/vendor/theus-arsenal/skills/destilado-reglas/scripts/scan-skills.sh +0 -129
  479. package/vendor/theus-arsenal/skills/diagnostico-bgp/SKILL.md +0 -170
  480. package/vendor/theus-arsenal/skills/direccion-estetica/SKILL.md +0 -220
  481. package/vendor/theus-arsenal/skills/direccion-estetica/references/taxonomia-generos.md +0 -89
  482. package/vendor/theus-arsenal/skills/diseno-api/SKILL.md +0 -522
  483. package/vendor/theus-arsenal/skills/diseno-liquid-glass/SKILL.md +0 -282
  484. package/vendor/theus-arsenal/skills/e2e-escritorio-windows/SKILL.md +0 -879
  485. package/vendor/theus-arsenal/skills/edicion-video/SKILL.md +0 -289
  486. package/vendor/theus-arsenal/skills/enfoque-producto/SKILL.md +0 -91
  487. package/vendor/theus-arsenal/skills/entornos-flox/SKILL.md +0 -493
  488. package/vendor/theus-arsenal/skills/estandares-codigo/SKILL.md +0 -548
  489. package/vendor/theus-arsenal/skills/estandares-cpp/SKILL.md +0 -727
  490. package/vendor/theus-arsenal/skills/estandares-java/SKILL.md +0 -389
  491. package/vendor/theus-arsenal/skills/estilo-legado/SKILL.md +0 -149
  492. package/vendor/theus-arsenal/skills/estructura-informes-competencia/SKILL.md +0 -95
  493. package/vendor/theus-arsenal/skills/evaluacion-academica/SKILL.md +0 -165
  494. package/vendor/theus-arsenal/skills/explorador-skills/SKILL.md +0 -129
  495. package/vendor/theus-arsenal/skills/flujo-git/SKILL.md +0 -714
  496. package/vendor/theus-arsenal/skills/flujo-ingenieria-ml/SKILL.md +0 -343
  497. package/vendor/theus-arsenal/skills/flujo-tdd/SKILL.md +0 -584
  498. package/vendor/theus-arsenal/skills/forja-personas/SKILL.md +0 -298
  499. package/vendor/theus-arsenal/skills/forja-personas/gacha.py +0 -224
  500. package/vendor/theus-arsenal/skills/forja-personas/gacha.sh +0 -5
  501. package/vendor/theus-arsenal/skills/forja-personas/references/avatar-style.md +0 -123
  502. package/vendor/theus-arsenal/skills/forja-personas/references/boundary-rules.md +0 -53
  503. package/vendor/theus-arsenal/skills/forja-personas/references/error-handling.md +0 -53
  504. package/vendor/theus-arsenal/skills/forja-personas/references/identity-tension.md +0 -48
  505. package/vendor/theus-arsenal/skills/forja-personas/references/naming-system.md +0 -39
  506. package/vendor/theus-arsenal/skills/forja-personas/references/output-template.md +0 -166
  507. package/vendor/theus-arsenal/skills/fundamentos-animacion/SKILL.md +0 -296
  508. package/vendor/theus-arsenal/skills/generacion-iconos-ios/SKILL.md +0 -156
  509. package/vendor/theus-arsenal/skills/generacion-iconos-ios/scripts/generate_icons.swift +0 -258
  510. package/vendor/theus-arsenal/skills/generacion-iconos-ios/scripts/iconify_gen.sh +0 -235
  511. package/vendor/theus-arsenal/skills/gestion-excepciones-logisticas/SKILL.md +0 -208
  512. package/vendor/theus-arsenal/skills/gestion-transportistas/SKILL.md +0 -204
  513. package/vendor/theus-arsenal/skills/guia-adopcion-ml/SKILL.md +0 -64
  514. package/vendor/theus-arsenal/skills/harness-agente-autonomo/SKILL.md +0 -252
  515. package/vendor/theus-arsenal/skills/harness-eval-clinico/SKILL.md +0 -212
  516. package/vendor/theus-arsenal/skills/harness-evaluacion/SKILL.md +0 -296
  517. package/vendor/theus-arsenal/skills/harness-generador-evaluador/SKILL.md +0 -254
  518. package/vendor/theus-arsenal/skills/homelab-diseno-red/SKILL.md +0 -120
  519. package/vendor/theus-arsenal/skills/homelab-dns-pihole/SKILL.md +0 -264
  520. package/vendor/theus-arsenal/skills/homelab-preparacion-red/SKILL.md +0 -144
  521. package/vendor/theus-arsenal/skills/homelab-segmentacion-vlan/SKILL.md +0 -307
  522. package/vendor/theus-arsenal/skills/homelab-vpn-wireguard/SKILL.md +0 -299
  523. package/vendor/theus-arsenal/skills/ingenieria-agentica/SKILL.md +0 -96
  524. package/vendor/theus-arsenal/skills/inspeccion-animaciones-blender/SKILL.md +0 -164
  525. package/vendor/theus-arsenal/skills/instaladores-python/SKILL.md +0 -820
  526. package/vendor/theus-arsenal/skills/integracion-jira/SKILL.md +0 -307
  527. package/vendor/theus-arsenal/skills/inteligencia-leads/SKILL.md +0 -312
  528. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/agente-enriquecimiento.md +0 -87
  529. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/mapeador-mutuos.md +0 -76
  530. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/puntuador-senales.md +0 -60
  531. package/vendor/theus-arsenal/skills/inteligencia-leads/agents/redactor-outreach.md +0 -102
  532. package/vendor/theus-arsenal/skills/inteligencia-mercados-prediccion/SKILL.md +0 -53
  533. package/vendor/theus-arsenal/skills/introspeccion-agente/SKILL.md +0 -150
  534. package/vendor/theus-arsenal/skills/inventario-skills/SKILL.md +0 -194
  535. package/vendor/theus-arsenal/skills/inventario-skills/scripts/quick-diff.sh +0 -87
  536. package/vendor/theus-arsenal/skills/inventario-skills/scripts/save-results.sh +0 -57
  537. package/vendor/theus-arsenal/skills/inventario-skills/scripts/scan.sh +0 -170
  538. package/vendor/theus-arsenal/skills/investigacion-mercado/SKILL.md +0 -87
  539. package/vendor/theus-arsenal/skills/investigacion-oraculos-prediccion/SKILL.md +0 -59
  540. package/vendor/theus-arsenal/skills/investigacion-profunda/SKILL.md +0 -161
  541. package/vendor/theus-arsenal/skills/keccak256-nodejs/SKILL.md +0 -100
  542. package/vendor/theus-arsenal/skills/libro-decisiones-recursivo/SKILL.md +0 -82
  543. package/vendor/theus-arsenal/skills/lienzo-planes/SKILL.md +0 -111
  544. package/vendor/theus-arsenal/skills/limpieza-configuracion/SKILL.md +0 -116
  545. package/vendor/theus-arsenal/skills/logistica-inversa-devoluciones/SKILL.md +0 -241
  546. package/vendor/theus-arsenal/skills/manejo-errores/SKILL.md +0 -375
  547. package/vendor/theus-arsenal/skills/materiales-inversores/SKILL.md +0 -101
  548. package/vendor/theus-arsenal/skills/memoria-por-proyecto/SKILL.md +0 -170
  549. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/forget.mjs +0 -44
  550. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/info.mjs +0 -24
  551. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/init.mjs +0 -152
  552. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/list.mjs +0 -40
  553. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/migrate.mjs +0 -214
  554. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/resume.mjs +0 -36
  555. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/save.mjs +0 -210
  556. package/vendor/theus-arsenal/skills/memoria-por-proyecto/commands/shared.mjs +0 -402
  557. package/vendor/theus-arsenal/skills/memoria-por-proyecto/hooks/session-start.mjs +0 -238
  558. package/vendor/theus-arsenal/skills/metodologia-benchmarks/SKILL.md +0 -131
  559. package/vendor/theus-arsenal/skills/migraciones-bd/SKILL.md +0 -430
  560. package/vendor/theus-arsenal/skills/modelos-fundacionales-en-dispositivo/SKILL.md +0 -244
  561. package/vendor/theus-arsenal/skills/modo-seguro/SKILL.md +0 -86
  562. package/vendor/theus-arsenal/skills/motion-avanzado/SKILL.md +0 -592
  563. package/vendor/theus-arsenal/skills/motor-de-contenido/SKILL.md +0 -136
  564. package/vendor/theus-arsenal/skills/no-conformidades-calidad/SKILL.md +0 -249
  565. package/vendor/theus-arsenal/skills/onboarding-codigo/SKILL.md +0 -244
  566. package/vendor/theus-arsenal/skills/operaciones-agentes-empresariales/SKILL.md +0 -51
  567. package/vendor/theus-arsenal/skills/operaciones-conocimiento/SKILL.md +0 -159
  568. package/vendor/theus-arsenal/skills/operaciones-correo/SKILL.md +0 -123
  569. package/vendor/theus-arsenal/skills/operaciones-facturacion/SKILL.md +0 -142
  570. package/vendor/theus-arsenal/skills/operaciones-flujo-proyectos/SKILL.md +0 -110
  571. package/vendor/theus-arsenal/skills/operaciones-github/SKILL.md +0 -143
  572. package/vendor/theus-arsenal/skills/operaciones-google-workspace/SKILL.md +0 -100
  573. package/vendor/theus-arsenal/skills/operaciones-investigacion/SKILL.md +0 -124
  574. package/vendor/theus-arsenal/skills/operaciones-mensajes/SKILL.md +0 -103
  575. package/vendor/theus-arsenal/skills/operaciones-terminal/SKILL.md +0 -110
  576. package/vendor/theus-arsenal/skills/optimizacion-benchmark/SKILL.md +0 -70
  577. package/vendor/theus-arsenal/skills/optimizacion-costos-llm/SKILL.md +0 -182
  578. package/vendor/theus-arsenal/skills/optimizador-conexiones/SKILL.md +0 -191
  579. package/vendor/theus-arsenal/skills/optimizador-paralelismo/SKILL.md +0 -75
  580. package/vendor/theus-arsenal/skills/optimizador-prompts/SKILL.md +0 -374
  581. package/vendor/theus-arsenal/skills/orq-agregar-funcionalidad/SKILL.md +0 -37
  582. package/vendor/theus-arsenal/skills/orq-cambiar-funcionalidad/SKILL.md +0 -36
  583. package/vendor/theus-arsenal/skills/orq-construir-mvp/SKILL.md +0 -38
  584. package/vendor/theus-arsenal/skills/orq-corregir-defecto/SKILL.md +0 -36
  585. package/vendor/theus-arsenal/skills/orq-pipeline/SKILL.md +0 -134
  586. package/vendor/theus-arsenal/skills/orq-refinar-codigo/SKILL.md +0 -49
  587. package/vendor/theus-arsenal/skills/orquestacion-equipos-agentes/SKILL.md +0 -117
  588. package/vendor/theus-arsenal/skills/pagos-agentes-x402/SKILL.md +0 -237
  589. package/vendor/theus-arsenal/skills/patrones-angular/SKILL.md +0 -153
  590. package/vendor/theus-arsenal/skills/patrones-angular/references/angular-animations.md +0 -160
  591. package/vendor/theus-arsenal/skills/patrones-angular/references/angular-aria.md +0 -410
  592. package/vendor/theus-arsenal/skills/patrones-angular/references/cli.md +0 -86
  593. package/vendor/theus-arsenal/skills/patrones-angular/references/component-harnesses.md +0 -59
  594. package/vendor/theus-arsenal/skills/patrones-angular/references/component-styling.md +0 -91
  595. package/vendor/theus-arsenal/skills/patrones-angular/references/components.md +0 -117
  596. package/vendor/theus-arsenal/skills/patrones-angular/references/creating-services.md +0 -97
  597. package/vendor/theus-arsenal/skills/patrones-angular/references/data-resolvers.md +0 -69
  598. package/vendor/theus-arsenal/skills/patrones-angular/references/define-routes.md +0 -67
  599. package/vendor/theus-arsenal/skills/patrones-angular/references/defining-providers.md +0 -72
  600. package/vendor/theus-arsenal/skills/patrones-angular/references/di-fundamentals.md +0 -120
  601. package/vendor/theus-arsenal/skills/patrones-angular/references/e2e-testing.md +0 -56
  602. package/vendor/theus-arsenal/skills/patrones-angular/references/effects.md +0 -83
  603. package/vendor/theus-arsenal/skills/patrones-angular/references/hierarchical-injectors.md +0 -43
  604. package/vendor/theus-arsenal/skills/patrones-angular/references/host-elements.md +0 -80
  605. package/vendor/theus-arsenal/skills/patrones-angular/references/injection-context.md +0 -63
  606. package/vendor/theus-arsenal/skills/patrones-angular/references/inputs.md +0 -101
  607. package/vendor/theus-arsenal/skills/patrones-angular/references/linked-signal.md +0 -59
  608. package/vendor/theus-arsenal/skills/patrones-angular/references/loading-strategies.md +0 -61
  609. package/vendor/theus-arsenal/skills/patrones-angular/references/mcp.md +0 -67
  610. package/vendor/theus-arsenal/skills/patrones-angular/references/navigate-to-routes.md +0 -69
  611. package/vendor/theus-arsenal/skills/patrones-angular/references/outputs.md +0 -86
  612. package/vendor/theus-arsenal/skills/patrones-angular/references/reactive-forms.md +0 -122
  613. package/vendor/theus-arsenal/skills/patrones-angular/references/rendering-strategies.md +0 -44
  614. package/vendor/theus-arsenal/skills/patrones-angular/references/resource.md +0 -77
  615. package/vendor/theus-arsenal/skills/patrones-angular/references/route-animations.md +0 -56
  616. package/vendor/theus-arsenal/skills/patrones-angular/references/route-guards.md +0 -52
  617. package/vendor/theus-arsenal/skills/patrones-angular/references/router-lifecycle.md +0 -45
  618. package/vendor/theus-arsenal/skills/patrones-angular/references/router-testing.md +0 -87
  619. package/vendor/theus-arsenal/skills/patrones-angular/references/show-routes-with-outlets.md +0 -68
  620. package/vendor/theus-arsenal/skills/patrones-angular/references/signal-forms.md +0 -795
  621. package/vendor/theus-arsenal/skills/patrones-angular/references/signals-overview.md +0 -94
  622. package/vendor/theus-arsenal/skills/patrones-angular/references/tailwind-css.md +0 -69
  623. package/vendor/theus-arsenal/skills/patrones-angular/references/template-driven-forms.md +0 -114
  624. package/vendor/theus-arsenal/skills/patrones-angular/references/testing-fundamentals.md +0 -65
  625. package/vendor/theus-arsenal/skills/patrones-animacion/SKILL.md +0 -432
  626. package/vendor/theus-arsenal/skills/patrones-backend/SKILL.md +0 -560
  627. package/vendor/theus-arsenal/skills/patrones-cdss-clinico/SKILL.md +0 -249
  628. package/vendor/theus-arsenal/skills/patrones-cisco-ios/SKILL.md +0 -148
  629. package/vendor/theus-arsenal/skills/patrones-clickhouse/SKILL.md +0 -443
  630. package/vendor/theus-arsenal/skills/patrones-compose-multiplatform/SKILL.md +0 -298
  631. package/vendor/theus-arsenal/skills/patrones-dart-flutter/SKILL.md +0 -566
  632. package/vendor/theus-arsenal/skills/patrones-despliegue/SKILL.md +0 -426
  633. package/vendor/theus-arsenal/skills/patrones-django/SKILL.md +0 -739
  634. package/vendor/theus-arsenal/skills/patrones-django-celery/SKILL.md +0 -456
  635. package/vendor/theus-arsenal/skills/patrones-docker/SKILL.md +0 -363
  636. package/vendor/theus-arsenal/skills/patrones-dotnet/SKILL.md +0 -321
  637. package/vendor/theus-arsenal/skills/patrones-emr-clinico/SKILL.md +0 -168
  638. package/vendor/theus-arsenal/skills/patrones-fastapi/SKILL.md +0 -513
  639. package/vendor/theus-arsenal/skills/patrones-frontend/SKILL.md +0 -655
  640. package/vendor/theus-arsenal/skills/patrones-go/SKILL.md +0 -674
  641. package/vendor/theus-arsenal/skills/patrones-jpa/SKILL.md +0 -156
  642. package/vendor/theus-arsenal/skills/patrones-kotlin/SKILL.md +0 -717
  643. package/vendor/theus-arsenal/skills/patrones-kotlin-exposed/SKILL.md +0 -724
  644. package/vendor/theus-arsenal/skills/patrones-kotlin-ktor/SKILL.md +0 -694
  645. package/vendor/theus-arsenal/skills/patrones-kubernetes/SKILL.md +0 -754
  646. package/vendor/theus-arsenal/skills/patrones-laravel/SKILL.md +0 -414
  647. package/vendor/theus-arsenal/skills/patrones-mcp/SKILL.md +0 -66
  648. package/vendor/theus-arsenal/skills/patrones-mysql/SKILL.md +0 -420
  649. package/vendor/theus-arsenal/skills/patrones-nestjs/SKILL.md +0 -229
  650. package/vendor/theus-arsenal/skills/patrones-nextjs/SKILL.md +0 -56
  651. package/vendor/theus-arsenal/skills/patrones-nuxt4/SKILL.md +0 -99
  652. package/vendor/theus-arsenal/skills/patrones-perl/SKILL.md +0 -508
  653. package/vendor/theus-arsenal/skills/patrones-postgres/SKILL.md +0 -141
  654. package/vendor/theus-arsenal/skills/patrones-prisma/SKILL.md +0 -399
  655. package/vendor/theus-arsenal/skills/patrones-python/SKILL.md +0 -750
  656. package/vendor/theus-arsenal/skills/patrones-pytorch/SKILL.md +0 -400
  657. package/vendor/theus-arsenal/skills/patrones-quarkus/SKILL.md +0 -729
  658. package/vendor/theus-arsenal/skills/patrones-react/SKILL.md +0 -339
  659. package/vendor/theus-arsenal/skills/patrones-react-native/SKILL.md +0 -325
  660. package/vendor/theus-arsenal/skills/patrones-redis/SKILL.md +0 -401
  661. package/vendor/theus-arsenal/skills/patrones-rust/SKILL.md +0 -504
  662. package/vendor/theus-arsenal/skills/patrones-springboot/SKILL.md +0 -314
  663. package/vendor/theus-arsenal/skills/patrones-swiftui/SKILL.md +0 -261
  664. package/vendor/theus-arsenal/skills/patrones-tinystruct/SKILL.md +0 -281
  665. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/architecture.md +0 -90
  666. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/data-handling.md +0 -60
  667. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/database.md +0 -99
  668. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/routing.md +0 -64
  669. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/system-usage.md +0 -97
  670. package/vendor/theus-arsenal/skills/patrones-tinystruct/references/testing.md +0 -72
  671. package/vendor/theus-arsenal/skills/patrones-vite/SKILL.md +0 -449
  672. package/vendor/theus-arsenal/skills/patrones-vue/SKILL.md +0 -469
  673. package/vendor/theus-arsenal/skills/persistencia-actores-swift/SKILL.md +0 -148
  674. package/vendor/theus-arsenal/skills/pipeline-opensource/SKILL.md +0 -254
  675. package/vendor/theus-arsenal/skills/planificacion-demanda-inventario/SKILL.md +0 -236
  676. package/vendor/theus-arsenal/skills/planificador-trades-prediccion/SKILL.md +0 -60
  677. package/vendor/theus-arsenal/skills/plano-tecnico/SKILL.md +0 -102
  678. package/vendor/theus-arsenal/skills/presentaciones-html/SKILL.md +0 -189
  679. package/vendor/theus-arsenal/skills/presentaciones-html/STYLE_PRESETS.md +0 -330
  680. package/vendor/theus-arsenal/skills/presentaciones-html/animation-patterns.md +0 -122
  681. package/vendor/theus-arsenal/skills/presentaciones-html/html-template.md +0 -419
  682. package/vendor/theus-arsenal/skills/presentaciones-html/scripts/export-pdf.sh +0 -418
  683. package/vendor/theus-arsenal/skills/presentaciones-html/scripts/extract-pptx.py +0 -96
  684. package/vendor/theus-arsenal/skills/presentaciones-html/viewport-base.css +0 -153
  685. package/vendor/theus-arsenal/skills/presupuesto-contexto/SKILL.md +0 -263
  686. package/vendor/theus-arsenal/skills/procesamiento-documentos-nutrient/SKILL.md +0 -168
  687. package/vendor/theus-arsenal/skills/programacion-produccion/SKILL.md +0 -220
  688. package/vendor/theus-arsenal/skills/publicacion-cruzada/SKILL.md +0 -117
  689. package/vendor/theus-arsenal/skills/publicador-social/SKILL.md +0 -121
  690. package/vendor/theus-arsenal/skills/puerta-de-entrega/SKILL.md +0 -164
  691. package/vendor/theus-arsenal/skills/puerta-de-entrega/hooks/puerta-entrega.py +0 -242
  692. package/vendor/theus-arsenal/skills/pulir-interfaces/SKILL.md +0 -126
  693. package/vendor/theus-arsenal/skills/qa-navegador/SKILL.md +0 -103
  694. package/vendor/theus-arsenal/skills/ranking-grafo-social/SKILL.md +0 -153
  695. package/vendor/theus-arsenal/skills/recuperacion-iterativa/SKILL.md +0 -236
  696. package/vendor/theus-arsenal/skills/redaccion-articulos/SKILL.md +0 -81
  697. package/vendor/theus-arsenal/skills/regex-vs-llm/SKILL.md +0 -221
  698. package/vendor/theus-arsenal/skills/regresion-codigo-ia/SKILL.md +0 -388
  699. package/vendor/theus-arsenal/skills/rendimiento-react/SKILL.md +0 -567
  700. package/vendor/theus-arsenal/skills/revision-codigo-flutter-dart/SKILL.md +0 -442
  701. package/vendor/theus-arsenal/skills/revision-literatura-cientifica/SKILL.md +0 -191
  702. package/vendor/theus-arsenal/skills/revision-multiperspectiva/SKILL.md +0 -302
  703. package/vendor/theus-arsenal/skills/revision-riesgo-prediccion/SKILL.md +0 -56
  704. package/vendor/theus-arsenal/skills/revision-seguridad/SKILL.md +0 -505
  705. package/vendor/theus-arsenal/skills/revision-seguridad/cloud-infrastructure-security.md +0 -361
  706. package/vendor/theus-arsenal/skills/runtime-bun/SKILL.md +0 -83
  707. package/vendor/theus-arsenal/skills/salud-codigo-codescene/SKILL.md +0 -163
  708. package/vendor/theus-arsenal/skills/salud-interfaces-red/SKILL.md +0 -143
  709. package/vendor/theus-arsenal/skills/seguimiento-costos/SKILL.md +0 -122
  710. package/vendor/theus-arsenal/skills/seguridad-agentes-trading/SKILL.md +0 -145
  711. package/vendor/theus-arsenal/skills/seguridad-amm-defi/SKILL.md +0 -166
  712. package/vendor/theus-arsenal/skills/seguridad-django/SKILL.md +0 -648
  713. package/vendor/theus-arsenal/skills/seguridad-laravel/SKILL.md +0 -945
  714. package/vendor/theus-arsenal/skills/seguridad-perl/SKILL.md +0 -507
  715. package/vendor/theus-arsenal/skills/seguridad-quarkus/SKILL.md +0 -474
  716. package/vendor/theus-arsenal/skills/seguridad-springboot/SKILL.md +0 -279
  717. package/vendor/theus-arsenal/skills/seo/SKILL.md +0 -166
  718. package/vendor/theus-arsenal/skills/sistema-diseno/SKILL.md +0 -81
  719. package/vendor/theus-arsenal/skills/sistema-operativo-agentico/SKILL.md +0 -375
  720. package/vendor/theus-arsenal/skills/sistemas-latencia-critica/SKILL.md +0 -65
  721. package/vendor/theus-arsenal/skills/tdd-django/SKILL.md +0 -735
  722. package/vendor/theus-arsenal/skills/tdd-laravel/SKILL.md +0 -673
  723. package/vendor/theus-arsenal/skills/tdd-quarkus/SKILL.md +0 -817
  724. package/vendor/theus-arsenal/skills/tdd-springboot/SKILL.md +0 -165
  725. package/vendor/theus-arsenal/skills/testing-cpp/SKILL.md +0 -328
  726. package/vendor/theus-arsenal/skills/testing-csharp/SKILL.md +0 -321
  727. package/vendor/theus-arsenal/skills/testing-e2e/SKILL.md +0 -325
  728. package/vendor/theus-arsenal/skills/testing-go/SKILL.md +0 -719
  729. package/vendor/theus-arsenal/skills/testing-kotlin/SKILL.md +0 -829
  730. package/vendor/theus-arsenal/skills/testing-perl/SKILL.md +0 -479
  731. package/vendor/theus-arsenal/skills/testing-protocolos-di-swift/SKILL.md +0 -196
  732. package/vendor/theus-arsenal/skills/testing-python/SKILL.md +0 -815
  733. package/vendor/theus-arsenal/skills/testing-react/SKILL.md +0 -421
  734. package/vendor/theus-arsenal/skills/testing-rust/SKILL.md +0 -506
  735. package/vendor/theus-arsenal/skills/tours-de-codigo/SKILL.md +0 -252
  736. package/vendor/theus-arsenal/skills/traduccion-documentos-visado/SKILL.md +0 -121
  737. package/vendor/theus-arsenal/skills/ui-a-vue/SKILL.md +0 -141
  738. package/vendor/theus-arsenal/skills/validacion-config-red/SKILL.md +0 -211
  739. package/vendor/theus-arsenal/skills/verificacion-django/SKILL.md +0 -470
  740. package/vendor/theus-arsenal/skills/verificacion-factual/SKILL.md +0 -142
  741. package/vendor/theus-arsenal/skills/verificacion-laravel/SKILL.md +0 -184
  742. package/vendor/theus-arsenal/skills/verificacion-quarkus/SKILL.md +0 -485
  743. package/vendor/theus-arsenal/skills/verificacion-springboot/SKILL.md +0 -237
  744. package/vendor/theus-arsenal/skills/videodb/SKILL.md +0 -374
  745. package/vendor/theus-arsenal/skills/videodb/reference/api-reference.md +0 -550
  746. package/vendor/theus-arsenal/skills/videodb/reference/capture-reference.md +0 -407
  747. package/vendor/theus-arsenal/skills/videodb/reference/capture.md +0 -101
  748. package/vendor/theus-arsenal/skills/videodb/reference/editor.md +0 -443
  749. package/vendor/theus-arsenal/skills/videodb/reference/generative.md +0 -331
  750. package/vendor/theus-arsenal/skills/videodb/reference/rtstream-reference.md +0 -564
  751. package/vendor/theus-arsenal/skills/videodb/reference/rtstream.md +0 -65
  752. package/vendor/theus-arsenal/skills/videodb/reference/search.md +0 -230
  753. package/vendor/theus-arsenal/skills/videodb/reference/streaming.md +0 -406
  754. package/vendor/theus-arsenal/skills/videodb/reference/use-cases.md +0 -118
  755. package/vendor/theus-arsenal/skills/videodb/scripts/ws_listener.py +0 -279
  756. package/vendor/theus-arsenal/skills/videos-manim/SKILL.md +0 -91
  757. package/vendor/theus-arsenal/skills/videos-manim/assets/network_graph_scene.py +0 -52
  758. package/vendor/theus-arsenal/skills/vigilancia-canary/SKILL.md +0 -108
  759. 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