context-map-ai 2.2.0__tar.gz → 2.2.1__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 (190) hide show
  1. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/copilot-instructions.md +1 -1
  2. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/CHANGELOG.md +13 -0
  3. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/PKG-INFO +2 -2
  4. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/README.md +1 -1
  5. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/README_EN.md +1 -1
  6. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_ast_summary.py +0 -1
  7. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_cyclomatic.py +0 -1
  8. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_doctor.py +5 -6
  9. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_domain_extractor.py +1 -3
  10. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_hardware.py +1 -2
  11. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_hooks.py +0 -1
  12. context_map_ai-2.2.1/context_map/__tests__/test_mcp_server_seguridad.py +31 -0
  13. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_ollama.py +0 -1
  14. context_map_ai-2.2.1/context_map/__tests__/test_pack_unpack.py +135 -0
  15. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_scan_cache.py +1 -1
  16. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_security_scanner.py +1 -0
  17. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_similarity.py +1 -2
  18. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_tokenization.py +0 -1
  19. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_wrap.py +0 -1
  20. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/cli/parser.py +9 -1
  21. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/doctor_cmd.py +3 -6
  22. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/enrich.py +4 -6
  23. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/export.py +5 -6
  24. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/hook.py +7 -3
  25. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/refresh.py +1 -0
  26. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/update.py +101 -15
  27. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/watch.py +2 -2
  28. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/__init__.py +0 -1
  29. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/generators/generadores.py +16 -0
  30. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/tokenization.py +2 -5
  31. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analysis/checker.py +20 -0
  32. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analysis/reporting.py +1 -0
  33. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analysis/signals.py +0 -1
  34. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analyzers/ast_audit.py +21 -18
  35. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analyzers/ast_summary.py +7 -8
  36. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analyzers/cyclomatic.py +3 -4
  37. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ecosystem/hooks.py +3 -3
  38. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/health/doctor.py +2 -4
  39. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/health/hardware.py +2 -3
  40. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/normalization/domain_extractor.py +2 -3
  41. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/normalization/similarity.py +6 -5
  42. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/reglas/reglas.py +1 -1
  43. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/scanning/cache.py +5 -5
  44. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/scanning/security.py +4 -5
  45. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/storage/packer.py +70 -29
  46. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/synchronization/watcher.py +2 -2
  47. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/integrations/ollama.py +6 -6
  48. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/mcp_server.py +85 -16
  49. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/version_check.py +11 -4
  50. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/briefs/brief.py +0 -2
  51. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/briefs/extractors.py +1 -1
  52. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/briefs/sections.py +1 -1
  53. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/pyproject.toml +1 -1
  54. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/uv.lock +3 -3
  55. context_map_ai-2.2.0/context_map/__tests__/test_pack_unpack.py +0 -60
  56. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  57. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  58. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  59. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/workflows/ci.yml +0 -0
  60. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/workflows/docs.yml +0 -0
  61. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.github/workflows/publish.yml +0 -0
  62. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.gitignore +0 -0
  63. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.hermes/config.yaml +0 -0
  64. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.hermes/shields/pre-commit.md +0 -0
  65. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.hermes/triggers/post-commit.md +0 -0
  66. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.hermes/workflows/dev-loop.md +0 -0
  67. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/.pre-commit-hooks.yaml +0 -0
  68. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/AGENTS.md +0 -0
  69. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/CODE_OF_CONDUCT.md +0 -0
  70. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/CONTRIBUTING.md +0 -0
  71. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/LICENSE +0 -0
  72. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/Makefile +0 -0
  73. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/action.yml +0 -0
  74. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__init__.py +0 -0
  75. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/conftest.py +0 -0
  76. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/smoke.py +0 -0
  77. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_ast_audit.py +0 -0
  78. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_checker_frescura.py +1 -1
  79. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_cli.py +0 -0
  80. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_conexiones.py +0 -0
  81. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_diario_consolidado.py +0 -0
  82. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_ecosistema.py +0 -0
  83. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_enterprise_features.py +0 -0
  84. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_export.py +1 -1
  85. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_hermes_clasificacion.py +0 -0
  86. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_hook_memoria_viva.py +0 -0
  87. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_ingest.py +0 -0
  88. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_mermaid.py +0 -0
  89. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_metrica_memoria_viva.py +0 -0
  90. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_parsing.py +0 -0
  91. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_personal.py +0 -0
  92. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_refresh_temporales.py +0 -0
  93. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_reglas_catalogo.py +0 -0
  94. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_scanner.py +0 -0
  95. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_standardize.py +0 -0
  96. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_topologia_arbol.py +0 -0
  97. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_vault_consolidation.py +0 -0
  98. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/__tests__/test_watcher.py +0 -0
  99. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/__init__.py +0 -0
  100. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/cli/__init__.py +0 -0
  101. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/cli/cli.py +3 -3
  102. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/__init__.py +2 -2
  103. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/_helpers.py +0 -0
  104. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/adapt.py +0 -0
  105. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/auto.py +0 -0
  106. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/build.py +0 -0
  107. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/importers.py +0 -0
  108. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/ingest.py +0 -0
  109. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/pack.py +0 -0
  110. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/personal.py +0 -0
  111. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/scan.py +0 -0
  112. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/sync.py +0 -0
  113. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/tools.py +0 -0
  114. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/application/commands/wrap.py +0 -0
  115. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/cli.py +0 -0
  116. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/generators/__init__.py +0 -0
  117. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/generators/narrative_templates.py +0 -0
  118. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/logging_setup.py +0 -0
  119. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/models/__init__.py +0 -0
  120. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/models/config.py +0 -0
  121. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/models/models.py +0 -0
  122. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/normalization/__init__.py +0 -0
  123. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/normalization/cleaning.py +0 -0
  124. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/normalization/inference.py +0 -0
  125. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/normalization/mappings.py +0 -0
  126. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/normalization/standardize.py +0 -0
  127. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/parsing/__init__.py +0 -0
  128. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/parsing/cargadores.py +0 -0
  129. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/parsing/clasificacion.py +0 -0
  130. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/parsing/dedup.py +0 -0
  131. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/parsing/grafo.py +0 -0
  132. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/personal/__init__.py +0 -0
  133. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/personal/bd.py +0 -0
  134. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/storage/__init__.py +0 -0
  135. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/storage/config_loader.py +0 -0
  136. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/core/storage/store.py +0 -0
  137. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/__init__.py +0 -0
  138. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analysis/__init__.py +0 -0
  139. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analysis/complexity.py +0 -0
  140. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/analysis/models.py +0 -0
  141. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ecosystem/__init__.py +0 -0
  142. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ecosystem/adaptador.py +0 -0
  143. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ecosystem/detector.py +0 -0
  144. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ecosystem/rules_templates.py +0 -0
  145. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/health/__init__.py +0 -0
  146. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ingestion/__init__.py +0 -0
  147. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/ingestion/ingest.py +0 -0
  148. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/reporting/__init__.py +0 -0
  149. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/reporting/reporter.py +0 -0
  150. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/scanning/__init__.py +0 -0
  151. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/scanning/scanner.py +0 -0
  152. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/synchronization/__init__.py +0 -0
  153. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/synchronization/relaciones.py +0 -0
  154. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/domain/synchronization/sync.py +0 -0
  155. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/__init__.py +0 -0
  156. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/analyzers/__init__.py +0 -0
  157. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/analyzers/content.py +0 -0
  158. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/analyzers/structure.py +0 -0
  159. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/integrations/__init__.py +0 -0
  160. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/integrations/antigravity.py +0 -0
  161. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/integrations/chat_export.py +0 -0
  162. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/integrations/git.py +0 -0
  163. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/infrastructure/integrations/hermes.py +0 -0
  164. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/__init__.py +0 -0
  165. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/briefs/__init__.py +0 -0
  166. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/briefs/agents.py +0 -0
  167. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/briefs/skill.py +0 -0
  168. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/__init__.py +0 -0
  169. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/atomic.py +0 -0
  170. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/__init__.py +0 -0
  171. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/canvas.py +0 -0
  172. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/common.py +0 -0
  173. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/consolidado.py +0 -0
  174. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/jerarquico.py +0 -0
  175. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/notas_ideas.py +0 -0
  176. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/rutas.py +0 -0
  177. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/secciones_backlog.py +0 -0
  178. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/secciones_estructura.py +0 -0
  179. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/secciones_historial.py +0 -0
  180. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/secciones_ideas.py +0 -0
  181. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/secciones_proposito.py +0 -0
  182. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/consolidated/secciones_riesgos.py +0 -0
  183. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/mermaid.py +0 -0
  184. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/preservar.py +0 -0
  185. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/templates.py +0 -0
  186. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/context_map/presentation/vault/writer.py +0 -0
  187. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/docs/LAUNCH_KIT.md +0 -0
  188. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/docs/plans/2026-08-10-mapa-mental-conectado.md +0 -0
  189. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/docs/plans/PLAN-MEJORAS-CONTEXTO-VIVO-2026-08-14.md +0 -0
  190. {context_map_ai-2.2.0 → context_map_ai-2.2.1}/mkdocs.yml +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-19).
