code-context-control 2.66.0__tar.gz → 2.67.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 (395) hide show
  1. {code_context_control-2.66.0/code_context_control.egg-info → code_context_control-2.67.0}/PKG-INFO +53 -3
  2. {code_context_control-2.66.0 → code_context_control-2.67.0}/README.md +52 -2
  3. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/c3.py +1 -1
  4. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_server.py +170 -37
  5. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/drill_panel.js +2 -0
  6. code_context_control-2.67.0/cli/hub_ui/components/hub_enforcement.js +1162 -0
  7. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/server.py +18 -0
  8. {code_context_control-2.66.0 → code_context_control-2.67.0/code_context_control.egg-info}/PKG-INFO +53 -3
  9. {code_context_control-2.66.0 → code_context_control-2.67.0}/pyproject.toml +1 -1
  10. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/access_telemetry.py +48 -0
  11. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/enforcement_policy.py +140 -30
  12. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_enforcement_policy.py +228 -0
  13. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_enforcement_routes.py +19 -0
  14. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_enforcement_routes.py +204 -0
  15. code_context_control-2.66.0/cli/hub_ui/components/hub_enforcement.js +0 -342
  16. {code_context_control-2.66.0 → code_context_control-2.67.0}/LICENSE +0 -0
  17. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/__init__.py +0 -0
  18. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/_hook_utils.py +0 -0
  19. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/commands/__init__.py +0 -0
  20. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/commands/common.py +0 -0
  21. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/commands/parser.py +0 -0
  22. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/docs.html +0 -0
  23. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/edits.html +0 -0
  24. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/access.html +0 -0
  25. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/bitbucket.html +0 -0
  26. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/credentials.html +0 -0
  27. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/getting-started.html +0 -0
  28. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/index.html +0 -0
  29. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/masking.html +0 -0
  30. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/oracle.html +0 -0
  31. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/shared.css +0 -0
  32. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/tools.html +0 -0
  33. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/guide/workflow.html +0 -0
  34. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_access_guard.py +0 -0
  35. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_artifact.py +0 -0
  36. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_auto_snapshot.py +0 -0
  37. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_c3_signal.py +0 -0
  38. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_c3read.py +0 -0
  39. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_dispatch.py +0 -0
  40. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_edit_ledger.py +0 -0
  41. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_edit_unlock.py +0 -0
  42. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_filter.py +0 -0
  43. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_ghost_files.py +0 -0
  44. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_pretool_enforce.py +0 -0
  45. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_prompt_recall.py +0 -0
  46. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_read.py +0 -0
  47. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_session_stats.py +0 -0
  48. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hook_terse_advisor.py +0 -0
  49. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/app.js +0 -0
  50. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/add_project.js +0 -0
  51. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/config_editor.js +0 -0
  52. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  53. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/drill_health.js +0 -0
  54. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  55. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  56. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/drill_views.js +0 -0
  57. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/global_search.js +0 -0
  58. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  59. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/hub_locks.js +0 -0
  60. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  61. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/modals.js +0 -0
  62. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/project_card.js +0 -0
  63. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/project_tree.js +0 -0
  64. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/session_drawer.js +0 -0
  65. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/settings_modal.js +0 -0
  66. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/sidebar.js +0 -0
  67. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/summary_bar.js +0 -0
  68. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/task_board.js +0 -0
  69. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/toasts.js +0 -0
  70. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/components/topbar.js +0 -0
  71. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui/state.js +0 -0
  72. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/hub_ui.html +0 -0
  73. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/mcp_proxy.py +0 -0
  74. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/mcp_server.py +0 -0
  75. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/progress.py +0 -0
  76. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/__init__.py +0 -0
  77. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/_helpers.py +0 -0
  78. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/agent.py +0 -0
  79. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/artifacts.py +0 -0
  80. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/bitbucket.py +0 -0
  81. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/compress.py +0 -0
  82. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/credentials.py +0 -0
  83. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/delegate.py +0 -0
  84. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/edit.py +0 -0
  85. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/edits.py +0 -0
  86. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/federate.py +0 -0
  87. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/filter.py +0 -0
  88. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/impact.py +0 -0
  89. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/jira.py +0 -0
  90. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/locks.py +0 -0
  91. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/memory.py +0 -0
  92. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/project.py +0 -0
  93. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/read.py +0 -0
  94. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/search.py +0 -0
  95. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/session.py +0 -0
  96. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/shell.py +0 -0
  97. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/status.py +0 -0
  98. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/tasks.py +0 -0
  99. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/tools/validate.py +0 -0
  100. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/api.js +0 -0
  101. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/app.js +0 -0
  102. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/access.js +0 -0
  103. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/bitbucket.js +0 -0
  104. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/chat.js +0 -0
  105. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/credentials.js +0 -0
  106. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/dashboard.js +0 -0
  107. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/edits.js +0 -0
  108. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/enforcement.js +0 -0
  109. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/instructions.js +0 -0
  110. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/jira.js +0 -0
  111. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/memory.js +0 -0
  112. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/sessions.js +0 -0
  113. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/settings.js +0 -0
  114. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/sidebar.js +0 -0
  115. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/components/tasks.js +0 -0
  116. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/icons.js +0 -0
  117. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/pm_shared.js +0 -0
  118. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/shared.js +0 -0
  119. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui/theme.js +0 -0
  120. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui.html +0 -0
  121. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui_legacy.html +0 -0
  122. {code_context_control-2.66.0 → code_context_control-2.67.0}/cli/ui_nano.html +0 -0
  123. {code_context_control-2.66.0 → code_context_control-2.67.0}/code_context_control.egg-info/SOURCES.txt +0 -0
  124. {code_context_control-2.66.0 → code_context_control-2.67.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  125. {code_context_control-2.66.0 → code_context_control-2.67.0}/code_context_control.egg-info/entry_points.txt +0 -0
  126. {code_context_control-2.66.0 → code_context_control-2.67.0}/code_context_control.egg-info/requires.txt +0 -0
  127. {code_context_control-2.66.0 → code_context_control-2.67.0}/code_context_control.egg-info/top_level.txt +0 -0
  128. {code_context_control-2.66.0 → code_context_control-2.67.0}/core/__init__.py +0 -0
  129. {code_context_control-2.66.0 → code_context_control-2.67.0}/core/config.py +0 -0
  130. {code_context_control-2.66.0 → code_context_control-2.67.0}/core/ide.py +0 -0
  131. {code_context_control-2.66.0 → code_context_control-2.67.0}/core/mcp_toml.py +0 -0
  132. {code_context_control-2.66.0 → code_context_control-2.67.0}/core/web_security.py +0 -0
  133. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/__init__.py +0 -0
  134. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/config.py +0 -0
  135. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/mcp_oracle.py +0 -0
  136. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/oracle_server.py +0 -0
  137. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/oracle_ui.html +0 -0
  138. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/__init__.py +0 -0
  139. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/activity_reporter.py +0 -0
  140. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/api_auth.py +0 -0
  141. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/c3_bridge.py +0 -0
  142. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/chat_engine.py +0 -0
  143. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/chat_store.py +0 -0
  144. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/cross_memory.py +0 -0
  145. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/discovery_audit.py +0 -0
  146. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/federated_graph.py +0 -0
  147. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/health_checker.py +0 -0
  148. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/insight_engine.py +0 -0
  149. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/local_session.py +0 -0
  150. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/memory_reader.py +0 -0
  151. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/memory_writer.py +0 -0
  152. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/project_scanner.py +0 -0
  153. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/review_agent.py +0 -0
  154. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/tool_executor.py +0 -0
  155. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/services/tool_registry.py +0 -0
  156. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/activity.js +0 -0
  157. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/agents.js +0 -0
  158. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/app.js +0 -0
  159. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/busy.js +0 -0
  160. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/chat/conversations.js +0 -0
  161. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/chat/input.js +0 -0
  162. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/chat/markdown.js +0 -0
  163. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/chat/send.js +0 -0
  164. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/chat/stream_renderer.js +0 -0
  165. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/chat/toolbar.js +0 -0
  166. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/core.js +0 -0
  167. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/crossgraph.js +0 -0
  168. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/header.js +0 -0
  169. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/insights.js +0 -0
  170. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/projects.js +0 -0
  171. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/settings.js +0 -0
  172. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/suggestions.js +0 -0
  173. {code_context_control-2.66.0 → code_context_control-2.67.0}/oracle/ui/theme_tabs.js +0 -0
  174. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/__init__.py +0 -0
  175. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/access_guard.py +0 -0
  176. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/activity_log.py +0 -0
  177. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/agent_base.py +0 -0
  178. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/agent_locks.py +0 -0
  179. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/agents.py +0 -0
  180. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/artifact_defs.py +0 -0
  181. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/artifact_store.py +0 -0
  182. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/auto_memory.py +0 -0
  183. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/bench/__init__.py +0 -0
  184. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/bench/external/__init__.py +0 -0
  185. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/bench/external/aider_polyglot.py +0 -0
  186. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/bench/external/swe_bench.py +0 -0
  187. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/benchmark_dashboard.py +0 -0
  188. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/bitbucket_client.py +0 -0
  189. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/bitbucket_credentials.py +0 -0
  190. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/circuit_breaker.py +0 -0
  191. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/claude_md.py +0 -0
  192. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/compressor.py +0 -0
  193. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/context_snapshot.py +0 -0
  194. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/conversation_store.py +0 -0
  195. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/credential_store.py +0 -0
  196. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/doc_index.py +0 -0
  197. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/e2e_benchmark.py +0 -0
  198. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/e2e_evaluator.py +0 -0
  199. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/e2e_tasks.py +0 -0
  200. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/edit_ledger.py +0 -0
  201. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/embedding_index.py +0 -0
  202. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/error_reporting.py +0 -0
  203. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/file_memory.py +0 -0
  204. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/git_context.py +0 -0
  205. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/hub_service.py +0 -0
  206. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/indexer.py +0 -0
  207. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/jira_client.py +0 -0
  208. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/jira_cloud.py +0 -0
  209. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/jira_credentials.py +0 -0
  210. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/jira_data_center.py +0 -0
  211. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/jira_links.py +0 -0
  212. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/mask_activation.py +0 -0
  213. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/mask_mirror.py +0 -0
  214. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/mask_presets.py +0 -0
  215. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory.py +0 -0
  216. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory_consolidator.py +0 -0
  217. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory_distiller.py +0 -0
  218. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory_graph.py +0 -0
  219. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory_grounder.py +0 -0
  220. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory_queue.py +0 -0
  221. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/memory_scorer.py +0 -0
  222. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/metrics.py +0 -0
  223. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/notifications.py +0 -0
  224. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/ollama_bridge.py +0 -0
  225. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/ollama_client.py +0 -0
  226. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/ollama_credentials.py +0 -0
  227. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/output_filter.py +0 -0
  228. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/parser.py +0 -0
  229. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/project_manager.py +0 -0
  230. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/project_runtime.py +0 -0
  231. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/protocol.py +0 -0
  232. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/proxy_state.py +0 -0
  233. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/repo_map.py +0 -0
  234. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/retention.py +0 -0
  235. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/retrieval_broker.py +0 -0
  236. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/router.py +0 -0
  237. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/runtime.py +0 -0
  238. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/scanner.py +0 -0
  239. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/session_benchmark.py +0 -0
  240. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/session_manager.py +0 -0
  241. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/session_preloader.py +0 -0
  242. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/subprojects.py +0 -0
  243. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/task_store.py +0 -0
  244. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/telemetry.py +0 -0
  245. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/text_index.py +0 -0
  246. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/time_tracker.py +0 -0
  247. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/tool_classifier.py +0 -0
  248. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/transcript_index.py +0 -0
  249. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/validation_cache.py +0 -0
  250. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/vector_store.py +0 -0
  251. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/watcher.py +0 -0
  252. {code_context_control-2.66.0 → code_context_control-2.67.0}/services/win_subprocess.py +0 -0
  253. {code_context_control-2.66.0 → code_context_control-2.67.0}/setup.cfg +0 -0
  254. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_access_builtin_optout.py +0 -0
  255. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_access_guard.py +0 -0
  256. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_access_guard_meta.py +0 -0
  257. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_access_guard_shell_project.py +0 -0
  258. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_access_guard_surfaces.py +0 -0
  259. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_access_guard_wiring.py +0 -0
  260. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_activity_reporter.py +0 -0
  261. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_agent_locks.py +0 -0
  262. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_aider_polyglot.py +0 -0
  263. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_antigravity_transition.py +0 -0
  264. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_artifact_store.py +0 -0
  265. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_artifact_tool.py +0 -0
  266. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  267. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_bitbucket_client.py +0 -0
  268. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_bitbucket_config_fallback.py +0 -0
  269. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_bitbucket_credentials.py +0 -0
  270. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_bitbucket_tool.py +0 -0
  271. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  272. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_c3_shell.py +0 -0
  273. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_circuit_breaker.py +0 -0
  274. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_claude_md_merge.py +0 -0
  275. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_cli_smoke.py +0 -0
  276. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_compressor_large_file.py +0 -0
  277. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_credential_store.py +0 -0
  278. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_credentials_routes.py +0 -0
  279. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_credentials_tool.py +0 -0
  280. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_creds_cli_smoke.py +0 -0
  281. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_delegate_cascade.py +0 -0
  282. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_e2e_benchmark.py +0 -0
  283. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_edit_ledger_hook.py +0 -0
  284. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_edit_locking.py +0 -0
  285. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_edit_normalization.py +0 -0
  286. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_enforcement_flip.py +0 -0
  287. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_federated_graph.py +0 -0
  288. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_filter_backoff.py +0 -0
  289. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_ghost_files.py +0 -0
  290. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_ghost_generation.py +0 -0
  291. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_git_branch_awareness.py +0 -0
  292. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_access_guard.py +0 -0
  293. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_dispatch.py +0 -0
  294. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_pretool_enforce.py +0 -0
  295. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_prompt_recall.py +0 -0
  296. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_smoke.py +0 -0
  297. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_state.py +0 -0
  298. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hook_utf8_stdio.py +0 -0
  299. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_credentials_route.py +0 -0
  300. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_credentials_routes_write.py +0 -0
  301. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_inspect_api.py +0 -0
  302. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_locks_routes.py +0 -0
  303. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_server_smoke.py +0 -0
  304. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_hub_subproject_links.py +0 -0
  305. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_ide_workflow_adaptation.py +0 -0
  306. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_init_scan.py +0 -0
  307. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_install_mcp_entrypoint.py +0 -0
  308. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_cli_smoke.py +0 -0
  309. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_client.py +0 -0
  310. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_config_fallback.py +0 -0
  311. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_credentials.py +0 -0
  312. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_links.py +0 -0
  313. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_routes.py +0 -0
  314. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_jira_tool.py +0 -0
  315. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_lazy_store_init.py +0 -0
  316. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mask_guard.py +0 -0
  317. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mask_routes.py +0 -0
  318. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mask_surfaces.py +0 -0
  319. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mcp_host_guard.py +0 -0
  320. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mcp_memory_timeout.py +0 -0
  321. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mcp_server_smoke.py +0 -0
  322. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_mcp_toml.py +0 -0
  323. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_memory_distiller.py +0 -0
  324. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_memory_graph_api.py +0 -0
  325. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_memory_queue.py +0 -0
  326. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_memory_system.py +0 -0
  327. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_no_stale_model_pins.py +0 -0
  328. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_notification_dedup.py +0 -0
  329. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_notification_discipline.py +0 -0
  330. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_ollama_credentials.py +0 -0
  331. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_api_auth.py +0 -0
  332. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_apikey_api.py +0 -0
  333. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_c3_bridge.py +0 -0
  334. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_chat_engine.py +0 -0
  335. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_chat_store.py +0 -0
  336. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_discovery_api.py +0 -0
  337. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_discovery_audit.py +0 -0
  338. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_local_auth.py +0 -0
  339. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_ollama_bridge.py +0 -0
  340. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_scanner_cache.py +0 -0
  341. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_security_fixes.py +0 -0
  342. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_session_bootstrap.py +0 -0
  343. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_subproject_awareness.py +0 -0
  344. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_oracle_ui_bundle.py +0 -0
  345. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_output_filter.py +0 -0
  346. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_permissions.py +0 -0
  347. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_pm_api.py +0 -0
  348. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_project_manager.py +0 -0
  349. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_project_manager_merge.py +0 -0
  350. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_project_tool.py +0 -0
  351. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_read_coercion.py +0 -0
  352. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_read_edit_parity.py +0 -0
  353. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_related_facts.py +0 -0
  354. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_repo_map.py +0 -0
  355. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_response_boilerplate.py +0 -0
  356. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_retention.py +0 -0
  357. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_review_digest.py +0 -0
  358. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_service_durability.py +0 -0
  359. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_session_benchmark.py +0 -0
  360. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_session_budget.py +0 -0
  361. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_shell_creds.py +0 -0
  362. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_shell_robustness.py +0 -0
  363. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_subproject_exclusion.py +0 -0
  364. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_subproject_federation.py +0 -0
  365. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_subprojects.py +0 -0
  366. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_swe_bench.py +0 -0
  367. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_task_store.py +0 -0
  368. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_task_tool.py +0 -0
  369. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_time_tracker.py +0 -0
  370. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_token_telemetry.py +0 -0
  371. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_tool_registry.py +0 -0
  372. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_upgrade_and_version.py +0 -0
  373. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_validate.py +0 -0
  374. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_vault_write_guard.py +0 -0
  375. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_version_sync.py +0 -0
  376. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_web_security.py +0 -0
  377. {code_context_control-2.66.0 → code_context_control-2.67.0}/tests/test_windows_reliability.py +0 -0
  378. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/__init__.py +0 -0
  379. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/backend.py +0 -0
  380. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/main.py +0 -0
  381. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/__init__.py +0 -0
  382. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/benchmark_view.py +0 -0
  383. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/claudemd_view.py +0 -0
  384. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/compress_view.py +0 -0
  385. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/index_view.py +0 -0
  386. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/init_view.py +0 -0
  387. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/mcp_view.py +0 -0
  388. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/optimize_view.py +0 -0
  389. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/pipe_view.py +0 -0
  390. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/projects_view.py +0 -0
  391. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/search_view.py +0 -0
  392. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/session_view.py +0 -0
  393. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/stats.py +0 -0
  394. {code_context_control-2.66.0 → code_context_control-2.67.0}/tui/screens/ui_view.py +0 -0
  395. {code_context_control-2.66.0 → code_context_control-2.67.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.66.0
3
+ Version: 2.67.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
@@ -186,7 +186,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
186
186
 
187
187
  ## The MCP tool suite
188
188
 
189
- C3 exposes **20 tools** as a native MCP server. Your IDE calls them directly:
189
+ C3 exposes **21 tools** as a native MCP server. Your IDE calls them directly:
190
190
 
191
191
  | Tool | What it does |
192
192
  |---|---|
@@ -201,6 +201,7 @@ C3 exposes **20 tools** as a native MCP server. Your IDE calls them directly:
201
201
  | `c3_memory` | Fact store with categories, recall, graph queries, `index`→`fetch` two-step |
202
202
  | `c3_session` | Snapshot, restore, log decisions, compact history |
203
203
  | `c3_impact` | Blast-radius analysis before editing shared symbols |
204
+ | `c3_locks` | Agent leases — who is working on which file, so two agents don't collide (v2.65.0) |
204
205
  | `c3_delegate` | Offload heavy work to local Ollama / Codex / Gemini |
205
206
  | `c3_agent` | Workflows: `review_changes`, `investigate`, `preflight`, `prepare_context`, `validate_compress` |
206
207
  | `c3_edits` | Edit-ledger queries, version diffs, restore points, per-branch filter |
@@ -211,7 +212,7 @@ C3 exposes **20 tools** as a native MCP server. Your IDE calls them directly:
211
212
  | `c3_jira` | Jira Cloud + Data Center — JQL, issues, transitions (v2.56.0) |
212
213
  | `c3_project` | Cross-project discovery & operations; guarded writes (v2.31.0) |
213
214
 
214
- Every tool is **read-only safe in plan mode** except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, `c3_delegate` with write delegation enabled, and write actions on `c3_bitbucket` / `c3_jira` / `c3_credentials` / `c3_project` / `c3_task`.
215
+ Every tool is **read-only safe in plan mode** except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, `c3_delegate` with write delegation enabled, and write actions on `c3_bitbucket` / `c3_jira` / `c3_credentials` / `c3_project` / `c3_task` / `c3_locks`.
215
216
 
216
217
  On Windows `c3_shell` uses Git Bash when available. Git Bash bundles no `jq`; use `python -m json.tool` for portable JSON formatting.
217
218
 
@@ -242,12 +243,61 @@ c3 access mask activate # purge pre-mask artifacts, buil
242
243
  - **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
243
244
  - **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
244
245
  - **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
246
+ - **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
245
247
  - **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
246
248
 
247
249
  → [Access Guard](https://github.com/drknowhow/code-context-control/blob/main/docs/access-guard.md) · [Mask Guard](https://github.com/drknowhow/code-context-control/blob/main/docs/mask-guard.md)
248
250
 
249
251
  ---
250
252
 
253
+ ## Agent Locks — several agents, one repo (v2.65.0)
254
+
255
+ Guards answer *may the agent touch this?* Locks answer *is someone already touching it?*
256
+
257
+ Two agents editing one file used to be silent data loss. `c3_edit` serialized
258
+ same-file edits with an in-process lock, but every session runs its own `c3-mcp`
259
+ server — so two sessions could interleave read → replace → write and lose an edit
260
+ with no error on either side. Create mode was worse: both agents "succeeded" and
261
+ one file won.
262
+
263
+ Now there are two mechanisms, because they solve different problems:
264
+
265
+ - **Torn writes** — a cross-process file lock, held across create, single-edit and
266
+ batch alike. No daemon, no configuration, nothing to switch on.
267
+ - **Overlapping work** — a *lease*. `c3_edit` takes one on the file it edits,
268
+ carrying the intent from your edit summary. A second agent gets told who holds
269
+ it and why:
270
+
271
+ ```text
272
+ [c3-lock:held] services/router.py is held by claude-code:a3f19c2b.
273
+ intent: "refactor retry backoff"
274
+ lease expires in 6m12s.
275
+ ```
276
+
277
+ ```bash
278
+ c3 locks list # who holds what, across the project
279
+ c3 locks force-release services/router.py # break a stuck lease (human-only, audited)
280
+ ```
281
+
282
+ - **TTL is the real release mechanism.** Agents forget to release, so nothing
283
+ assumes they will — a crashed agent can never wedge a repo.
284
+ - **Acquisition is all-or-nothing** over a sorted path list, so two agents grabbing
285
+ the same pair in opposite order cannot deadlock.
286
+ - **`force-release` bumps a fencing counter**, so a holder that comes back is stale
287
+ by construction rather than by hope. It lives in the CLI and the Hub, never in
288
+ the agent-facing tool.
289
+ - **The Hub's Locks tab badges a project it cannot read as `UNREADABLE`**, not as
290
+ zero leases — "all clear" is a different claim from "we don't know".
291
+ - **Honest coverage, again.** Leases gate C3's own tool surfaces. A raw `c3_shell`
292
+ redirect, a non-Claude agent, or a human in an editor is *not* covered, and the
293
+ UI says so on screen.
294
+
295
+ Set `locks.enabled: false` in `.c3/config.json` to opt out.
296
+
297
+ → [Agent Locks](https://github.com/drknowhow/code-context-control/blob/main/docs/agent-locks.md)
298
+
299
+ ---
300
+
251
301
  ## Integrations
252
302
 
253
303
  | | What you get | Guide |
@@ -123,7 +123,7 @@ Twelve tabs. The dashboard above shows token savings, indexed files, the live se
123
123
 
124
124
  ## The MCP tool suite
125
125
 
126
- C3 exposes **20 tools** as a native MCP server. Your IDE calls them directly:
126
+ C3 exposes **21 tools** as a native MCP server. Your IDE calls them directly:
127
127
 
128
128
  | Tool | What it does |
129
129
  |---|---|
@@ -138,6 +138,7 @@ C3 exposes **20 tools** as a native MCP server. Your IDE calls them directly:
138
138
  | `c3_memory` | Fact store with categories, recall, graph queries, `index`→`fetch` two-step |
139
139
  | `c3_session` | Snapshot, restore, log decisions, compact history |
140
140
  | `c3_impact` | Blast-radius analysis before editing shared symbols |
141
+ | `c3_locks` | Agent leases — who is working on which file, so two agents don't collide (v2.65.0) |
141
142
  | `c3_delegate` | Offload heavy work to local Ollama / Codex / Gemini |
142
143
  | `c3_agent` | Workflows: `review_changes`, `investigate`, `preflight`, `prepare_context`, `validate_compress` |
143
144
  | `c3_edits` | Edit-ledger queries, version diffs, restore points, per-branch filter |
@@ -148,7 +149,7 @@ C3 exposes **20 tools** as a native MCP server. Your IDE calls them directly:
148
149
  | `c3_jira` | Jira Cloud + Data Center — JQL, issues, transitions (v2.56.0) |
149
150
  | `c3_project` | Cross-project discovery & operations; guarded writes (v2.31.0) |
150
151
 
151
- Every tool is **read-only safe in plan mode** except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, `c3_delegate` with write delegation enabled, and write actions on `c3_bitbucket` / `c3_jira` / `c3_credentials` / `c3_project` / `c3_task`.
152
+ Every tool is **read-only safe in plan mode** except `c3_edit`, `c3_shell`, `c3_artifacts(action='restore')`, `c3_delegate` with write delegation enabled, and write actions on `c3_bitbucket` / `c3_jira` / `c3_credentials` / `c3_project` / `c3_task` / `c3_locks`.
152
153
 
153
154
  On Windows `c3_shell` uses Git Bash when available. Git Bash bundles no `jq`; use `python -m json.tool` for portable JSON formatting.
154
155
 
@@ -179,12 +180,61 @@ c3 access mask activate # purge pre-mask artifacts, buil
179
180
  - **Masked means read-only, always.** Cropped rows have no inverse, so an edit in transformed coordinates would corrupt the one file you protected.
180
181
  - **Four deterministic presets, no LLM in the read path:** `redact_secrets`, `redact_columns` (salted one-way pseudonyms — joins survive, no reverse dictionary), `sample_rows`, `signatures_only`.
181
182
  - **Rule changes are human-only** (UI tab or CLI) and ledger-logged. Agents have no mutation surface.
183
+ - **Built-ins can be switched off when you need to** (v2.65.0). `**/.env*`, `**/.c3/**`, `**/.claude/settings*.json` and `**/.git/**` yield to `c3 access builtin disable <glob>`, which makes you retype the glob first. It takes **two keys** — a config entry *and* a keyring attestation — so an agent that manages to write `config.json` still cannot grant itself write access to your settings. The credential vault stays absolute.
182
184
  - **Honest coverage.** This guards *cooperative* agents against mistakes and prompt injection. It is not a sandbox — a raw shell outside C3's tools still sees the real bytes.
183
185
 
184
186
  → [Access Guard](https://github.com/drknowhow/code-context-control/blob/main/docs/access-guard.md) · [Mask Guard](https://github.com/drknowhow/code-context-control/blob/main/docs/mask-guard.md)
185
187
 
186
188
  ---
187
189
 
190
+ ## Agent Locks — several agents, one repo (v2.65.0)
191
+
192
+ Guards answer *may the agent touch this?* Locks answer *is someone already touching it?*
193
+
194
+ Two agents editing one file used to be silent data loss. `c3_edit` serialized
195
+ same-file edits with an in-process lock, but every session runs its own `c3-mcp`
196
+ server — so two sessions could interleave read → replace → write and lose an edit
197
+ with no error on either side. Create mode was worse: both agents "succeeded" and
198
+ one file won.
199
+
200
+ Now there are two mechanisms, because they solve different problems:
201
+
202
+ - **Torn writes** — a cross-process file lock, held across create, single-edit and
203
+ batch alike. No daemon, no configuration, nothing to switch on.
204
+ - **Overlapping work** — a *lease*. `c3_edit` takes one on the file it edits,
205
+ carrying the intent from your edit summary. A second agent gets told who holds
206
+ it and why:
207
+
208
+ ```text
209
+ [c3-lock:held] services/router.py is held by claude-code:a3f19c2b.
210
+ intent: "refactor retry backoff"
211
+ lease expires in 6m12s.
212
+ ```
213
+
214
+ ```bash
215
+ c3 locks list # who holds what, across the project
216
+ c3 locks force-release services/router.py # break a stuck lease (human-only, audited)
217
+ ```
218
+
219
+ - **TTL is the real release mechanism.** Agents forget to release, so nothing
220
+ assumes they will — a crashed agent can never wedge a repo.
221
+ - **Acquisition is all-or-nothing** over a sorted path list, so two agents grabbing
222
+ the same pair in opposite order cannot deadlock.
223
+ - **`force-release` bumps a fencing counter**, so a holder that comes back is stale
224
+ by construction rather than by hope. It lives in the CLI and the Hub, never in
225
+ the agent-facing tool.
226
+ - **The Hub's Locks tab badges a project it cannot read as `UNREADABLE`**, not as
227
+ zero leases — "all clear" is a different claim from "we don't know".
228
+ - **Honest coverage, again.** Leases gate C3's own tool surfaces. A raw `c3_shell`
229
+ redirect, a non-Claude agent, or a human in an editor is *not* covered, and the
230
+ UI says so on screen.
231
+
232
+ Set `locks.enabled: false` in `.c3/config.json` to opt out.
233
+
234
+ → [Agent Locks](https://github.com/drknowhow/code-context-control/blob/main/docs/agent-locks.md)
235
+
236
+ ---
237
+
188
238
  ## Integrations
189
239
 
190
240
  | | What you get | Guide |
@@ -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.66.0"
95
+ __version__ = "2.67.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -435,9 +435,9 @@ def api_hub_config_set():
435
435
  cfg["projects_view"] = projects_view
436
436
  if "main_view" in data:
437
437
  main_view = str(data["main_view"]).strip().lower()
438
- if main_view not in {"projects", "board", "creds", "locks"}:
438
+ if main_view not in {"projects", "board", "creds", "locks", "enforce"}:
439
439
  return jsonify({"error": "main_view must be 'projects', 'board', "
440
- "'creds' or 'locks'"}), 400
440
+ "'creds', 'locks' or 'enforce'"}), 400
441
441
  cfg["main_view"] = main_view
442
442
  if "oracle_url" in data:
443
443
  cfg["oracle_url"] = str(data["oracle_url"]).strip()
@@ -1723,6 +1723,9 @@ def api_search_global():
1723
1723
  _CONFIG_READ_SECTIONS = ("hybrid", "agents", "delegate", "proxy", "mcp", "bitbucket", "meta",
1724
1724
  "memory_llm")
1725
1725
  _CONFIG_WRITE_SECTIONS = ("hybrid", "agents", "delegate", "proxy", "mcp", "meta", "memory_llm")
1726
+ # "enforcement" is deliberately NOT writable here: the generic deep-merge would
1727
+ # bypass mode/ttl/blocked_tools validation and the set_by provenance rules.
1728
+ # POST /api/projects/enforcement is the only write path.
1726
1729
  # api_key: secrets never transit the hub or land in config.json — the Ollama
1727
1730
  # cloud key lives in the OS keyring (project Settings UI / OLLAMA_API_KEY env).
1728
1731
  _CONFIG_REFUSED_KEYS = ("version", "project_path", "permission_tier", "subprojects", "parent",
@@ -2166,6 +2169,7 @@ def api_hub_enforcement_overview():
2166
2169
  row["set_by"] = policy.set_by
2167
2170
  row["signal_ttl_s"] = policy.signal_ttl_s
2168
2171
  row["warnings"] = list(policy.warnings)
2172
+ row["blocked_tools"] = sorted(policy.blocked_tools)
2169
2173
 
2170
2174
  cfg_path = Path(ppath) / ".c3" / "config.json"
2171
2175
  try:
@@ -2188,12 +2192,28 @@ def api_hub_enforcement_overview():
2188
2192
  row["error"] = str(e)
2189
2193
  rows.append(row)
2190
2194
 
2195
+ # The global (~/.c3) section, shown as its own card. A corrupt global
2196
+ # config must not blank the tab — report the error inside the object.
2197
+ try:
2198
+ g = ep.resolve_global()
2199
+ global_policy = {
2200
+ "configured": g.scope == "global",
2201
+ "mode": g.mode or None,
2202
+ "set_by": g.set_by,
2203
+ "signal_ttl_s": g.signal_ttl_s,
2204
+ "blocked_tools": sorted(g.blocked_tools),
2205
+ "warnings": list(g.warnings),
2206
+ }
2207
+ except Exception as e:
2208
+ global_policy = {"configured": False, "mode": None, "error": str(e)}
2209
+
2191
2210
  return jsonify({
2192
2211
  "projects": rows,
2193
2212
  "modes": [{"id": m, "help": ep.MODE_HELP[m]} for m in ep.MODES],
2194
2213
  "default_mode": ep.DEFAULT_MODE,
2195
2214
  "tier_map": ep.TIER_TO_MODE,
2196
2215
  "totals": totals,
2216
+ "global_policy": global_policy,
2197
2217
  # Stated so the tab can never imply that turning discipline down also
2198
2218
  # turns the security boundaries down. Mirrors docs/enforcement.md.
2199
2219
  "coverage_note": (
@@ -2206,58 +2226,171 @@ def api_hub_enforcement_overview():
2206
2226
  })
2207
2227
 
2208
2228
 
2229
+ @app.route("/api/projects/enforcement", methods=["GET"])
2230
+ def api_projects_enforcement_get():
2231
+ """One project's effective policy plus its denial evidence.
2232
+
2233
+ Hub-side mirror of the per-project GET /api/enforcement — feeds the drill
2234
+ panel's Discipline tab. Optional ``?session=`` narrows the denial
2235
+ aggregate to one session id (full id; the event search route does prefix
2236
+ matching for the UI's 8-char short ids).
2237
+ """
2238
+ from services import access_telemetry as at
2239
+ from services import enforcement_policy as ep
2240
+
2241
+ path = (request.args.get("path") or "").strip()
2242
+ if not path:
2243
+ return jsonify({"error": "path is required"}), 400
2244
+ try:
2245
+ resolved = _resolve_project_path(path)
2246
+ except ValueError as e:
2247
+ return jsonify({"error": str(e)}), 404
2248
+
2249
+ policy = ep.resolve(resolved)
2250
+ try:
2251
+ cfg = json.loads((Path(resolved) / ".c3" / "config.json")
2252
+ .read_text(encoding="utf-8"))
2253
+ tier = str(cfg.get("permission_tier") or "") if isinstance(cfg, dict) else ""
2254
+ except Exception:
2255
+ tier = ""
2256
+ session = (request.args.get("session") or "").strip()
2257
+ agg = at.aggregate(resolved, session_id=session)
2258
+
2259
+ return jsonify({
2260
+ "mode": policy.mode,
2261
+ "scope": policy.scope,
2262
+ "set_by": policy.set_by,
2263
+ "signal_ttl_s": policy.signal_ttl_s,
2264
+ "blocked_tools": sorted(policy.blocked_tools),
2265
+ "warnings": list(policy.warnings),
2266
+ "tier": tier,
2267
+ "tier_implies": ep.derive_from_tier(tier) if tier else "",
2268
+ "default_mode": ep.DEFAULT_MODE,
2269
+ "modes": [{"id": m, "help": ep.MODE_HELP[m]} for m in ep.MODES],
2270
+ "denials": {
2271
+ "total": agg["total"],
2272
+ "by_layer": agg["by_layer"],
2273
+ "rows": [{**r, "fix": at.suggest(r)} for r in agg["rows"][:12]],
2274
+ },
2275
+ })
2276
+
2277
+
2209
2278
  @app.route("/api/projects/enforcement", methods=["POST"])
2210
2279
  def api_projects_enforcement_set():
2211
- """Set one project's tool-discipline mode. Human-only, audited on target.
2212
-
2213
- Always writes ``set_by='user'``: a change made deliberately in the Hub is
2214
- an explicit choice and must survive a later permission-tier change, the
2215
- same as `c3 enforce`.
2280
+ """Set tool-discipline policy fields. Human-only, audited on target.
2281
+
2282
+ Body: ``{path?, scope?, mode?, signal_ttl_s?, blocked_tools?}``.
2283
+ ``scope`` defaults to project (``path`` required); ``global`` writes
2284
+ ``~/.c3`` and ignores ``path``. A body with ``mode`` goes through
2285
+ ``set_mode`` — always ``set_by='user'``: a change made deliberately in
2286
+ the Hub is an explicit choice and must survive a later permission-tier
2287
+ change, the same as `c3 enforce`. A mode-less body goes through
2288
+ ``set_fields``, which never touches ``mode``/``set_by``.
2216
2289
  """
2217
2290
  from services import enforcement_policy as ep
2218
2291
 
2219
2292
  data = request.get_json(force=True) or {}
2220
2293
  path = (data.get("path") or "").strip()
2294
+ scope = (data.get("scope") or "project").strip().lower()
2221
2295
  mode = (data.get("mode") or "").strip().lower()
2222
2296
  ttl = data.get("signal_ttl_s")
2223
- if not path or not mode:
2224
- return jsonify({"error": "path and mode are required"}), 400
2225
- try:
2226
- resolved = _resolve_project_path(path)
2227
- except ValueError as e:
2228
- return jsonify({"error": str(e)}), 404
2297
+ blocked = data.get("blocked_tools")
2298
+ if scope not in ("project", "global"):
2299
+ return jsonify({"error": "scope must be 'project' or 'global'"}), 400
2300
+ if scope == "project":
2301
+ if not path:
2302
+ return jsonify({"error": "path is required for project scope"}), 400
2303
+ try:
2304
+ resolved = _resolve_project_path(path)
2305
+ except ValueError as e:
2306
+ return jsonify({"error": str(e)}), 404
2307
+ else:
2308
+ resolved = "."
2229
2309
 
2230
2310
  try:
2231
- result = ep.set_mode(mode, resolved, set_by=ep.SET_BY_USER,
2232
- scope="project",
2233
- signal_ttl_s=int(ttl) if ttl else None)
2311
+ if mode:
2312
+ result = ep.set_mode(mode, resolved, set_by=ep.SET_BY_USER,
2313
+ scope=scope, signal_ttl_s=ttl,
2314
+ blocked_tools=blocked)
2315
+ elif ttl is not None or blocked is not None:
2316
+ result = ep.set_fields(resolved, scope=scope,
2317
+ signal_ttl_s=ttl, blocked_tools=blocked)
2318
+ else:
2319
+ return jsonify({"error": "nothing to set — pass mode, "
2320
+ "signal_ttl_s or blocked_tools"}), 400
2234
2321
  except (ValueError, TypeError) as e:
2235
2322
  return jsonify({"error": str(e)}), 400
2236
2323
 
2237
- try:
2238
- from services.activity_log import ActivityLog
2239
- ActivityLog(resolved).log("access_action", {
2240
- "kind": "enforcement", "action": "set_mode",
2241
- "mode": result["mode"], "previous": result.get("previous", ""),
2242
- "scope": result["scope"], "via": "hub"})
2243
- except Exception:
2244
- pass
2245
- try:
2246
- from services.edit_ledger import EditLedger
2247
- EditLedger(resolved).log_edit(
2248
- file=f"enforcement://{result['scope']}",
2249
- change_type="enforcement_set_mode",
2250
- summary=(f"tool discipline {result.get('previous') or 'default'} "
2251
- f"-> {result['mode']} via the Hub"),
2252
- tags=["enforcement", "access"],
2253
- detail={"kind": "enforcement", "mode": result["mode"],
2254
- "previous": result.get("previous", ""),
2255
- "scope": result["scope"], "via": "hub"})
2256
- except Exception:
2257
- pass
2324
+ # Audit on the target project. Global scope has no target project to
2325
+ # audit into — the ~/.c3/config.json write is itself the record.
2326
+ if scope == "project":
2327
+ action = "set_mode" if mode else "set_fields"
2328
+ detail = {"kind": "enforcement", "action": action,
2329
+ "mode": result.get("mode", ""),
2330
+ "previous": result.get("previous", ""),
2331
+ "scope": result["scope"], "via": "hub"}
2332
+ if "signal_ttl_s" in result:
2333
+ detail["signal_ttl_s"] = result["signal_ttl_s"]
2334
+ if "blocked_tools" in result:
2335
+ detail["blocked_tools"] = result["blocked_tools"]
2336
+ if mode:
2337
+ summary = (f"tool discipline {result.get('previous') or 'default'} "
2338
+ f"-> {result['mode']} via the Hub")
2339
+ else:
2340
+ parts = []
2341
+ if "signal_ttl_s" in result:
2342
+ parts.append(f"signal_ttl_s={result['signal_ttl_s']}")
2343
+ if "blocked_tools" in result:
2344
+ parts.append("blocked_tools="
2345
+ + ",".join(result["blocked_tools"] or ["<none>"]))
2346
+ summary = "tool discipline " + ", ".join(parts) + " via the Hub"
2347
+ try:
2348
+ from services.activity_log import ActivityLog
2349
+ ActivityLog(resolved).log("access_action", dict(detail))
2350
+ except Exception:
2351
+ pass
2352
+ try:
2353
+ from services.edit_ledger import EditLedger
2354
+ EditLedger(resolved).log_edit(
2355
+ file=f"enforcement://{result['scope']}",
2356
+ change_type=f"enforcement_{action}",
2357
+ summary=summary,
2358
+ tags=["enforcement", "access"],
2359
+ detail=detail)
2360
+ except Exception:
2361
+ pass
2258
2362
  return jsonify(result)
2259
2363
 
2260
2364
 
2365
+ @app.route("/api/projects/enforcement/denials/search", methods=["GET"])
2366
+ def api_projects_enforcement_denials_search():
2367
+ """Search one project's raw denial events. Read-only; newest first.
2368
+
2369
+ Params: ``path`` (required), ``q`` (AND'd case-insensitive substrings over
2370
+ path/rule/tool), ``layer``, ``tool`` (exact), ``session`` (prefix — the UI
2371
+ shows 8-char short ids), ``since`` (ISO-8601; events store
2372
+ second-resolution UTC isoformat, so plain string comparison is correct),
2373
+ ``limit`` (default 200, cap 500).
2374
+ """
2375
+ from services import access_telemetry as at
2376
+
2377
+ path = (request.args.get("path") or "").strip()
2378
+ if not path:
2379
+ return jsonify({"error": "path is required"}), 400
2380
+ try:
2381
+ resolved = _resolve_project_path(path)
2382
+ except ValueError as e:
2383
+ return jsonify({"error": str(e)}), 404
2384
+ return jsonify(at.search_events(
2385
+ resolved,
2386
+ q=request.args.get("q") or "",
2387
+ layer=request.args.get("layer") or "",
2388
+ tool=request.args.get("tool") or "",
2389
+ session=request.args.get("session") or "",
2390
+ since=request.args.get("since") or "",
2391
+ limit=request.args.get("limit") or 200))
2392
+
2393
+
2261
2394
  @app.route("/api/projects/enforcement/denials", methods=["DELETE"])
2262
2395
  def api_projects_enforcement_denials_clear():
2263
2396
  """Reset one project's denial counters (they are diagnostics, not audit)."""
@@ -14,6 +14,7 @@ const DRILL_PANEL_TABS = [
14
14
  ['health', 'Health'],
15
15
  ['budget', 'Budget'],
16
16
  ['creds', 'Credentials'],
17
+ ['discipline', 'Discipline'],
17
18
  ['config', 'Config'],
18
19
  ['mcp', 'MCP'],
19
20
  ];
@@ -134,6 +135,7 @@ function DrillPanel({ project, tab, setTab, onClose, onChanged, onOpenModal, pro
134
135
  case 'health': return <DrillHealth project={project} onChanged={onChanged} />;
135
136
  case 'budget': return <DrillBudget project={project} />;
136
137
  case 'creds': return <DrillCredentials project={project} />;
138
+ case 'discipline': return <DrillDiscipline project={project} />;
137
139
  case 'config': return <ConfigEditor project={project} />;
138
140
  case 'mcp': return <McpManager project={project} onChanged={onChanged} />;
139
141
  default: return <DrillOverview project={project} onChanged={onChanged} setTab={setTab} />;