context-map-ai 2.0.0__tar.gz → 2.2.0__tar.gz

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 (188) hide show
  1. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/copilot-instructions.md +1 -1
  2. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/AGENTS.md +2 -0
  3. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/CHANGELOG.md +25 -0
  4. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/PKG-INFO +16 -8
  5. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/README.md +15 -7
  6. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/README_EN.md +18 -10
  7. context_map_ai-2.2.0/context_map/__tests__/test_ast_audit.py +38 -0
  8. context_map_ai-2.2.0/context_map/__tests__/test_ast_summary.py +30 -0
  9. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_conexiones.py +3 -2
  10. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_doctor.py +6 -1
  11. context_map_ai-2.2.0/context_map/__tests__/test_domain_extractor.py +17 -0
  12. context_map_ai-2.2.0/context_map/__tests__/test_hardware.py +13 -0
  13. context_map_ai-2.2.0/context_map/__tests__/test_ollama.py +14 -0
  14. context_map_ai-2.2.0/context_map/__tests__/test_pack_unpack.py +60 -0
  15. context_map_ai-2.2.0/context_map/__tests__/test_similarity.py +41 -0
  16. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/cli/cli.py +6 -0
  17. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/cli/parser.py +13 -0
  18. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/__init__.py +5 -0
  19. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/_helpers.py +29 -4
  20. context_map_ai-2.2.0/context_map/application/commands/enrich.py +86 -0
  21. context_map_ai-2.2.0/context_map/application/commands/pack.py +68 -0
  22. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/refresh.py +10 -0
  23. context_map_ai-2.2.0/context_map/domain/analyzers/ast_audit.py +155 -0
  24. context_map_ai-2.2.0/context_map/domain/analyzers/ast_summary.py +126 -0
  25. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ecosystem/rules_templates.py +1 -0
  26. context_map_ai-2.2.0/context_map/domain/health/hardware.py +109 -0
  27. context_map_ai-2.2.0/context_map/domain/normalization/domain_extractor.py +78 -0
  28. context_map_ai-2.2.0/context_map/domain/normalization/similarity.py +146 -0
  29. context_map_ai-2.2.0/context_map/domain/storage/packer.py +147 -0
  30. context_map_ai-2.2.0/context_map/infrastructure/integrations/ollama.py +128 -0
  31. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/briefs/agents.py +1 -0
  32. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/briefs/brief.py +4 -0
  33. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/briefs/sections.py +12 -0
  34. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/briefs/skill.py +3 -0
  35. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/common.py +6 -31
  36. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/secciones_riesgos.py +6 -3
  37. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/pyproject.toml +1 -1
  38. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  39. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  40. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  41. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/workflows/ci.yml +0 -0
  42. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/workflows/docs.yml +0 -0
  43. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.github/workflows/publish.yml +0 -0
  44. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.gitignore +0 -0
  45. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.hermes/config.yaml +0 -0
  46. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.hermes/shields/pre-commit.md +0 -0
  47. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.hermes/triggers/post-commit.md +0 -0
  48. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.hermes/workflows/dev-loop.md +0 -0
  49. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/.pre-commit-hooks.yaml +0 -0
  50. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/CODE_OF_CONDUCT.md +0 -0
  51. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/CONTRIBUTING.md +0 -0
  52. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/LICENSE +0 -0
  53. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/Makefile +0 -0
  54. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/action.yml +0 -0
  55. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__init__.py +0 -0
  56. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/conftest.py +0 -0
  57. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/smoke.py +0 -0
  58. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_checker_frescura.py +0 -0
  59. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_cli.py +0 -0
  60. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_cyclomatic.py +0 -0
  61. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_diario_consolidado.py +0 -0
  62. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_ecosistema.py +0 -0
  63. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_enterprise_features.py +0 -0
  64. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_export.py +0 -0
  65. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_hermes_clasificacion.py +0 -0
  66. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_hook_memoria_viva.py +0 -0
  67. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_hooks.py +0 -0
  68. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_ingest.py +0 -0
  69. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_mermaid.py +0 -0
  70. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_metrica_memoria_viva.py +0 -0
  71. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_parsing.py +0 -0
  72. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_personal.py +0 -0
  73. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_refresh_temporales.py +0 -0
  74. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_reglas_catalogo.py +0 -0
  75. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_scan_cache.py +0 -0
  76. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_scanner.py +0 -0
  77. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_security_scanner.py +0 -0
  78. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_standardize.py +0 -0
  79. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_tokenization.py +0 -0
  80. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_topologia_arbol.py +0 -0
  81. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_vault_consolidation.py +0 -0
  82. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_watcher.py +0 -0
  83. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/__tests__/test_wrap.py +0 -0
  84. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/__init__.py +0 -0
  85. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/cli/__init__.py +0 -0
  86. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/adapt.py +0 -0
  87. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/auto.py +0 -0
  88. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/build.py +0 -0
  89. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/doctor_cmd.py +0 -0
  90. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/export.py +0 -0
  91. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/hook.py +0 -0
  92. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/importers.py +0 -0
  93. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/ingest.py +0 -0
  94. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/personal.py +0 -0
  95. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/scan.py +0 -0
  96. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/sync.py +0 -0
  97. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/tools.py +0 -0
  98. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/update.py +0 -0
  99. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/watch.py +0 -0
  100. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/application/commands/wrap.py +0 -0
  101. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/cli.py +0 -0
  102. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/__init__.py +0 -0
  103. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/generators/__init__.py +0 -0
  104. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/generators/generadores.py +0 -0
  105. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/generators/narrative_templates.py +0 -0
  106. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/logging_setup.py +0 -0
  107. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/models/__init__.py +0 -0
  108. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/models/config.py +0 -0
  109. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/models/models.py +0 -0
  110. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/normalization/__init__.py +0 -0
  111. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/normalization/cleaning.py +0 -0
  112. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/normalization/inference.py +0 -0
  113. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/normalization/mappings.py +0 -0
  114. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/normalization/standardize.py +0 -0
  115. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/parsing/__init__.py +0 -0
  116. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/parsing/cargadores.py +0 -0
  117. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/parsing/clasificacion.py +0 -0
  118. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/parsing/dedup.py +0 -0
  119. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/parsing/grafo.py +0 -0
  120. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/personal/__init__.py +0 -0
  121. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/personal/bd.py +0 -0
  122. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/storage/__init__.py +0 -0
  123. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/storage/config_loader.py +0 -0
  124. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/storage/store.py +0 -0
  125. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/core/tokenization.py +0 -0
  126. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/__init__.py +0 -0
  127. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analysis/__init__.py +0 -0
  128. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analysis/checker.py +0 -0
  129. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analysis/complexity.py +0 -0
  130. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analysis/models.py +0 -0
  131. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analysis/reporting.py +0 -0
  132. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analysis/signals.py +0 -0
  133. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/analyzers/cyclomatic.py +0 -0
  134. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ecosystem/__init__.py +0 -0
  135. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ecosystem/adaptador.py +0 -0
  136. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ecosystem/detector.py +0 -0
  137. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ecosystem/hooks.py +0 -0
  138. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/health/__init__.py +0 -0
  139. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/health/doctor.py +0 -0
  140. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ingestion/__init__.py +0 -0
  141. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/ingestion/ingest.py +0 -0
  142. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/reglas/reglas.py +0 -0
  143. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/reporting/__init__.py +0 -0
  144. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/reporting/reporter.py +0 -0
  145. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/scanning/__init__.py +0 -0
  146. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/scanning/cache.py +0 -0
  147. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/scanning/scanner.py +0 -0
  148. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/scanning/security.py +0 -0
  149. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/synchronization/__init__.py +0 -0
  150. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/synchronization/relaciones.py +0 -0
  151. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/synchronization/sync.py +0 -0
  152. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/domain/synchronization/watcher.py +0 -0
  153. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/__init__.py +0 -0
  154. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/analyzers/__init__.py +0 -0
  155. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/analyzers/content.py +0 -0
  156. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/analyzers/structure.py +0 -0
  157. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/integrations/__init__.py +0 -0
  158. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/integrations/antigravity.py +0 -0
  159. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/integrations/chat_export.py +0 -0
  160. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/integrations/git.py +0 -0
  161. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/integrations/hermes.py +0 -0
  162. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/mcp_server.py +0 -0
  163. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/infrastructure/version_check.py +0 -0
  164. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/__init__.py +0 -0
  165. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/briefs/__init__.py +0 -0
  166. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/briefs/extractors.py +0 -0
  167. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/__init__.py +0 -0
  168. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/atomic.py +0 -0
  169. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/__init__.py +0 -0
  170. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/canvas.py +0 -0
  171. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/consolidado.py +0 -0
  172. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/jerarquico.py +0 -0
  173. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/notas_ideas.py +0 -0
  174. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/rutas.py +0 -0
  175. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/secciones_backlog.py +0 -0
  176. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/secciones_estructura.py +0 -0
  177. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/secciones_historial.py +0 -0
  178. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/secciones_ideas.py +0 -0
  179. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/consolidated/secciones_proposito.py +0 -0
  180. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/mermaid.py +0 -0
  181. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/preservar.py +0 -0
  182. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/templates.py +0 -0
  183. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/context_map/presentation/vault/writer.py +0 -0
  184. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/docs/LAUNCH_KIT.md +0 -0
  185. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/docs/plans/2026-08-10-mapa-mental-conectado.md +0 -0
  186. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/docs/plans/PLAN-MEJORAS-CONTEXTO-VIVO-2026-08-14.md +0 -0
  187. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/mkdocs.yml +0 -0
  188. {context_map_ai-2.0.0 → context_map_ai-2.2.0}/uv.lock +0 -0