21
+ > Generado automáticamente por **ContextMap** (2026-08-21).
22
22
 
23
23
  ## Antes de sugerir código
24
24
 
@@ -5,6 +5,19 @@ 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.1] — 2026-08-21
9
+
10
+ ### 🔧 Correcciones — Saneamiento de release
11
+
12
+ - **fix: flag `--version` real**: `ctxmap --version` ahora imprime la versión instalada (antes no existía y `update` mostraba un mensaje hardcodeado).
13
+ - **fix: detección de versión con el paquete renombrado**: `version_check` prioriza `context-map-ai` (nombre canónico actual) sobre el heredado `context-map`, eliminando avisos falsos de actualización.
14
+ - **fix: lint (ruff) 100% limpio**: corregidos 11 errores (`F811` redefinición en `brief.py`, `F841` variables sin usar, `SIM102/105/108`).
15
+ - **style: ruff --fix e isort** aplicados en todo el paquete (anotaciones modernas `dict`/`| None` y orden de imports).
16
+
17
+ Suite: 176/176 tests verdes · ruff limpio.
18
+
19
+ ---
20
+
8
21
  ## [2.2.0] — 2026-08-19
9
22
 
10
23
  ### 🗜️ Nuevo — Paquetes de Contexto Portátiles Offline, Escáner de Auditoría AST & Fallback de Modelos
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: context-map-ai
3
- Version: 2.2.0
3
+ Version: 2.2.1
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,7 @@ 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.2.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
44
+ [![Release](https://img.shields.io/badge/version-v2.2.1-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
45
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/)
46
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/)
47
47
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](LICENSE)
@@ -9,7 +9,7 @@
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.2.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
12
+ [![Release](https://img.shields.io/badge/version-v2.2.1-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
13
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/)
14
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/)
15
15
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](LICENSE)
@@ -9,7 +9,7 @@
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.2.0-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
12
+ [![Release](https://img.shields.io/badge/version-v2.2.1-blue.svg?style=for-the-badge)](https://github.com/kudawasama/ContextMap)
13
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/)
14
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/)
15
15
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge)](LICENSE)
@@ -1,6 +1,5 @@
1
1
  """Pruebas unitarias para el módulo context_map.domain.analyzers.ast_summary."""
