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.
Files changed (274) hide show
  1. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/PKG-INFO +1 -1
  2. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/index.py +10 -0
  3. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/initialisation.py +22 -0
  4. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/mcp.py +1 -1
  5. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/stats.py +0 -1
  6. contextual_engine-0.9.5/contextual/cli/commands/workspace.py +100 -0
  7. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/mcp_config.py +9 -0
  8. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/indexing.py +4 -16
  9. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/paths.py +1 -0
  10. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/retrieval_config.py +0 -2
  11. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/core/models.py +49 -1
  12. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/incremental_git.py +65 -2
  13. contextual_engine-0.9.5/contextual/graph/extractor.py +1246 -0
  14. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/integrator.py +29 -2
  15. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/resolver.py +137 -8
  16. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/traversal.py +9 -0
  17. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/file_watcher.py +31 -0
  18. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/incremental_indexer.py +8 -0
  19. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/__init__.py +2 -0
  20. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/_config.py +0 -4
  21. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/chunker.py +105 -6
  22. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/pipeline.py +351 -107
  23. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/symbol_extractor.py +42 -1
  24. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/__init__.py +1 -1
  25. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/access.py +14 -0
  26. contextual_engine-0.9.5/contextual/mcp/memory_monitor.py +294 -0
  27. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/audit.py +1 -1
  28. contextual_engine-0.9.5/contextual/mcp/middleware/identity.py +185 -0
  29. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/workspace.py +13 -23
  30. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/server.py +129 -24
  31. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/session_manager.py +46 -107
  32. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/shim.py +135 -58
  33. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/__init__.py +284 -1
  34. contextual_engine-0.9.5/contextual/mcp/tools/_gcf.py +279 -0
  35. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/graph.py +208 -21
  36. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/nexus.py +74 -16
  37. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/semantic.py +165 -30
  38. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/system.py +150 -10
  39. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/tools/temporal.py +23 -13
  40. contextual_engine-0.9.5/contextual/mcp/workspace_registry.py +410 -0
  41. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/__init__.py +5 -3
  42. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/pipeline.py +32 -7
  43. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/__init__.py +20 -2
  44. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/blame_pipeline.py +2 -2
  45. contextual_engine-0.9.5/docs/ADRs/ADR-006-remove-bm25-k1-b-dead-config.md +92 -0
  46. contextual_engine-0.9.5/docs/DRs/GEMINI-DR-analysis-extraction.md +319 -0
  47. contextual_engine-0.9.5/docs/DRs/GEMINI_DR_extraction-optimisation.md +158 -0
  48. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/pyproject.toml +1 -1
  49. contextual_engine-0.9.5/scripts/mcp_stress_test.py +482 -0
  50. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_graph.py +68 -0
  51. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_indexing.py +48 -0
  52. contextual_engine-0.9.2/contextual/cli/commands/workspace.py +0 -53
  53. contextual_engine-0.9.2/contextual/graph/extractor.py +0 -571
  54. contextual_engine-0.9.2/contextual/mcp/middleware/identity.py +0 -65
  55. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.contextualignore +0 -0
  56. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.cursor/rules/contextual.mdc +0 -0
  57. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.github/workflows/ci.yml +0 -0
  58. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.github/workflows/release.yml +0 -0
  59. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.gitignore +0 -0
  60. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/.mcp.json +0 -0
  61. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/LICENSE +0 -0
  62. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/README.md +0 -0
  63. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/__init__.py +0 -0
  64. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/__main__.py +0 -0
  65. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/__init__.py +0 -0
  66. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/__init__.py +0 -0
  67. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/auth.py +0 -0
  68. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/client.py +0 -0
  69. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/config.py +0 -0
  70. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/doctor.py +0 -0
  71. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/fetch.py +0 -0
  72. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/commands/install.py +0 -0
  73. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/__init__.py +0 -0
  74. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/context.py +0 -0
  75. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/decorators.py +0 -0
  76. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/editor.py +0 -0
  77. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/cli/core/output.py +0 -0
  78. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/__init__.py +0 -0
  79. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/base.py +0 -0
  80. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/__init__.py +0 -0
  81. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/security_config.py +0 -0
  82. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/global_/storage_config.py +0 -0
  83. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/__init__.py +0 -0
  84. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/cache_config.py +0 -0
  85. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/indexing_config.py +0 -0
  86. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/observability_config.py +0 -0
  87. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/config/workspace/workspace_config.py +0 -0
  88. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/core/__init__.py +0 -0
  89. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/core/errors.py +0 -0
  90. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/__init__.py +0 -0
  91. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/blame.py +0 -0
  92. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/git/hooks.py +0 -0
  93. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/__init__.py +0 -0
  94. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/dedup.py +0 -0
  95. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/staleness.py +0 -0
  96. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/graph/store.py +0 -0
  97. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/__init__.py +0 -0
  98. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/incremental/daemon_embed.py +0 -0
  99. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/_ignore.py +0 -0
  100. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/docs_pipeline.py +0 -0
  101. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/index_writer.py +0 -0
  102. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/merkle_tree.py +0 -0
  103. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/indexing/processor.py +0 -0
  104. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/integrations/__init__.py +0 -0
  105. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/integrations/client_content.py +0 -0
  106. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/integrations/client_writer.py +0 -0
  107. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/__main__.py +0 -0
  108. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/_platform.py +0 -0
  109. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/bootstrap.py +0 -0
  110. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/config.py +0 -0
  111. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/daemon.py +0 -0
  112. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/__init__.py +0 -0
  113. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/auth.py +0 -0
  114. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/ratelimit.py +0 -0
  115. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/middleware/warmup.py +0 -0
  116. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/mcp/router.py +0 -0
  117. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/__init__.py +0 -0
  118. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/_inference.py +0 -0
  119. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/allowlist.py +0 -0
  120. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/base_embedder.py +0 -0
  121. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/reranker_model.py +0 -0
  122. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/models/unified_embedder.py +0 -0
  123. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/__init__.py +0 -0
  124. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/config.py +0 -0
  125. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/exporters.py +0 -0
  126. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/logging.py +0 -0
  127. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/retention.py +0 -0
  128. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/observability/tracer.py +0 -0
  129. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/context_assembler.py +0 -0
  130. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/mmr.py +0 -0
  131. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/ranker.py +0 -0
  132. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/retrieval/tokenizer.py +0 -0
  133. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/__init__.py +0 -0
  134. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/paths.py +0 -0
  135. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/sanitize.py +0 -0
  136. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/security/workspace.py +0 -0
  137. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/cache.py +0 -0
  138. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/connection.py +0 -0
  139. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/fts.py +0 -0
  140. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/lancedb_provider.py +0 -0
  141. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/__init__.py +0 -0
  142. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me001_orgs.py +0 -0
  143. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me002_org_members.py +0 -0
  144. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me003_teams.py +0 -0
  145. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me004_team_members.py +0 -0
  146. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me005_org_workspaces.py +0 -0
  147. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me006_workspace_permissions.py +0 -0
  148. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me007_idp_sync_log.py +0 -0
  149. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me008_org_policies.py +0 -0
  150. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me009_api_keys.py +0 -0
  151. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me010_org_audit_log.py +0 -0
  152. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/enterprise/me011_workspace_traceability.py +0 -0
  153. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m001_global.py +0 -0
  154. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m002_embeddings.py +0 -0
  155. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m003_temporal.py +0 -0
  156. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m004_graph.py +0 -0
  157. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m005_cache.py +0 -0
  158. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m006_logs.py +0 -0
  159. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m007_terminal_sessions.py +0 -0
  160. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m008_queue.py +0 -0
  161. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m009_swarm.py +0 -0
  162. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m010_task_force.py +0 -0
  163. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m011_reminders.py +0 -0
  164. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m013_temporal_l2.py +0 -0
  165. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/m014_nexus_foundation.py +0 -0
  166. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/runner.py +0 -0
  167. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m001_global.py +0 -0
  168. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m002_embeddings.py +0 -0
  169. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m003_temporal.py +0 -0
  170. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m004_graph.py +0 -0
  171. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m005_cache.py +0 -0
  172. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m006_logs.py +0 -0
  173. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m007_terminal_sessions.py +0 -0
  174. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m008_queue.py +0 -0
  175. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m009_swarm.py +0 -0
  176. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m010_task_force.py +0 -0
  177. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m011_reminders.py +0 -0
  178. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m012_workspace_metadata.py +0 -0
  179. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m013_temporal_l2.py +0 -0
  180. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/solo/m014_nexus_foundation.py +0 -0
  181. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt001_orgs.py +0 -0
  182. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt002_org_members.py +0 -0
  183. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt003_teams.py +0 -0
  184. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt004_team_members.py +0 -0
  185. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt005_team_workspaces.py +0 -0
  186. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt006_workspace_permissions.py +0 -0
  187. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt007_team_audit_log.py +0 -0
  188. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/migrations/teams/mt008_workspace_traceability.py +0 -0
  189. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema.py +0 -0
  190. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema_base.py +0 -0
  191. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema_ent.py +0 -0
  192. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/storage/schema_team.py +0 -0
  193. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/__init__.py +0 -0
  194. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/adr.py +0 -0
  195. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/context.py +0 -0
  196. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/query.py +0 -0
  197. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/contextual/temporal/velocity.py +0 -0
  198. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-001-lancedb-over-vec0.md +0 -0
  199. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-002-retry-exponential-backoff.md +0 -0
  200. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-003-blake3-deduplication.md +0 -0
  201. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-004-async-first-architecture.md +0 -0
  202. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ADRs/ADR-005-model-lineup.md +0 -0
  203. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ARCHITECTURE.md +0 -0
  204. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/CHANGELOG.md +0 -0
  205. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DATABASE.md +0 -0
  206. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DEPLOYMENT.md +0 -0
  207. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DISTRIBUTIONS.md +0 -0
  208. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CHATGPT-DR-mcp-cli-security-testing-distribution.md +0 -0
  209. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CHATGPT-DR-web-ui-experience.md +0 -0
  210. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-ai-agents-teams.md +0 -0
  211. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-competitive-landscape-market-analysis.md +0 -0
  212. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-core-architecture.md +0 -0
  213. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-mvp-phase0-technical-plan.md +0 -0
  214. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/CLAUDE-DR-strategic-briefing.md +0 -0
  215. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-graph-implementation.md +0 -0
  216. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-hybrid-retrieval-local-optimization.md +0 -0
  217. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-infrastructure-security.md +0 -0
  218. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-lance-specs.md +0 -0
  219. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-nexus-graph-architecture.md +0 -0
  220. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-nexus-graph-engineering.md +0 -0
  221. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GEMINI-DR-vec0-vs-lancedb.md +0 -0
  222. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/GRAPH_LAYER_OPEN_QUESTIONS_RESOLVED.md +0 -0
  223. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/KIMI-DR-tech-stack-optimization.md +0 -0
  224. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-L2-temporal.md +0 -0
  225. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-client-integration.md +0 -0
  226. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-indexing-optimisation.md +0 -0
  227. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-lancedb-implementation.md +0 -0
  228. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-local-data-infrastructure.md +0 -0
  229. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-mcp-config.md +0 -0
  230. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-mcp-security-hardening.md +0 -0
  231. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-models-pipelines.md +0 -0
  232. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-python-async-ai-pipelines.md +0 -0
  233. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/DRs/PERPLEXITY-DR-semantic-indexing.md +0 -0
  234. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/FRONTEND.md +0 -0
  235. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/GITHUB.md +0 -0
  236. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/INTEGRATIONS.md +0 -0
  237. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/MCP_TOOLS.md +0 -0
  238. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/MEMORY.md +0 -0
  239. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/PROJECT_MANAGEMENT.md +0 -0
  240. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/PROJECT_PHASES.md +0 -0
  241. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/RESOURCES.md +0 -0
  242. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/ROADMAP.md +0 -0
  243. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/SECURITY.md +0 -0
  244. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/TEAMS.md +0 -0
  245. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/TECHNICAL_SPEC.md +0 -0
  246. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/TESTING.md +0 -0
  247. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/docs/VERSION.MD +0 -0
  248. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/pytest.ini +0 -0
  249. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/README.md +0 -0
  250. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/__init__.py +0 -0
  251. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/conftest.py +0 -0
  252. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/fixtures/__init__.py +0 -0
  253. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/fixtures/sample_code.py +0 -0
  254. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/fixtures/sample_docs.md +0 -0
  255. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_accuracy.py +0 -0
  256. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_architecture.py +0 -0
  257. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_async.py +0 -0
  258. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_behaviour.py +0 -0
  259. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_cache_stats.py +0 -0
  260. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_cli.py +0 -0
  261. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_flow.py +0 -0
  262. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_git.py +0 -0
  263. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_graph_resolution_order.py +0 -0
  264. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_incremental.py +0 -0
  265. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_latency.py +0 -0
  266. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_mcp.py +0 -0
  267. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_mcp_hardening.py +0 -0
  268. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_observability.py +0 -0
  269. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_performance.py +0 -0
  270. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_query_cache_roundtrip.py +0 -0
  271. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_retrieval.py +0 -0
  272. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_retry.py +0 -0
  273. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_security.py +0 -0
  274. {contextual_engine-0.9.2 → contextual_engine-0.9.5}/tests/test_storage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: contextual-engine
3
- Version: 0.9.2
3
+ Version: 0.9.5
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
@@ -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,
@@ -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()
@@ -144,7 +144,7 @@ def mcp_logs(
144
144
  console.print(line, highlight=False, end="")
145
145
  except Exception as e:
146
146
  print_error(f"Failed to read logs: {e}")
147
- return
147
+ raise typer.Exit(1)
148
148
 
149
149
  if follow:
150
150
  try:
@@ -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=True)
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 = True
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 = True
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": True,
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
@@ -6,8 +6,6 @@ from pydantic import BaseModel
6
6
  class BM25Config(BaseModel):
7
7
  """BM25 retrieval settings."""
8
8
 
9
- k1: float = 1.2
10
- b: float = 0.3
11
9
  top_k: int = 100
12
10
 
13
11
 
@@ -98,7 +98,14 @@ class FactSource(StrEnum):
98
98
  class Language(StrEnum):
99
99
  """Supported programming languages for indexing.
100
100
 
101
- Week 1 MVP: Python, TypeScript, JavaScript, Go, Java, Rust, C#
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=1,
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