contextual-engine 0.9.4__tar.gz → 0.9.6__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.4 → contextual_engine-0.9.6}/.gitignore +4 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/PKG-INFO +7 -11
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/doctor.py +4 -9
- contextual_engine-0.9.6/contextual/cli/commands/fetch.py +158 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/index.py +10 -5
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/initialisation.py +22 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/install.py +1 -2
- contextual_engine-0.9.6/contextual/cli/commands/workspace.py +100 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/__init__.py +0 -2
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/base.py +1 -1
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/mcp_config.py +15 -7
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/indexing.py +15 -69
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/paths.py +19 -17
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/__init__.py +0 -2
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/retrieval_config.py +0 -10
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/core/errors.py +1 -2
- contextual_engine-0.9.6/contextual/core/memory.py +46 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/incremental_git.py +65 -2
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/extractor.py +521 -10
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/integrator.py +4 -2
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/resolver.py +127 -8
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/traversal.py +9 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/daemon_embed.py +6 -5
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/file_watcher.py +2 -30
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/incremental_indexer.py +132 -7
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/__init__.py +2 -37
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/_config.py +0 -9
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/index_writer.py +2 -1
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/pipeline.py +427 -121
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/processor.py +0 -86
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/__init__.py +1 -1
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/__main__.py +6 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/memory_monitor.py +4 -25
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/audit.py +1 -1
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/auth.py +0 -2
- contextual_engine-0.9.6/contextual/mcp/middleware/identity.py +185 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/ratelimit.py +9 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/warmup.py +3 -3
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/workspace.py +24 -23
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/router.py +12 -6
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/server.py +73 -88
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/session_manager.py +80 -163
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/shim.py +222 -88
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/__init__.py +284 -1
- contextual_engine-0.9.6/contextual/mcp/tools/_gcf.py +279 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/graph.py +251 -24
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/nexus.py +69 -10
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/semantic.py +194 -31
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/system.py +153 -22
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/tools/temporal.py +22 -12
- contextual_engine-0.9.6/contextual/mcp/workspace_registry.py +410 -0
- contextual_engine-0.9.6/contextual/models/__init__.py +353 -0
- contextual_engine-0.9.6/contextual/models/_inference.py +15 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/models/allowlist.py +2 -3
- contextual_engine-0.9.6/contextual/models/base_embedder.py +23 -0
- contextual_engine-0.9.6/contextual/models/unified_embedder.py +353 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/__init__.py +3 -24
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/mmr.py +1 -46
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/pipeline.py +271 -137
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/ranker.py +2 -34
- contextual_engine-0.9.6/contextual/retrieval/structural_similarity.py +150 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/__init__.py +20 -2
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/connection.py +11 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/fts.py +38 -1
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/lancedb_provider.py +84 -16
- contextual_engine-0.9.6/contextual/storage/migrations/m015_symbol_ngram.py +1 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/runner.py +18 -1
- contextual_engine-0.9.6/contextual/storage/migrations/solo/m015_symbol_ngram.py +154 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema.py +15 -4
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/blame_pipeline.py +11 -84
- contextual_engine-0.9.6/docs/ADRs/ADR-006-remove-bm25-k1-b-dead-config.md +92 -0
- contextual_engine-0.9.6/docs/DRs/GEMINI-DR-analysis-extraction.md +319 -0
- contextual_engine-0.9.6/docs/DRs/GEMINI_DR_extraction-optimisation.md +158 -0
- contextual_engine-0.9.6/docs/SECURITY.md +116 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/pyproject.toml +12 -14
- contextual_engine-0.9.6/scripts/benchmark_golden.json +56 -0
- contextual_engine-0.9.6/scripts/run_benchmark.py +161 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/conftest.py +0 -15
- contextual_engine-0.9.6/tests/test_accuracy.py +90 -0
- contextual_engine-0.9.6/tests/test_async.py +121 -0
- contextual_engine-0.9.6/tests/test_mcp.py +155 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_retrieval.py +8 -54
- contextual_engine-0.9.6/tests/test_security.py +153 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_storage.py +171 -0
- contextual_engine-0.9.4/.cursor/rules/contextual.mdc +0 -87
- contextual_engine-0.9.4/contextual/cli/commands/fetch.py +0 -221
- contextual_engine-0.9.4/contextual/cli/commands/workspace.py +0 -53
- contextual_engine-0.9.4/contextual/mcp/middleware/identity.py +0 -65
- contextual_engine-0.9.4/contextual/models/__init__.py +0 -575
- contextual_engine-0.9.4/contextual/models/_inference.py +0 -21
- contextual_engine-0.9.4/contextual/models/base_embedder.py +0 -72
- contextual_engine-0.9.4/contextual/models/reranker_model.py +0 -386
- contextual_engine-0.9.4/contextual/models/unified_embedder.py +0 -429
- contextual_engine-0.9.4/docs/SECURITY.md +0 -0
- contextual_engine-0.9.4/pytest.ini +0 -80
- contextual_engine-0.9.4/tests/test_accuracy.py +0 -23
- contextual_engine-0.9.4/tests/test_async.py +0 -23
- contextual_engine-0.9.4/tests/test_mcp.py +0 -33
- contextual_engine-0.9.4/tests/test_security.py +0 -23
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.contextualignore +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.github/workflows/ci.yml +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.github/workflows/release.yml +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/.mcp.json +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/LICENSE +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/README.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/__main__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/auth.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/client.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/mcp.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/commands/stats.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/context.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/decorators.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/editor.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/cli/core/output.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/security_config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/global_/storage_config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/cache_config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/indexing_config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/observability_config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/config/workspace/workspace_config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/core/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/core/models.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/blame.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/git/hooks.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/dedup.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/staleness.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/graph/store.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/incremental/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/_ignore.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/chunker.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/docs_pipeline.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/merkle_tree.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/indexing/symbol_extractor.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/integrations/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/integrations/client_content.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/integrations/client_writer.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/_platform.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/access.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/bootstrap.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/daemon.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/mcp/middleware/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/config.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/exporters.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/logging.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/retention.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/observability/tracer.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/context_assembler.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/retrieval/tokenizer.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/paths.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/sanitize.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/security/workspace.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/cache.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me001_orgs.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me002_org_members.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me003_teams.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me004_team_members.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me005_org_workspaces.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me006_workspace_permissions.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me007_idp_sync_log.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me008_org_policies.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me009_api_keys.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me010_org_audit_log.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me011_workspace_traceability.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m001_global.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m002_embeddings.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m003_temporal.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m004_graph.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m005_cache.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m006_logs.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m007_terminal_sessions.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m008_queue.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m009_swarm.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m010_task_force.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m011_reminders.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m013_temporal_l2.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/m014_nexus_foundation.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m001_global.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m002_embeddings.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m003_temporal.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m004_graph.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m005_cache.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m006_logs.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m007_terminal_sessions.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m008_queue.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m009_swarm.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m010_task_force.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m011_reminders.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m012_workspace_metadata.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m013_temporal_l2.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m014_nexus_foundation.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt001_orgs.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt002_org_members.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt003_teams.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt004_team_members.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt005_team_workspaces.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt006_workspace_permissions.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt007_team_audit_log.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt008_workspace_traceability.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema_base.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema_ent.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/storage/schema_team.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/adr.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/context.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/query.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/contextual/temporal/velocity.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-001-lancedb-over-vec0.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-002-retry-exponential-backoff.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-003-blake3-deduplication.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-004-async-first-architecture.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ADRs/ADR-005-model-lineup.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ARCHITECTURE.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/CHANGELOG.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DATABASE.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DEPLOYMENT.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DISTRIBUTIONS.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-mcp-cli-security-testing-distribution.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-web-ui-experience.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-ai-agents-teams.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-competitive-landscape-market-analysis.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-core-architecture.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-mvp-phase0-technical-plan.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-strategic-briefing.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-graph-implementation.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-hybrid-retrieval-local-optimization.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-infrastructure-security.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-lance-specs.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-architecture.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-engineering.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-vec0-vs-lancedb.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/GRAPH_LAYER_OPEN_QUESTIONS_RESOLVED.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/KIMI-DR-tech-stack-optimization.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-L2-temporal.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-client-integration.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-indexing-optimisation.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-lancedb-implementation.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-local-data-infrastructure.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-config.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-security-hardening.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-models-pipelines.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-python-async-ai-pipelines.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-semantic-indexing.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/FRONTEND.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/GITHUB.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/INTEGRATIONS.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/MCP_TOOLS.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/MEMORY.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/PROJECT_MANAGEMENT.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/PROJECT_PHASES.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/RESOURCES.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/ROADMAP.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/TEAMS.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/TECHNICAL_SPEC.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/TESTING.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/docs/VERSION.MD +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/scripts/mcp_stress_test.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/README.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/fixtures/__init__.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/fixtures/sample_code.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/fixtures/sample_docs.md +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_architecture.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_behaviour.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_cache_stats.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_cli.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_flow.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_git.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_graph.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_graph_resolution_order.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_incremental.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_indexing.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_latency.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_mcp_hardening.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_observability.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_performance.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_query_cache_roundtrip.py +0 -0
- {contextual_engine-0.9.4 → contextual_engine-0.9.6}/tests/test_retry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: contextual-engine
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.6
|
|
4
4
|
Summary: Temporal-first local code memory for AI tools via MCP
|
|
5
5
|
Project-URL: Homepage, https://contextuallabs.dev
|
|
6
6
|
Project-URL: Documentation, https://contextuallabs.dev/docs
|
|
@@ -125,16 +125,19 @@ Classifier: Environment :: Console
|
|
|
125
125
|
Classifier: Intended Audience :: Developers
|
|
126
126
|
Classifier: License :: Other/Proprietary License
|
|
127
127
|
Classifier: Operating System :: OS Independent
|
|
128
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
128
129
|
Classifier: Programming Language :: Python :: 3.12
|
|
129
130
|
Classifier: Programming Language :: Python :: 3.13
|
|
131
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
130
132
|
Classifier: Topic :: Software Development :: Libraries
|
|
131
133
|
Classifier: Topic :: Text Processing :: Indexing
|
|
132
134
|
Classifier: Typing :: Typed
|
|
133
|
-
Requires-Python: <3.
|
|
135
|
+
Requires-Python: <3.15,>=3.11
|
|
134
136
|
Requires-Dist: blake3>=0.4.1
|
|
137
|
+
Requires-Dist: datasketch>=1.6.4
|
|
135
138
|
Requires-Dist: docutils>=0.21
|
|
136
139
|
Requires-Dist: dulwich>=0.21
|
|
137
|
-
Requires-Dist:
|
|
140
|
+
Requires-Dist: fastembed>=0.4.2
|
|
138
141
|
Requires-Dist: fastmcp<4,>=3.2
|
|
139
142
|
Requires-Dist: httpx[http2]>=0.27.0
|
|
140
143
|
Requires-Dist: huggingface-hub>=0.23
|
|
@@ -153,8 +156,7 @@ Requires-Dist: pygit2>=1.15
|
|
|
153
156
|
Requires-Dist: python-frontmatter
|
|
154
157
|
Requires-Dist: rapidfuzz>=3
|
|
155
158
|
Requires-Dist: rich>=13.0
|
|
156
|
-
Requires-Dist:
|
|
157
|
-
Requires-Dist: sentence-transformers>=3.0
|
|
159
|
+
Requires-Dist: setproctitle>=1.3.0
|
|
158
160
|
Requires-Dist: simsimd<6,>=3.9
|
|
159
161
|
Requires-Dist: sqlglot>=20.0
|
|
160
162
|
Requires-Dist: starlette>=0.37
|
|
@@ -162,10 +164,7 @@ Requires-Dist: structlog>=25.4
|
|
|
162
164
|
Requires-Dist: tantivy>=0.20.1
|
|
163
165
|
Requires-Dist: tenacity>=8.0
|
|
164
166
|
Requires-Dist: tiktoken>=0.5
|
|
165
|
-
Requires-Dist: tokenizers<=0.23.0,>=0.19
|
|
166
167
|
Requires-Dist: tomli-w>=1.0.0
|
|
167
|
-
Requires-Dist: torch>=2.2
|
|
168
|
-
Requires-Dist: transformers<4.60,>=4.40
|
|
169
168
|
Requires-Dist: tree-sitter-language-pack>=0.7.2
|
|
170
169
|
Requires-Dist: typer<1.0,>=0.9
|
|
171
170
|
Requires-Dist: uvicorn>=0.27
|
|
@@ -178,9 +177,6 @@ Requires-Dist: build>=1.0; extra == 'dev'
|
|
|
178
177
|
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
179
178
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
180
179
|
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
181
|
-
Provides-Extra: mps
|
|
182
|
-
Requires-Dist: torch>=2.4.0; extra == 'mps'
|
|
183
|
-
Requires-Dist: torchvision>=0.19.0; extra == 'mps'
|
|
184
180
|
Provides-Extra: test
|
|
185
181
|
Requires-Dist: anyio[trio]>=4.3.0; extra == 'test'
|
|
186
182
|
Requires-Dist: freezegun>=1.5.0; extra == 'test'
|
|
@@ -14,7 +14,6 @@ from contextual.config.paths import (
|
|
|
14
14
|
LOG_DIR,
|
|
15
15
|
MODELS_DIR,
|
|
16
16
|
embed_model_present,
|
|
17
|
-
rerank_model_present,
|
|
18
17
|
workspace_config,
|
|
19
18
|
workspace_db,
|
|
20
19
|
workspace_logs,
|
|
@@ -85,14 +84,10 @@ async def doctor(
|
|
|
85
84
|
# 3. Models Check — check the actual weight dirs, not MODELS_DIR (which
|
|
86
85
|
# always contains cache/ after setup and would false-positive before fetch).
|
|
87
86
|
embed_ok = embed_model_present()
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
elif embed_ok and not rerank_ok:
|
|
93
|
-
model_detail = "Embed weights present. Reranker missing — run 'contextual fetch --rerank'."
|
|
94
|
-
else:
|
|
95
|
-
model_detail = "Embed weights missing or empty. Run 'contextual fetch'."
|
|
87
|
+
models_ok = embed_ok
|
|
88
|
+
model_detail = (
|
|
89
|
+
"Embed weights present." if embed_ok else "Embed weights missing. Run 'contextual fetch'."
|
|
90
|
+
)
|
|
96
91
|
checks.append(HealthCheck(name="Models", status=models_ok, detail=model_detail))
|
|
97
92
|
|
|
98
93
|
# 4. Daemon & Locks Check
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Global model fetch command for Contextual.
|
|
2
|
+
|
|
3
|
+
Downloads the fastembed/ONNX embedding model into ~/.contextual/models/
|
|
4
|
+
(the canonical global model directory) using fastembed's cache_dir parameter.
|
|
5
|
+
After download, computes and stores a BLAKE3 hash pin for integrity verification
|
|
6
|
+
on every subsequent model load.
|
|
7
|
+
|
|
8
|
+
The old sentence-transformers download path is fully removed.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
|
|
15
|
+
import structlog
|
|
16
|
+
import typer
|
|
17
|
+
|
|
18
|
+
from contextual.cli.core.decorators import register_command, require_config
|
|
19
|
+
from contextual.cli.core.output import (
|
|
20
|
+
model_download_progress,
|
|
21
|
+
print_error,
|
|
22
|
+
print_fetch_complete,
|
|
23
|
+
print_fetch_start,
|
|
24
|
+
)
|
|
25
|
+
from contextual.config.paths import GLOBAL_CONFIG, MODELS_DIR, ONNX_PIN_FILE, VERSION_FILE
|
|
26
|
+
from contextual.models.unified_embedder import _FASTEMBED_MODEL, _find_onnx_model_path
|
|
27
|
+
|
|
28
|
+
_EMBED_FRIENDLY = "Nomic Embed v1.5-Q (ONNX/fastembed)"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FetchError(Exception):
|
|
32
|
+
"""Raised when a global model fetch cannot complete."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, message: str, step: str | None = None, recoverable: bool = False) -> None:
|
|
35
|
+
super().__init__(message)
|
|
36
|
+
self.step = step
|
|
37
|
+
self.recoverable = recoverable
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _is_fastembed_model_cached() -> bool:
|
|
41
|
+
"""Return True if the ONNX model already exists in ~/.contextual/models/."""
|
|
42
|
+
onnx_path = _find_onnx_model_path(MODELS_DIR)
|
|
43
|
+
return onnx_path is not None and onnx_path.exists()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _verify_setup() -> None:
|
|
47
|
+
from contextual import __version__ as current_version
|
|
48
|
+
|
|
49
|
+
if not VERSION_FILE.exists():
|
|
50
|
+
print_error(
|
|
51
|
+
"Global setup not found.",
|
|
52
|
+
hint="Run: contextual setup",
|
|
53
|
+
)
|
|
54
|
+
raise typer.Exit(1)
|
|
55
|
+
|
|
56
|
+
if not GLOBAL_CONFIG.exists():
|
|
57
|
+
print_error(
|
|
58
|
+
"Global config missing.",
|
|
59
|
+
hint="Run: contextual setup",
|
|
60
|
+
)
|
|
61
|
+
raise typer.Exit(1)
|
|
62
|
+
|
|
63
|
+
installed = VERSION_FILE.read_text(encoding="utf-8").strip()
|
|
64
|
+
if installed != current_version:
|
|
65
|
+
print_error(
|
|
66
|
+
f"Version mismatch: installed={installed}, current={current_version}.",
|
|
67
|
+
hint="Run: contextual setup to upgrade.",
|
|
68
|
+
)
|
|
69
|
+
raise typer.Exit(1)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def download_embed_model() -> None:
|
|
73
|
+
"""Download the fastembed ONNX model into ~/.contextual/models/ and pin its hash."""
|
|
74
|
+
logger = structlog.get_logger()
|
|
75
|
+
|
|
76
|
+
with model_download_progress(_FASTEMBED_MODEL, size_hint="~130MB"):
|
|
77
|
+
try:
|
|
78
|
+
def _load() -> None:
|
|
79
|
+
from fastembed import TextEmbedding
|
|
80
|
+
MODELS_DIR.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
# cache_dir routes fastembed to store weights under ~/.contextual/models/
|
|
82
|
+
# using HuggingFace Hub directory layout.
|
|
83
|
+
model = TextEmbedding(
|
|
84
|
+
model_name=_FASTEMBED_MODEL,
|
|
85
|
+
threads=1,
|
|
86
|
+
cache_dir=str(MODELS_DIR),
|
|
87
|
+
)
|
|
88
|
+
# One inference pass — verifies the ONNX session loads correctly.
|
|
89
|
+
list(model.embed(["warmup"], batch_size=1))
|
|
90
|
+
|
|
91
|
+
await asyncio.to_thread(_load)
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
raise FetchError(
|
|
94
|
+
f"Failed to download fastembed model: {exc}", step="embed"
|
|
95
|
+
) from exc
|
|
96
|
+
|
|
97
|
+
# Pin the BLAKE3 hash of the ONNX file so _load_model() can verify integrity
|
|
98
|
+
# on every subsequent load without re-downloading.
|
|
99
|
+
try:
|
|
100
|
+
import blake3 as _blake3
|
|
101
|
+
|
|
102
|
+
onnx_path = _find_onnx_model_path(MODELS_DIR)
|
|
103
|
+
if onnx_path and onnx_path.exists():
|
|
104
|
+
pin = _blake3.blake3(onnx_path.read_bytes()).hexdigest()
|
|
105
|
+
ONNX_PIN_FILE.write_text(pin, encoding="utf-8")
|
|
106
|
+
logger.info(
|
|
107
|
+
"onnx_pin_written",
|
|
108
|
+
hash_prefix=pin[:16],
|
|
109
|
+
onnx_path=str(onnx_path),
|
|
110
|
+
)
|
|
111
|
+
else:
|
|
112
|
+
logger.warning("onnx_pin_skipped", reason="model_file_not_found_after_download")
|
|
113
|
+
except Exception as exc:
|
|
114
|
+
logger.warning("onnx_pin_write_failed", error=str(exc))
|
|
115
|
+
|
|
116
|
+
logger.info("fastembed_model_ready", model=_FASTEMBED_MODEL, cache_dir=str(MODELS_DIR))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@register_command()
|
|
120
|
+
@require_config
|
|
121
|
+
def fetch(
|
|
122
|
+
embed: bool = typer.Option(False, "--embed", help="Download the Nomic embed model (ONNX)."),
|
|
123
|
+
all_: bool = typer.Option(False, "--all", help="Download all models (default)."),
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Pre-download fastembed ONNX model weights into ~/.contextual/models/.
|
|
126
|
+
|
|
127
|
+
Model is stored in the global Contextual directory alongside the LanceDB
|
|
128
|
+
index and daemon config. Running this before the first `contextual index`
|
|
129
|
+
avoids an inline download during indexing and pins the BLAKE3 integrity hash.
|
|
130
|
+
"""
|
|
131
|
+
_verify_setup()
|
|
132
|
+
|
|
133
|
+
print_fetch_start([_EMBED_FRIENDLY])
|
|
134
|
+
|
|
135
|
+
downloaded: list[str] = []
|
|
136
|
+
already_present: list[str] = []
|
|
137
|
+
|
|
138
|
+
if _is_fastembed_model_cached():
|
|
139
|
+
already_present.append(_EMBED_FRIENDLY)
|
|
140
|
+
# Re-pin even if cached — updates stale or missing pin file.
|
|
141
|
+
try:
|
|
142
|
+
import blake3 as _blake3
|
|
143
|
+
|
|
144
|
+
onnx_path = _find_onnx_model_path(MODELS_DIR)
|
|
145
|
+
if onnx_path and onnx_path.exists():
|
|
146
|
+
pin = _blake3.blake3(onnx_path.read_bytes()).hexdigest()
|
|
147
|
+
ONNX_PIN_FILE.write_text(pin, encoding="utf-8")
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
else:
|
|
151
|
+
try:
|
|
152
|
+
asyncio.run(download_embed_model())
|
|
153
|
+
downloaded.append(_EMBED_FRIENDLY)
|
|
154
|
+
except FetchError as exc:
|
|
155
|
+
print_error(str(exc), hint="contextual fetch --embed")
|
|
156
|
+
raise typer.Exit(1) from exc
|
|
157
|
+
|
|
158
|
+
print_fetch_complete(downloaded, already_present)
|
|
@@ -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."""
|
|
@@ -86,16 +95,11 @@ async def index(
|
|
|
86
95
|
try:
|
|
87
96
|
with index_progress() as prog:
|
|
88
97
|
try:
|
|
89
|
-
# Suppress BLAKE3 pin warning during model load — pins are not
|
|
90
|
-
# registered until `contextual fetch` is run with a real model.
|
|
91
|
-
# The warning fires during SentenceTransformer.__init__, before
|
|
92
|
-
# the outer warnings.simplefilter("ignore") wrapper takes effect.
|
|
93
98
|
warnings.filterwarnings(
|
|
94
99
|
"ignore",
|
|
95
100
|
message=".*No BLAKE3 hash pins.*",
|
|
96
101
|
category=UserWarning,
|
|
97
102
|
)
|
|
98
|
-
# Reranker is search-only — never load at index time (~1.2GB saved).
|
|
99
103
|
await ensure_models_warm(models=["code", "docs"])
|
|
100
104
|
|
|
101
105
|
chunking_started = False
|
|
@@ -151,6 +155,7 @@ async def index(
|
|
|
151
155
|
context=cli_ctx.request_context,
|
|
152
156
|
force=force,
|
|
153
157
|
incremental=incremental,
|
|
158
|
+
bootstrap_cochange=bootstrap_cochange,
|
|
154
159
|
on_discovery=_on_discovery,
|
|
155
160
|
on_file_chunked=_on_file_chunked,
|
|
156
161
|
on_batch_embedded=_on_batch_embedded,
|
{contextual_engine-0.9.4 → contextual_engine-0.9.6}/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()
|
|
@@ -103,8 +103,7 @@ def _write_default_config() -> None:
|
|
|
103
103
|
'tier = "free"\n\n'
|
|
104
104
|
"[models]\n"
|
|
105
105
|
'embed_model = "nomic-ai/nomic-embed-text-v1.5"\n'
|
|
106
|
-
|
|
107
|
-
f'models_dir = "{MODELS_DIR}"\n'
|
|
106
|
+
f'models_dir = "{MODELS_DIR}"\n'
|
|
108
107
|
f'cache_dir = "{MODELS_CACHE_DIR}"\n\n'
|
|
109
108
|
"[storage]\n"
|
|
110
109
|
f'global_db_path = "{GLOBAL_DB_DIR}"\n'
|
|
@@ -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
|
|
@@ -19,7 +19,6 @@ from contextual.config.workspace.retrieval_config import (
|
|
|
19
19
|
BM25Config,
|
|
20
20
|
DenseConfig,
|
|
21
21
|
MMRConfig,
|
|
22
|
-
RerankerConfig,
|
|
23
22
|
RetrievalConfig,
|
|
24
23
|
)
|
|
25
24
|
from contextual.config.workspace.workspace_config import WorkspaceConfig
|
|
@@ -109,7 +108,6 @@ __all__ = [
|
|
|
109
108
|
"MMRConfig",
|
|
110
109
|
"ObservabilityConfig",
|
|
111
110
|
"PipelineConfig",
|
|
112
|
-
"RerankerConfig",
|
|
113
111
|
"RetrievalConfig",
|
|
114
112
|
"SecurityConfig",
|
|
115
113
|
"StorageConfig",
|
|
@@ -25,7 +25,7 @@ class ContextualConfig(BaseModel):
|
|
|
25
25
|
project_root: Absolute path to the project being indexed.
|
|
26
26
|
indexing: Indexing configuration for code and workspace files.
|
|
27
27
|
embedding: Embedding model configuration.
|
|
28
|
-
retrieval: Retrieval configuration for search
|
|
28
|
+
retrieval: Retrieval configuration for search (RRF fusion + MMR).
|
|
29
29
|
storage: Storage configuration for database and index paths.
|
|
30
30
|
security: Security configuration for filesystem and workspace policy.
|
|
31
31
|
"""
|
|
@@ -34,10 +34,16 @@ class DaemonConfig(BaseModel):
|
|
|
34
34
|
port: int = 9091 # must match _platform.WINDOWS_PORT/TCP_PORT
|
|
35
35
|
|
|
36
36
|
# Lifecycle
|
|
37
|
-
idle_sleep_minutes:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
# idle_sleep_minutes: minutes of no incoming MCP requests before the daemon
|
|
38
|
+
# unloads the ONNX model and enters sleep state. Active shim connections
|
|
39
|
+
# (idle SSE sessions) do NOT prevent this — only actual HTTP requests reset
|
|
40
|
+
# the clock. die_after_sleep_hours: hours asleep before a clean SIGTERM
|
|
41
|
+
# exit. Total inactivity before full exit = idle_sleep_minutes +
|
|
42
|
+
# die_after_sleep_hours * 60. Set die_after_sleep_hours = 0 to never exit.
|
|
43
|
+
idle_sleep_minutes: int = 30 # Minutes of no requests before sleeping
|
|
44
|
+
die_after_sleep_hours: float = 1.0 # Hours asleep before clean exit (0 = never)
|
|
45
|
+
startup_timeout: float = 15.0 # Seconds to wait for the daemon to start serving
|
|
46
|
+
# (ONNX model loads in ~2-5s from ~/.contextual/models/)
|
|
41
47
|
|
|
42
48
|
# Rate limiting
|
|
43
49
|
rate_limit_per_minute: int = 120 # Max tool calls per minute per client
|
|
@@ -53,11 +59,13 @@ class DaemonConfig(BaseModel):
|
|
|
53
59
|
# Heap / memory trimmer
|
|
54
60
|
# When the daemon's physical footprint exceeds heap_trim_threshold_mb a
|
|
55
61
|
# 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,
|
|
57
|
-
#
|
|
62
|
+
# the threshold on the next tick and no sessions are active, the ONNX model
|
|
63
|
+
# session is unloaded (freed from memory). Set to 0 to disable.
|
|
64
|
+
# 1500 MB accounts for: ONNX session (~130 MB) + LanceDB PyArrow buffers
|
|
65
|
+
# (~400-800 MB active) + graph/cache overhead — triggers before OOM pressure.
|
|
58
66
|
heap_monitor_enabled: bool = True
|
|
59
67
|
heap_monitor_interval_seconds: int = 30
|
|
60
|
-
heap_trim_threshold_mb: int =
|
|
68
|
+
heap_trim_threshold_mb: int = 1500
|
|
61
69
|
|
|
62
70
|
# Logging
|
|
63
71
|
log_level: str = "INFO"
|