2
2
 
3
- import pytest
4
3
  from context_map.domain.analyzers.ast_summary import ASTSummaryExtractor
5
4
 
6
5
 
@@ -1,6 +1,5 @@
1
1
  """Pruebas unitarias para el módulo context_map.domain.analyzers.cyclomatic."""
2
2
 
3
- import pytest
4
3
  from context_map.domain.analyzers.cyclomatic import calcular_complejidad_ciclomatica
5
4
 
6
5
 
@@ -3,7 +3,8 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import os
6
- from context_map.domain.health.doctor import diagnosticar_salud, reparar_salud, run
6
+
7
+ from context_map.domain.health.doctor import diagnosticar_salud, reparar_salud
7
8
  from context_map.presentation.briefs.extractors import vault_nombre
8
9
 
9
10
 
@@ -13,7 +14,7 @@ def test_doctor_diagnosticar_salud(tmp_path, monkeypatch):
13
14
  fake_home = tmp_path / "fake_home"
14
15
  fake_home.mkdir()
15
16
  monkeypatch.setattr("os.path.expanduser", lambda path: str(fake_home) if "~" in path else os.path.expanduser(path))
16
-
17
+
17
18
  report = diagnosticar_salud(str(tmp_path))
18
19
  assert report.ok
19
20
  assert len(report.checks) >= 4