@@ -18,7 +18,7 @@
18
18
 
19
19
  # GitHub Copilot — Instrucciones para ContextMap
20
20
 
21
- > Generado automáticamente por **ContextMap** (2026-08-18).
21
+ > Generado automáticamente por **ContextMap** (2026-08-19).
22
22
 
23
23
  ## Antes de sugerir código
24
24
 
@@ -67,6 +67,8 @@ Cualquier agente que tome una tarea en este proyecto **DEBE** seguir estos pasos
67
67
  Inspeccionar `.context-map/vault-ContextMap/2.0-IDEAS/2.1-Ideas-Pendientes/` y `5.0-BACKLOG/5.1-Tareas.md`.
68
68
  6. **No Suponer Rutas o Lógica**:
69
69
  Inspeccionar el código fuente antes de formular hipótesis de cambio.
70
+ 7. **Captura Autónoma del Dominio**:
71
+ Al inicializar o ponerse en contexto en un proyecto, inspeccionar los submódulos de lógica nuclear (algoritmos, ecuaciones implícitas, reglas de negocio) y documentar lo descubierto en `7.0-MANUAL/DOMINIO.md` o en las notas del Vault, ejecutando `ctxmap refresh .` para que el brief y el Vault contengan el alma matemática y funcional del sistema.
70
72
 
71
73
  > ⚠️ **NUNCA respondas "¿qué quedó pendiente?" basándote solo en un documento
72
74
  > suelto (auditoría, CHANGELOG, docs/)** — cruza SIEMPRE el brief + backlog manual
