context-map-ai 2.7.1__tar.gz → 2.7.2__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 (257) hide show
  1. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CHANGELOG.md +28 -0
  2. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/PKG-INFO +5 -3
  3. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/README.md +4 -2
  4. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/README_EN.md +2 -2
  5. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/README_TECNICO.md +3 -1
  6. context_map_ai-2.7.2/context_map/__tests__/test_analyzers_content.py +154 -0
  7. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_diario_consolidado.py +51 -0
  8. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/content.py +47 -2
  9. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/canvas.py +7 -0
  10. context_map_ai-2.7.2/docs/PI_PACKAGE.md +62 -0
  11. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/pyproject.toml +1 -1
  12. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/uv.lock +1 -1
  13. context_map_ai-2.7.1/context_map/__tests__/test_analyzers_content.py +0 -69
  14. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.agents/skills/contextmap/SKILL.md +0 -0
  15. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  16. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  17. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  18. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/copilot-instructions.md +0 -0
  19. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/workflows/ci.yml +0 -0
  20. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/workflows/docs.yml +0 -0
  21. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/workflows/publish.yml +0 -0
  22. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.gitignore +0 -0
  23. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/config.yaml +0 -0
  24. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/shields/pre-commit.md +0 -0
  25. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/triggers/post-commit.md +0 -0
  26. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/workflows/contextmap.yaml +0 -0
  27. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/workflows/dev-loop.md +0 -0
  28. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.pre-commit-hooks.yaml +0 -0
  29. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/AGENTS.md +0 -0
  30. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CLAUDE.md +0 -0
  31. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CODE_OF_CONDUCT.md +0 -0
  32. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CONTRIBUTING.md +0 -0
  33. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/LICENSE +0 -0
  34. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/Makefile +0 -0
  35. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/action.yml +0 -0
  36. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__init__.py +0 -0
  37. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/conftest.py +0 -0
  38. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/smoke.py +0 -0
  39. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ast_audit.py +0 -0
  40. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ast_summary.py +0 -0
  41. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_brief_identidad.py +0 -0
  42. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_build_sin_eventos.py +0 -0
  43. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_captura.py +0 -0
  44. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_cargadores_chats.py +0 -0
  45. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_checker_frescura.py +0 -0
  46. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_clasificacion_chat.py +0 -0
  47. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_cli.py +0 -0
  48. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_conexiones.py +0 -0
  49. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_conocimiento_brief.py +0 -0
  50. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_cyclomatic.py +0 -0
  51. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_dependencias_mcp.py +0 -0
  52. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_doctor.py +0 -0
  53. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_domain_extractor.py +0 -0
  54. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ecosistema.py +0 -0
  55. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_embeddings_opcionales.py +0 -0
  56. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_enrich.py +0 -0
  57. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_enterprise_features.py +0 -0
  58. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_exclusiones_escaneo.py +0 -0
  59. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_export.py +0 -0
  60. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_fechas_conversaciones.py +0 -0
  61. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hardware.py +0 -0
  62. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hermes_clasificacion.py +0 -0
  63. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hook_memoria_viva.py +0 -0
  64. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hooks.py +0 -0
  65. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_humanizacion.py +0 -0
  66. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_inbox.py +0 -0
  67. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ingest.py +0 -0
  68. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ingesta_rica.py +0 -0
  69. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_llm_opcional.py +0 -0
  70. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_mcp_server_seguridad.py +0 -0
  71. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_mermaid.py +0 -0
  72. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_metrica_memoria_viva.py +0 -0
  73. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_obsidian_config.py +0 -0
  74. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ollama.py +0 -0
  75. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_pack_unpack.py +0 -0
  76. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_parsing.py +0 -0
  77. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal.py +0 -0
  78. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_identidad.py +0 -0
  79. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_panorama.py +0 -0
  80. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_repair.py +0 -0
  81. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_ruta.py +0 -0
  82. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_sync.py +0 -0
  83. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_prompt_caching.py +0 -0
  84. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_readiness_signals.py +0 -0
  85. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_refresh_multicanal.py +0 -0
  86. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_refresh_temporales.py +0 -0
  87. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_reglas_catalogo.py +0 -0
  88. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_review.py +0 -0
  89. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_scan_cache.py +0 -0
  90. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_scanner.py +0 -0
  91. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_security.py +0 -0
  92. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_security_scanner.py +0 -0
  93. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_similarity.py +0 -0
  94. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_standardize.py +0 -0
  95. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_templates_filenames.py +0 -0
  96. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_tokenization.py +0 -0
  97. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_topologia_arbol.py +0 -0
  98. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_vault_consolidation.py +0 -0
  99. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_watcher.py +0 -0
  100. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_web_clipper.py +0 -0
  101. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_wiki.py +0 -0
  102. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_wiki_avanzado.py +0 -0
  103. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_wrap.py +0 -0
  104. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/__init__.py +0 -0
  105. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/cli/__init__.py +0 -0
  106. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/cli/cli.py +0 -0
  107. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/cli/parser.py +0 -0
  108. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/__init__.py +0 -0
  109. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/_helpers.py +0 -0
  110. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/adapt.py +0 -0
  111. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/auto.py +0 -0
  112. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/build.py +0 -0
  113. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/doctor_cmd.py +0 -0
  114. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/enrich.py +0 -0
  115. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/export.py +0 -0
  116. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/hook.py +0 -0
  117. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/importers.py +0 -0
  118. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/inbox.py +0 -0
  119. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/ingest.py +0 -0
  120. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/pack.py +0 -0
  121. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/__init__.py +0 -0
  122. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/common.py +0 -0
  123. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/export.py +0 -0
  124. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/panorama.py +0 -0
  125. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/query.py +0 -0
  126. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/repair.py +0 -0
  127. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/sync.py +0 -0
  128. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/timeline.py +0 -0
  129. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/refresh.py +0 -0
  130. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/review.py +0 -0
  131. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/scan.py +0 -0
  132. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/sync.py +0 -0
  133. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/tools.py +0 -0
  134. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/update.py +0 -0
  135. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/watch.py +0 -0
  136. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/wiki.py +0 -0
  137. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/wrap.py +0 -0
  138. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/cli.py +0 -0
  139. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/__init__.py +0 -0
  140. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/generators/__init__.py +0 -0
  141. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/generators/generadores.py +0 -0
  142. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/generators/narrative_templates.py +0 -0
  143. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/logging_setup.py +0 -0
  144. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/models/__init__.py +0 -0
  145. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/models/config.py +0 -0
  146. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/models/models.py +0 -0
  147. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/__init__.py +0 -0
  148. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/cleaning.py +0 -0
  149. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/humanizacion.py +0 -0
  150. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/inference.py +0 -0
  151. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/mappings.py +0 -0
  152. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/standardize.py +0 -0
  153. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/__init__.py +0 -0
  154. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/cargadores.py +0 -0
  155. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/clasificacion.py +0 -0
  156. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/dedup.py +0 -0
  157. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/grafo.py +0 -0
  158. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/__init__.py +0 -0
  159. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/bd.py +0 -0
  160. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/panorama.py +0 -0
  161. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/repair.py +0 -0
  162. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/storage/__init__.py +0 -0
  163. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/storage/config_loader.py +0 -0
  164. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/storage/store.py +0 -0
  165. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/tokenization.py +0 -0
  166. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/__init__.py +0 -0
  167. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/__init__.py +0 -0
  168. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/checker.py +0 -0
  169. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/models.py +0 -0
  170. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/reporting.py +0 -0
  171. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/signals.py +0 -0
  172. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/__init__.py +0 -0
  173. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/ast_audit.py +0 -0
  174. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/ast_summary.py +0 -0
  175. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/cyclomatic.py +0 -0
  176. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/__init__.py +0 -0
  177. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/adaptador.py +0 -0
  178. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/detector.py +0 -0
  179. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/hooks.py +0 -0
  180. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/rules_templates.py +0 -0
  181. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/health/__init__.py +0 -0
  182. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/health/doctor.py +0 -0
  183. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/health/hardware.py +0 -0
  184. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ingestion/__init__.py +0 -0
  185. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ingestion/ingest.py +0 -0
  186. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/__init__.py +0 -0
  187. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/captura.py +0 -0
  188. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/clip.py +0 -0
  189. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/embeddings.py +0 -0
  190. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/inbox.py +0 -0
  191. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/indices.py +0 -0
  192. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/llm.py +0 -0
  193. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/review.py +0 -0
  194. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/wiki.py +0 -0
  195. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/normalization/domain_extractor.py +0 -0
  196. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/normalization/similarity.py +0 -0
  197. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/reglas/reglas.py +0 -0
  198. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/reporting/__init__.py +0 -0
  199. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/reporting/reporter.py +0 -0
  200. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/__init__.py +0 -0
  201. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/cache.py +0 -0
  202. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/scanner.py +0 -0
  203. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/security.py +0 -0
  204. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/storage/packer.py +0 -0
  205. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/__init__.py +0 -0
  206. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/relaciones.py +0 -0
  207. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/sync.py +0 -0
  208. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/watcher.py +0 -0
  209. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/__init__.py +0 -0
  210. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/__init__.py +0 -0
  211. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/exclusions.py +0 -0
  212. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/structure.py +0 -0
  213. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/__init__.py +0 -0
  214. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/antigravity.py +0 -0
  215. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/chat_export.py +0 -0
  216. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/git.py +0 -0
  217. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/hermes.py +0 -0
  218. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/ollama.py +0 -0
  219. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/mcp_server.py +0 -0
  220. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/version_check.py +0 -0
  221. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/__init__.py +0 -0
  222. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/__init__.py +0 -0
  223. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/agents.py +0 -0
  224. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/brief.py +0 -0
  225. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/extractors.py +0 -0
  226. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/sections.py +0 -0
  227. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/skill.py +0 -0
  228. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/__init__.py +0 -0
  229. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/atomic.py +0 -0
  230. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/__init__.py +0 -0
  231. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/conocimiento.py +0 -0
  232. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/consolidado.py +0 -0
  233. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/dominios.py +0 -0
  234. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/escritura.py +0 -0
  235. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/graph_style.py +0 -0
  236. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/jerarquico.py +0 -0
  237. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/nodos.py +0 -0
  238. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/notas_ideas.py +0 -0
  239. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/obsidian_config.py +0 -0
  240. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/readme_extract.py +0 -0
  241. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/rutas.py +0 -0
  242. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_backlog.py +0 -0
  243. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_estructura.py +0 -0
  244. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_historial.py +0 -0
  245. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_ideas.py +0 -0
  246. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_proposito.py +0 -0
  247. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_riesgos.py +0 -0
  248. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/mermaid.py +0 -0
  249. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/preservar.py +0 -0
  250. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/templates.py +0 -0
  251. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/writer.py +0 -0
  252. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/LAUNCH_KIT.md +0 -0
  253. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/LLM.md +0 -0
  254. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/WEB_CLIPPER.md +0 -0
  255. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/plans/2026-08-10-mapa-mental-conectado.md +0 -0
  256. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/plans/PLAN-MEJORAS-CONTEXTO-VIVO-2026-08-14.md +0 -0
  257. {context_map_ai-2.7.1 → context_map_ai-2.7.2}/mkdocs.yml +0 -0