@@ -41,8 +42,6 @@ def test_doctor_reparar_vaults_desalineados(tmp_path):
41
42
  (ctx_dir / "vault-Viejo").mkdir(parents=True)
42
43
  (ctx_dir / "vault-Viejo" / "nota.md").write_text("# Nota", encoding="utf-8")
43
44
 
44
- repo_name = os.path.basename(os.path.abspath(str(tmp_path)))
45
- # El vault esperado para tmp_path será vault-<repo_name>
46
-
47
- report = reparar_salud(str(tmp_path))
45
+ # El vault esperado para tmp_path será vault-<nombre del directorio>
46
+ reparar_salud(str(tmp_path))
48
47
  assert os.path.isdir(ctx_dir / "_legacy" / "vault-Viejo")
@@ -1,8 +1,6 @@
1
1
  """Pruebas unitarias para el módulo context_map.domain.normalization.domain_extractor."""
2
2
 
3
- import pytest
4
- from pathlib import Path
5
- from context_map.domain.normalization.domain_extractor import DomainConceptExtractor, extraer_conceptos_proyecto
3
+ from context_map.domain.normalization.domain_extractor import DomainConceptExtractor
6
4
 
7
5
 
8
6
  def test_domain_concept_extractor() -> None:
@@ -1,7 +1,6 @@
1
1
  """Pruebas unitarias para el módulo context_map.domain.health.hardware."""
2
2
 
3
- import pytest
4
- from context_map.domain.health.hardware import evaluar_hardware_pc, EspecificacionesHardware
3
+ from context_map.domain.health.hardware import EspecificacionesHardware, evaluar_hardware_pc
5
4
 
6
5
 
7
6
  def test_evaluar_hardware_pc() -> None:
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import os
6
5
  from context_map.domain.ecosystem.hooks import desinstalar_git_hooks, instalar_git_hooks
7
6
 
8
7
 