@@ -5,6 +5,31 @@ Todas las notas de versión y cambios destacables en este proyecto serán docume
5
5
  El formato está basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/),
6
6
  y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.2.0] — 2026-08-19
9
+
10
+ ### 🗜️ Nuevo — Paquetes de Contexto Portátiles Offline, Escáner de Auditoría AST & Fallback de Modelos
11
+
12
+ - **🗜️ Empaquetado y Desempaquetado Portátil (`ctxmap pack` / `ctxmap unpack`)**: Nuevo sistema para comprimir la memoria viva completa de cualquier proyecto en un archivo único binario `.ctxpack` con manifiesto de integridad (`pack_manifest.json`) y restaurarlo 100% offline en cualquier equipo.
13
+ - **🛡️ Escáner Sintáctico AST de Auditoría Local (`domain/analyzers/ast_audit.py`)**: Motor determinístico de análisis estático que detecta ejecuciones dinámicas inseguras (`eval/exec`), concatenaciones de SQL dinámicas, bloques `except Exception: pass` silenciosos, desuso de administradores de contexto en archivos y credenciales hardcodadas.
14
+ - **🦙 Fallback Inteligente de Modelos Ollama (`infrastructure/integrations/ollama.py`)**: Auto-resolución de modelos locales instalados vía API `/api/tags` para seleccionar automáticamente modelos disponibles (`coder`, `qwen`, `llama`, `deepseek`, `phi`) sin fallar por modelos ausentes.
15
+ - **⚙️ Generación Automática de Plantilla `dominios.yaml` (`application/commands/_helpers.py`)**: Creación transparente de la plantilla por defecto de agrupamiento temático para Obsidian.
16
+ - **Suite de Pruebas**: 176/176 tests unitarios pasados al 100% verde.
17
+
18
+ ---
19
+
20
+ ## [2.1.0] — 2026-08-18
21
+
22
+ ### ✨ Nuevo — Suite de Inteligencia Offline, Tokenización Profesional & Protocolo Agéntico de Dominio
23
+
24
+ - **🧮 Visualización Profesional de Tokenización**: Medición en tiempo real del presupuesto de tokens en consola CLI y tabla ejecutiva en `CONTEXT.md` mostrando >99% de ahorro de ventana de contexto respecto al código crudo.
25
+ - **🦙 Integración Ollama Local Adaptativa (`infrastructure/integrations/ollama.py`)**: Conexión opcional a Ollama en `http://localhost:11434` sin costo de API ni internet.
26
+ - **🖥️ Diagnóstico de RAM y Guardián de Hardware (`domain/health/hardware.py`)**: Evaluación previa de memoria RAM y CPU para recomendar modelos de bajo consumo (`qwen2.5-coder:1.5b` ~1.2 GB RAM) y conmutar a AST determinístico si la RAM es baja (<3.5 GB libres).
27
+ - **✍️ Enriquecedor de Código Función por Función (`ctxmap enrich`)**: Comando CLI (`application/commands/enrich.py`) que audita y documenta funciones sin docstring en Español Técnico (Google Style).
28
+ - **🏷️ Extractor de Conceptos TF-IDF (`domain/normalization/domain_extractor.py`)**: Descubrimiento determinístico local de términos de dominio del negocio (`FACTURACION`, `INVENTARIO`, `TCG`, `AUTENTICACION`).
29
+ - **🧠 Protocolo Agéntico de Captura del Dominio (`AGENTS.md`)**: Protocolo estandarizado en reglas agénticas para que cualquier IA en el IDE (`Antigravity`, `Cursor`, `Claude`) interprete y documente automáticamente ecuaciones implícitas y reglas nucleares en `7.0-MANUAL/DOMINIO.md`.
30
+ - **🎨 Grupos de Color del Graph View Profesionalizados (`common.py`)**: Grafo de Obsidian limpio y estructurado únicamente por las 8 secciones de dominio principales y tipos de nodos base.
31
+ - **Suite de Pruebas**: 173/173 tests unitarios pasados al 100% verde.
32
+
8
33
  ---
9
34
 
10
35
  ## [2.0.0] — 2026-08-17
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: context-map-ai
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Mapa mental narrativo de proyectos para agentes de IA
5
5
  Project-URL: Homepage, https://github.com/kudawasama/ContextMap
6
6
  Project-URL: Repository, https://github.com/kudawasama/ContextMap
@@ -41,7 +41,8 @@ Description-Content-Type: text/markdown
41
41
 
42
42
  *Captura el alma de tu proyecto, establece gobernanza automática y mantiene vivo el contexto para cualquier Agente de IA (`Antigravity`, `Cursor`, `Claude`, `Hermes`, `Copilot`, `Windsurf`, `Gemini`).*
43
43
 
