code-context-control 2.101.0__tar.gz → 2.109.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. {code_context_control-2.101.0/code_context_control.egg-info → code_context_control-2.109.0}/PKG-INFO +3 -1
  2. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/c3.py +103 -26
  3. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/commands/common.py +26 -3
  4. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/commands/parser.py +24 -1
  5. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_access_guard.py +106 -9
  6. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_dispatch.py +91 -1
  7. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_pretool_enforce.py +24 -5
  8. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/mcp_server.py +20 -5
  9. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/_grants.py +26 -9
  10. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/artifacts.py +33 -2
  11. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/federate.py +6 -3
  12. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/override.py +15 -5
  13. code_context_control-2.109.0/cli/tools/search.py +659 -0
  14. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/shell.py +82 -1
  15. {code_context_control-2.101.0 → code_context_control-2.109.0/code_context_control.egg-info}/PKG-INFO +3 -1
  16. {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/SOURCES.txt +13 -0
  17. {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/requires.txt +3 -0
  18. {code_context_control-2.101.0 → code_context_control-2.109.0}/pyproject.toml +7 -1
  19. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/access_guard.py +41 -5
  20. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/artifact_store.py +36 -9
  21. code_context_control-2.109.0/services/bench/search_eval.py +708 -0
  22. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/claude_md.py +22 -2
  23. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/embedding_index.py +129 -4
  24. code_context_control-2.109.0/services/index_store.py +366 -0
  25. code_context_control-2.109.0/services/indexer.py +1387 -0
  26. code_context_control-2.109.0/services/lexical_index.py +245 -0
  27. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_grants.py +20 -9
  28. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/parser.py +27 -1
  29. code_context_control-2.109.0/services/reranker.py +126 -0
  30. code_context_control-2.109.0/services/retrieval.py +58 -0
  31. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/runtime.py +16 -0
  32. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/session_manager.py +18 -0
  33. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/subprojects.py +12 -1
  34. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/watcher.py +14 -2
  35. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_artifact_tool.py +41 -4
  36. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_confirm_guard.py +46 -6
  37. code_context_control-2.109.0/tests/test_confirm_guard_wiring.py +482 -0
  38. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cooccurrence_bounds.py +3 -1
  39. code_context_control-2.109.0/tests/test_ide_workflow_adaptation.py +235 -0
  40. code_context_control-2.109.0/tests/test_index_cap_not_hardcoded.py +131 -0
  41. code_context_control-2.109.0/tests/test_search_eval.py +162 -0
  42. code_context_control-2.109.0/tests/test_search_p1.py +276 -0
  43. code_context_control-2.109.0/tests/test_search_p2.py +296 -0
  44. code_context_control-2.109.0/tests/test_search_p2b.py +244 -0
  45. code_context_control-2.109.0/tests/test_search_p3.py +358 -0
  46. code_context_control-2.109.0/tests/test_search_p4.py +200 -0
  47. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/index_view.py +13 -4
  48. code_context_control-2.101.0/cli/tools/search.py +0 -417
  49. code_context_control-2.101.0/services/indexer.py +0 -845
  50. code_context_control-2.101.0/tests/test_ide_workflow_adaptation.py +0 -121
  51. {code_context_control-2.101.0 → code_context_control-2.109.0}/LICENSE +0 -0
  52. {code_context_control-2.101.0 → code_context_control-2.109.0}/README.md +0 -0
  53. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/__init__.py +0 -0
  54. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/_hook_utils.py +0 -0
  55. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/_shell_writes.py +0 -0
  56. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/commands/__init__.py +0 -0
  57. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/docs.html +0 -0
  58. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/edits.html +0 -0
  59. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/access.html +0 -0
  60. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/bitbucket.html +0 -0
  61. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/credentials.html +0 -0
  62. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/getting-started.html +0 -0
  63. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/index.html +0 -0
  64. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/masking.html +0 -0
  65. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/oracle.html +0 -0
  66. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/shared.css +0 -0
  67. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/tools.html +0 -0
  68. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/guide/workflow.html +0 -0
  69. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_artifact.py +0 -0
  70. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_auto_snapshot.py +0 -0
  71. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_c3_signal.py +0 -0
  72. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_c3read.py +0 -0
  73. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_edit_ledger.py +0 -0
  74. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_edit_unlock.py +0 -0
  75. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_filter.py +0 -0
  76. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_ghost_files.py +0 -0
  77. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_prompt_recall.py +0 -0
  78. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_read.py +0 -0
  79. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_session_stats.py +0 -0
  80. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hook_terse_advisor.py +0 -0
  81. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_server.py +0 -0
  82. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/app.js +0 -0
  83. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/add_project.js +0 -0
  84. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/config_editor.js +0 -0
  85. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  86. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_health.js +0 -0
  87. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_panel.js +0 -0
  88. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  89. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  90. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/drill_views.js +0 -0
  91. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/global_search.js +0 -0
  92. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_access.js +0 -0
  93. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_ci.js +0 -0
  94. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  95. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  96. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  97. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_locks.js +0 -0
  98. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/hub_tokens.js +0 -0
  99. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  100. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/modals.js +0 -0
  101. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/project_card.js +0 -0
  102. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/project_tree.js +0 -0
  103. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/session_drawer.js +0 -0
  104. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/settings_modal.js +0 -0
  105. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/sidebar.js +0 -0
  106. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/summary_bar.js +0 -0
  107. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/task_board.js +0 -0
  108. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/toasts.js +0 -0
  109. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/components/topbar.js +0 -0
  110. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui/state.js +0 -0
  111. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/hub_ui.html +0 -0
  112. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/mcp_proxy.py +0 -0
  113. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/progress.py +0 -0
  114. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/server.py +0 -0
  115. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/__init__.py +0 -0
  116. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/_helpers.py +0 -0
  117. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/agent.py +0 -0
  118. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/bitbucket.py +0 -0
  119. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/ci.py +0 -0
  120. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/compress.py +0 -0
  121. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/credentials.py +0 -0
  122. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/delegate.py +0 -0
  123. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/edit.py +0 -0
  124. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/edit_verify.py +0 -0
  125. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/edits.py +0 -0
  126. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/filter.py +0 -0
  127. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/impact.py +0 -0
  128. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/jira.py +0 -0
  129. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/locks.py +0 -0
  130. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/memory.py +0 -0
  131. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/project.py +0 -0
  132. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/read.py +0 -0
  133. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/session.py +0 -0
  134. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/status.py +0 -0
  135. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/tasks.py +0 -0
  136. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/tools/validate.py +0 -0
  137. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/api.js +0 -0
  138. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/app.js +0 -0
  139. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/access.js +0 -0
  140. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/bitbucket.js +0 -0
  141. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/chat.js +0 -0
  142. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/credentials.js +0 -0
  143. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/dashboard.js +0 -0
  144. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/edits.js +0 -0
  145. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/enforcement.js +0 -0
  146. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/instructions.js +0 -0
  147. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/jira.js +0 -0
  148. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/memory.js +0 -0
  149. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/sessions.js +0 -0
  150. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/settings.js +0 -0
  151. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/sidebar.js +0 -0
  152. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/components/tasks.js +0 -0
  153. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/icons.js +0 -0
  154. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/pm_shared.js +0 -0
  155. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/shared.js +0 -0
  156. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui/theme.js +0 -0
  157. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui.html +0 -0
  158. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui_legacy.html +0 -0
  159. {code_context_control-2.101.0 → code_context_control-2.109.0}/cli/ui_nano.html +0 -0
  160. {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  161. {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/entry_points.txt +0 -0
  162. {code_context_control-2.101.0 → code_context_control-2.109.0}/code_context_control.egg-info/top_level.txt +0 -0
  163. {code_context_control-2.101.0 → code_context_control-2.109.0}/core/__init__.py +0 -0
  164. {code_context_control-2.101.0 → code_context_control-2.109.0}/core/config.py +0 -0
  165. {code_context_control-2.101.0 → code_context_control-2.109.0}/core/ide.py +0 -0
  166. {code_context_control-2.101.0 → code_context_control-2.109.0}/core/mcp_toml.py +0 -0
  167. {code_context_control-2.101.0 → code_context_control-2.109.0}/core/web_security.py +0 -0
  168. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/__init__.py +0 -0
  169. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/config.py +0 -0
  170. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/mcp_oracle.py +0 -0
  171. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/oracle_server.py +0 -0
  172. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/oracle_ui.html +0 -0
  173. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/__init__.py +0 -0
  174. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/activity_reporter.py +0 -0
  175. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/api_auth.py +0 -0
  176. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/c3_bridge.py +0 -0
  177. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/chat_engine.py +0 -0
  178. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/chat_poll.py +0 -0
  179. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/chat_store.py +0 -0
  180. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/cross_memory.py +0 -0
  181. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/discovery_audit.py +0 -0
  182. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/federated_graph.py +0 -0
  183. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/health_checker.py +0 -0
  184. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/insight_engine.py +0 -0
  185. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/local_session.py +0 -0
  186. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/memory_reader.py +0 -0
  187. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/memory_writer.py +0 -0
  188. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/mobile_api.py +0 -0
  189. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/project_scanner.py +0 -0
  190. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/review_agent.py +0 -0
  191. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/tool_executor.py +0 -0
  192. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/services/tool_registry.py +0 -0
  193. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/activity.js +0 -0
  194. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/agents.js +0 -0
  195. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/app.js +0 -0
  196. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/busy.js +0 -0
  197. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/conversations.js +0 -0
  198. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/input.js +0 -0
  199. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/markdown.js +0 -0
  200. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/send.js +0 -0
  201. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/stream_renderer.js +0 -0
  202. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/chat/toolbar.js +0 -0
  203. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/core.js +0 -0
  204. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/crossgraph.js +0 -0
  205. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/header.js +0 -0
  206. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/insights.js +0 -0
  207. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/projects.js +0 -0
  208. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/qrcode.js +0 -0
  209. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/settings.js +0 -0
  210. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/suggestions.js +0 -0
  211. {code_context_control-2.101.0 → code_context_control-2.109.0}/oracle/ui/theme_tabs.js +0 -0
  212. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/__init__.py +0 -0
  213. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/access_telemetry.py +0 -0
  214. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/activity_log.py +0 -0
  215. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/agent_base.py +0 -0
  216. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/agent_locks.py +0 -0
  217. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/agents.py +0 -0
  218. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/artifact_defs.py +0 -0
  219. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/auto_memory.py +0 -0
  220. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/background_service.py +0 -0
  221. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/__init__.py +0 -0
  222. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/external/__init__.py +0 -0
  223. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/external/aider_polyglot.py +0 -0
  224. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bench/external/swe_bench.py +0 -0
  225. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/benchmark_dashboard.py +0 -0
  226. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bitbucket_client.py +0 -0
  227. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/bitbucket_credentials.py +0 -0
  228. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_act.py +0 -0
  229. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_cache.py +0 -0
  230. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_expr.py +0 -0
  231. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_failures.py +0 -0
  232. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_github.py +0 -0
  233. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_impact.py +0 -0
  234. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_intel.py +0 -0
  235. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_runner.py +0 -0
  236. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ci_workflow.py +0 -0
  237. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/circuit_breaker.py +0 -0
  238. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/compressor.py +0 -0
  239. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/context_snapshot.py +0 -0
  240. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/conversation_store.py +0 -0
  241. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/cred_audit.py +0 -0
  242. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/cred_telemetry.py +0 -0
  243. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/credential_store.py +0 -0
  244. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/doc_index.py +0 -0
  245. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/e2e_benchmark.py +0 -0
  246. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/e2e_evaluator.py +0 -0
  247. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/e2e_tasks.py +0 -0
  248. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/edit_ledger.py +0 -0
  249. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/enforcement_policy.py +0 -0
  250. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/error_reporting.py +0 -0
  251. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/file_memory.py +0 -0
  252. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/git_context.py +0 -0
  253. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/hub_service.py +0 -0
  254. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_client.py +0 -0
  255. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_cloud.py +0 -0
  256. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_credentials.py +0 -0
  257. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_data_center.py +0 -0
  258. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/jira_links.py +0 -0
  259. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/mask_activation.py +0 -0
  260. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/mask_mirror.py +0 -0
  261. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/mask_presets.py +0 -0
  262. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory.py +0 -0
  263. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_consolidator.py +0 -0
  264. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_distiller.py +0 -0
  265. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_graph.py +0 -0
  266. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_grounder.py +0 -0
  267. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_queue.py +0 -0
  268. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/memory_scorer.py +0 -0
  269. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/metrics.py +0 -0
  270. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/notifications.py +0 -0
  271. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ollama_bridge.py +0 -0
  272. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ollama_client.py +0 -0
  273. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/ollama_credentials.py +0 -0
  274. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/oracle_service.py +0 -0
  275. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/output_filter.py +0 -0
  276. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_policy.py +0 -0
  277. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_requests.py +0 -0
  278. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/override_wake.py +0 -0
  279. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/project_manager.py +0 -0
  280. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/project_runtime.py +0 -0
  281. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/protocol.py +0 -0
  282. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/proxy_state.py +0 -0
  283. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/repo_map.py +0 -0
  284. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/repo_shape.py +0 -0
  285. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/retention.py +0 -0
  286. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/retrieval_broker.py +0 -0
  287. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/router.py +0 -0
  288. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/scanner.py +0 -0
  289. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/session_benchmark.py +0 -0
  290. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/session_preloader.py +0 -0
  291. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/task_store.py +0 -0
  292. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/telemetry.py +0 -0
  293. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/text_index.py +0 -0
  294. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/time_tracker.py +0 -0
  295. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/tool_classifier.py +0 -0
  296. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/transcript_index.py +0 -0
  297. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/validation_cache.py +0 -0
  298. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/vector_store.py +0 -0
  299. {code_context_control-2.101.0 → code_context_control-2.109.0}/services/win_subprocess.py +0 -0
  300. {code_context_control-2.101.0 → code_context_control-2.109.0}/setup.cfg +0 -0
  301. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_builtin_optout.py +0 -0
  302. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard.py +0 -0
  303. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_meta.py +0 -0
  304. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_shell_project.py +0 -0
  305. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_surfaces.py +0 -0
  306. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_access_guard_wiring.py +0 -0
  307. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_activity_reporter.py +0 -0
  308. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_agent_locks.py +0 -0
  309. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_aider_polyglot.py +0 -0
  310. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_antigravity_transition.py +0 -0
  311. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_artifact_store.py +0 -0
  312. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_background_service.py +0 -0
  313. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  314. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_client.py +0 -0
  315. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_config_fallback.py +0 -0
  316. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_credentials.py +0 -0
  317. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_bitbucket_tool.py +0 -0
  318. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_builtin_modes.py +0 -0
  319. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  320. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_c3_shell.py +0 -0
  321. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_chat_poll.py +0 -0
  322. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_act.py +0 -0
  323. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_cache.py +0 -0
  324. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_expr.py +0 -0
  325. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_impact.py +0 -0
  326. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_intel.py +0 -0
  327. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_runner.py +0 -0
  328. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ci_workflow.py +0 -0
  329. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_circuit_breaker.py +0 -0
  330. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_claude_md_merge.py +0 -0
  331. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cli_smoke.py +0 -0
  332. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_compressor_large_file.py +0 -0
  333. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cred_audit.py +0 -0
  334. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_cred_telemetry.py +0 -0
  335. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credential_login_kind.py +0 -0
  336. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credential_store.py +0 -0
  337. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credential_ui_parity.py +0 -0
  338. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credentials_routes.py +0 -0
  339. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_credentials_tool.py +0 -0
  340. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_creds_cli_smoke.py +0 -0
  341. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_delegate_cascade.py +0 -0
  342. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_delegate_version_probe.py +0 -0
  343. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_e2e_benchmark.py +0 -0
  344. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_ledger_deadline.py +0 -0
  345. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_ledger_hook.py +0 -0
  346. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_locking.py +0 -0
  347. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_normalization.py +0 -0
  348. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_edit_verify.py +0 -0
  349. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_embedding_index_deadlock.py +0 -0
  350. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_enforcement_flip.py +0 -0
  351. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_enforcement_policy.py +0 -0
  352. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_enforcement_routes.py +0 -0
  353. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_env_parser.py +0 -0
  354. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
  355. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_federated_graph.py +0 -0
  356. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_filter_backoff.py +0 -0
  357. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ghost_files.py +0 -0
  358. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ghost_generation.py +0 -0
  359. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_git_branch_awareness.py +0 -0
  360. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_access_guard.py +0 -0
  361. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_codex_compat.py +0 -0
  362. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_dispatch.py +0 -0
  363. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_pretool_enforce.py +0 -0
  364. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_prompt_recall.py +0 -0
  365. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_smoke.py +0 -0
  366. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_state.py +0 -0
  367. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hook_utf8_stdio.py +0 -0
  368. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_credentials_route.py +0 -0
  369. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_credentials_routes_write.py +0 -0
  370. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_enforcement_routes.py +0 -0
  371. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_inspect_api.py +0 -0
  372. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_locks_routes.py +0 -0
  373. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_oracle_service_routes.py +0 -0
  374. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_override_routes.py +0 -0
  375. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_server_smoke.py +0 -0
  376. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_hub_subproject_links.py +0 -0
  377. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_init_clear_preserves_user_content.py +0 -0
  378. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_init_scan.py +0 -0
  379. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_install_mcp_entrypoint.py +0 -0
  380. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_cli_smoke.py +0 -0
  381. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_client.py +0 -0
  382. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_config_fallback.py +0 -0
  383. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_credentials.py +0 -0
  384. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_links.py +0 -0
  385. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_routes.py +0 -0
  386. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_jira_tool.py +0 -0
  387. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_lazy_store_init.py +0 -0
  388. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mask_guard.py +0 -0
  389. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mask_routes.py +0 -0
  390. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mask_surfaces.py +0 -0
  391. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_host_guard.py +0 -0
  392. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_memory_timeout.py +0 -0
  393. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_server_smoke.py +0 -0
  394. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mcp_toml.py +0 -0
  395. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_distiller.py +0 -0
  396. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_graph_api.py +0 -0
  397. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_queue.py +0 -0
  398. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_memory_system.py +0 -0
  399. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_api.py +0 -0
  400. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_extras.py +0 -0
  401. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_override_routes.py +0 -0
  402. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_mobile_security_api.py +0 -0
  403. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_no_stale_model_pins.py +0 -0
  404. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_notification_dedup.py +0 -0
  405. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_notification_discipline.py +0 -0
  406. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ollama_credentials.py +0 -0
  407. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_api_auth.py +0 -0
  408. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_apikey_api.py +0 -0
  409. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_c3_bridge.py +0 -0
  410. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_chat_engine.py +0 -0
  411. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_chat_store.py +0 -0
  412. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_discovery_api.py +0 -0
  413. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_discovery_audit.py +0 -0
  414. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_health_probe.py +0 -0
  415. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_local_auth.py +0 -0
  416. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_ollama_bridge.py +0 -0
  417. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_scanner_cache.py +0 -0
  418. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_security_fixes.py +0 -0
  419. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_session_bootstrap.py +0 -0
  420. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_subproject_awareness.py +0 -0
  421. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_oracle_ui_bundle.py +0 -0
  422. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_output_filter.py +0 -0
  423. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_grants.py +0 -0
  424. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_grants_mcp.py +0 -0
  425. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_requests.py +0 -0
  426. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_override_wake.py +0 -0
  427. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_permissions.py +0 -0
  428. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_pm_api.py +0 -0
  429. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_project_manager.py +0 -0
  430. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_project_manager_merge.py +0 -0
  431. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_project_tool.py +0 -0
  432. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_read_coercion.py +0 -0
  433. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_read_edit_parity.py +0 -0
  434. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_related_facts.py +0 -0
  435. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_repo_map.py +0 -0
  436. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_repo_shape.py +0 -0
  437. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_response_boilerplate.py +0 -0
  438. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_retention.py +0 -0
  439. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_review_digest.py +0 -0
  440. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_service_durability.py +0 -0
  441. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_session_benchmark.py +0 -0
  442. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_session_budget.py +0 -0
  443. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_creds.py +0 -0
  444. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_robustness.py +0 -0
  445. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_write_ledger.py +0 -0
  446. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_shell_writes.py +0 -0
  447. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_clear_scope.py +0 -0
  448. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_depth_consumers.py +0 -0
  449. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_exclusion.py +0 -0
  450. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_federation.py +0 -0
  451. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subproject_linkage_api.py +0 -0
  452. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_subprojects.py +0 -0
  453. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_swe_bench.py +0 -0
  454. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_task_store.py +0 -0
  455. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_task_tool.py +0 -0
  456. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_time_tracker.py +0 -0
  457. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_token_telemetry.py +0 -0
  458. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_token_tracking.py +0 -0
  459. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_tool_registry.py +0 -0
  460. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_ui_jsx_syntax.py +0 -0
  461. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_upgrade_and_version.py +0 -0
  462. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_validate.py +0 -0
  463. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_vault_write_guard.py +0 -0
  464. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_version_sync.py +0 -0
  465. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_web_security.py +0 -0
  466. {code_context_control-2.101.0 → code_context_control-2.109.0}/tests/test_windows_reliability.py +0 -0
  467. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/__init__.py +0 -0
  468. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/backend.py +0 -0
  469. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/main.py +0 -0
  470. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/__init__.py +0 -0
  471. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/benchmark_view.py +0 -0
  472. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/claudemd_view.py +0 -0
  473. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/compress_view.py +0 -0
  474. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/init_view.py +0 -0
  475. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/mcp_view.py +0 -0
  476. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/optimize_view.py +0 -0
  477. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/pipe_view.py +0 -0
  478. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/projects_view.py +0 -0
  479. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/search_view.py +0 -0
  480. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/session_view.py +0 -0
  481. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/stats.py +0 -0
  482. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/screens/ui_view.py +0 -0
  483. {code_context_control-2.101.0 → code_context_control-2.109.0}/tui/theme.tcss +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.101.0
3
+ Version: 2.109.0
4
4
  Summary: Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -47,6 +47,8 @@ Provides-Extra: vector
47
47
  Requires-Dist: scikit-learn>=1.3.0; extra == "vector"
48
48
  Requires-Dist: numpy>=1.24.0; extra == "vector"
49
49
  Requires-Dist: chromadb>=0.4.24; extra == "vector"
50
+ Provides-Extra: rerank
51
+ Requires-Dist: flashrank>=0.2.10; extra == "rerank"
50
52
  Provides-Extra: tui
51
53
  Requires-Dist: textual>=0.50.0; extra == "tui"
52
54
  Provides-Extra: telemetry
@@ -92,7 +92,7 @@ console = Console() if HAS_RICH else None
92
92
  # Config
93
93
  CONFIG_DIR = ".c3"
94
94
  CONFIG_FILE = ".c3/config.json"
95
- __version__ = "2.101.0"
95
+ __version__ = "2.109.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -591,21 +591,21 @@ def _check_c3_health(project_path: str) -> dict:
591
591
  issues.append(f"missing directories: {', '.join(missing_dirs)}")
592
592
  info["missing_dirs"] = missing_dirs
593
593
 
594
- # Index presence and basic stats
595
- index_file = c3_dir / "index" / "index.json"
596
- if not index_file.exists():
597
- issues.append("code index not built")
598
- info["index_files"] = 0
599
- info["index_chunks"] = 0
600
- else:
601
- try:
602
- data = json.loads(index_file.read_text(encoding="utf-8"))
603
- info["index_files"] = len(data.get("documents", {}))
604
- info["index_chunks"] = len(data.get("chunks", {}))
605
- except Exception:
606
- issues.append("code index corrupt")
607
- info["index_files"] = 0
608
- info["index_chunks"] = 0
594
+ # Index presence and basic stats (services/index_store; index.json is
595
+ # the pre-2.107.0 layout and counts as "present, needs a rebuild").
596
+ try:
597
+ from services.index_store import IndexStore
598
+ store = IndexStore(c3_dir / "index")
599
+ n_docs, n_chunks = store.counts()
600
+ except Exception:
601
+ store, n_docs, n_chunks = None, 0, 0
602
+ info["index_files"] = n_docs
603
+ info["index_chunks"] = n_chunks
604
+ if n_docs == 0:
605
+ if (c3_dir / "index" / "index.json").exists():
606
+ issues.append("code index in the pre-2.107.0 layout; run `c3 index` to migrate")
607
+ else:
608
+ issues.append("code index not built")
609
609
 
610
610
  # Stale file changes (tracked by the watcher inside CodeIndex)
611
611
  # The watcher writes pending changes to .c3/index/changes.json
@@ -1500,6 +1500,42 @@ def cmd_stats(args):
1500
1500
  return common_cmd_stats(args, _command_deps())
1501
1501
 
1502
1502
 
1503
+ def cmd_search_eval(args):
1504
+ """Run the c3_search relevance suite and compare it to its baseline.
1505
+
1506
+ Exit status 1 when the baseline is violated (a must_pass case failed, a
1507
+ canary leaked, or an aggregate fell under its floor), so the command can
1508
+ stand in a pre-push gate. See docs/search-eval.md.
1509
+ """
1510
+ from services.bench import search_eval as se
1511
+
1512
+ try:
1513
+ report = se.run_suite(args.suite, repo=args.repo, rebuild=args.rebuild,
1514
+ semantic=args.semantic, baseline=args.baseline,
1515
+ rerank=getattr(args, "rerank", "off"))
1516
+ except FileNotFoundError as e:
1517
+ raise RuntimeError(str(e))
1518
+
1519
+ if args.update_baseline:
1520
+ path = args.baseline or se.BUNDLED_BASELINES.get(report.suite)
1521
+ if not path:
1522
+ raise RuntimeError(
1523
+ f"suite {report.suite!r} has no bundled baseline; pass --baseline PATH")
1524
+ floors = json.loads(args.floors) if args.floors else None
1525
+ se.write_baseline(report, path, floors=floors)
1526
+ # Re-compare so the printed verdict reflects the file just written.
1527
+ report.baseline_violations, report.baseline_warnings = se.compare_to_baseline(
1528
+ report, se.load_baseline(path))
1529
+ print(f"baseline written: {path}")
1530
+
1531
+ if args.json:
1532
+ print(json.dumps(report.to_dict(), indent=2))
1533
+ else:
1534
+ print(report.render())
1535
+ if report.baseline_violations:
1536
+ sys.exit(1)
1537
+
1538
+
1503
1539
  def _benchmark_extract_preview(full_path: Path, compressor: CodeCompressor, pattern: str = "", max_lines: int = 50) -> str:
1504
1540
  """Approximate c3_filter behavior for local benchmarking without MCP startup."""
1505
1541
  import re as _re
@@ -4212,6 +4248,7 @@ def cmd_pipe(args):
4212
4248
 
4213
4249
 
4214
4250
  from services.claude_md import C3_COMPACT_WORKFLOW as _SHARED_C3_COMPACT_WORKFLOW
4251
+ from services.claude_md import VSCODE_INSTRUCTIONS_FILE
4215
4252
  from services.claude_md import VSCODE_SESSION_INIT as _VSCODE_SESSION_INIT
4216
4253
  from services.claude_md import adapt_workflow_for_ide as _adapt_workflow_for_ide
4217
4254
 
@@ -4433,14 +4470,27 @@ def _toml_section_bool_value(toml_path: Path, section: str, key: str) -> bool |
4433
4470
  return None
4434
4471
 
4435
4472
 
4436
- def _ensure_instruction_workflow(instructions_path: Path, template: str, required_markers: list[str]) -> str:
4437
- """Ensure an instructions file has required C3 workflow markers.
4473
+ def _ensure_instruction_workflow(instructions_path: Path, template: str,
4474
+ required_markers: list[str],
4475
+ project_path: str = "") -> str:
4476
+ """Ensure an instructions file carries the CURRENT C3 workflow.
4438
4477
 
4439
4478
  Returns one of: "written", "updated", "kept".
4479
+
4480
+ Marker PRESENCE used to mean "up to date", which is why this function
4481
+ could report `kept` on a doc generated four releases ago: the markers are
4482
+ stable words like "SEARCH FIRST" and "c3_edit", so they survive every
4483
+ template change. A doc carrying the managed sentinels is now refreshed
4484
+ through ``merge_c3_block`` — the same non-destructive regeneration
4485
+ CLAUDE.md and AGENTS.md get — and `kept` means the block already matches
4486
+ byte for byte (v2.102.0). A marker-less legacy doc keeps the old
4487
+ prepend-and-preserve path, which ``write_c3_instruction_doc`` handles.
4440
4488
  """
4489
+ from services.claude_md import C3_BLOCK_BEGIN, merge_c3_block, wrap_c3_block, write_c3_instruction_doc
4490
+
4441
4491
  if not instructions_path.exists():
4442
- instructions_path.parent.mkdir(parents=True, exist_ok=True)
4443
- instructions_path.write_text(template, encoding="utf-8")
4492
+ write_c3_instruction_doc(instructions_path, template,
4493
+ project_path=project_path or None)
4444
4494
  return "written"
4445
4495
 
4446
4496
  try:
@@ -4448,6 +4498,14 @@ def _ensure_instruction_workflow(instructions_path: Path, template: str, require
4448
4498
  except Exception:
4449
4499
  existing = ""
4450
4500
 
4501
+ # Managed doc → regenerate the block in place, preserving user content.
4502
+ if C3_BLOCK_BEGIN in existing:
4503
+ if merge_c3_block(existing, wrap_c3_block(template)) == existing:
4504
+ return "kept"
4505
+ write_c3_instruction_doc(instructions_path, template,
4506
+ project_path=project_path or None)
4507
+ return "updated"
4508
+
4451
4509
  if all(marker in existing for marker in required_markers):
4452
4510
  return "kept"
4453
4511
 
@@ -4460,7 +4518,8 @@ def _ensure_instruction_workflow(instructions_path: Path, template: str, require
4460
4518
  return "updated"
4461
4519
 
4462
4520
 
4463
- def _ensure_codex_agents_workflow(agents_md_path: Path) -> str:
4521
+ def _ensure_codex_agents_workflow(agents_md_path: Path,
4522
+ project_path: str = "") -> str:
4464
4523
  """Ensure AGENTS.md contains the mandatory C3 workflow for Codex sessions."""
4465
4524
  required_markers = [
4466
4525
  "C3 Tools",
@@ -4474,10 +4533,12 @@ def _ensure_codex_agents_workflow(agents_md_path: Path) -> str:
4474
4533
  "c3_memory",
4475
4534
  "c3_filter",
4476
4535
  ]
4477
- return _ensure_instruction_workflow(agents_md_path, _AGENTS_MD_CONTENT, required_markers)
4536
+ return _ensure_instruction_workflow(agents_md_path, _AGENTS_MD_CONTENT,
4537
+ required_markers, project_path)
4478
4538
 
4479
4539
 
4480
- def _ensure_vscode_instructions_workflow(instructions_path: Path) -> str:
4540
+ def _ensure_vscode_instructions_workflow(instructions_path: Path,
4541
+ project_path: str = "") -> str:
4481
4542
  """Ensure VS Code Copilot instructions include the latest C3 workflow markers."""
4482
4543
  required_markers = [
4483
4544
  "C3 Tools",
@@ -4491,7 +4552,9 @@ def _ensure_vscode_instructions_workflow(instructions_path: Path) -> str:
4491
4552
  "c3_memory",
4492
4553
  "c3_filter",
4493
4554
  ]
4494
- return _ensure_instruction_workflow(instructions_path, _COPILOT_INSTRUCTIONS_CONTENT, required_markers)
4555
+ return _ensure_instruction_workflow(instructions_path,
4556
+ _COPILOT_INSTRUCTIONS_CONTENT,
4557
+ required_markers, project_path)
4495
4558
 
4496
4559
 
4497
4560
  def _safe_read_json(path: Path, label: str = "") -> dict:
@@ -4957,6 +5020,7 @@ back to native tools as the task progresses.
4957
5020
  - **Bitbucket** (v2.30.0+, when `c3 bitbucket login` has run): `c3_bitbucket(action='list_prs|get_pr|merge_pr|...')` — self-hosted Bitbucket Data Center / Server. Token in OS keyring; mutating actions auto-log to the edit ledger.
4958
5021
  - **Cross-project** (v2.31.0+): `c3_project(action='list|scan|search|read|edit|...', project='<name|path>')` — discover and operate on OTHER c3-installed projects. Reads run freely; writes (edit/shell/memory) need `allow_write=true`.
4959
5022
  - **Masked paths** (v2.63.0+): content prefixed `[c3-mask:transformed]` is a policy-transformed VIEW, not the file. Values may be synthetic, rows withheld, bodies stripped — don't copy literals out of it or infer completeness from it. Masked paths are read-only and refuse shell/git/validate/impact/filter/delegate (`[c3-mask:unsupported]`). That's policy, not a transient error — report the block instead of routing around it.
5023
+ - **Confirm holds** (v2.97.0+): `[c3-access:confirm]` is a PAUSE, not a block — a human must approve this exact write. Since v2.100.0 the agent-config files (`.mcp.json`, instruction docs, `.claude` hook/skill/agent/command bodies) hold by default in EVERY C3 project, reads stay open. Read the S8 tail: it names the filed request (`c3_override(action='wait', request_id='...', timeout_s=180)`, then retry the same call once if approved), or names a surface that files one, or gives a reason to obey. Never retry before a decision and never route around a hold via the shell.
4960
5024
 
4961
5025
  ## Self-Check
4962
5026
  If you haven't called a c3_* tool in several turns during active development, re-engage
@@ -5034,10 +5098,20 @@ def _instruction_documents_for_project() -> list[tuple[str, str]]:
5034
5098
 
5035
5099
  Used by uninstall/cleanup paths, so it must keep listing legacy docs
5036
5100
  (GEMINI.md — profile removed in v2.52; empty template, never generated).
5101
+
5102
+ ``.github/copilot-instructions.md`` was absent from this list until
5103
+ v2.102.0, and that absence was the whole bug: the managed-block sync
5104
+ that regenerates CLAUDE.md and AGENTS.md on every install-mcp never
5105
+ touched it, while ``_ensure_vscode_instructions_workflow`` reported
5106
+ `kept` on marker presence alone. In a vscode-primary project the third
5107
+ git-tracked instruction doc silently drifted a release behind on every
5108
+ template change — v2.100.0's agent-config confirm tier reached the
5109
+ Claude Code and Codex docs and never reached Copilot's.
5037
5110
  """
5038
5111
  return [
5039
5112
  ("CLAUDE.md", _CLAUDE_MD_CONTENT),
5040
5113
  ("AGENTS.md", _AGENTS_MD_CONTENT),
5114
+ (VSCODE_INSTRUCTIONS_FILE, _COPILOT_INSTRUCTIONS_CONTENT),
5041
5115
  ("GEMINI.md", ""),
5042
5116
  ]
5043
5117
 
@@ -5692,7 +5766,8 @@ def cmd_install_mcp(args):
5692
5766
  if profile.name == "vscode":
5693
5767
  # 1. Ensure copilot-instructions.md has the latest C3 workflow markers
5694
5768
  instructions_path = target / ".github" / "copilot-instructions.md"
5695
- vs_state = _ensure_vscode_instructions_workflow(instructions_path)
5769
+ vs_state = _ensure_vscode_instructions_workflow(instructions_path,
5770
+ str(target))
5696
5771
  if vs_state == "written":
5697
5772
  print(f"Wrote {instructions_path}")
5698
5773
  elif vs_state == "updated":
@@ -5731,7 +5806,8 @@ def cmd_install_mcp(args):
5731
5806
  # ── Codex AGENTS.md enforcement file ──────────────────────
5732
5807
  if profile.name == "codex":
5733
5808
  agents_md_path = target / "AGENTS.md"
5734
- agents_state = _ensure_codex_agents_workflow(agents_md_path)
5809
+ agents_state = _ensure_codex_agents_workflow(agents_md_path,
5810
+ str(target))
5735
5811
  if agents_state == "written":
5736
5812
  print(f"Wrote {agents_md_path}")
5737
5813
  elif agents_state == "updated":
@@ -9123,6 +9199,7 @@ def main():
9123
9199
  "claudemd": cmd_claudemd,
9124
9200
  "map": cmd_map,
9125
9201
  "stats": cmd_stats,
9202
+ "search-eval": cmd_search_eval,
9126
9203
  "benchmark": cmd_benchmark,
9127
9204
  "session-benchmark": cmd_session_benchmark,
9128
9205
  "benchmark-e2e": cmd_benchmark_e2e,
@@ -26,25 +26,48 @@ class CommandDeps:
26
26
 
27
27
 
28
28
  def cmd_index(args, deps: CommandDeps):
29
- """Rebuild the code index."""
29
+ """Rebuild the code index.
30
+
31
+ ``--max-files`` defaults to None so an unset flag falls through to
32
+ ``CodeIndex.build_index``, which reads ``index_max_files`` from
33
+ ``.c3/config.json`` (2000 by default). Passing a hard-coded number here
34
+ would shadow that config for every caller who did not type the flag.
35
+
36
+ A truncated index is reported, never silent: the caller who sees only
37
+ "Files Indexed: 500" has no way to know 1400 files were skipped, and a
38
+ partial index answers searches with confident absences.
39
+ """
30
40
  config = deps.load_config()
31
41
  project_path = config.get("project_path", ".")
32
42
 
33
43
  deps.print_header("Rebuilding Code Index")
34
44
  indexer = deps.CodeIndex(project_path)
35
- result = indexer.build_index(max_files=args.max_files or 500)
45
+ result = indexer.build_index(max_files=args.max_files)
46
+
47
+ capped = result.get("files_capped", 0) or 0
48
+ candidates = result["files_indexed"] + capped
36
49
 
37
50
  if deps.HAS_RICH:
38
51
  table = deps.Table(title="Index Results")
39
52
  table.add_column("Metric", style="cyan")
40
53
  table.add_column("Value", style="green")
41
- table.add_row("Files Indexed", str(result["files_indexed"]))
54
+ files_cell = str(result["files_indexed"])
55
+ if capped:
56
+ files_cell = f"{result['files_indexed']} of {candidates}"
57
+ table.add_row("Files Indexed", files_cell)
42
58
  table.add_row("Chunks Created", str(result["chunks_created"]))
43
59
  table.add_row("Unique Symbols", str(result["unique_symbols"]))
60
+ if capped:
61
+ table.add_row("Files Skipped (cap)", str(capped))
44
62
  deps.console.print(table)
45
63
  else:
46
64
  print(f" Files: {result['files_indexed']}, Chunks: {result['chunks_created']}, Symbols: {result['unique_symbols']}")
47
65
 
66
+ if capped:
67
+ print(f" [!] Indexed {result['files_indexed']} of {candidates} candidate files "
68
+ f"(cap: index_max_files={result.get('max_files')}). {capped} skipped.")
69
+ print(" Raise index_max_files in .c3/config.json for full coverage.")
70
+
48
71
 
49
72
  def cmd_compress(args, deps: CommandDeps):
50
73
  """Compress a file and show results."""
@@ -34,7 +34,30 @@ def build_parser(version: str, parse_cli_ide_arg):
34
34
  help="Only report whether a newer version exists; don't install")
35
35
 
36
36
  p_index = subparsers.add_parser("index", help="Rebuild code index")
37
- p_index.add_argument("--max-files", type=int, default=500)
37
+ p_index.add_argument("--max-files", type=int, default=None,
38
+ help="Cap files indexed this run. Unset reads "
39
+ "index_max_files from .c3/config.json (2000).")
40
+
41
+ p_search_eval = subparsers.add_parser(
42
+ "search-eval", help="Run the c3_search relevance suite (docs/search-eval.md)")
43
+ p_search_eval.add_argument("--suite", default="fixture",
44
+ help="'fixture' (synthetic repo, CI gate), 'golden' (this repo), or a .jsonl path")
45
+ p_search_eval.add_argument("--repo", default=None,
46
+ help="Project to evaluate; overrides the suite header (real repos only)")
47
+ p_search_eval.add_argument("--semantic", choices=["off", "auto", "on"], default="auto",
48
+ help="off: skip semantic cases; auto: run when embeddings are ready; "
49
+ "on: build embeddings first (needs Ollama)")
50
+ p_search_eval.add_argument("--rerank", choices=["off", "on"], default="off",
51
+ help="on: attach the FlashRank reranker (needs the `rerank` extra) to measure it "
52
+ "against the same suite; off: the project's own config decides")
53
+ p_search_eval.add_argument("--rebuild", action="store_true",
54
+ help="Rebuild the code index before running (real repos; fixtures always rebuild)")
55
+ p_search_eval.add_argument("--baseline", default=None, help="Baseline JSON to compare against / write")
56
+ p_search_eval.add_argument("--update-baseline", action="store_true",
57
+ help="Write aggregates + per-query status to the baseline (floors are kept)")
58
+ p_search_eval.add_argument("--floors", default=None,
59
+ help='With --update-baseline: JSON object of metric floors, e.g. \'{"mrr": 0.85}\'')
60
+ p_search_eval.add_argument("--json", action="store_true", help="Emit the full report as JSON")
38
61
 
39
62
  p_compress = subparsers.add_parser("compress", help="Compress a file")
40
63
  p_compress.add_argument("file", help="File to compress")
@@ -6,9 +6,11 @@ dispatcher's deny-beats-allow merge makes a deny here final. hook_dispatch
6
6
  treats this module as _FAIL_CLOSED: if it fails to import or raises, write-
7
7
  class native tools are denied instead of sailing through.
8
8
 
9
- Bash coverage is a best-effort, existence-gated token scan — advisory by
10
- design (docs/access-guard.md §3/§6); it catches an agent naming a denied
11
- path, not an adversary hiding one.
9
+ Bash coverage is a best-effort token scan — advisory by design
10
+ (docs/access-guard.md §3/§6); it catches an agent naming a denied path, not
11
+ an adversary hiding one. Two passes: every path-shaped token as a READ
12
+ (existence-gated), then the command's WRITE targets as writes (v2.102.0), so
13
+ a redirect into a confirm-held or read-only file holds like any other write.
12
14
  """
13
15
  import os
14
16
  import re
@@ -29,6 +31,16 @@ try:
29
31
  except Exception: # pragma: no cover — telemetry is never load-bearing
30
32
  access_telemetry = None
31
33
 
34
+ # The same write-target extractor the edit ledger uses after the fact. Its
35
+ # absence degrades the shell branch to the read-only scan, never to a crash.
36
+ try:
37
+ from _shell_writes import shell_write_targets
38
+ except Exception: # pragma: no cover — package-style import (dispatcher, tests)
39
+ try:
40
+ from cli._shell_writes import shell_write_targets
41
+ except Exception:
42
+ shell_write_targets = None
43
+
32
44
  _WRITE_TOOLS = {"Edit", "Write", "MultiEdit", "NotebookEdit"}
33
45
  _READ_TOOLS = {"Read", "SearchText"}
34
46
  _SEARCH_TOOLS = {"Grep", "Glob", "FindFiles"}
@@ -206,21 +218,41 @@ def _record(denial, tool: str, operation: str, path: str,
206
218
 
207
219
 
208
220
  def _override_allows(base: str, denial, *, tool: str, op: str, path: str,
209
- session_id: str):
221
+ session_id: str, peek: bool = False):
210
222
  """A live override grant covering this exact call, or None (spec §5).
211
223
 
212
224
  Lazy import and policy-before-grants ordering keep the hot path free: a
213
225
  project that never turned overrides on pays one dict lookup and never
214
226
  opens the grants file. Any failure returns None — the denial stands.
227
+
228
+ ``peek`` looks without consuming; see ``_granted`` for why.
215
229
  """
216
230
  try:
217
231
  from services import override_grants as og # noqa: PLC0415 — lazy
218
232
  return og.gate_access(base, denial, tool=tool, op=op, path=path,
219
- session_id=session_id)
233
+ session_id=session_id, peek=peek)
220
234
  except Exception:
221
235
  return None # fail closed: no grant, ordinary denial
222
236
 
223
237
 
238
+ def _granted(line: str, defer: bool, consume) -> dict:
239
+ """The allow-by-grant output.
240
+
241
+ Under the dispatcher (``defer`` True) the use is NOT burned here: the
242
+ provisional line goes out with an ``_on_allow`` callable, and
243
+ hook_dispatch runs it only once every PreToolUse sub-hook has voted
244
+ allow. Before v2.102.0 this hook consumed first and a strict-mode
245
+ discipline deny from hook_pretool_enforce then won the merge — grant
246
+ spent, nothing written, and the user asked twice for one edit. Run
247
+ standalone (``defer`` False) the use was already consumed by the peek-
248
+ less lookup, so the line is final.
249
+ """
250
+ out = {"additionalContext": line}
251
+ if defer:
252
+ out["_on_allow"] = consume
253
+ return out
254
+
255
+
224
256
  def _confirm_request(base: str, denial, *, tool: str, op: str, path: str,
225
257
  session_id: str) -> tuple:
226
258
  """Auto-file an Override Request for a ``confirm`` denial (S8).
@@ -349,7 +381,68 @@ def _scan_shell(cmd: str, base: str):
349
381
  return None, ""
350
382
 
351
383
 
352
- def run(payload: dict, project_path: Path | None = None) -> dict | None:
384
+ def _scan_shell_writes(cmd: str, base: str, session_id: str,
385
+ defer: bool) -> dict | None:
386
+ """WRITE-class verdict for the files a shell command writes (v2.102.0).
387
+
388
+ ``_scan_shell`` evaluates every token as a READ. Confirm holds, read_only
389
+ rules and the builtin write-denies are all write-class, so ``cat >>
390
+ CLAUDE.md``, ``sed -i`` on .mcp.json or a heredoc into a hook body sailed
391
+ through with no hold — the one bypass docs/confirm-guard.md could only
392
+ ask the agent not to use. Targets come from the extractor the edit
393
+ ledger already trusts after the fact (cli/_shell_writes), with the same
394
+ best-effort caveat: a missed target costs a missed hold, a false one
395
+ costs a hold the human clears in one tap. Synthetic spelling denials are
396
+ skipped exactly as the read scan skips them (a token that is not a path
397
+ must not veto the command); the corrupt-config deny-all still refuses.
398
+
399
+ Grant identity is ``tool="Bash", op="write", path=<target>`` — bound to
400
+ the file, not the command text, the same stated limitation as the
401
+ shell_warn layer. Several held targets need several grants; the command
402
+ runs only when every one is covered, and the uses are burned together
403
+ (or not at all) by the dispatcher's settle step.
404
+ """
405
+ if shell_write_targets is None:
406
+ return None
407
+ lines, consumers = [], []
408
+ for target in shell_write_targets(cmd, base):
409
+ denial = ag.check(target, "write", base)
410
+ if denial is None:
411
+ continue
412
+ if denial.rule.startswith("<") and denial.rule != "<corrupt-config>":
413
+ continue
414
+ granted = _override_allows(base, denial, tool="Bash", op="write",
415
+ path=target, session_id=session_id,
416
+ peek=defer)
417
+ if granted:
418
+ lines.append(granted)
419
+ if defer:
420
+ consumers.append(lambda t=target, d=denial: _override_allows(
421
+ base, d, tool="Bash", op="write", path=t,
422
+ session_id=session_id))
423
+ continue
424
+ _record(denial, "Bash", "write", target, base, session_id)
425
+ if denial.kind == "confirm":
426
+ rid, note = _confirm_request(base, denial, tool="Bash", op="write",
427
+ path=target, session_id=session_id)
428
+ return _deny(ag.refusal(denial, target, "write", surface="hook",
429
+ tool="Bash", request_id=rid,
430
+ request_note=note)
431
+ + " (best-effort shell scan)")
432
+ return _deny(ag.refusal(denial, target, "write", surface="hook",
433
+ tool="Bash") + " (best-effort shell scan)")
434
+ if not lines:
435
+ return None
436
+
437
+ def _settle():
438
+ got = [fn() for fn in consumers]
439
+ return "\n".join(got) if all(got) else None
440
+
441
+ return _granted("\n".join(lines), bool(consumers), _settle)
442
+
443
+
444
+ def run(payload: dict, project_path: Path | None = None,
445
+ defer_consume: bool = False) -> dict | None:
353
446
  tool = normalize_tool_name(payload.get("tool_name", ""))
354
447
  tool_input = payload.get("tool_input", {}) or {}
355
448
  base = str(project_path if project_path is not None else Path.cwd())
@@ -363,9 +456,13 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
363
456
  denial = ag.check(fp, op, base)
364
457
  if denial:
365
458
  granted = _override_allows(base, denial, tool=tool, op=op,
366
- path=fp, session_id=session_id)
459
+ path=fp, session_id=session_id,
460
+ peek=defer_consume)
367
461
  if granted:
368
- return {"additionalContext": granted}
462
+ return _granted(granted, defer_consume,
463
+ lambda: _override_allows(
464
+ base, denial, tool=tool, op=op, path=fp,
465
+ session_id=session_id))
369
466
  _record(denial, tool, op, fp, base, session_id)
370
467
  if denial.kind == "confirm":
371
468
  # A confirm hold files its own request (grants were consulted
@@ -401,6 +498,6 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
401
498
  return _deny(ag.refusal(denial, tok, "read",
402
499
  surface="hook", tool=tool)
403
500
  + " (best-effort shell scan)")
404
- return None
501
+ return _scan_shell_writes(cmd, base, session_id, defer_consume)
405
502
 
406
503
  return None
@@ -36,6 +36,7 @@ emit a short "[c3:hook-error] ..." additionalContext warning so enforcement
36
36
  cannot silently stop enforcing.
37
37
  """
38
38
  import importlib
39
+ import inspect
39
40
  import json
40
41
  import sys
41
42
  from pathlib import Path
@@ -166,6 +167,16 @@ def _routes(event: str, raw_tool: str, norm_tool: str, host: str = HOST_CLAUDE):
166
167
 
167
168
  _RUN_CACHE: dict = {}
168
169
 
170
+ # PreToolUse sub-hooks that consult override grants. Under the dispatcher
171
+ # they are asked to DEFER consumption (`defer_consume=True`): each returns a
172
+ # provisional allow carrying an `_on_allow` callable, and `_settle_grants`
173
+ # runs those only once every sub-hook has voted allow. Before v2.102.0 the
174
+ # access guard consumed a grant first and a strict-mode discipline deny from
175
+ # the next sub-hook then won the merge — grant spent, nothing written, the
176
+ # user asked twice for one edit. The same hole ran the other way for a
177
+ # discipline grant followed by a policy deny.
178
+ _DEFER_CONSUME = {"hook_access_guard", "hook_pretool_enforce"}
179
+
169
180
  # Modules whose failure must DENY rather than fall through (fail closed).
170
181
  # Scoped to write-class tools + shell: a broken guard must not let mutations
171
182
  # sail through, but read-class fail-open avoids bricking whole sessions.
@@ -189,6 +200,77 @@ def _fail_closed_deny(module_name: str, err: str) -> dict:
189
200
  }
190
201
 
191
202
 
203
+ def _is_deny(out) -> bool:
204
+ hso = out.get("hookSpecificOutput") if isinstance(out, dict) else None
205
+ return isinstance(hso, dict) and hso.get("permissionDecision") == "deny"
206
+
207
+
208
+ def _call_run(run_fn, module_name: str, event: str, payload: dict,
209
+ project_path):
210
+ """Invoke a sub-hook, asking the grant-aware ones to defer consumption.
211
+
212
+ Signature-checked rather than assumed: tests stub these modules with
213
+ two-argument lambdas, and a legacy single-file hook must keep working.
214
+ """
215
+ if event == "pretool" and module_name in _DEFER_CONSUME:
216
+ try:
217
+ accepts = "defer_consume" in inspect.signature(run_fn).parameters
218
+ except (TypeError, ValueError):
219
+ accepts = False
220
+ if accepts:
221
+ return run_fn(payload, project_path, defer_consume=True)
222
+ return run_fn(payload, project_path)
223
+
224
+
225
+ def _grant_lost_deny() -> dict:
226
+ return {
227
+ "hookSpecificOutput": {
228
+ "hookEventName": "PreToolUse",
229
+ "permissionDecision": "deny",
230
+ "permissionDecisionReason": (
231
+ "[c3-override:spent] the override grant that would have "
232
+ "allowed this call was used up between check and use (a "
233
+ "concurrent call spent it). The rule stands — ask again "
234
+ "with c3_override if it is still needed."
235
+ ),
236
+ }
237
+ }
238
+
239
+
240
+ def _settle_grants(outputs: list) -> list:
241
+ """Burn deferred grant uses — only when the merged verdict is allow.
242
+
243
+ Any deny among the outputs means the call will not run, so every
244
+ `_on_allow` is dropped unrun and the grants stay live for the retry. On
245
+ an allow each consumer runs; the line it returns replaces the
246
+ provisional one (it carries the post-consumption uses count). A consumer
247
+ that finds nothing left — the grant was spent by a concurrent call
248
+ between peek and settle — turns its allow into a deny: the call must
249
+ not proceed on a grant that no longer exists.
250
+ """
251
+ denied = any(_is_deny(o) for o in outputs)
252
+ settled = []
253
+ for out in outputs:
254
+ if not isinstance(out, dict):
255
+ settled.append(out)
256
+ continue
257
+ consume = out.pop("_on_allow", None)
258
+ if consume is None or denied:
259
+ settled.append(out)
260
+ continue
261
+ try:
262
+ line = consume()
263
+ except Exception as exc:
264
+ log_hook_error("hook_dispatch:settle", exc)
265
+ line = None
266
+ if line:
267
+ out["additionalContext"] = str(line)
268
+ settled.append(out)
269
+ else:
270
+ settled.append(_grant_lost_deny())
271
+ return settled
272
+
273
+
192
274
  def _load_run(module_name: str):
193
275
  """Import cli.<module_name> and return its run() (cached).
194
276
 
@@ -353,7 +435,7 @@ def dispatch(event: str, payload: dict, project_path: Path | None = None) -> dic
353
435
  outputs.append(_fail_closed_deny(module_name, err))
354
436
  continue
355
437
  try:
356
- out = run_fn(payload, project_path)
438
+ out = _call_run(run_fn, module_name, event, payload, project_path)
357
439
  if out:
358
440
  outputs.append(out)
359
441
  except Exception as exc:
@@ -368,7 +450,15 @@ def dispatch(event: str, payload: dict, project_path: Path | None = None) -> dic
368
450
  # Critical state-layer warnings (corrupt enforcement_state.json)
369
451
  # become visible instead of silently disabling enforcement.
370
452
  warnings.extend(_hook_utils.drain_state_warnings())
453
+ # A PreToolUse deny is final — merge keeps the first deny and no
454
+ # allow readmits it — so the sub-hooks after it have nothing to add,
455
+ # and running them could only spend a grant or log a block for a
456
+ # call that will not happen.
457
+ if event == "pretool" and outputs and _is_deny(outputs[-1]):
458
+ break
371
459
 
460
+ if event == "pretool":
461
+ outputs = _settle_grants(outputs)
372
462
  return merge_outputs(outputs, warnings, event=event, host=host)
373
463
 
374
464