@@ -0,0 +1,31 @@
1
+ """Tests de seguridad del servidor MCP: confirmación destructiva y validación de rutas."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from context_map.infrastructure import mcp_server
6
+
7
+
8
+ def test_mcp_build_clean_sin_confirmacion_es_rechazado():
9
+ """Verifica que build(clean=True) exige confirm=True."""
10
+ res = mcp_server.build(target=".", clean=True)
11
+ assert "rechazada por seguridad" in res
12
+ assert "confirm=True" in res
13
+
14
+
15
+ def test_mcp_doctor_fix_sin_confirmacion_es_rechazado():
16
+ """Verifica que doctor(fix=True) exige confirm=True."""
17
+ res = mcp_server.doctor(target=".", fix=True)
18
+ assert "rechazada por seguridad" in res
19
+
20
+
21
+ def test_mcp_install_hooks_sin_confirmacion_es_rechazado():
22
+ """Verifica que install_hooks exige confirm=True."""
23
+ res = mcp_server.install_hooks(target=".", force=True)
24
+ assert "rechazada por seguridad" in res
25
+
26
+
27
+ def test_mcp_target_invalido_devuelve_error():
28
+ """Verifica que un target inexistente no se procesa."""
29
+ res = mcp_server.check(target="/ruta/inexistente/xyz-123")
30
+ assert "ERROR" in res
31
+ assert "no es un directorio" in res
@@ -1,6 +1,5 @@
1
1
  """Pruebas unitarias para el módulo context_map.infrastructure.integrations.ollama."""
2
2
 
3
- import pytest
4
3
  from context_map.infrastructure.integrations.ollama import OllamaLocalClient
5
4
 
6
5
 
@@ -0,0 +1,135 @@
1
+ """Tests unitarios para el empaquetado y desempaquetado de contexto (.ctxpack)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import io
6
+ import os
7
+ import tarfile
8
+
9
+ import pytest
10
+
11
+ from context_map.domain.storage.packer import (
12
+ _sha256_archivo,
13
+ crear_paquete_contexto,
14
+ desempaquetar_contexto,
15
+ )
16
+
17
+
18
+ def test_pack_y_unpack_flujo_completo(tmp_path):
19
+ """Verifica la creación y extracción completa de un archivo .ctxpack."""
20
+ # 1. Crear estructura simulada .context-map/
21
+ src_dir = tmp_path / "proyecto_origen"
22
+ ctx_dir = src_dir / ".context-map"
23
+ state_dir = ctx_dir / "state"
24
+ state_dir.mkdir(parents=True)
25
+
26
+ graph_file = state_dir / "graph.jsonl"
27
+ graph_file.write_text(
28
+ '{"id": "idea_1", "type": "IDEA", "title": "Idea 1"}\n'
29
+ '{"id": "base_1", "type": "BASE", "title": "Base 1"}\n',
30
+ encoding="utf-8",
31
+ )
32
+
33
+ brief_file = ctx_dir / "CONTEXT.md"
34
+ brief_file.write_text("# Brief de Contexto", encoding="utf-8")
35
+
36
+ agents_file = src_dir / "AGENTS.md"
37
+ agents_file.write_text("# Reglas Agénticas", encoding="utf-8")
38
+
39
+ # 2. Empaquetar
40
+ out_file = tmp_path / "backup.ctxpack"
41
+ ruta_gen, size, manifest = crear_paquete_contexto(
42
+ target_dir=str(src_dir),
43
+ output_path=str(out_file),
44
+ project_name="ProyectoPrueba",
45
+ )
46
+
47
+ assert os.path.isfile(ruta_gen)
48
+ assert size > 0
49
+ assert manifest["project"] == "ProyectoPrueba"
50
+ assert manifest["node_count"] == 2
51
+
52
+ # 3. Desempaquetar en directorio destino
53
+ dst_dir = tmp_path / "proyecto_destino"
54
+ res_manifest = desempaquetar_contexto(
55
+ archive_path=str(out_file),
56
+ target_dir=str(dst_dir),
57
+ )
58
+
59
+ assert res_manifest["project"] == "ProyectoPrueba"
60
+ assert (dst_dir / ".context-map" / "state" / "graph.jsonl").exists()
61
+ assert (dst_dir / ".context-map" / "CONTEXT.md").exists()
62
+ assert (dst_dir / "AGENTS.md").exists()
63
+
64
+ content = (dst_dir / ".context-map" / "state" / "graph.jsonl").read_text(encoding="utf-8")
65
+ assert "idea_1" in content
66
+ assert "base_1" in content
67
+
68
+
69
+ def test_manifest_incluye_checksums_sha256(tmp_path):
70
+ """Verifica que el manifiesto registra un checksum SHA-256 por archivo."""
71
+ src_dir = tmp_path / "origen"
72
+ state_dir = src_dir / ".context-map" / "state"
73
+ state_dir.mkdir(parents=True)
74
+ (state_dir / "graph.jsonl").write_text("hola\n", encoding="utf-8")
75
+
76
+ out_file = tmp_path / "backup.ctxpack"
77
+ _, _, manifest = crear_paquete_contexto(str(src_dir), str(out_file), project_name="Checksums")
78
+
79
+ ruta_rel = os.path.join(".context-map", "state", "graph.jsonl")
80
+ assert ruta_rel in manifest["files"]
81
+ assert manifest["files"][ruta_rel] == _sha256_archivo(str(state_dir / "graph.jsonl"))
82
+
83
+
84
+ def test_unpack_detecta_integridad_comprometida(tmp_path):
85
+ """Verifica que un paquete con contenido alterado se rechaza por checksum."""
86
+ src_dir = tmp_path / "origen"
87
+ state_dir = src_dir / ".context-map" / "state"
88
+ state_dir.mkdir(parents=True)
89
+ (state_dir / "graph.jsonl").write_text('{"id": "a", "type": "IDEA"}\n', encoding="utf-8")
90
+
91
+ out_file = tmp_path / "backup.ctxpack"
92
+ crear_paquete_contexto(str(src_dir), str(out_file), project_name="Integridad")
93
+
94
+ # Reescribir el tar alterando graph.jsonl sin actualizar el manifiesto
95
+ tampered = tmp_path / "tampered.ctxpack"
96
+ with tarfile.open(str(out_file), "r:gz") as tar, tarfile.open(str(tampered), "w:gz") as out:
97
+ for m in tar.getmembers():
98
+ f = tar.extractfile(m)
99
+ contenido = f.read() if f else b""
100
+ if m.name == ".context-map/state/graph.jsonl":
101
+ contenido = b'{"id": "ALTERADO_TAMPERED"}\n'
102
+ ti = tarfile.TarInfo(m.name)
103
+ ti.size = len(contenido)
104
+ ti.mode = m.mode
105
+ out.addfile(ti, io.BytesIO(contenido))
106
+
107
+ with pytest.raises(ValueError, match="Integridad"):
108
+ desempaquetar_contexto(str(tampered), str(tmp_path / "destino"))
109
+
110
+
111
+ def _crear_tar_con_symlink(path: str) -> None:
112
+ """Crea un .ctxpack malicioso con un symlink apuntando fuera del destino."""
113
+ with tarfile.open(path, "w:gz") as tar:
114
+ data = b"contenido"
115
+ ti = tarfile.TarInfo(".context-map/state/graph.jsonl")
116
+ ti.size = len(data)
117
+ tar.addfile(ti, io.BytesIO(data))
118
+
119
+ # Symlink malicioso que apunta fuera del directorio destino
120
+ sl = tarfile.TarInfo("escape")
121
+ sl.type = tarfile.SYMTYPE
122
+ sl.linkname = "/tmp/ctxmap_escape_target"
123
+ tar.addfile(sl)
124
+
125
+
126
+ def test_unpack_rechaza_symlinks(tmp_path):
127
+ """Verifica que un .ctxpack con symlinks no los extrae (hardening)."""
128
+ archivo = tmp_path / "malicioso.ctxpack"
129
+ _crear_tar_con_symlink(str(archivo))
130
+
131
+ destino = tmp_path / "destino"
132
+ desempaquetar_contexto(str(archivo), str(destino))
133
+
134
+ assert (destino / ".context-map" / "state" / "graph.jsonl").exists()
135
+ assert not (destino / "escape").exists() # el symlink no se extrae
@@ -1,7 +1,7 @@
1
1
  """Pruebas unitarias para el módulo context_map.domain.scanning.cache."""
