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