theus-cli 0.2.83 → 0.2.85

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