@@ -7,6 +7,34 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.h
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### 🧩 Paquete de pi: `@kudawa/pi-contextmap`
11
+
12
+ - Publicado en npm el paquete que trae ContextMap a [pi](https://pi.dev):
13
+ extensión que **registra el servidor MCP** (avisa si falta el CLI), skill
14
+ `contextmap` y los prompts `/contextmap-contexto`, `/contextmap-cierre` y
15
+ `/contextmap-preguntar`.
16
+ - Install: `pi install npm:@kudawa/pi-contextmap`. Repo propio con publicación
17
+ automática en npm por **Trusted Publishing (OIDC, sin tokens)**:
18
+ https://github.com/kudawasama/pi-contextmap
19
+ - Guía: `docs/PI_PACKAGE.md`. (El nombre `pi-contextmap` fue rechazado por npm
20
+ por parecido a `pi-context-map`; se publicó con ámbito `@kudawa`.)
21
+
22
+ ## [2.7.2] — 2026-10-08
23
+
24
+ ### 🐛 Arreglado
25
+
26
+ - **Ruido de TODO en el Diario**: `render_nota_dia` volcaba los TODO del código
27
+ (`TODO (ruta.py:Ln): …`) en la nota del día. Ahora aplica el mismo filtro
28
+ `_es_todo_codigo` que ya usaban backlog, historial e ideas: la deuda técnica
29
+ vive en `5.0-BACKLOG/5.1-Tareas`, no en el diario.
30
+ - **Falsos positivos del extractor de TODO**: en archivos `.py` se analizan
31
+ **solo comentarios reales** con `tokenize` (un docstring o un string que
32
+ *menciona* el marcador ya no cuenta) y `**TODO**` en negrita Markdown dejó de
33
+ parecer un comentario. Descubierto al documentar el propio filtro, que generó
34
+ nodos fantasma.
35
+ - Tests: `test_analyzers_content.py` (8) y `test_diario_consolidado.py` (6);
36
+ suite **362/362**.
37
+
10
38
  ## [2.7.1] — 2026-10-08
11
39
 
12
40
  ### 🐛 Arreglado
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: context-map-ai
3
- Version: 2.7.1
3
+ Version: 2.7.2
4
4
  Summary: ContextMap IA — Memoria permanente y mapa mental narrativo para agentes de IA
5
5
  Project-URL: Homepage, https://github.com/kudawasama/ContextMap
6
6
  Project-URL: Repository, https://github.com/kudawasama/ContextMap
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
42
42
 
43
43
  ### *Evita que tu IA olvide tus decisiones, gaste dinero en tokens y rompa tu código.*
44
44
 
45
- [![Release](https://img.shields.io/badge/version-v2.7.1-blue.svg?style=for-the-badge)](CHANGELOG.md)
45
+ [![Release](https://img.shields.io/badge/version-v2.7.2-blue.svg?style=for-the-badge)](CHANGELOG.md)
46
46
  [![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/)
47
47
  [![Python](https://img.shields.io/badge/python-3.10+-3776AB.svg?style=for-the-badge&logo=python&logoColor=white)](pyproject.toml)
48
48
  [![Tests: 314 Passing](https://img.shields.io/badge/tests-314%2F314%20passing-brightgreen.svg?style=for-the-badge)](context_map/__tests__/)
@@ -144,6 +144,8 @@ Bot-Automatizacion 🟡 Tibio 21d 32 2/1 0
144
144
  ### 🔌 3. Control Directo para Agentes de IA (Servidor MCP Nativo & Skills)
145
145
  ContextMap incluye un servidor **MCP nativo (29 herramientas)** y generador de **Skills para Antigravity**. Asistentes como **Antigravity, Hermes Agent, Claude Desktop, Cursor o Windsurf** pueden sincronizar el mapa, consultar lecciones y registrar decisiones de forma completamente autónoma sin que toques la terminal.
146
146
 
147
+ > 🧩 También disponible como **paquete de [pi](https://pi.dev)**: `pi install npm:@kudawa/pi-contextmap` (trae el MCP, una skill y 3 prompts). Ver [docs/PI_PACKAGE.md](docs/PI_PACKAGE.md).
148
+
147
149
  ### 🛡️ 4. Reglas y Skills Universales para 10+ Editores e IAs
148
150
  Escribe tus normas una sola vez y ContextMap las inyecta en el formato nativo de cada herramienta:
149
151
  * **Google Antigravity**: `.agents/skills/contextmap/SKILL.md`
@@ -159,7 +161,7 @@ Escribe tus normas una sola vez y ContextMap las inyecta en el formato nativo de
159
161
 
160
162
  ## ⚖️ Comparativa: ContextMap vs. Otras Soluciones
161
163
 
162
- | ¿Qué necesitas? | Copiar y Pegar Todo<br>*(Repomix / Gitingest)* | Indexadores de Editor<br>*(Cursor / Windsurf)* | **ContextMap v2.7.1** |
164
+ | ¿Qué necesitas? | Copiar y Pegar Todo<br>*(Repomix / Gitingest)* | Indexadores de Editor<br>*(Cursor / Windsurf)* | **ContextMap v2.7.2** |
163
165
  | :--- | :---: | :---: | :---: |
164
166
  | **Gasto de Tokens** | 🔴 Altísimo (quema tu dinero) | 🟡 Medio | 🟢 **Mínimo (>99% de ahorro)** |
165
167
  | **Prompt Caching Determinista** | ❌ Incompatible (cambia el hash) | 🟡 Parcial | **✅ Prefijo congelado (>90% Hit Rate)** |
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### *Evita que tu IA olvide tus decisiones, gaste dinero en tokens y rompa tu código.*
8
8
 
9
- [![Release](https://img.shields.io/badge/version-v2.7.1-blue.svg?style=for-the-badge)](CHANGELOG.md)
9
+ [![Release](https://img.shields.io/badge/version-v2.7.2-blue.svg?style=for-the-badge)](CHANGELOG.md)
10
10
  [![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/)
11
11
  [![Python](https://img.shields.io/badge/python-3.10+-3776AB.svg?style=for-the-badge&logo=python&logoColor=white)](pyproject.toml)
12
12
  [![Tests: 314 Passing](https://img.shields.io/badge/tests-314%2F314%20passing-brightgreen.svg?style=for-the-badge)](context_map/__tests__/)
@@ -108,6 +108,8 @@ Bot-Automatizacion 🟡 Tibio 21d 32 2/1 0
108
108
  ### 🔌 3. Control Directo para Agentes de IA (Servidor MCP Nativo & Skills)
109
109
  ContextMap incluye un servidor **MCP nativo (29 herramientas)** y generador de **Skills para Antigravity**. Asistentes como **Antigravity, Hermes Agent, Claude Desktop, Cursor o Windsurf** pueden sincronizar el mapa, consultar lecciones y registrar decisiones de forma completamente autónoma sin que toques la terminal.
110
110
 
111
+ > 🧩 También disponible como **paquete de [pi](https://pi.dev)**: `pi install npm:@kudawa/pi-contextmap` (trae el MCP, una skill y 3 prompts). Ver [docs/PI_PACKAGE.md](docs/PI_PACKAGE.md).
112
+
111
113
  ### 🛡️ 4. Reglas y Skills Universales para 10+ Editores e IAs
112
114
  Escribe tus normas una sola vez y ContextMap las inyecta en el formato nativo de cada herramienta:
113
115
  * **Google Antigravity**: `.agents/skills/contextmap/SKILL.md`
@@ -123,7 +125,7 @@ Escribe tus normas una sola vez y ContextMap las inyecta en el formato nativo de
123
125
 
124
126
  ## ⚖️ Comparativa: ContextMap vs. Otras Soluciones
125
127
 
126
- | ¿Qué necesitas? | Copiar y Pegar Todo<br>*(Repomix / Gitingest)* | Indexadores de Editor<br>*(Cursor / Windsurf)* | **ContextMap v2.7.1** |
128
+ | ¿Qué necesitas? | Copiar y Pegar Todo<br>*(Repomix / Gitingest)* | Indexadores de Editor<br>*(Cursor / Windsurf)* | **ContextMap v2.7.2** |
127
129
  | :--- | :---: | :---: | :---: |
128
130
  | **Gasto de Tokens** | 🔴 Altísimo (quema tu dinero) | 🟡 Medio | 🟢 **Mínimo (>99% de ahorro)** |
129
131
  | **Prompt Caching Determinista** | ❌ Incompatible (cambia el hash) | 🟡 Parcial | **✅ Prefijo congelado (>90% Hit Rate)** |
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### *Stop your AI from forgetting architectural decisions, burning tokens, and breaking working code.*
8
8
 
9
- [![Release](https://img.shields.io/badge/version-v2.7.1-blue.svg?style=for-the-badge)](CHANGELOG.md)
9
+ [![Release](https://img.shields.io/badge/version-v2.7.2-blue.svg?style=for-the-badge)](CHANGELOG.md)
10
10
  [![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/)
11
11
  [![Python](https://img.shields.io/badge/python-3.10+-3776AB.svg?style=for-the-badge&logo=python&logoColor=white)](pyproject.toml)
12
12
  [![Tests: 314 Passing](https://img.shields.io/badge/tests-314%2F314%20passing-brightgreen.svg?style=for-the-badge)](context_map/__tests__/)
@@ -123,7 +123,7 @@ Write project rules once, and ContextMap auto-syncs them to every tool's native
123
123
 
124
124
  ## ⚖️ Comparison: ContextMap vs. Alternatives
125
125
 
126
- | What do you need? | Raw Dumps<br>*(Repomix / Gitingest)* | IDE-Locked Indexers<br>*(Cursor / Windsurf)* | **ContextMap v2.7.1** |
126
+ | What do you need? | Raw Dumps<br>*(Repomix / Gitingest)* | IDE-Locked Indexers<br>*(Cursor / Windsurf)* | **ContextMap v2.7.2** |
127
127
  | :--- | :---: | :---: | :---: |
128
128
  | **Token Consumption** | 🔴 Massive (expensive & slow) | 🟡 Medium | 🟢 **Ultra-efficient (>99% savings)** |
129
129
  | **Deterministic Prompt Caching** | ❌ Incompatible (breaks hash) | 🟡 Partial | **✅ Frozen Prefix (>90% Hit Rate)** |
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Documentación de Ingeniería de Software, Patrones de Diseño, AST y Protocolos**
6
6
 
7
- [![Version: v2.7.1](https://img.shields.io/badge/version-v2.7.1-blue.svg?style=for-the-badge)](CHANGELOG.md)
7
+ [![Version: v2.7.2](https://img.shields.io/badge/version-v2.7.2-blue.svg?style=for-the-badge)](CHANGELOG.md)
8
8
  [![Tests: 314 Passing](https://img.shields.io/badge/tests-314%2F314%20passing-brightgreen.svg?style=for-the-badge)](context_map/__tests__/)
9
9
  [![Type Check: Strict MyPy](https://img.shields.io/badge/mypy-100%25%20strict%20blocking-00599C.svg?style=for-the-badge&logo=python&logoColor=white)](.github/workflows/ci.yml)
10
10
  [![Prompt Cache: Optimized](https://img.shields.io/badge/Prompt%20Cache->90%25%20Hit%20Rate-orange.svg?style=for-the-badge)](context_map/presentation/briefs/)
@@ -84,6 +84,8 @@ Para garantizar un Graph View de Obsidian legible, limpio y sin colisiones:
84
84
 
85
85
  El módulo `infrastructure/mcp_server.py` implementa el protocolo **MCP sobre transporte `stdio`**, permitiendo que agentes como **Hermes Agent**, **Cursor**, **Claude Desktop** y **Windsurf** ejecuten 29 herramientas nativas:
86
86
 
87
+ > 🧩 Para **pi** hay un paquete que registra este MCP, añade la skill `contextmap` y 3 prompts: `pi install npm:@kudawa/pi-contextmap` (ver [docs/PI_PACKAGE.md](../docs/PI_PACKAGE.md)).
88
+
87
89
  | Tool MCP | Descripción |
88
90
  | :--- | :--- |
89
91
  | `refresh` | Flujo completo de sincronización (scan + build con preservación + check). |
@@ -0,0 +1,154 @@
1
+ """Pruebas de la extracción de marcadores TODO/FIXME/HACK de comentarios.
2
+
3
+ Caso real de la auditoría 2026-09-21: la heurística buscaba la subcadena
4
+ ``todo``/``bug`` en cualquier línea, así que 647 de los 685 eventos ``TODO``
5
+ de la BD personal eran prosa en español («todo el rango», «todos los módulos»),
6
+ llamadas ``logger.debug`` o líneas de docstring.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from context_map.infrastructure.analyzers.content import extraer_todos
12
+
13
+ CODIGO_CON_FALSOS_POSITIVOS = '''"""Carpetas base que se escanean en ``sync --todos``."""
14
+
15
+ import logging
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ def cargar():
21
+ """Carga y re-estandariza todo el grafo (por si quedaron viejos)."""
22
+ for item in todos_los_items:
23
+ # Cubre todo el rango y todo dia del periodo
24
+ logger.debug("Encoding detection on empty bytes, %s", item)
25
+ # Avoid unoptimized RSS usage.
26
+ yield item
27
+ '''
28
+
29
+ CODIGO_CON_MARCADORES_REALES = """# TODO: unificar el descubrimiento de proyectos
30
+ import os # FIXME: ruta hardcodeada a F:
31
+ # HACK: parche temporal hasta migrar la BD
32
+ # XXX revisar antes del release
33
+ valor = 1 # TODO(c) pendiente de tipar
34
+ """
35
+
36
+
37
+ def test_no_marca_prosa_en_espanol_ni_debug_ni_docstrings(tmp_path) -> None:
38
+ """La prosa con «todo», `logger.debug` y los docstrings NO son pendientes."""
39
+ archivo = tmp_path / "modulo.py"
40
+ archivo.write_text(CODIGO_CON_FALSOS_POSITIVOS, encoding="utf-8")
41
+
42
+ assert extraer_todos(str(archivo)) == []
43
+
44
+
45
+ def test_detecta_marcadores_reales_en_comentarios(tmp_path) -> None:
46
+ """Los marcadores en MAYÚSCULAS dentro de comentarios sí se detectan."""
47
+ archivo = tmp_path / "modulo.py"
48
+ archivo.write_text(CODIGO_CON_MARCADORES_REALES, encoding="utf-8")
49
+
50
+ todos = extraer_todos(str(archivo))
51
+
52
+ assert len(todos) == 5, todos
53
+ assert todos[0].startswith("L1: # TODO: unificar")
54
+ assert any("FIXME" in t for t in todos)
55
+ assert any("HACK" in t for t in todos)
56
+ assert any("XXX" in t for t in todos)
57
+
58
+
59
+ def test_todo_minuscula_no_es_marcador(tmp_path) -> None:
60
+ """`# todo` en un comentario en español es prosa, no un marcador."""
61
+ archivo = tmp_path / "modulo.py"
62
+ archivo.write_text("# todo esto hay que revisarlo luego\n", encoding="utf-8")
63
+
64
+ assert extraer_todos(str(archivo)) == []
65
+
66
+
67
+ def test_archivo_inexistente_no_falla() -> None:
68
+ """Un archivo ilegible devuelve una lista vacía, sin propagar la excepción."""
69
+ assert extraer_todos("ruta/que/no/existe.py") == []
70
+
71
+
72
+ CODIGO_CON_NEGRITA_MARKDOWN = '''"""Docstring que explica el filtro: los **TODO** crudos del código se excluyen."""
73
+
74
+
75
+
76
+ def f():
77
+ """Ojo con **TODO** en negrita y con *TODO suelto en prosa."""
78
+ return 1
79
+ '''
80
+
81
+
82
+ CODIGO_CON_COMENTARIOS_DE_BLOQUE = '''/* TODO: refactorizar el parser */
83
+ * FIXME: ojo con el encoding
84
+ /** HACK: puente temporal */
85
+ <!-- TODO: documentar la API -->
86
+ '''
87
+
88
+
89
+ def test_negrita_markdown_no_es_marcador(tmp_path) -> None:
90
+ """Regresión 2026-10-08: ``**TODO**`` (negrita Markdown) no es un comentario.
91
+
92
+ Dogfooding: al documentar el filtro del diario, el propio docstring generó un
93
+ nodo ``TODO (…/canvas.py:L203)`` porque ``*`` contaba como signo de comentario.
94
+ """
95
+ archivo = tmp_path / "modulo.py"
96
+ archivo.write_text(CODIGO_CON_NEGRITA_MARKDOWN, encoding="utf-8")
97
+
98
+ assert extraer_todos(str(archivo)) == []
99
+
100
+
101
+ def test_marcadores_en_comentarios_de_bloque_siguen_detectandose(tmp_path) -> None:
102
+ """``/* TODO */``, `` * TODO`` y ``<!-- TODO -->`` siguen siendo marcadores.
103
+
104
+ Se prueba en un ``.ts``: los comentarios de bloque no existen en Python, así
105
+ que ahí manda la heurística por líneas (no ``tokenize``).
106
+ """
107
+ archivo = tmp_path / "modulo.ts"
108
+ archivo.write_text(CODIGO_CON_COMENTARIOS_DE_BLOQUE, encoding="utf-8")
109
+
110
+ todos = extraer_todos(str(archivo))
111
+
112
+ assert len(todos) == 4, todos
113
+ assert any("refactorizar el parser" in t for t in todos)
114
+ assert any("encoding" in t for t in todos)
115
+ assert any("puente temporal" in t for t in todos)
116
+ assert any("documentar la API" in t for t in todos)
117
+
118
+
119
+ def test_python_solo_mira_comentarios_reales(tmp_path) -> None:
120
+ """En ``.py`` un marcador dentro de un string o docstring NO cuenta.
121
+
122
+ Regresión 2026-10-08: documentar el filtro generó nodos TODO fantasma porque
123
+ se miraban líneas sueltas. Con ``tokenize`` solo cuentan los comentarios.
124
+ """
125
+ archivo = tmp_path / "doc.py"
126
+ archivo.write_text(
127
+ '"""Docstring que cita el marcador # TODO: no es un pendiente."""\n'
128
+ '\n'
129
+ 'MENSAJE = "# FIXME: tampoco, es un string"\n'
130
+ 'RE = r"# TODO"\n'
131
+ '\n'
132
+ 'x = 1 # TODO: este sí es un pendiente real\n',
133
+ encoding="utf-8",
134
+ )
135
+
136
+ todos = extraer_todos(str(archivo))
137
+
138
+ assert len(todos) == 1, todos
139
+ assert "pendiente real" in todos[0]
140
+
141
+
142
+ def test_javascript_usa_la_heuristica_por_lineas(tmp_path) -> None:
143
+ """En lenguajes sin ``tokenize`` se mantiene la heurística por líneas."""
144
+ archivo = tmp_path / "app.ts"
145
+ archivo.write_text(
146
+ '// TODO: tipar el retorno\n'
147
+ 'const x = 1;\n',
148
+ encoding="utf-8",
149
+ )
150
+
151
+ todos = extraer_todos(str(archivo))
152
+
153
+ assert len(todos) == 1, todos
154
+ assert "tipar el retorno" in todos[0]
@@ -101,3 +101,54 @@ def test_preserva_contenido_del_agente_despues_del_scanner(tmp_path):
101
101
  assert "Nodo B" in final
102
102
  assert final.count("🤖 Ingresados por el scanner") == 1
103
103
 
104
+
105
+ def test_excluye_todos_de_codigo_y_conserva_los_conversados(tmp_path):
106
+ """Los TODO crudos del código NO se vuelcan al diario; los conversados sí.
107
+
108
+ Dogfooding 2026-10-08: el diario acumulaba volcados de código (p. ej.
109
+ ``TODO (context_map/x.py:L10): return valor``), que son deuda técnica y
110
+ viven en ``5.0-BACKLOG/5.1-Tareas``. El filtro ``_es_todo_codigo`` que ya
111
+ usaban backlog/historial/ideas faltaba en el generador del diario.
112
+ """
113
+ out = str(tmp_path)
114
+ hoy = date.today().isoformat()
115
+ codigo = Node(
116
+ id="t1",
117
+ type="FUTURO",
118
+ title="TODO (context_map/app.py:L10): return valor # pendiente de tipar",
119
+ created_at=f"{hoy}T10:00:00",
120
+ )
121
+ prueba = Node(
122
+ id="t2",
123
+ type="FUTURO",
124
+ title="TODO (context_map/__tests__/test_x.py:L5): assert algo",
125
+ created_at=f"{hoy}T10:30:00",
126
+ )
127
+ conversado = Node(
128
+ id="t3",
129
+ type="FUTURO",
130
+ title="Revisar el flujo de captura móvil con el usuario",
131
+ created_at=f"{hoy}T11:00:00",
132
+ )
133
+
134
+ render_nota_dia(out, "MiProyecto", [codigo, prueba, conversado])
135
+ contenido = _ruta_diario(tmp_path, hoy).read_text(encoding="utf-8")
136
+
137
+ assert "Revisar el flujo de captura móvil" in contenido
138
+ assert "return valor" not in contenido
139
+ assert "assert algo" not in contenido
140
+
141
+
142
+ def test_sin_nodos_utiles_no_crea_diario(tmp_path):
143
+ """Un día con solo TODO de código no genera diario (sin ruido)."""
144
+ out = str(tmp_path)
145
+ hoy = date.today().isoformat()
146
+ solo_codigo = Node(
147
+ id="t1",
148
+ type="FUTURO",
149
+ title="TODO (context_map/app.py:L10): def foo(): pass",
150
+ created_at=f"{hoy}T10:00:00",
151
+ )
152
+ assert render_nota_dia(out, "MiProyecto", [solo_codigo]) is None
153
+ assert not _ruta_diario(tmp_path, hoy).exists()
154
+
@@ -97,7 +97,8 @@ def extraer_funciones(ruta: str) -> list[str]:
97
97
 
98
98
 
99
99
  _RE_MARCADOR_TODO = re.compile(
100
- r"(?:#|//|/\*|\*|<!--|--)\s*(?:TODO|FIXME|HACK|BUG|OPTIMIZE|XXX)[Ss]?\b:?"
100
+ r"(?:#|//|/\*+|^\s*\*(?!\*)|<!--|--)\s*(?:TODO|FIXME|HACK|BUG|OPTIMIZE|XXX)[Ss]?\b:?",
101
+ re.MULTILINE,
101
102
  )
102
103
  """Marcador de tarea pendiente: requiere signo de comentario y palabra en MAYÚSCULAS.
103
104
 
@@ -107,11 +108,50 @@ módulos»), las llamadas ``logger.debug(...)`` y los docstrings. En la BD perso
107
108
  eso produjo 647 de 685 eventos ``TODO`` falsos (94%). La coincidencia en
108
109
  mayúsculas es deliberada: ``# todo`` en un comentario en español es prosa, no un
109
110
  marcador; ``# TODO`` sí lo es.
111
+
112
+ Ajuste 2026-10-08: el ``*`` suelto solo cuenta como comentario de bloque al
113
+ inicio de línea y si no es el primero de una negrita (``**TODO**`` en Markdown
114
+ no es un pendiente). ``/*`` y ``/**`` siguen valiendo dentro de la línea.
110
115
  """
111
116
 
112
117
 
118
+ def _todos_de_python(ruta: str) -> list[str] | None:
119
+ """Marcadores hallados en COMENTARIOS reales de un ``.py`` (con ``tokenize``).
120
+
121
+ Evita la clase de falsos positivos más terca: un docstring o un string que
122
+ *menciona* un marcador (p. ej. documentar ``# TODO`` o escribir ``**TODO**``
123
+ en negrita) no es un pendiente del código. Devuelve None si el archivo no es
124
+ un Python válido, para que el llamador use la heurística por líneas.
125
+
126
+ Args:
127
+ ruta (str): Ruta del archivo Python.
128
+
129
+ Returns:
130
+ list[str] | None: Líneas ``L<n>: <comentario>`` (máx. 10), o None si no
131
+ se pudo tokenizar.
132
+ """
133
+ import tokenize
134
+
135
+ encontrados: list[str] = []
136
+ try:
137
+ with open(ruta, "rb") as f:
138
+ for token in tokenize.tokenize(f.readline):
139
+ if token.type == tokenize.COMMENT and _RE_MARCADOR_TODO.search(token.string):
140
+ encontrados.append(f"L{token.start[0]}: {token.string.strip()[:100]}")
141
+ if len(encontrados) >= 10:
142
+ break
143
+ except Exception as err: # noqa: BLE001 — sintaxis inválida: fallback por líneas
144
+ logger.debug("No se pudo tokenizar %s: %s", ruta, err)
145
+ return None
146
+ return encontrados
147
+
148
+
113
149
  def extraer_todos(ruta: str) -> list[str]:
114
- """Extrae los marcadores TODO/FIXME/HACK/BUG/OPTIMIZE/XXX escritos en comentarios.
150
+ """Extrae los marcadores TODO/FIXME/HACK/BUG/OPTIMIZE/XXX de comentarios.
151
+
152
+ En archivos ``.py`` analiza **solo comentarios** (``tokenize``), de modo que
153
+ docstrings y strings que mencionan un marcador no cuentan. En el resto de
154
+ lenguajes (JS/TS/C/HTML/SQL…) usa la heurística por líneas.
115
155
 
116
156
  Args:
117
157
  ruta (str): Ruta del archivo a analizar.
@@ -120,6 +160,11 @@ def extraer_todos(ruta: str) -> list[str]:
120
160
  list[str]: Líneas con marcador, con el formato ``L<n>: <texto>``
121
161
  (máximo 10 por archivo).
122
162
  """
163
+ if ruta.endswith(".py"):
164
+ comentarios = _todos_de_python(ruta)
165
+ if comentarios is not None:
166
+ return comentarios
167
+
123
168
  todos = []
124
169
  try:
125
170
  with open(ruta, encoding="utf-8", errors="ignore") as f:
@@ -200,6 +200,10 @@ def render_nota_dia(output_dir: str, project_name: str, nodes: list[Node]) -> st
200
200
  Escribe en la zona protegida ``.manual/Diario/YYYY-MM-DD.md`` con wikilinks
201
201
  a los nodos cuyo ``created_at`` coincide con la fecha de hoy.
202
202
 
203
+ Los **TODO crudos del código** (y el ruido de tests/chat) se excluyen: son
204
+ deuda técnica y viven en ``5.0-BACKLOG/5.1-Tareas``. Sin este filtro el
205
+ diario se llenaba de volcados de código (regla del skill: títulos legibles).
206
+
203
207
  Args:
204
208
  output_dir (str): Directorio raíz del proyecto.
205
209
  project_name (str): Nombre del proyecto.
@@ -211,6 +215,9 @@ def render_nota_dia(output_dir: str, project_name: str, nodes: list[Node]) -> st
211
215
  safe = project_name.strip().replace(" ", "-").replace("/", "-")
212
216
  hoy = date.today().isoformat()
213
217
  ingresados = [n for n in nodes if (n.created_at or "")[:10] == hoy]
218
+ from context_map.presentation.vault.consolidated.secciones_backlog import _es_todo_codigo
219
+
220
+ ingresados = [n for n in ingresados if not _es_todo_codigo(n)]
214
221
 
215
222
  if not ingresados:
216
223
  return None
@@ -0,0 +1,62 @@
1
+ # 🧩 Paquete de pi — `@kudawa/pi-contextmap`
2
+
3
+ ContextMap también se distribuye como **paquete de [pi](https://pi.dev)** para que
4
+ cualquier agente traiga la memoria viva del proyecto con un solo comando.
5
+
6
+ ```bash
7
+ pi install npm:@kudawa/pi-contextmap
8
+ ```
9
+
10
+ - **Registro npm**: https://www.npmjs.com/package/@kudawa/pi-contextmap
11
+ - **Código**: https://github.com/kudawasama/pi-contextmap
12
+ - **Galería de pi**: https://pi.dev/packages (aparece por la keyword `pi-package`)
13
+
14
+ ## Requisitos
15
+
16
+ El paquete no incluye el motor: instala el CLI de ContextMap.
17
+
18
+ ```bash
19
+ uv tool install "context-map-ai[mcp]" # o: pip install "context-map-ai[mcp]"
20
+ ```
21
+
22
+ Si falta, la extensión **avisa al iniciar la sesión** con el comando exacto (no
23
+ deja errores de conexión ruidosos).
24
+
25
+ ## Qué aporta
26
+
27
+ | Recurso | Nombre | Para qué |
28
+ |---|---|---|
29
+ | Extensión | MCP `contextmap` | Registra `ctxmap mcp` (29 herramientas). Las 4 de lectura (`context`, `personal_panorama`, `personal_query`, `knowledge_wiki_ask`) van `direct`; el resto en `codemode` |
30
+ | Skill | `/skill:contextmap` | Protocolo: ponerse en contexto, actualizar sin ensuciar, memoria viva, topología del vault |
31
+ | Prompt | `/contextmap-contexto` | Arrancar con brief + pendientes reales |
32
+ | Prompt | `/contextmap-cierre` | Cerrar sesión: refresh → verificar → documentar |
33
+ | Prompt | `/contextmap-preguntar` | Preguntar a la memoria de todos los proyectos, con citas |
34
+
35
+ ## Publicación (Trusted Publishing / OIDC)
36
+
37
+ El paquete vive en su propio repo y se publica **sin tokens ni códigos**:
38
+ `.github/workflows/publish.yml` usa el OIDC de GitHub Actions + npm.
39
+
40
+ Un único paso manual (una sola vez): en npmjs.com → paquete →
41
+ **Settings → Trusted Publisher → GitHub Actions**, autorizar
42
+ `kudawasama/pi-contextmap` con el workflow `publish.yml`.
43
+
44
+ Después, publicar una versión nueva es:
45
+
46
+ ```bash
47
+ npm version patch --no-git-tag-version # sube package.json
48
+ python scripts/make_preview.py # regenera la tarjeta si cambió el texto
49
+ git commit -am "chore: vX.Y.Z" && git tag vX.Y.Z && git push --follow-tags
50
+ ```
51
+
52
+ El workflow verifica que el tag coincide con `package.json` y publica con
53
+ proveniencia firmada.
54
+
55
+ ## Notas
56
+
57
+ - El nombre npm original (`pi-contextmap`) fue **rechazado por npm** por ser
58
+ demasiado parecido a `pi-context-map`; se publicó con ámbito `@kudawa`.
59
+ - El paquete se mantiene **fuera** del repo de ContextMap para no meter npm/TS en
60
+ el escáner del proyecto Python; aquí solo se documenta.
61
+ - Versiones: la del paquete de pi es **independiente** de la de PyPI
62
+ (`context-map-ai`).
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "context-map-ai"
7
- version = "2.7.1"
7
+ version = "2.7.2"
8
8
  description = "ContextMap IA — Memoria permanente y mapa mental narrativo para agentes de IA"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -249,7 +249,7 @@ wheels = [
249
249
 
250
250
  [[package]]
251
251
  name = "context-map-ai"
252
- version = "2.7.1"
252
+ version = "2.7.2"
253
253
  source = { editable = "." }
254
254
  dependencies = [
255
255
  { name = "tomli", marker = "python_full_version < '3.11'" },
@@ -1,69 +0,0 @@
1
- """Pruebas de la extracción de marcadores TODO/FIXME/HACK de comentarios.
2
-
3
- Caso real de la auditoría 2026-09-21: la heurística buscaba la subcadena
4
- ``todo``/``bug`` en cualquier línea, así que 647 de los 685 eventos ``TODO``
5
- de la BD personal eran prosa en español («todo el rango», «todos los módulos»),
6
- llamadas ``logger.debug`` o líneas de docstring.
7
- """
8
-
9
- from __future__ import annotations
10
-
11
- from context_map.infrastructure.analyzers.content import extraer_todos
12
-
13
- CODIGO_CON_FALSOS_POSITIVOS = '''"""Carpetas base que se escanean en ``sync --todos``."""
14
-
15
- import logging
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
-
20
- def cargar():
21
- """Carga y re-estandariza todo el grafo (por si quedaron viejos)."""
22
- for item in todos_los_items:
23
- # Cubre todo el rango y todo dia del periodo
24
- logger.debug("Encoding detection on empty bytes, %s", item)
25
- # Avoid unoptimized RSS usage.
26
- yield item
27
- '''
28
-
29
- CODIGO_CON_MARCADORES_REALES = """# TODO: unificar el descubrimiento de proyectos
30
- import os # FIXME: ruta hardcodeada a F:
31
- # HACK: parche temporal hasta migrar la BD
32
- # XXX revisar antes del release
33
- valor = 1 # TODO(c) pendiente de tipar
34
- """
35
-
36
-
37
- def test_no_marca_prosa_en_espanol_ni_debug_ni_docstrings(tmp_path) -> None:
38
- """La prosa con «todo», `logger.debug` y los docstrings NO son pendientes."""
39
- archivo = tmp_path / "modulo.py"
40
- archivo.write_text(CODIGO_CON_FALSOS_POSITIVOS, encoding="utf-8")
41
-
42
- assert extraer_todos(str(archivo)) == []
43
-
44
-
45
- def test_detecta_marcadores_reales_en_comentarios(tmp_path) -> None:
46
- """Los marcadores en MAYÚSCULAS dentro de comentarios sí se detectan."""
47
- archivo = tmp_path / "modulo.py"
48
- archivo.write_text(CODIGO_CON_MARCADORES_REALES, encoding="utf-8")
49
-
50
- todos = extraer_todos(str(archivo))
51
-
52
- assert len(todos) == 5, todos
53
- assert todos[0].startswith("L1: # TODO: unificar")
54
- assert any("FIXME" in t for t in todos)
55
- assert any("HACK" in t for t in todos)
56
- assert any("XXX" in t for t in todos)
57
-
58
-
59
- def test_todo_minuscula_no_es_marcador(tmp_path) -> None:
60
- """`# todo` en un comentario en español es prosa, no un marcador."""
61
- archivo = tmp_path / "modulo.py"
62
- archivo.write_text("# todo esto hay que revisarlo luego\n", encoding="utf-8")
63
-
64
- assert extraer_todos(str(archivo)) == []
65
-
66
-
67
- def test_archivo_inexistente_no_falla() -> None:
68
- """Un archivo ilegible devuelve una lista vacía, sin propagar la excepción."""
69
- assert extraer_todos("ruta/que/no/existe.py") == []
File without changes
File without changes
File without changes
File without changes