2
2
 
3
- import pytest
4
3
  from pathlib import Path
4
+
5
5
  from context_map.domain.scanning.cache import ScanCacheManager
6
6
 
7
7
 
@@ -1,6 +1,7 @@
1
1
  """Pruebas unitarias para el detector preventivo de secretos en el código fuente."""
2
2
 
3
3
  from pathlib import Path
4
+
4
5
  from context_map.domain.scanning.security import SecurityScanner, escanear_secretos_archivo
5
6
 
6
7
 
@@ -1,11 +1,10 @@
1
1
  """Pruebas unitarias para el módulo context_map.domain.normalization.similarity."""
2
2
 
3
- import pytest
4
3
  from context_map.domain.normalization.similarity import (
4
+ deduplicar_elementos_similares,
5
5
  distancia_levenshtein,
6
6
  similitud_jaccard_ngramas,
7
7
  son_textos_similares,
8
- deduplicar_elementos_similares,
9
8
  )
10
9
 
11
10
 
@@ -1,6 +1,5 @@
1
1
  """Pruebas unitarias para el módulo de tokenización context_map.core.tokenization."""
2
2
 
3
- import pytest
4
3
  from context_map.core.tokenization import TokenCounter, contar_tokens_texto, normalize_model_name
5
4
 
6
5
 
@@ -8,7 +8,6 @@ lo registrado (eventos en events.jsonl) vs lo que queda sin importar
8
8
  from __future__ import annotations
9
9
 
10
10
  import json
11
- import os
12
11
 
13
12
  from context_map.application.commands.wrap import cmd_wrap
14
13
 
@@ -8,6 +8,8 @@ from __future__ import annotations
8
8
 
9
9
  import argparse
10
10
 
11
+ from context_map.infrastructure.version_check import version_local
12
+
11
13
 