44
- [![Release](https://img.shields.io/badge/version-v2.0.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
44
+ [![Release](https://img.shields.io/badge/version-v2.2.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
45
+ [![PyPI](https://img.shields.io/pypi/v/context-map-ai.svg?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/context-map-ai/)
45
46
  [![Python](https://img.shields.io/badge/python-3.10+-3776AB.svg?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/downloads/)
46
47
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](LICENSE)
47
48
  [![Readiness](https://img.shields.io/badge/Readiness-100%2F100-brightgreen.svg?style=for-the-badge)](file:///.context-map/CONTEXT.md)
@@ -62,7 +63,7 @@ Description-Content-Type: text/markdown
62
63
  ContextMap creates an interconnected **Obsidian Vault** and **AI Executive Brief (`CONTEXT.md`)** to manage context, multi-IDE rules, living memory, and autonomous self-maintenance for your software projects across agents like `Antigravity`, `Cursor`, `Claude Code`, `Copilot`, `Hermes`, and `Gemini`.
63
64
 
64
65
  - 📖 **Full English Documentation:** See [**README_EN.md**](README_EN.md)
65
- - ⚡ **Quick Install:** `uv tool install git+https://github.com/kudawasama/ContextMap.git`
66
+ - ⚡ **PyPI Install:** `pip install context-map-ai` or `uv tool install context-map-ai`
66
67
  - 💬 **Initialize:** Tell your AI Agent: *"Initialize ContextMap for this project"* or run `ctxmap auto .`
67
68
  </details>
68
69
 
@@ -85,14 +86,17 @@ Construye una bóveda interconectada en **Obsidian** ([Graph View en Árbol Estr
85
86
 
86
87
  ## ⚡ Inicio Rápido en 10 Segundos
87
88
 
88
- ### 1. Instalación Global (con `uv`)
89
+ ### 1. Instalación Global (con `pip` o `uv`)
89
90
 
90
91
  ```bash
91
- # Recomendado: instalación directa en 1 comando (requiere https://docs.astral.sh/uv/)
92
- uv tool install git+https://github.com/kudawasama/ContextMap.git
92
+ # Opción 1: Desde PyPI oficial (recomendado con pip)
93
+ pip install context-map-ai
94
+
95
+ # Opción 2: Instalación aislada global con uv (ultra-rápido)
96
+ uv tool install context-map-ai
93
97
 
94
- # O con pip desde un clon local:
95
- # git clone https://github.com/kudawasama/ContextMap.git && cd ContextMap && pip install -e .
98
+ # Opción 3: Desde el repositorio en GitHub
99
+ uv tool install git+https://github.com/kudawasama/ContextMap.git
96
100
  ```
97
101
 
98
102
  ### 2. Poner en Contexto un Proyecto
@@ -224,6 +228,10 @@ ctxmap hook install # Inyecta pre-commit y post-commit transpa
224
228
  # 🔄 Cierre de sesión de trabajo
225
229
  ctxmap wrap # refresh + resumen de memoria viva registrada
226
230
 
231
+ # 📦 Empaquetado y Transporte Offline Portátil
232
+ ctxmap pack . --output mi_proyecto.ctxpack # Comprime la memoria viva en un paquete único
233
+ ctxmap unpack mi_proyecto.ctxpack ./destino # Restaura el contexto completo 100% offline
234
+
227
235
  # 📦 Exportación de Contexto Portable (Repomix compatible)
228
236
  ctxmap export . --format xml # Exporta contexto plano en XML, JSON o Markdown
229
237
 
@@ -9,7 +9,8 @@
9
9
 
10
10
  *Captura el alma de tu proyecto, establece gobernanza automática y mantiene vivo el contexto para cualquier Agente de IA (`Antigravity`, `Cursor`, `Claude`, `Hermes`, `Copilot`, `Windsurf`, `Gemini`).*
11
11
 
12
- [![Release](https://img.shields.io/badge/version-v2.0.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
12
+ [![Release](https://img.shields.io/badge/version-v2.2.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
13
+ [![PyPI](https://img.shields.io/pypi/v/context-map-ai.svg?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/context-map-ai/)
13
14
  [![Python](https://img.shields.io/badge/python-3.10+-3776AB.svg?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/downloads/)
14
15
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](LICENSE)
15
16
  [![Readiness](https://img.shields.io/badge/Readiness-100%2F100-brightgreen.svg?style=for-the-badge)](file:///.context-map/CONTEXT.md)
@@ -30,7 +31,7 @@
30
31
  ContextMap creates an interconnected **Obsidian Vault** and **AI Executive Brief (`CONTEXT.md`)** to manage context, multi-IDE rules, living memory, and autonomous self-maintenance for your software projects across agents like `Antigravity`, `Cursor`, `Claude Code`, `Copilot`, `Hermes`, and `Gemini`.
31
32
 
32
33
  - 📖 **Full English Documentation:** See [**README_EN.md**](README_EN.md)
33
- - ⚡ **Quick Install:** `uv tool install git+https://github.com/kudawasama/ContextMap.git`
34
+ - ⚡ **PyPI Install:** `pip install context-map-ai` or `uv tool install context-map-ai`
34
35
  - 💬 **Initialize:** Tell your AI Agent: *"Initialize ContextMap for this project"* or run `ctxmap auto .`
35
36
  </details>
36
37
 
@@ -53,14 +54,17 @@ Construye una bóveda interconectada en **Obsidian** ([Graph View en Árbol Estr
53
54
 
54
55
  ## ⚡ Inicio Rápido en 10 Segundos
55
56
 
56
- ### 1. Instalación Global (con `uv`)
57
+ ### 1. Instalación Global (con `pip` o `uv`)
57
58
 
58
59
  ```bash
59
- # Recomendado: instalación directa en 1 comando (requiere https://docs.astral.sh/uv/)
60
- uv tool install git+https://github.com/kudawasama/ContextMap.git
60
+ # Opción 1: Desde PyPI oficial (recomendado con pip)
61
+ pip install context-map-ai
62
+
63
+ # Opción 2: Instalación aislada global con uv (ultra-rápido)
64
+ uv tool install context-map-ai
61
65
 
62
- # O con pip desde un clon local:
63
- # git clone https://github.com/kudawasama/ContextMap.git && cd ContextMap && pip install -e .
66
+ # Opción 3: Desde el repositorio en GitHub
67
+ uv tool install git+https://github.com/kudawasama/ContextMap.git
64
68
  ```
65
69
 
66
70
  ### 2. Poner en Contexto un Proyecto
@@ -192,6 +196,10 @@ ctxmap hook install # Inyecta pre-commit y post-commit transpa
192
196
  # 🔄 Cierre de sesión de trabajo
193
197
  ctxmap wrap # refresh + resumen de memoria viva registrada
194
198
 
199
+ # 📦 Empaquetado y Transporte Offline Portátil
200
+ ctxmap pack . --output mi_proyecto.ctxpack # Comprime la memoria viva en un paquete único
201
+ ctxmap unpack mi_proyecto.ctxpack ./destino # Restaura el contexto completo 100% offline
202
+
195
203
  # 📦 Exportación de Contexto Portable (Repomix compatible)
196
204
  ctxmap export . --format xml # Exporta contexto plano en XML, JSON o Markdown
197
205
 
@@ -9,7 +9,8 @@
9
9
 
10
10
  *Capture the soul of your project, establish automated governance, and keep living context available for any AI Agent (`Antigravity`, `Cursor`, `Claude Code`, `Hermes`, `Copilot`, `Windsurf`, `Gemini`).*
11
11
 
12
- [![Release](https://img.shields.io/badge/version-v2.0.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
12
+ [![Release](https://img.shields.io/badge/version-v2.2.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
13
+ [![PyPI](https://img.shields.io/pypi/v/context-map-ai.svg?style=for-the-badge&logo=pypi&logoColor=white)](https://pypi.org/project/context-map-ai/)
13
14
  [![Python](https://img.shields.io/badge/python-3.10+-3776AB.svg?style=for-the-badge&logo=python&logoColor=white)](https://www.python.org/downloads/)
14
15
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](LICENSE)
15
16
  [![Readiness](https://img.shields.io/badge/Readiness-100%2F100-brightgreen.svg?style=for-the-badge)](file:///.context-map/CONTEXT.md)
@@ -25,14 +26,14 @@
25
26
 
26
27
  ## 💡 What is ContextMap and why does it exist?
27
28
 
28
- When working with AI Agents in your IDE (`Antigravity`, `Cursor`, `Claude Code`, `Copilot`, etc.), AI models frequently forget past architectural decisions, miss core project rules, or propose blind refactorings that break your codebase.
29
+ When working with AI Agents in your IDE (`Antigravity`, `Cursor`, `Claude Code`, `Copilot`, etc.), AI often forgets past decisions, ignores strict architecture constraints, or proposes blind refactors that break the system.
29
30
 
30
31
  **ContextMap solves this by creating a living memory for your project:**
31
32
  It builds an interconnected **Obsidian Vault** ([Strict Tree Graph View](file:///.context-map/vault-ContextMap/)) and an AI Executive Brief ([`CONTEXT.md`](file:///.context-map/CONTEXT.md)) that teach any AI Agent:
32
- - **Why does the project exist?** (Purpose, business domain, and scope).
33
- - **What risks does it face?** (Static complexity hotspots, warnings, and fragile areas).
33
+ - **Why does the project exist?** (Purpose, business, and identity).
34
+ - **What risks does it face?** (Static complexity, code alerts, and sensitive zones).
34
35
  - **What is implemented vs. pending?** (Deduplicated graph of ideas, bases, and changes).
35
- - **What architectural decisions were made?** (Living memory of past sessions and commit history).
36
+ - **What architecture decisions were made?** (Living memory of past conversations and commit histories).
36
37
 
37
38
  > 🚫 **ContextMap is not just a passive doc generator.** It is an active system for **Agentic Governance**, **Permanent Memory**, **Readiness Assessment**, and **Autonomous Self-Maintenance**.
38
39
 
@@ -40,14 +41,17 @@ It builds an interconnected **Obsidian Vault** ([Strict Tree Graph View](file://
40
41
 
41
42
  ## ⚡ 10-Second Quick Start
42
43
 
43
- ### 1. Global Installation (with `uv`)
44
+ ### 1. Global Installation (via `pip` or `uv`)
44
45
 
45
46
  ```bash
46
- # Recommended: 1-command direct install (requires https://docs.astral.sh/uv/)
47
- uv tool install git+https://github.com/kudawasama/ContextMap.git
47
+ # Option 1: Official PyPI Package (Recommended via pip)
48
+ pip install context-map-ai
49
+
50
+ # Option 2: Global isolated tool via uv
51
+ uv tool install context-map-ai
48
52
 
49
- # Or with pip from local clone:
50
- # git clone https://github.com/kudawasama/ContextMap.git && cd ContextMap && pip install -e .
53
+ # Option 3: Direct from GitHub repository
54
+ uv tool install git+https://github.com/kudawasama/ContextMap.git
51
55
  ```
52
56
 
53
57
  ### 2. Contextualize a Project
@@ -173,6 +177,10 @@ ctxmap hook install # Injects transparent pre-commit & post-co
173
177
  # 🔄 Work session closing
174
178
  ctxmap wrap # refresh + summary of logged living memory
175
179
 
180
+ # 📦 Offline Portable Context Packaging
181
+ ctxmap pack . --output project.ctxpack # Packs living context into a single archive
182
+ ctxmap unpack project.ctxpack ./target # Restores context 100% offline
183
+
176
184
  # 📦 Portable Context Exporter (Repomix compatible)
177
185
  ctxmap export . --format xml # Exports flat context XML, JSON, or Markdown
178
186
 
@@ -0,0 +1,38 @@
1
+ """Tests para el módulo de auditoría AST local (ast_audit.py)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from context_map.domain.analyzers.ast_audit import auditar_archivo_python, auditar_proyecto_python
6
+
7
+
8
+ def test_auditar_archivo_python_detecta_eval_y_pass(tmp_path):
9
+ """Verifica la detección de eval() y except pass."""
10
+ code_file = tmp_path / "vulnerable.py"
11
+ code_file.write_text(
12
+ "def test():\n"
13
+ " eval('1 + 1')\n"
14
+ " try:\n"
15
+ " pass\n"
16
+ " except Exception:\n"
17
+ " pass\n",
18
+ encoding="utf-8",
19
+ )
20
+
21
+ alertas = auditar_archivo_python(str(code_file))
22
+ assert len(alertas) >= 2
23
+ categorias = [a.categoria for a in alertas]
24
+ assert "SEGURIDAD" in categorias
25
+ assert "ROBUSTEZ" in categorias
26
+
27
+
28
+ def test_auditar_proyecto_python(tmp_path):
29
+ """Verifica que el escáner de proyecto audite archivos .py recursivamente."""
30
+ sub_dir = tmp_path / "core"
31
+ sub_dir.mkdir()
32
+ f1 = sub_dir / "db.py"
33
+ f1.write_text("password = 'super_secret_12345'", encoding="utf-8")
34
+
35
+ alertas = auditar_proyecto_python(str(tmp_path))
36
+ assert len(alertas) == 1
37
+ assert alertas[0].categoria == "SEGURIDAD"
38
+ assert "password" in alertas[0].mensaje
@@ -0,0 +1,30 @@
1
+ """Pruebas unitarias para el módulo context_map.domain.analyzers.ast_summary."""
2
+
3
+ import pytest
4
+ from context_map.domain.analyzers.ast_summary import ASTSummaryExtractor
5
+
6
+
7
+ def test_ast_summary_extractor_docstring() -> None:
8
+ """Verifica que si existe docstring de módulo se priorice en el resumen."""
9
+ codigo = '''"""Módulo principal de autenticación OAuth2 para ContextMap."""
10
+
11
+ def login():
12
+ pass
13
+ '''
14
+ extractor = ASTSummaryExtractor(codigo)
15
+ resumen = extractor.inferir_resumen()
16
+ assert "Módulo principal de autenticación OAuth2" in resumen
17
+
18
+
19
+ def test_ast_summary_extractor_imports() -> None:
20
+ """Verifica la inferencia de propósito basada en las importaciones AST."""
21
+ codigo = """import requests
22
+ import pytest
23
+
24
+ def test_api():
25
+ res = requests.get('https://api.example.com')
26
+ assert res.status_code == 200
27
+ """
28
+ extractor = ASTSummaryExtractor(codigo)
29
+ resumen = extractor.inferir_resumen()
30
+ assert "cliente HTTP" in resumen or "pruebas" in resumen
@@ -466,11 +466,12 @@ def test_grupos_grafo_por_tag_y_path() -> None:
466
466
  graph = json.load(f)
467
467
  grupos = {g["query"]: g for g in graph["colorGroups"]}
468
468
  assert "tag:#riesgo" in grupos
469
- assert "tag:#DEVOPS" in grupos
469
+ assert "tag:#idea" in grupos
470
+ assert "tag:#documento" in grupos
470
471
  assert "path:4.0-RIESGOS" in grupos
471
472
  assert "path:7.0-MANUAL" in grupos
472
473
  # colores distintos para grupos distintos
473
- assert grupos["tag:#riesgo"]["color"]["rgb"] != grupos["tag:#DEVOPS"]["color"]["rgb"]
474
+ assert grupos["tag:#riesgo"]["color"]["rgb"] != grupos["tag:#idea"]["color"]["rgb"]
474
475
  finally:
475
476
  shutil.rmtree(temp_dir, ignore_errors=True)
476
477
 
@@ -7,8 +7,13 @@ from context_map.domain.health.doctor import diagnosticar_salud, reparar_salud,
7
7
  from context_map.presentation.briefs.extractors import vault_nombre
8
8
 
9
9
 
10
- def test_doctor_diagnosticar_salud(tmp_path):
10
+ def test_doctor_diagnosticar_salud(tmp_path, monkeypatch):
11
11
  """Verifica que diagnosticar_salud retorna un reporte OK."""
12
+ # Aísla la verificación de ~/.context-map-update a un directorio limpio
13
+ fake_home = tmp_path / "fake_home"
14
+ fake_home.mkdir()
15
+ monkeypatch.setattr("os.path.expanduser", lambda path: str(fake_home) if "~" in path else os.path.expanduser(path))
16
+
12
17
  report = diagnosticar_salud(str(tmp_path))
13
18
  assert report.ok
14
19
  assert len(report.checks) >= 4
@@ -0,0 +1,17 @@
1
+ """Pruebas unitarias para el módulo context_map.domain.normalization.domain_extractor."""
2
+
3
+ import pytest
4
+ from pathlib import Path
5
+ from context_map.domain.normalization.domain_extractor import DomainConceptExtractor, extraer_conceptos_proyecto
6
+
7
+
8
+ def test_domain_concept_extractor() -> None:
9
+ """Verifica la extracción de términos de negocio dominantes."""
10
+ extractor = DomainConceptExtractor()
11
+ extractor.registrar_texto("FacturacionElectronicaService")
12
+ extractor.registrar_texto("procesar_facturacion")
13
+ extractor.registrar_texto("FacturacionDetalle")
14
+
15
+ conceptos = extractor.obtener_conceptos_dominantes(top_n=2)
16
+ assert len(conceptos) > 0
17
+ assert "FACTURACION" in conceptos[0]
@@ -0,0 +1,13 @@
1
+ """Pruebas unitarias para el módulo context_map.domain.health.hardware."""
2
+
3
+ import pytest
4
+ from context_map.domain.health.hardware import evaluar_hardware_pc, EspecificacionesHardware
5
+
6
+
7
+ def test_evaluar_hardware_pc() -> None:
8
+ """Verifica que el diagnóstico de hardware retorne un objeto EspecificacionesHardware válido."""
9
+ hw = evaluar_hardware_pc()
10
+ assert isinstance(hw, EspecificacionesHardware)
11
+ assert hw.ram_total_gb > 0
12
+ assert hw.cpu_cores >= 1
13
+ assert hw.mensaje_diagnostico != ""
@@ -0,0 +1,14 @@
1
+ """Pruebas unitarias para el módulo context_map.infrastructure.integrations.ollama."""
2
+
3
+ import pytest
4
+ from context_map.infrastructure.integrations.ollama import OllamaLocalClient
5
+
6
+
7
+ def test_ollama_client_init() -> None:
8
+ """Verifica la inicialización del cliente de Ollama local."""
9
+ client = OllamaLocalClient()
10
+ assert client.host == "http://localhost:11434"
11
+ assert client.hardware is not None
12
+ # Si no hay Ollama corriendo en el entorno de test, esta_disponible() debe retornar False sin lanzar excepción
13
+ disponible = client.esta_disponible()
14
+ assert isinstance(disponible, bool)
@@ -0,0 +1,60 @@
1
+ """Tests unitarios para el empaquetado y desempaquetado de contexto (.ctxpack)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from context_map.domain.storage.packer import (
7
+ crear_paquete_contexto,
8
+ desempaquetar_contexto,
9
+ )
10
+
11
+
12
+ def test_pack_y_unpack_flujo_completo(tmp_path):
13
+ """Verifica la creación y extracción completa de un archivo .ctxpack."""
14
+ # 1. Crear estructura simulada .context-map/
15
+ src_dir = tmp_path / "proyecto_origen"
16
+ ctx_dir = src_dir / ".context-map"
17
+ state_dir = ctx_dir / "state"
18
+ state_dir.mkdir(parents=True)
19
+
20
+ graph_file = state_dir / "graph.jsonl"
21
+ graph_file.write_text(
22
+ '{"id": "idea_1", "type": "IDEA", "title": "Idea 1"}\n'
23
+ '{"id": "base_1", "type": "BASE", "title": "Base 1"}\n',
24
+ encoding="utf-8",
25
+ )
26
+
27
+ brief_file = ctx_dir / "CONTEXT.md"
28
+ brief_file.write_text("# Brief de Contexto", encoding="utf-8")
29
+
30
+ agents_file = src_dir / "AGENTS.md"
31
+ agents_file.write_text("# Reglas Agénticas", encoding="utf-8")
32
+
33
+ # 2. Empaquetar
34
+ out_file = tmp_path / "backup.ctxpack"
35
+ ruta_gen, size, manifest = crear_paquete_contexto(
36
+ target_dir=str(src_dir),
37
+ output_path=str(out_file),
38
+ project_name="ProyectoPrueba",
39
+ )
40
+
41
+ assert os.path.isfile(ruta_gen)
42
+ assert size > 0
43
+ assert manifest["project"] == "ProyectoPrueba"
44
+ assert manifest["node_count"] == 2
45
+
46
+ # 3. Desempaquetar en directorio destino
47
+ dst_dir = tmp_path / "proyecto_destino"
48
+ res_manifest = desempaquetar_contexto(
49
+ archive_path=str(out_file),
50
+ target_dir=str(dst_dir),
51
+ )
52
+
53
+ assert res_manifest["project"] == "ProyectoPrueba"
54
+ assert (dst_dir / ".context-map" / "state" / "graph.jsonl").exists()
55
+ assert (dst_dir / ".context-map" / "CONTEXT.md").exists()
56
+ assert (dst_dir / "AGENTS.md").exists()
57
+
58
+ content = (dst_dir / ".context-map" / "state" / "graph.jsonl").read_text(encoding="utf-8")
59
+ assert "idea_1" in content
60
+ assert "base_1" in content
@@ -0,0 +1,41 @@
1
+ """Pruebas unitarias para el módulo context_map.domain.normalization.similarity."""
2
+
3
+ import pytest
4
+ from context_map.domain.normalization.similarity import (
5
+ distancia_levenshtein,
6
+ similitud_jaccard_ngramas,
7
+ son_textos_similares,
8
+ deduplicar_elementos_similares,
9
+ )
10
+
11
+
12
+ def test_distancia_levenshtein() -> None:
13
+ """Verifica el cálculo de distancia de edición."""
14
+ assert distancia_levenshtein("gato", "gato") == 0
15
+ assert distancia_levenshtein("casa", "caza") == 1
16
+
17
+
18
+ def test_similitud_jaccard() -> None:
19
+ """Verifica el índice de similitud de Jaccard por n-gramas."""
20
+ sim = similitud_jaccard_ngramas("Falta de pruebas unitarias", "Falta de tests unitarios")
21
+ assert sim > 0.4
22
+
23
+
24
+ def test_son_textos_similares() -> None:
25
+ """Verifica la detección de similitud difusa."""
26
+ t1 = "Falta de pruebas unitarias en el módulo de autenticación"
27
+ t2 = "Ausencia de pruebas unitarias en el módulo autenticación"
28
+ assert son_textos_similares(t1, t2, umbral=0.75)
29
+
30
+
31
+ def test_deduplicar_elementos_similares() -> None:
32
+ """Verifica la deduplicación de listas por texto similar."""
33
+ items = [
34
+ "Riesgo 1: Falta de cobertura de pruebas unitarias",
35
+ "Riesgo 1: Ausencia de cobertura de pruebas unitarias",
36
+ "Riesgo 2: Vulnerabilidad de seguridad en dependencias",
37
+ ]
38
+ filtrados = deduplicar_elementos_similares(items, lambda x: x, umbral=0.75)
39
+ assert len(filtrados) == 2
40
+ assert filtrados[0] == items[0]
41
+ assert filtrados[1] == items[2]
@@ -29,6 +29,9 @@ from context_map.application.commands import (
29
29
  cmd_watch,
30
30
  cmd_weekly,
31
31
  cmd_wrap,
32
+ cmd_enrich,
33
+ cmd_pack,
34
+ cmd_unpack,
32
35
  )
33
36
  from context_map.application.commands.adapt import cmd_adapt
34
37
  from context_map.application.commands.export import exportar_contexto
@@ -119,6 +122,9 @@ def main() -> None:
119
122
  "adapt": cmd_adapt,
120
123
  "personal": cmd_personal,
121
124
  "export": cmd_export,
125
+ "enrich": cmd_enrich,
126
+ "pack": cmd_pack,
127
+ "unpack": cmd_unpack,
122
128
  "mcp": cmd_mcp,
123
129
  }
124
130
 
@@ -48,6 +48,11 @@ def create_parser() -> argparse.ArgumentParser:
48
48
  help="Arranca el servidor MCP (stdio) que expone las herramientas de ctxmap como tools",
49
49
  )
50
50
 
51
+ s_enrich = sub.add_parser("enrich", help="Enriquece el código con docstrings función por función usando Ollama local o AST")
52
+ s_enrich.add_argument("path", nargs="?", default=".", help="Ruta del archivo o directorio a enriquecer")
53
+ s_enrich.add_argument("--model", default=None, help="Modelo de Ollama preferido (ej. qwen2.5-coder:1.5b)")
54
+ s_enrich.add_argument("--dry-run", action="store_true", help="Solo muestra la vista previa sin modificar archivos")
55
+
51
56
  sub.add_parser("init", help="Crea estructura .context-map/")
52
57
 
53
58
  s_build = sub.add_parser("build", help="Genera vault completo")
@@ -201,4 +206,12 @@ def create_parser() -> argparse.ArgumentParser:
201
206
  sp_backup.add_argument("--destino", required=True, help="Ruta destino (ej. /run/media/usb/personal.db)")
202
207
  sp_backup.add_argument("--db", default=None, help="Ruta a la BD personal (default: la activa)")
203
208
 
209
+ p_pack = sub.add_parser("pack", help="Empaqueta el contexto en un archivo comprimido .ctxpack portátil")
210
+ p_pack.add_argument("target", nargs="?", default=".", help="Ruta del proyecto (default: .)")
211
+ p_pack.add_argument("--output", "-o", default=None, help="Ruta del archivo de salida .ctxpack")
212
+
213
+ p_unpack = sub.add_parser("unpack", help="Desempaqueta un archivo .ctxpack y restaura el contexto")
214
+ p_unpack.add_argument("archive", help="Ruta del archivo .ctxpack")
215
+ p_unpack.add_argument("target", nargs="?", default=".", help="Directorio destino para la restauración (default: .)")
216
+
204
217
  return p
@@ -32,8 +32,13 @@ from context_map.application.commands.tools import (
32
32
  from context_map.application.commands.update import cmd_update
33
33
  from context_map.application.commands.watch import cmd_watch
34
34
  from context_map.application.commands.wrap import cmd_wrap
35
+ from context_map.application.commands.enrich import cmd_enrich
36
+ from context_map.application.commands.pack import cmd_pack, cmd_unpack
35
37
 
36
38
  __all__ = [
39
+ "cmd_pack",
40
+ "cmd_unpack",
41
+ "cmd_enrich",
37
42
  "cmd_auto",
38
43
  "cmd_build",
39
44
  "cmd_sync",
@@ -119,13 +119,38 @@ def project_name(args) -> str:
119
119
 
120
120
 
121
121
  def ensure_dirs(_proj: str | None = None) -> None:
122
- """Crea el árbol de directorios de .context-map/.
123
-
124
- NOTA: el vault se crea bajo demanda en build/sync, no acá.
125
- """
122
+ """Crea el árbol de directorios de .context-map/ y plantilla de dominios.yaml si no existe."""
126
123
  for path in [STATE_DIR, MAPS_DIR, HISTORY_DIR, CHATS_DIR, RAW_DIR]:
127
124
  os.makedirs(path, exist_ok=True)
128
125
 
126
+ dominios_file = os.path.join(CONTEXT_DIR, "dominios.yaml")
127
+ if not os.path.exists(dominios_file):
128
+ try:
129
+ default_template = (
130
+ "# Dominios temáticos del proyecto (grupos profesionales del contexto)\n"
131
+ "# Cada nota se etiqueta automáticamente con grupo-<dominio> según las\n"
132
+ "# palabras clave que aparecen en su título o resumen.\n\n"
133
+ "raiz:\n"
134
+ " - proposito\n"
135
+ " - que es\n"
136
+ " - identidad\n"
137
+ " - esencia\n"
138
+ " - objetivo\n\n"
139
+ "gobierno:\n"
140
+ " - gobierno\n"
141
+ " - verificar\n"
142
+ " - corregir\n"
143
+ " - regla\n\n"
144
+ "vault:\n"
145
+ " - vault\n"
146
+ " - obsidian\n"
147
+ " - nota manual\n"
148
+ )
149
+ with open(dominios_file, "w", encoding="utf-8") as f:
150
+ f.write(default_template)
151
+ except Exception as err:
152
+ logger.debug("No se pudo auto-crear dominios.yaml por defecto: %s", err)
153
+
129
154
 
130
155
  def resolve_vault_mode(args) -> str:
131
156
  """Resuelve el modo de generación del vault desde los argumentos del CLI.