contextual-engine 0.9.2__tar.gz → 0.9.5__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.
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/PKG-INFO +1 -1
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/index.py +10 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/initialisation.py +22 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/mcp.py +1 -1
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/stats.py +0 -1
- contextual_engine-0.9.5/contextual/cli/commands/workspace.py +100 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/mcp_config.py +9 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/indexing.py +4 -16
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/paths.py +1 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/retrieval_config.py +0 -2
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/core/models.py +49 -1
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/incremental_git.py +65 -2
- contextual_engine-0.9.5/contextual/graph/extractor.py +1246 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/integrator.py +29 -2
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/resolver.py +137 -8
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/traversal.py +9 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/file_watcher.py +31 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/incremental_indexer.py +8 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/__init__.py +2 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/_config.py +0 -4
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/chunker.py +105 -6
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/pipeline.py +351 -107
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/symbol_extractor.py +42 -1
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/__init__.py +1 -1
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/access.py +14 -0
- contextual_engine-0.9.5/contextual/mcp/memory_monitor.py +294 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/audit.py +1 -1
- contextual_engine-0.9.5/contextual/mcp/middleware/identity.py +185 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/workspace.py +13 -23
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/server.py +129 -24
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/session_manager.py +46 -107
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/shim.py +135 -58
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/__init__.py +284 -1
- contextual_engine-0.9.5/contextual/mcp/tools/_gcf.py +279 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/graph.py +208 -21
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/nexus.py +74 -16
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/semantic.py +165 -30
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/system.py +150 -10
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/temporal.py +23 -13
- contextual_engine-0.9.5/contextual/mcp/workspace_registry.py +410 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/__init__.py +5 -3
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/pipeline.py +32 -7
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/__init__.py +20 -2
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/blame_pipeline.py +2 -2
- contextual_engine-0.9.5/docs/ADRs/ADR-006-remove-bm25-k1-b-dead-config.md +92 -0
- contextual_engine-0.9.5/docs/DRs/GEMINI-DR-analysis-extraction.md +319 -0
- contextual_engine-0.9.5/docs/DRs/GEMINI_DR_extraction-optimisation.md +158 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/pyproject.toml +1 -1
- contextual_engine-0.9.5/scripts/mcp_stress_test.py +482 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_graph.py +68 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_indexing.py +48 -0
- contextual_engine-0.9.2/contextual/cli/commands/workspace.py +0 -53
- contextual_engine-0.9.2/contextual/graph/extractor.py +0 -571
- contextual_engine-0.9.2/contextual/mcp/middleware/identity.py +0 -65
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.contextualignore +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.cursor/rules/contextual.mdc +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.github/workflows/ci.yml +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.github/workflows/release.yml +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.gitignore +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.mcp.json +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/LICENSE +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/README.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/__main__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/auth.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/client.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/doctor.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/fetch.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/install.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/context.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/decorators.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/editor.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/output.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/base.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/security_config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/storage_config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/cache_config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/indexing_config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/observability_config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/workspace_config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/core/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/core/errors.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/blame.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/hooks.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/dedup.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/staleness.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/store.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/daemon_embed.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/_ignore.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/docs_pipeline.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/index_writer.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/merkle_tree.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/processor.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/integrations/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/integrations/client_content.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/integrations/client_writer.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/__main__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/_platform.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/bootstrap.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/daemon.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/auth.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/ratelimit.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/warmup.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/router.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/_inference.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/allowlist.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/base_embedder.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/reranker_model.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/unified_embedder.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/config.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/exporters.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/logging.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/retention.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/tracer.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/context_assembler.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/mmr.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/ranker.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/tokenizer.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/paths.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/sanitize.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/workspace.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/cache.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/connection.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/fts.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/lancedb_provider.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me001_orgs.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me002_org_members.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me003_teams.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me004_team_members.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me005_org_workspaces.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me006_workspace_permissions.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me007_idp_sync_log.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me008_org_policies.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me009_api_keys.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me010_org_audit_log.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me011_workspace_traceability.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m001_global.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m002_embeddings.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m003_temporal.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m004_graph.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m005_cache.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m006_logs.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m007_terminal_sessions.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m008_queue.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m009_swarm.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m010_task_force.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m011_reminders.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m013_temporal_l2.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m014_nexus_foundation.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/runner.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m001_global.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m002_embeddings.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m003_temporal.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m004_graph.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m005_cache.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m006_logs.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m007_terminal_sessions.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m008_queue.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m009_swarm.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m010_task_force.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m011_reminders.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m012_workspace_metadata.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m013_temporal_l2.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m014_nexus_foundation.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt001_orgs.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt002_org_members.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt003_teams.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt004_team_members.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt005_team_workspaces.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt006_workspace_permissions.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt007_team_audit_log.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt008_workspace_traceability.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema_base.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema_ent.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema_team.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/adr.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/context.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/query.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/velocity.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-001-lancedb-over-vec0.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-002-retry-exponential-backoff.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-003-blake3-deduplication.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-004-async-first-architecture.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-005-model-lineup.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ARCHITECTURE.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/CHANGELOG.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DATABASE.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DEPLOYMENT.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DISTRIBUTIONS.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CHATGPT-DR-mcp-cli-security-testing-distribution.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CHATGPT-DR-web-ui-experience.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-ai-agents-teams.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-competitive-landscape-market-analysis.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-core-architecture.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-mvp-phase0-technical-plan.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-strategic-briefing.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-graph-implementation.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-hybrid-retrieval-local-optimization.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-infrastructure-security.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-lance-specs.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-nexus-graph-architecture.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-nexus-graph-engineering.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-vec0-vs-lancedb.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GRAPH_LAYER_OPEN_QUESTIONS_RESOLVED.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/KIMI-DR-tech-stack-optimization.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-L2-temporal.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-client-integration.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-indexing-optimisation.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-lancedb-implementation.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-local-data-infrastructure.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-mcp-config.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-mcp-security-hardening.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-models-pipelines.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-python-async-ai-pipelines.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-semantic-indexing.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/FRONTEND.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/GITHUB.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/INTEGRATIONS.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/MCP_TOOLS.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/MEMORY.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/PROJECT_MANAGEMENT.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/PROJECT_PHASES.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/RESOURCES.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ROADMAP.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/SECURITY.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/TEAMS.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/TECHNICAL_SPEC.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/TESTING.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/VERSION.MD +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/pytest.ini +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/README.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/conftest.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/fixtures/__init__.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/fixtures/sample_code.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/fixtures/sample_docs.md +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_accuracy.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_architecture.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_async.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_behaviour.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_cache_stats.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_cli.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_flow.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_git.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_graph_resolution_order.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_incremental.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_latency.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_mcp.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_mcp_hardening.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_observability.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_performance.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_query_cache_roundtrip.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_retrieval.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_retry.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_security.py +0 -0
- {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_storage.py +0 -0
|
@@ -47,6 +47,15 @@ async def index(
|
|
|
47
47
|
"-f",
|
|
48
48
|
help="Force full re-index even if already up-to-date",
|
|
49
49
|
),
|
|
50
|
+
bootstrap_cochange: bool = typer.Option(
|
|
51
|
+
False,
|
|
52
|
+
"--bootstrap-cochange",
|
|
53
|
+
help=(
|
|
54
|
+
"Walk up to 2000 git commits to pre-populate entity_commits for "
|
|
55
|
+
"co-change analysis. Only effective with --force. Commits touching "
|
|
56
|
+
">50 files are excluded as noise."
|
|
57
|
+
),
|
|
58
|
+
),
|
|
50
59
|
ctx: str | None = typer.Option(None, hidden=True),
|
|
51
60
|
) -> None:
|
|
52
61
|
"""Index codebase for semantic search."""
|
|
@@ -151,6 +160,7 @@ async def index(
|
|
|
151
160
|
context=cli_ctx.request_context,
|
|
152
161
|
force=force,
|
|
153
162
|
incremental=incremental,
|
|
163
|
+
bootstrap_cochange=bootstrap_cochange,
|
|
154
164
|
on_discovery=_on_discovery,
|
|
155
165
|
on_file_chunked=_on_file_chunked,
|
|
156
166
|
on_batch_embedded=_on_batch_embedded,
|
{contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/initialisation.py
RENAMED
|
@@ -531,6 +531,28 @@ async def run_workspace_init(workspace_root: Path) -> None:
|
|
|
531
531
|
|
|
532
532
|
await _register_workspace_globally(global_conn, workspace_id, workspace_root, logger)
|
|
533
533
|
|
|
534
|
+
# Also register in workspaces.json for multi-workspace MCP support.
|
|
535
|
+
# Non-fatal: the DB registration above is authoritative for init; the
|
|
536
|
+
# registry entry is a convenience that `contextual workspace add` can
|
|
537
|
+
# replicate if this fails.
|
|
538
|
+
try:
|
|
539
|
+
from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
|
|
540
|
+
|
|
541
|
+
try:
|
|
542
|
+
WORKSPACE_REGISTRY.add_workspace(workspace_root.name, workspace_root)
|
|
543
|
+
logger.info(
|
|
544
|
+
"workspace_registry_json_added",
|
|
545
|
+
name=workspace_root.name,
|
|
546
|
+
path=str(workspace_root),
|
|
547
|
+
)
|
|
548
|
+
except ValueError:
|
|
549
|
+
logger.debug(
|
|
550
|
+
"workspace_registry_json_already_registered",
|
|
551
|
+
name=workspace_root.name,
|
|
552
|
+
)
|
|
553
|
+
except Exception as exc:
|
|
554
|
+
logger.warning("workspace_registry_json_add_failed", error=str(exc))
|
|
555
|
+
|
|
534
556
|
try:
|
|
535
557
|
if not (
|
|
536
558
|
config_path.exists()
|
|
@@ -22,7 +22,6 @@ from contextual.security.sanitize import sql_str_literal
|
|
|
22
22
|
@require_config
|
|
23
23
|
@require_index
|
|
24
24
|
async def stats(
|
|
25
|
-
path: str = typer.Option(".", "--path", "-p", help="Repository path"),
|
|
26
25
|
temporal: bool = typer.Option(False, "--temporal", "-t", help="Show temporal stats"),
|
|
27
26
|
graph: bool = typer.Option(False, "--graph", "-g", help="Show graph stats"),
|
|
28
27
|
show_all: bool = typer.Option(False, "--all", "-a", help="Show all stats"),
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Workspace management commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from contextual.cli.core import register_command
|
|
11
|
+
from contextual.cli.core.output import print_error, print_workspace_list
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@register_command(group="workspace", name="list")
|
|
15
|
+
async def workspace_list() -> None:
|
|
16
|
+
"""List all registered workspaces."""
|
|
17
|
+
from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
|
|
18
|
+
|
|
19
|
+
ws_map = WORKSPACE_REGISTRY.load_registered_workspaces()
|
|
20
|
+
if not ws_map:
|
|
21
|
+
print_workspace_list([])
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
workspaces = []
|
|
25
|
+
for name, path_str in ws_map.items():
|
|
26
|
+
path = Path(path_str)
|
|
27
|
+
workspace_id = ""
|
|
28
|
+
last_indexed_at = "never"
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
state_file = path / ".contextual" / "state.json"
|
|
32
|
+
if state_file.exists():
|
|
33
|
+
state_data = json.loads(state_file.read_text(encoding="utf-8"))
|
|
34
|
+
last_indexed_at = state_data.get("last_indexed_at", "never")
|
|
35
|
+
except Exception:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
from contextual.indexing._config import load_runtime_config
|
|
40
|
+
|
|
41
|
+
cfg = load_runtime_config(path)
|
|
42
|
+
workspace_id = str(cfg.workspace_id)
|
|
43
|
+
except Exception:
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
workspaces.append({
|
|
47
|
+
"path": f"{name} {path_str}",
|
|
48
|
+
"workspace_id": workspace_id,
|
|
49
|
+
"last_indexed_at": last_indexed_at,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
print_workspace_list(workspaces)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@register_command(group="workspace", name="add")
|
|
56
|
+
async def workspace_add(
|
|
57
|
+
path: str = typer.Argument(..., help="Absolute path to the workspace root"),
|
|
58
|
+
name: str = typer.Option(
|
|
59
|
+
None,
|
|
60
|
+
"--name",
|
|
61
|
+
"-n",
|
|
62
|
+
help="Human-readable workspace name (defaults to directory basename)",
|
|
63
|
+
),
|
|
64
|
+
) -> None:
|
|
65
|
+
"""Register a workspace in the multi-workspace registry."""
|
|
66
|
+
from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
|
|
67
|
+
|
|
68
|
+
resolved = Path(path).expanduser().resolve()
|
|
69
|
+
ws_name = name or resolved.name
|
|
70
|
+
if not ws_name:
|
|
71
|
+
print_error("Could not derive a workspace name.", hint="Use --name <name>")
|
|
72
|
+
raise typer.Exit(1)
|
|
73
|
+
|
|
74
|
+
try:
|
|
75
|
+
WORKSPACE_REGISTRY.add_workspace(ws_name, resolved)
|
|
76
|
+
typer.echo(f"Registered workspace '{ws_name}' at {resolved}")
|
|
77
|
+
except ValueError as exc:
|
|
78
|
+
print_error(str(exc))
|
|
79
|
+
raise typer.Exit(1) from exc
|
|
80
|
+
except Exception as exc:
|
|
81
|
+
print_error(f"Failed to register workspace: {exc}")
|
|
82
|
+
raise typer.Exit(1) from exc
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@register_command(group="workspace", name="remove")
|
|
86
|
+
async def workspace_remove(
|
|
87
|
+
name: str = typer.Argument(..., help="Workspace name to deregister"),
|
|
88
|
+
) -> None:
|
|
89
|
+
"""Remove a workspace from the multi-workspace registry."""
|
|
90
|
+
from contextual.mcp.workspace_registry import WORKSPACE_REGISTRY
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
WORKSPACE_REGISTRY.remove_workspace(name)
|
|
94
|
+
typer.echo(f"Removed workspace '{name}'")
|
|
95
|
+
except KeyError as exc:
|
|
96
|
+
print_error(str(exc))
|
|
97
|
+
raise typer.Exit(1) from exc
|
|
98
|
+
except Exception as exc:
|
|
99
|
+
print_error(f"Failed to remove workspace: {exc}")
|
|
100
|
+
raise typer.Exit(1) from exc
|
|
@@ -50,6 +50,15 @@ class DaemonConfig(BaseModel):
|
|
|
50
50
|
compaction_interval_hours: float = 6.0 # How often the background loop runs (0 disables)
|
|
51
51
|
compaction_retention_hours: float = 1.0 # Prune versions older than this; never 0 (breaks concurrent writes)
|
|
52
52
|
|
|
53
|
+
# Heap / memory trimmer
|
|
54
|
+
# When the daemon's physical footprint exceeds heap_trim_threshold_mb a
|
|
55
|
+
# hard trim fires (GC + malloc page return). If the footprint is still over
|
|
56
|
+
# the threshold on the next tick and no sessions are active, models are
|
|
57
|
+
# offloaded to CPU to recover MPS/GPU pages. Set to 0 to disable.
|
|
58
|
+
heap_monitor_enabled: bool = True
|
|
59
|
+
heap_monitor_interval_seconds: int = 30
|
|
60
|
+
heap_trim_threshold_mb: int = 2500
|
|
61
|
+
|
|
53
62
|
# Logging
|
|
54
63
|
log_level: str = "INFO"
|
|
55
64
|
|
|
@@ -113,7 +113,7 @@ class SearchConfig(BaseModel):
|
|
|
113
113
|
le=200,
|
|
114
114
|
description="Number of candidates retrieved before reranking.",
|
|
115
115
|
)
|
|
116
|
-
enable_reranker: bool = Field(default=
|
|
116
|
+
enable_reranker: bool = Field(default=False) # 124x latency overhead with no accuracy gain on MPS
|
|
117
117
|
rerank_top_k: int = Field(
|
|
118
118
|
default=10,
|
|
119
119
|
ge=5,
|
|
@@ -149,12 +149,10 @@ class RetrievalConfig:
|
|
|
149
149
|
bm25_candidates: int = 100
|
|
150
150
|
dense_candidates: int = 100
|
|
151
151
|
rrf_candidates: int = 50
|
|
152
|
-
bm25_k1: float = 1.2
|
|
153
|
-
bm25_b: float = 0.3
|
|
154
152
|
rrf_k: int = 60
|
|
155
153
|
rrf_dense_weight: float = 0.6
|
|
156
154
|
rrf_bm25_weight: float = 0.4
|
|
157
|
-
reranker_enabled: bool =
|
|
155
|
+
reranker_enabled: bool = False # 124x latency overhead with no accuracy gain on MPS
|
|
158
156
|
reranker_top_n: int = 15
|
|
159
157
|
reranker_max_chunk_chars: int = 2000
|
|
160
158
|
mmr_enabled: bool = True
|
|
@@ -195,8 +193,6 @@ class RetrievalConfig:
|
|
|
195
193
|
retrieval_data.get("dense_candidates", defaults.dense_candidates)
|
|
196
194
|
),
|
|
197
195
|
rrf_candidates=int(retrieval_data.get("rrf_candidates", defaults.rrf_candidates)),
|
|
198
|
-
bm25_k1=float(retrieval_data.get("bm25_k1", defaults.bm25_k1)),
|
|
199
|
-
bm25_b=float(retrieval_data.get("bm25_b", defaults.bm25_b)),
|
|
200
196
|
rrf_k=int(retrieval_data.get("rrf_k", defaults.rrf_k)),
|
|
201
197
|
rrf_dense_weight=float(
|
|
202
198
|
retrieval_data.get("rrf_dense_weight", defaults.rrf_dense_weight)
|
|
@@ -316,12 +312,10 @@ class RuntimeIndexingConfig:
|
|
|
316
312
|
|
|
317
313
|
@dataclass(slots=True)
|
|
318
314
|
class RuntimeRetrievalConfig:
|
|
319
|
-
bm25_k1: float = 1.2
|
|
320
|
-
bm25_b: float = 0.3
|
|
321
315
|
rrf_k: int = 60
|
|
322
316
|
rrf_dense_weight: float = 0.6
|
|
323
317
|
rrf_bm25_weight: float = 0.4
|
|
324
|
-
reranker_enabled: bool =
|
|
318
|
+
reranker_enabled: bool = False # 124x latency overhead with no accuracy gain on MPS
|
|
325
319
|
reranker_top_n: int = 15
|
|
326
320
|
mmr_lambda: float = 0.7
|
|
327
321
|
mmr_max_chunks_per_file: int = 2
|
|
@@ -393,12 +387,10 @@ class ConfigLoader:
|
|
|
393
387
|
"workers": 8,
|
|
394
388
|
},
|
|
395
389
|
"retrieval": {
|
|
396
|
-
"bm25_k1": 1.2,
|
|
397
|
-
"bm25_b": 0.3,
|
|
398
390
|
"rrf_k": 60,
|
|
399
391
|
"rrf_dense_weight": 0.6,
|
|
400
392
|
"rrf_bm25_weight": 0.4,
|
|
401
|
-
"reranker_enabled":
|
|
393
|
+
"reranker_enabled": False, # 124x latency overhead with no accuracy gain on MPS
|
|
402
394
|
"reranker_top_n": 15,
|
|
403
395
|
"mmr_lambda": 0.7,
|
|
404
396
|
"mmr_max_chunks_per_file": 2,
|
|
@@ -437,10 +429,6 @@ class ConfigLoader:
|
|
|
437
429
|
env_overrides["indexing"]["chunk_overlap"] = int(value)
|
|
438
430
|
if value := os.getenv("CONTEXTUAL_MAX_FILE_SIZE_KB"):
|
|
439
431
|
env_overrides["indexing"]["max_file_size_kb"] = int(value)
|
|
440
|
-
if value := os.getenv("CONTEXTUAL_BM25_K1"):
|
|
441
|
-
env_overrides["retrieval"]["bm25_k1"] = float(value)
|
|
442
|
-
if value := os.getenv("CONTEXTUAL_BM25_B"):
|
|
443
|
-
env_overrides["retrieval"]["bm25_b"] = float(value)
|
|
444
432
|
if value := os.getenv("CONTEXTUAL_RRF_K"):
|
|
445
433
|
env_overrides["retrieval"]["rrf_k"] = int(value)
|
|
446
434
|
if value := os.getenv("CONTEXTUAL_RRF_DENSE_WEIGHT"):
|
|
@@ -43,6 +43,7 @@ DAEMON_LOCK = CONTEXTUAL_HOME / "daemon.lock"
|
|
|
43
43
|
DAEMON_LOG = CONTEXTUAL_HOME / "daemon.log"
|
|
44
44
|
VERSION_FILE = CONTEXTUAL_HOME / ".version"
|
|
45
45
|
MCP_CONFIG_FILE = CONTEXTUAL_HOME / "mcp.json"
|
|
46
|
+
WORKSPACES_JSON_PATH = CONTEXTUAL_HOME / "workspaces.json"
|
|
46
47
|
LOG_DIR = Path.home() / ".local" / "state" / "contextual" / "logs"
|
|
47
48
|
|
|
48
49
|
# Canonical per-model weight directories. `contextual fetch` downloads into
|
|
@@ -98,7 +98,14 @@ class FactSource(StrEnum):
|
|
|
98
98
|
class Language(StrEnum):
|
|
99
99
|
"""Supported programming languages for indexing.
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Each value MUST equal the tree-sitter language name used by
|
|
102
|
+
``contextual.indexing.chunker.LANGUAGE_MAP`` (the string handed to
|
|
103
|
+
``tree_sitter_language_pack.get_parser``). The chunker maps a file
|
|
104
|
+
extension to that name; ``_build_chunk`` then does ``Language(name)``.
|
|
105
|
+
Any name present in ``LANGUAGE_MAP`` but absent here silently casts to
|
|
106
|
+
``Language.PYTHON`` — mislabelling the chunk and breaking language
|
|
107
|
+
filtering. Keep the two in lockstep. ``c_sharp`` is the sole divergence
|
|
108
|
+
(enum value ``csharp``) and is bridged by ``chunker._TS_TO_LANG``.
|
|
102
109
|
"""
|
|
103
110
|
|
|
104
111
|
PYTHON = "python"
|
|
@@ -109,12 +116,53 @@ class Language(StrEnum):
|
|
|
109
116
|
JAVA = "java"
|
|
110
117
|
RUST = "rust"
|
|
111
118
|
CSHARP = "csharp"
|
|
119
|
+
# C family
|
|
120
|
+
C = "c"
|
|
121
|
+
CPP = "cpp"
|
|
122
|
+
# JVM / mobile
|
|
123
|
+
KOTLIN = "kotlin"
|
|
124
|
+
SWIFT = "swift"
|
|
125
|
+
SCALA = "scala"
|
|
126
|
+
DART = "dart"
|
|
127
|
+
# Scripting
|
|
128
|
+
RUBY = "ruby"
|
|
129
|
+
PHP = "php"
|
|
130
|
+
LUA = "lua"
|
|
131
|
+
PERL = "perl"
|
|
132
|
+
R = "r"
|
|
133
|
+
BASH = "bash"
|
|
134
|
+
# Functional / emerging
|
|
135
|
+
HASKELL = "haskell"
|
|
136
|
+
ELIXIR = "elixir"
|
|
112
137
|
# Config formats (free wins)
|
|
113
138
|
JSON = "json"
|
|
114
139
|
YAML = "yaml"
|
|
115
140
|
TOML = "toml"
|
|
116
141
|
MARKDOWN = "markdown"
|
|
117
142
|
DOCKERFILE = "dockerfile"
|
|
143
|
+
# Data / schema / infra
|
|
144
|
+
SQL = "sql"
|
|
145
|
+
HCL = "hcl"
|
|
146
|
+
PROTO = "proto"
|
|
147
|
+
# Web frontend
|
|
148
|
+
HTML = "html"
|
|
149
|
+
CSS = "css"
|
|
150
|
+
SCSS = "scss"
|
|
151
|
+
# JVM / enterprise
|
|
152
|
+
GROOVY = "groovy"
|
|
153
|
+
# Systems / emerging
|
|
154
|
+
NIM = "nim"
|
|
155
|
+
ZIG = "zig"
|
|
156
|
+
V = "v"
|
|
157
|
+
# Functional
|
|
158
|
+
ELM = "elm"
|
|
159
|
+
OCAML = "ocaml"
|
|
160
|
+
ERLANG = "erlang"
|
|
161
|
+
# Scientific
|
|
162
|
+
JULIA = "julia"
|
|
163
|
+
# Platform / Web3
|
|
164
|
+
OBJC = "objc"
|
|
165
|
+
SOLIDITY = "solidity"
|
|
118
166
|
|
|
119
167
|
|
|
120
168
|
class ModelType(StrEnum):
|
|
@@ -202,6 +202,7 @@ class GitIntegration:
|
|
|
202
202
|
return []
|
|
203
203
|
|
|
204
204
|
entries: list[BlameEntry] = []
|
|
205
|
+
current_line = 1
|
|
205
206
|
for (commit, tree_entry), content in blamed:
|
|
206
207
|
try:
|
|
207
208
|
text = content.decode("utf-8", errors="replace")
|
|
@@ -232,11 +233,12 @@ class GitIntegration:
|
|
|
232
233
|
timestamp=datetime.fromtimestamp(commit.commit_time, tz=UTC),
|
|
233
234
|
commit_sha=commit.id.decode("ascii"),
|
|
234
235
|
commit_message=commit_message,
|
|
235
|
-
line_start=
|
|
236
|
-
line_end=line_count,
|
|
236
|
+
line_start=current_line,
|
|
237
|
+
line_end=current_line + line_count - 1,
|
|
237
238
|
path=tree_entry.path.decode("utf-8", errors="replace"),
|
|
238
239
|
)
|
|
239
240
|
)
|
|
241
|
+
current_line += line_count
|
|
240
242
|
|
|
241
243
|
return entries
|
|
242
244
|
|
|
@@ -281,6 +283,67 @@ def get_git_integration(repo_path: Path | str) -> GitIntegration:
|
|
|
281
283
|
return integration
|
|
282
284
|
|
|
283
285
|
|
|
286
|
+
async def walk_commit_history(
|
|
287
|
+
repo_root: Path,
|
|
288
|
+
max_commits: int = 2000,
|
|
289
|
+
max_files_per_commit: int = 50,
|
|
290
|
+
) -> list[dict]:
|
|
291
|
+
"""Walk git commit history, returning per-commit file change sets.
|
|
292
|
+
|
|
293
|
+
Commits touching more than ``max_files_per_commit`` files are excluded —
|
|
294
|
+
bulk operations (vendor drops, mass-renames) add noise to co-change coupling
|
|
295
|
+
and inflate pair counts across the entire repo.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
repo_root: Absolute path to the repository root.
|
|
299
|
+
max_commits: Maximum commits to inspect (most recent first).
|
|
300
|
+
max_files_per_commit: Commits with more changed files are skipped.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
List of ``{commit_hash, timestamp, author, files_changed}`` dicts,
|
|
304
|
+
ordered most-recent first.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
def _walk_sync() -> list[dict]:
|
|
308
|
+
try:
|
|
309
|
+
import pygit2 # type: ignore[import-untyped]
|
|
310
|
+
except ImportError:
|
|
311
|
+
return []
|
|
312
|
+
try:
|
|
313
|
+
repo = pygit2.Repository(str(repo_root))
|
|
314
|
+
head_target = repo.head.target
|
|
315
|
+
except Exception:
|
|
316
|
+
return []
|
|
317
|
+
|
|
318
|
+
results: list[dict] = []
|
|
319
|
+
count = 0
|
|
320
|
+
for commit in repo.walk(head_target, pygit2.GIT_SORT_TIME):
|
|
321
|
+
if count >= max_commits:
|
|
322
|
+
break
|
|
323
|
+
count += 1
|
|
324
|
+
try:
|
|
325
|
+
if commit.parents:
|
|
326
|
+
diff = repo.diff(commit.parents[0], commit)
|
|
327
|
+
else:
|
|
328
|
+
diff = commit.tree.diff_to_tree()
|
|
329
|
+
files = {d.new_file.path for d in diff.deltas if d.new_file.path}
|
|
330
|
+
if len(files) > max_files_per_commit:
|
|
331
|
+
continue
|
|
332
|
+
results.append(
|
|
333
|
+
{
|
|
334
|
+
"commit_hash": str(commit.id),
|
|
335
|
+
"timestamp": datetime.fromtimestamp(commit.commit_time, tz=UTC),
|
|
336
|
+
"author": commit.author.name,
|
|
337
|
+
"files_changed": sorted(files),
|
|
338
|
+
}
|
|
339
|
+
)
|
|
340
|
+
except Exception:
|
|
341
|
+
continue
|
|
342
|
+
return results
|
|
343
|
+
|
|
344
|
+
return await asyncio.to_thread(_walk_sync)
|
|
345
|
+
|
|
346
|
+
|
|
284
347
|
import atexit
|
|
285
348
|
|
|
286
349
|
|