12
14
  def create_parser() -> argparse.ArgumentParser:
13
15
  """Construye y configura el parser principal con sus subcomandos.
@@ -20,6 +22,12 @@ def create_parser() -> argparse.ArgumentParser:
20
22
  description="Mapa mental narrativo de proyectos para agentes de IA",
21
23
  )
22
24
  p.add_argument("-v", "--verbose", action="store_true", help="Logs detallados (nivel DEBUG)")
25
+ p.add_argument(
26
+ "--version",
27
+ action="version",
28
+ version=f"ContextMap v{version_local()}",
29
+ help="Muestra la versión instalada y sale",
30
+ )
23
31
  sub = p.add_subparsers(dest="cmd", help="Comandos disponibles")
24
32
 
25
33
  s_auto = sub.add_parser("auto", help="Automatización completa en 1 paso (scan + git + build)")
@@ -136,7 +144,7 @@ def create_parser() -> argparse.ArgumentParser:
136
144
  s_antigravity.add_argument("--limit", type=int, default=5, help="Máximo de conversaciones")
137
145
 
138
146
  sub.add_parser("update", help="Actualiza ContextMap a la última versión")
139
-
147
+
140
148
  s_doctor = sub.add_parser("doctor", help="Diagnóstico y auto-reparación (Self-Healing) del proyecto")
141
149
  s_doctor.add_argument("target", nargs="?", default=".", help="Ruta del proyecto a diagnosticar")
142
150
  s_doctor.add_argument("--fix", action="store_true", help="Auto-reparar anomalías e inconsistencias encontradas")
@@ -3,12 +3,12 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
- from typing import Any, Dict
6
+ from typing import Any
7
7
 
8
8
  from context_map.domain.health.doctor import diagnosticar_salud, reparar_salud
9
9
 
10
10
 
11
- def cmd_doctor(args: Dict[str, Any]) -> None:
11
+ def cmd_doctor(args: dict[str, Any]) -> None:
12
12
  """Manejador del comando CLI `ctxmap doctor`.
13
13
 
14
14
  Args:
@@ -18,10 +18,7 @@ def cmd_doctor(args: Dict[str, Any]) -> None:
18
18
  fix = bool(args.get("fix", False))
19
19
  as_json = bool(args.get("json", False))
20
20
 
21
- if fix:
22
- report = reparar_salud(target_dir)
23
- else:
24
- report = diagnosticar_salud(target_dir)
21
+ report = reparar_salud(target_dir) if fix else diagnosticar_salud(target_dir)
25
22
 
26
23
  if as_json:
