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.
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CHANGELOG.md +28 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/PKG-INFO +5 -3
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/README.md +4 -2
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/README_EN.md +2 -2
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/README_TECNICO.md +3 -1
- context_map_ai-2.7.2/context_map/__tests__/test_analyzers_content.py +154 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_diario_consolidado.py +51 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/content.py +47 -2
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/canvas.py +7 -0
- context_map_ai-2.7.2/docs/PI_PACKAGE.md +62 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/pyproject.toml +1 -1
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/uv.lock +1 -1
- context_map_ai-2.7.1/context_map/__tests__/test_analyzers_content.py +0 -69
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.agents/skills/contextmap/SKILL.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/copilot-instructions.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/workflows/ci.yml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/workflows/docs.yml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.github/workflows/publish.yml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.gitignore +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/config.yaml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/shields/pre-commit.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/triggers/post-commit.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/workflows/contextmap.yaml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.hermes/workflows/dev-loop.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/.pre-commit-hooks.yaml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/AGENTS.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CLAUDE.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CODE_OF_CONDUCT.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/CONTRIBUTING.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/LICENSE +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/Makefile +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/action.yml +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/conftest.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/smoke.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ast_audit.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ast_summary.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_brief_identidad.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_build_sin_eventos.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_captura.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_cargadores_chats.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_checker_frescura.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_clasificacion_chat.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_cli.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_conexiones.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_conocimiento_brief.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_cyclomatic.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_dependencias_mcp.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_doctor.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_domain_extractor.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ecosistema.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_embeddings_opcionales.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_enrich.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_enterprise_features.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_exclusiones_escaneo.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_export.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_fechas_conversaciones.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hardware.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hermes_clasificacion.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hook_memoria_viva.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_hooks.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_humanizacion.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_inbox.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ingest.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ingesta_rica.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_llm_opcional.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_mcp_server_seguridad.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_mermaid.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_metrica_memoria_viva.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_obsidian_config.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_ollama.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_pack_unpack.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_parsing.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_identidad.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_panorama.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_repair.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_ruta.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_personal_sync.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_prompt_caching.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_readiness_signals.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_refresh_multicanal.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_refresh_temporales.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_reglas_catalogo.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_review.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_scan_cache.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_scanner.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_security.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_security_scanner.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_similarity.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_standardize.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_templates_filenames.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_tokenization.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_topologia_arbol.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_vault_consolidation.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_watcher.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_web_clipper.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_wiki.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_wiki_avanzado.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_wrap.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/cli/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/cli/cli.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/cli/parser.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/_helpers.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/adapt.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/auto.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/build.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/doctor_cmd.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/enrich.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/export.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/hook.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/importers.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/inbox.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/ingest.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/pack.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/common.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/export.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/panorama.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/query.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/repair.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/sync.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/personal/timeline.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/refresh.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/review.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/scan.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/sync.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/tools.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/update.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/watch.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/wiki.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/application/commands/wrap.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/cli.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/generators/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/generators/generadores.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/generators/narrative_templates.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/logging_setup.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/models/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/models/config.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/models/models.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/cleaning.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/humanizacion.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/inference.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/mappings.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/normalization/standardize.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/cargadores.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/clasificacion.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/dedup.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/parsing/grafo.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/bd.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/panorama.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/personal/repair.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/storage/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/storage/config_loader.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/storage/store.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/core/tokenization.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/checker.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/models.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/reporting.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analysis/signals.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/ast_audit.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/ast_summary.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/analyzers/cyclomatic.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/adaptador.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/detector.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/hooks.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ecosystem/rules_templates.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/health/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/health/doctor.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/health/hardware.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ingestion/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/ingestion/ingest.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/captura.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/clip.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/embeddings.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/inbox.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/indices.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/llm.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/review.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/knowledge/wiki.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/normalization/domain_extractor.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/normalization/similarity.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/reglas/reglas.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/reporting/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/reporting/reporter.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/cache.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/scanner.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/scanning/security.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/storage/packer.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/relaciones.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/sync.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/domain/synchronization/watcher.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/exclusions.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/structure.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/antigravity.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/chat_export.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/git.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/hermes.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/integrations/ollama.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/mcp_server.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/version_check.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/agents.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/brief.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/extractors.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/sections.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/briefs/skill.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/atomic.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/__init__.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/conocimiento.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/consolidado.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/dominios.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/escritura.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/graph_style.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/jerarquico.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/nodos.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/notas_ideas.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/obsidian_config.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/readme_extract.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/rutas.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_backlog.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_estructura.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_historial.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_ideas.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_proposito.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/secciones_riesgos.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/mermaid.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/preservar.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/templates.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/writer.py +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/LAUNCH_KIT.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/LLM.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/WEB_CLIPPER.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/plans/2026-08-10-mapa-mental-conectado.md +0 -0
- {context_map_ai-2.7.1 → context_map_ai-2.7.2}/docs/plans/PLAN-MEJORAS-CONTEXTO-VIVO-2026-08-14.md +0 -0
- {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.
|
|
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
|
-
[](CHANGELOG.md)
|
|
46
46
|
[](https://pypi.org/project/context-map-ai/)
|
|
47
47
|
[](pyproject.toml)
|
|
48
48
|
[](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.
|
|
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
|
-
[](CHANGELOG.md)
|
|
10
10
|
[](https://pypi.org/project/context-map-ai/)
|
|
11
11
|
[](pyproject.toml)
|
|
12
12
|
[](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.
|
|
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
|
-
[](CHANGELOG.md)
|
|
10
10
|
[](https://pypi.org/project/context-map-ai/)
|
|
11
11
|
[](pyproject.toml)
|
|
12
12
|
[](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.
|
|
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
|
-
[](CHANGELOG.md)
|
|
8
8
|
[](context_map/__tests__/)
|
|
9
9
|
[](.github/workflows/ci.yml)
|
|
10
10
|
[](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]
|
{context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/__tests__/test_diario_consolidado.py
RENAMED
|
@@ -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
|
+
|
{context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/infrastructure/analyzers/content.py
RENAMED
|
@@ -97,7 +97,8 @@ def extraer_funciones(ruta: str) -> list[str]:
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
_RE_MARCADOR_TODO = re.compile(
|
|
100
|
-
r"(
|
|
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
|
|
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:
|
{context_map_ai-2.7.1 → context_map_ai-2.7.2}/context_map/presentation/vault/consolidated/canvas.py
RENAMED
|
@@ -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`).
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|