27
24
  data = {
@@ -4,13 +4,13 @@ Analiza archivos Python mediante AST y genera docstrings formales en Español T
4
4
  (Google Style) utilizando Ollama local si está disponible o inferencia AST estática.
5
5
  """
6
6
 
7
- import ast
8
7
  import argparse
8
+ import ast
9
9
  from pathlib import Path
10
- from typing import List, Optional
10
+
11
+ from context_map.domain.analyzers.ast_summary import ASTSummaryExtractor
11
12
  from context_map.domain.health.hardware import evaluar_hardware_pc
12
13
  from context_map.infrastructure.integrations.ollama import OllamaLocalClient
13
- from context_map.domain.analyzers.ast_summary import ASTSummaryExtractor
14
14
 
15
15
 
16
16
  def cmd_enrich(args: argparse.Namespace) -> int:
@@ -23,7 +23,6 @@ def cmd_enrich(args: argparse.Namespace) -> int:
23
23
  Código de salida 0 (éxito) o 1 (error).
24
24
  """
25
25
  ruta_target = Path(args.path).resolve() if hasattr(args, "path") and args.path else Path(".").resolve()
26
- dry_run = getattr(args, "dry_run", False)
27
26
 
28
27
  print(f"[enrich] Analizando directorio: {ruta_target}")
29
28
 
@@ -32,7 +31,7 @@ def cmd_enrich(args: argparse.Namespace) -> int:
32
31
  print(f"[enrich] Hardware: {hw.mensaje_diagnostico}")
33
32
 
34
33
  # 2. Inicializar cliente Ollama si es apto
35
- ollama_client: Optional[OllamaLocalClient] = None
34
+ ollama_client: OllamaLocalClient | None = None
36
35
  if hw.es_apto_para_ollama:
37
36
  client = OllamaLocalClient(model_name=getattr(args, "model", None) or hw.modelo_recomendado)
38
37
  if client.esta_disponible():
@@ -57,7 +56,6 @@ def cmd_enrich(args: argparse.Namespace) -> int:
57
56
  except Exception:
58
57
  continue
59
58
 
60
- modificado = False
61
59
  lineas = contenido.splitlines()
62
60
 
63
61
  for node in ast.walk(tree):
@@ -1,9 +1,8 @@
1
1
  """Comando de exportación portable (XML/JSON/Markdown) para chats web de LLMs."""
2
2
 
3
3
  import json
4
- from pathlib import Path
5
- from typing import Dict, List, Optional
6
4
  import xml.etree.ElementTree as ET
5
+ from pathlib import Path
7
6
  from xml.dom import minidom
8
7
 
9
8
  from context_map.core.models import Node
@@ -16,7 +15,7 @@ from context_map.presentation.briefs.brief import generar_brief
16
15
  def exportar_contexto(
17
16
  project_path: Path,
18
17
  format_type: str = "xml",
19
- output_file: Optional[Path] = None,
18
+ output_file: Path | None = None,
20
19
  brief_only: bool = False,
21
20
  model_name: str = "gpt-4o",
22
21
  ) -> Path:
@@ -42,7 +41,7 @@ def exportar_contexto(
42
41
  output_file = project_path / f"contextmap_export.{ext}"
43
42
 
44
43
  # Cargar nodos y edges del mapa
45
- nodos: List[Node] = []
44
+ nodos: list[Node] = []
46
45
  edges: list = []
47
46
  graph_file = project_path / ".context-map" / "maps" / "graph.jsonl"
48
47
  edges_file = project_path / ".context-map" / "maps" / "edges.jsonl"
@@ -50,7 +49,7 @@ def exportar_contexto(
50
49
  if graph_file.exists():
51
50
  records = load_jsonl(str(graph_file))
52
51
  nodos = [Node.from_dict(r) for r in records if isinstance(r, dict)]
53
-
52
+
54
53
  if edges_file.exists():
55
54
  edges = load_jsonl(str(edges_file))
56
55
 
@@ -87,7 +86,7 @@ def exportar_contexto(
87
86
  output_file.write_text(json.dumps(data_json, indent=2, ensure_ascii=False), encoding="utf-8")
88
87
 
89
88
  elif fmt == "markdown":
90
- parts: List[str] = [
89
+ parts: list[str] = [
91
90
  f"# ContextMap Export: {project_path.name}",
92
91
  f"> **Target Model:** {model_name} | **Brief Tokens:** {tokens_brief} | **Nodes:** {len(nodos)}",
93
92
  "",
@@ -2,9 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Dict
5
+ from typing import Any
6
6
 
7
- from context_map.domain.ecosystem.hooks import PRE_COMMIT_SCRIPT, desinstalar_git_hooks, instalar_git_hooks
7
+ from context_map.domain.ecosystem.hooks import (
8
+ PRE_COMMIT_SCRIPT,
9
+ desinstalar_git_hooks,
10
+ instalar_git_hooks,
11
+ )
8
12
 
9
13
 
10
14
  def _script_hook() -> str:
@@ -22,7 +26,7 @@ def cmd_hook_install(args=None) -> None:
22
26
  print(f"[OK] Pre-commit hook de ContextMap instalado en: {target_dir}/.git/hooks/pre-commit")
23
27
 
24
28
 
25
- def cmd_hook(args: Dict[str, Any]) -> None:
29
+ def cmd_hook(args: dict[str, Any]) -> None:
26
30
  """Manejador del comando CLI `ctxmap hook`.
27
31
 
28
32
  Args:
@@ -134,6 +134,7 @@ def cmd_refresh(args) -> None:
134
134
  if not quiet:
135
135
  try:
136
136
  from pathlib import Path
137
+
137
138
  from context_map.core.tokenization import TokenCounter
138
139
  brief_p = Path(".context-map/CONTEXT.md")
139
140
  if brief_p.exists():