code-context-control 2.64.0__tar.gz → 2.65.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 (387) hide show
  1. {code_context_control-2.64.0 → code_context_control-2.65.0}/PKG-INFO +1 -1
  2. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/c3.py +153 -3
  3. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/commands/parser.py +42 -0
  4. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_server.py +94 -2
  5. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/app.js +4 -2
  6. code_context_control-2.65.0/cli/hub_ui/components/hub_locks.js +248 -0
  7. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/topbar.js +1 -1
  8. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/mcp_server.py +18 -0
  9. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/edit.py +192 -94
  10. code_context_control-2.65.0/cli/tools/locks.py +132 -0
  11. {code_context_control-2.64.0 → code_context_control-2.65.0}/code_context_control.egg-info/PKG-INFO +1 -1
  12. {code_context_control-2.64.0 → code_context_control-2.65.0}/code_context_control.egg-info/SOURCES.txt +7 -0
  13. {code_context_control-2.64.0 → code_context_control-2.65.0}/pyproject.toml +1 -1
  14. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/access_guard.py +207 -10
  15. code_context_control-2.65.0/services/agent_locks.py +521 -0
  16. code_context_control-2.65.0/tests/test_access_builtin_optout.py +208 -0
  17. code_context_control-2.65.0/tests/test_agent_locks.py +470 -0
  18. code_context_control-2.65.0/tests/test_edit_locking.py +288 -0
  19. code_context_control-2.65.0/tests/test_hub_locks_routes.py +151 -0
  20. {code_context_control-2.64.0 → code_context_control-2.65.0}/LICENSE +0 -0
  21. {code_context_control-2.64.0 → code_context_control-2.65.0}/README.md +0 -0
  22. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/__init__.py +0 -0
  23. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/_hook_utils.py +0 -0
  24. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/commands/__init__.py +0 -0
  25. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/commands/common.py +0 -0
  26. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/docs.html +0 -0
  27. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/edits.html +0 -0
  28. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/access.html +0 -0
  29. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/bitbucket.html +0 -0
  30. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/credentials.html +0 -0
  31. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/getting-started.html +0 -0
  32. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/index.html +0 -0
  33. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/masking.html +0 -0
  34. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/oracle.html +0 -0
  35. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/shared.css +0 -0
  36. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/tools.html +0 -0
  37. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/guide/workflow.html +0 -0
  38. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_access_guard.py +0 -0
  39. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_artifact.py +0 -0
  40. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_auto_snapshot.py +0 -0
  41. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_c3_signal.py +0 -0
  42. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_c3read.py +0 -0
  43. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_dispatch.py +0 -0
  44. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_edit_ledger.py +0 -0
  45. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_edit_unlock.py +0 -0
  46. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_filter.py +0 -0
  47. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_ghost_files.py +0 -0
  48. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_pretool_enforce.py +0 -0
  49. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_prompt_recall.py +0 -0
  50. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_read.py +0 -0
  51. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_session_stats.py +0 -0
  52. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hook_terse_advisor.py +0 -0
  53. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/add_project.js +0 -0
  54. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/config_editor.js +0 -0
  55. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  56. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/drill_health.js +0 -0
  57. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/drill_panel.js +0 -0
  58. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  59. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  60. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/drill_views.js +0 -0
  61. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/global_search.js +0 -0
  62. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  63. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  64. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/modals.js +0 -0
  65. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/project_card.js +0 -0
  66. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/project_tree.js +0 -0
  67. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/session_drawer.js +0 -0
  68. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/settings_modal.js +0 -0
  69. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/sidebar.js +0 -0
  70. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/summary_bar.js +0 -0
  71. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/task_board.js +0 -0
  72. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/components/toasts.js +0 -0
  73. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui/state.js +0 -0
  74. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/hub_ui.html +0 -0
  75. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/mcp_proxy.py +0 -0
  76. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/progress.py +0 -0
  77. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/server.py +0 -0
  78. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/__init__.py +0 -0
  79. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/_helpers.py +0 -0
  80. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/agent.py +0 -0
  81. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/artifacts.py +0 -0
  82. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/bitbucket.py +0 -0
  83. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/compress.py +0 -0
  84. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/credentials.py +0 -0
  85. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/delegate.py +0 -0
  86. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/edits.py +0 -0
  87. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/federate.py +0 -0
  88. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/filter.py +0 -0
  89. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/impact.py +0 -0
  90. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/jira.py +0 -0
  91. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/memory.py +0 -0
  92. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/project.py +0 -0
  93. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/read.py +0 -0
  94. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/search.py +0 -0
  95. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/session.py +0 -0
  96. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/shell.py +0 -0
  97. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/status.py +0 -0
  98. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/tasks.py +0 -0
  99. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/tools/validate.py +0 -0
  100. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/api.js +0 -0
  101. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/app.js +0 -0
  102. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/access.js +0 -0
  103. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/bitbucket.js +0 -0
  104. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/chat.js +0 -0
  105. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/credentials.js +0 -0
  106. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/dashboard.js +0 -0
  107. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/edits.js +0 -0
  108. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/instructions.js +0 -0
  109. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/jira.js +0 -0
  110. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/memory.js +0 -0
  111. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/sessions.js +0 -0
  112. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/settings.js +0 -0
  113. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/sidebar.js +0 -0
  114. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/components/tasks.js +0 -0
  115. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/icons.js +0 -0
  116. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/pm_shared.js +0 -0
  117. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/shared.js +0 -0
  118. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui/theme.js +0 -0
  119. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui.html +0 -0
  120. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui_legacy.html +0 -0
  121. {code_context_control-2.64.0 → code_context_control-2.65.0}/cli/ui_nano.html +0 -0
  122. {code_context_control-2.64.0 → code_context_control-2.65.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  123. {code_context_control-2.64.0 → code_context_control-2.65.0}/code_context_control.egg-info/entry_points.txt +0 -0
  124. {code_context_control-2.64.0 → code_context_control-2.65.0}/code_context_control.egg-info/requires.txt +0 -0
  125. {code_context_control-2.64.0 → code_context_control-2.65.0}/code_context_control.egg-info/top_level.txt +0 -0
  126. {code_context_control-2.64.0 → code_context_control-2.65.0}/core/__init__.py +0 -0
  127. {code_context_control-2.64.0 → code_context_control-2.65.0}/core/config.py +0 -0
  128. {code_context_control-2.64.0 → code_context_control-2.65.0}/core/ide.py +0 -0
  129. {code_context_control-2.64.0 → code_context_control-2.65.0}/core/mcp_toml.py +0 -0
  130. {code_context_control-2.64.0 → code_context_control-2.65.0}/core/web_security.py +0 -0
  131. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/__init__.py +0 -0
  132. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/config.py +0 -0
  133. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/mcp_oracle.py +0 -0
  134. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/oracle_server.py +0 -0
  135. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/oracle_ui.html +0 -0
  136. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/__init__.py +0 -0
  137. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/activity_reporter.py +0 -0
  138. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/api_auth.py +0 -0
  139. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/c3_bridge.py +0 -0
  140. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/chat_engine.py +0 -0
  141. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/chat_store.py +0 -0
  142. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/cross_memory.py +0 -0
  143. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/discovery_audit.py +0 -0
  144. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/federated_graph.py +0 -0
  145. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/health_checker.py +0 -0
  146. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/insight_engine.py +0 -0
  147. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/local_session.py +0 -0
  148. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/memory_reader.py +0 -0
  149. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/memory_writer.py +0 -0
  150. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/project_scanner.py +0 -0
  151. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/review_agent.py +0 -0
  152. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/tool_executor.py +0 -0
  153. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/services/tool_registry.py +0 -0
  154. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/activity.js +0 -0
  155. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/agents.js +0 -0
  156. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/app.js +0 -0
  157. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/busy.js +0 -0
  158. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/chat/conversations.js +0 -0
  159. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/chat/input.js +0 -0
  160. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/chat/markdown.js +0 -0
  161. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/chat/send.js +0 -0
  162. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/chat/stream_renderer.js +0 -0
  163. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/chat/toolbar.js +0 -0
  164. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/core.js +0 -0
  165. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/crossgraph.js +0 -0
  166. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/header.js +0 -0
  167. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/insights.js +0 -0
  168. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/projects.js +0 -0
  169. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/settings.js +0 -0
  170. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/suggestions.js +0 -0
  171. {code_context_control-2.64.0 → code_context_control-2.65.0}/oracle/ui/theme_tabs.js +0 -0
  172. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/__init__.py +0 -0
  173. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/activity_log.py +0 -0
  174. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/agent_base.py +0 -0
  175. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/agents.py +0 -0
  176. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/artifact_defs.py +0 -0
  177. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/artifact_store.py +0 -0
  178. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/auto_memory.py +0 -0
  179. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/bench/__init__.py +0 -0
  180. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/bench/external/__init__.py +0 -0
  181. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/bench/external/aider_polyglot.py +0 -0
  182. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/bench/external/swe_bench.py +0 -0
  183. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/benchmark_dashboard.py +0 -0
  184. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/bitbucket_client.py +0 -0
  185. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/bitbucket_credentials.py +0 -0
  186. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/circuit_breaker.py +0 -0
  187. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/claude_md.py +0 -0
  188. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/compressor.py +0 -0
  189. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/context_snapshot.py +0 -0
  190. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/conversation_store.py +0 -0
  191. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/credential_store.py +0 -0
  192. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/doc_index.py +0 -0
  193. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/e2e_benchmark.py +0 -0
  194. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/e2e_evaluator.py +0 -0
  195. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/e2e_tasks.py +0 -0
  196. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/edit_ledger.py +0 -0
  197. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/embedding_index.py +0 -0
  198. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/error_reporting.py +0 -0
  199. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/file_memory.py +0 -0
  200. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/git_context.py +0 -0
  201. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/hub_service.py +0 -0
  202. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/indexer.py +0 -0
  203. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/jira_client.py +0 -0
  204. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/jira_cloud.py +0 -0
  205. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/jira_credentials.py +0 -0
  206. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/jira_data_center.py +0 -0
  207. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/jira_links.py +0 -0
  208. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/mask_activation.py +0 -0
  209. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/mask_mirror.py +0 -0
  210. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/mask_presets.py +0 -0
  211. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory.py +0 -0
  212. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory_consolidator.py +0 -0
  213. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory_distiller.py +0 -0
  214. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory_graph.py +0 -0
  215. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory_grounder.py +0 -0
  216. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory_queue.py +0 -0
  217. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/memory_scorer.py +0 -0
  218. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/metrics.py +0 -0
  219. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/notifications.py +0 -0
  220. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/ollama_bridge.py +0 -0
  221. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/ollama_client.py +0 -0
  222. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/ollama_credentials.py +0 -0
  223. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/output_filter.py +0 -0
  224. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/parser.py +0 -0
  225. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/project_manager.py +0 -0
  226. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/project_runtime.py +0 -0
  227. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/protocol.py +0 -0
  228. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/proxy_state.py +0 -0
  229. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/repo_map.py +0 -0
  230. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/retention.py +0 -0
  231. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/retrieval_broker.py +0 -0
  232. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/router.py +0 -0
  233. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/runtime.py +0 -0
  234. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/scanner.py +0 -0
  235. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/session_benchmark.py +0 -0
  236. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/session_manager.py +0 -0
  237. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/session_preloader.py +0 -0
  238. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/subprojects.py +0 -0
  239. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/task_store.py +0 -0
  240. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/telemetry.py +0 -0
  241. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/text_index.py +0 -0
  242. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/time_tracker.py +0 -0
  243. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/tool_classifier.py +0 -0
  244. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/transcript_index.py +0 -0
  245. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/validation_cache.py +0 -0
  246. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/vector_store.py +0 -0
  247. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/watcher.py +0 -0
  248. {code_context_control-2.64.0 → code_context_control-2.65.0}/services/win_subprocess.py +0 -0
  249. {code_context_control-2.64.0 → code_context_control-2.65.0}/setup.cfg +0 -0
  250. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_access_guard.py +0 -0
  251. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_access_guard_meta.py +0 -0
  252. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_access_guard_shell_project.py +0 -0
  253. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_access_guard_surfaces.py +0 -0
  254. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_access_guard_wiring.py +0 -0
  255. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_activity_reporter.py +0 -0
  256. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_aider_polyglot.py +0 -0
  257. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_antigravity_transition.py +0 -0
  258. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_artifact_store.py +0 -0
  259. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_artifact_tool.py +0 -0
  260. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  261. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_bitbucket_client.py +0 -0
  262. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_bitbucket_config_fallback.py +0 -0
  263. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_bitbucket_credentials.py +0 -0
  264. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_bitbucket_tool.py +0 -0
  265. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  266. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_c3_shell.py +0 -0
  267. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_circuit_breaker.py +0 -0
  268. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_claude_md_merge.py +0 -0
  269. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_cli_smoke.py +0 -0
  270. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_compressor_large_file.py +0 -0
  271. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_credential_store.py +0 -0
  272. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_credentials_routes.py +0 -0
  273. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_credentials_tool.py +0 -0
  274. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_creds_cli_smoke.py +0 -0
  275. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_delegate_cascade.py +0 -0
  276. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_e2e_benchmark.py +0 -0
  277. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_edit_ledger_hook.py +0 -0
  278. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_edit_normalization.py +0 -0
  279. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_enforcement_flip.py +0 -0
  280. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_federated_graph.py +0 -0
  281. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_filter_backoff.py +0 -0
  282. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_ghost_files.py +0 -0
  283. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_ghost_generation.py +0 -0
  284. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_git_branch_awareness.py +0 -0
  285. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_access_guard.py +0 -0
  286. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_dispatch.py +0 -0
  287. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_pretool_enforce.py +0 -0
  288. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_prompt_recall.py +0 -0
  289. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_smoke.py +0 -0
  290. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_state.py +0 -0
  291. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hook_utf8_stdio.py +0 -0
  292. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hub_credentials_route.py +0 -0
  293. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hub_credentials_routes_write.py +0 -0
  294. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hub_inspect_api.py +0 -0
  295. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hub_server_smoke.py +0 -0
  296. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_hub_subproject_links.py +0 -0
  297. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_ide_workflow_adaptation.py +0 -0
  298. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_init_scan.py +0 -0
  299. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_install_mcp_entrypoint.py +0 -0
  300. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_cli_smoke.py +0 -0
  301. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_client.py +0 -0
  302. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_config_fallback.py +0 -0
  303. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_credentials.py +0 -0
  304. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_links.py +0 -0
  305. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_routes.py +0 -0
  306. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_jira_tool.py +0 -0
  307. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_lazy_store_init.py +0 -0
  308. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mask_guard.py +0 -0
  309. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mask_routes.py +0 -0
  310. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mask_surfaces.py +0 -0
  311. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mcp_host_guard.py +0 -0
  312. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mcp_memory_timeout.py +0 -0
  313. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mcp_server_smoke.py +0 -0
  314. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_mcp_toml.py +0 -0
  315. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_memory_distiller.py +0 -0
  316. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_memory_graph_api.py +0 -0
  317. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_memory_queue.py +0 -0
  318. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_memory_system.py +0 -0
  319. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_no_stale_model_pins.py +0 -0
  320. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_notification_dedup.py +0 -0
  321. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_notification_discipline.py +0 -0
  322. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_ollama_credentials.py +0 -0
  323. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_api_auth.py +0 -0
  324. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_apikey_api.py +0 -0
  325. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_c3_bridge.py +0 -0
  326. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_chat_engine.py +0 -0
  327. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_chat_store.py +0 -0
  328. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_discovery_api.py +0 -0
  329. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_discovery_audit.py +0 -0
  330. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_local_auth.py +0 -0
  331. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_ollama_bridge.py +0 -0
  332. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_scanner_cache.py +0 -0
  333. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_security_fixes.py +0 -0
  334. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_session_bootstrap.py +0 -0
  335. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_subproject_awareness.py +0 -0
  336. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_oracle_ui_bundle.py +0 -0
  337. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_output_filter.py +0 -0
  338. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_permissions.py +0 -0
  339. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_pm_api.py +0 -0
  340. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_project_manager.py +0 -0
  341. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_project_manager_merge.py +0 -0
  342. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_project_tool.py +0 -0
  343. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_read_coercion.py +0 -0
  344. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_read_edit_parity.py +0 -0
  345. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_related_facts.py +0 -0
  346. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_repo_map.py +0 -0
  347. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_response_boilerplate.py +0 -0
  348. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_retention.py +0 -0
  349. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_review_digest.py +0 -0
  350. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_service_durability.py +0 -0
  351. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_session_benchmark.py +0 -0
  352. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_session_budget.py +0 -0
  353. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_shell_creds.py +0 -0
  354. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_shell_robustness.py +0 -0
  355. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_subproject_exclusion.py +0 -0
  356. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_subproject_federation.py +0 -0
  357. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_subprojects.py +0 -0
  358. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_swe_bench.py +0 -0
  359. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_task_store.py +0 -0
  360. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_task_tool.py +0 -0
  361. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_time_tracker.py +0 -0
  362. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_token_telemetry.py +0 -0
  363. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_tool_registry.py +0 -0
  364. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_upgrade_and_version.py +0 -0
  365. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_validate.py +0 -0
  366. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_vault_write_guard.py +0 -0
  367. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_version_sync.py +0 -0
  368. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_web_security.py +0 -0
  369. {code_context_control-2.64.0 → code_context_control-2.65.0}/tests/test_windows_reliability.py +0 -0
  370. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/__init__.py +0 -0
  371. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/backend.py +0 -0
  372. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/main.py +0 -0
  373. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/__init__.py +0 -0
  374. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/benchmark_view.py +0 -0
  375. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/claudemd_view.py +0 -0
  376. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/compress_view.py +0 -0
  377. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/index_view.py +0 -0
  378. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/init_view.py +0 -0
  379. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/mcp_view.py +0 -0
  380. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/optimize_view.py +0 -0
  381. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/pipe_view.py +0 -0
  382. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/projects_view.py +0 -0
  383. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/search_view.py +0 -0
  384. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/session_view.py +0 -0
  385. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/stats.py +0 -0
  386. {code_context_control-2.64.0 → code_context_control-2.65.0}/tui/screens/ui_view.py +0 -0
  387. {code_context_control-2.64.0 → code_context_control-2.65.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.64.0
3
+ Version: 2.65.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
@@ -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.64.0"
95
+ __version__ = "2.65.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -257,7 +257,8 @@ _C3_MCP_ALLOW = [
257
257
  "mcp__c3__c3_session", "mcp__c3__c3_status", "mcp__c3__c3_filter",
258
258
  "mcp__c3__c3_memory", "mcp__c3__c3_validate", "mcp__c3__c3_edit",
259
259
  "mcp__c3__c3_agent", "mcp__c3__c3_delegate", "mcp__c3__c3_edits",
260
- "mcp__c3__c3_impact", "mcp__c3__c3_shell", "mcp__c3__c3_bitbucket",
260
+ "mcp__c3__c3_impact", "mcp__c3__c3_locks", "mcp__c3__c3_shell",
261
+ "mcp__c3__c3_bitbucket",
261
262
  "mcp__c3__c3_jira", "mcp__c3__c3_credentials",
262
263
  "mcp__c3__c3_project", "mcp__c3__c3_task", "mcp__c3__c3_artifacts",
263
264
  ]
@@ -5208,6 +5209,7 @@ def cmd_install_mcp(args):
5208
5209
  "mcp__c3__c3_edit",
5209
5210
  "mcp__c3__c3_edits",
5210
5211
  "mcp__c3__c3_impact",
5212
+ "mcp__c3__c3_locks",
5211
5213
  "mcp__c3__c3_status",
5212
5214
  "mcp__c3__c3_delegate",
5213
5215
  "mcp__c3__c3_session",
@@ -5923,12 +5925,90 @@ def _creds_cmd_import(args, project_path: str) -> None:
5923
5925
  "(use --overwrite to replace)")
5924
5926
 
5925
5927
 
5928
+ def cmd_locks(args):
5929
+ """Agent Locks — human surface. force-release lives here, never in c3_locks."""
5930
+ from services import agent_locks as al
5931
+
5932
+ sub = getattr(args, "locks_cmd", None) or "list"
5933
+ project_path = getattr(args, "project_path", ".") or "."
5934
+ store = al.store_for(project_path)
5935
+ cfg = al.config(project_path)
5936
+
5937
+ if sub == "list":
5938
+ snap = store.snapshot()
5939
+ print(f"{snap['count']} active lease(s) — mode={cfg['mode']}, "
5940
+ f"enabled={cfg['enabled']}, fencing={snap['fencing']}")
5941
+ if not snap["locks"]:
5942
+ return
5943
+ print(f" {'file':<44} {'holder':<24} {'left':<8} intent")
5944
+ for row in snap["locks"]:
5945
+ left = int(max(0, row.get("expires_in_s", 0)))
5946
+ print(f" {row['relpath']:<44} {row['agent_id']:<24} "
5947
+ f"{left//60}m{left % 60:02d}s {row.get('intent', '')}")
5948
+ return
5949
+
5950
+ if sub == "release":
5951
+ res = store.release(session_id=args.session)
5952
+ print(f"Released {res['count']} lease(s)"
5953
+ + (f": {', '.join(res['released'])}" if res["released"] else ""))
5954
+ return
5955
+
5956
+ if sub == "force-release":
5957
+ res = store.force_release(args.file, by="cli", note=args.note)
5958
+ if not res.get("forced"):
5959
+ print(f"[error] {res.get('error')}: {res.get('reason', '')}")
5960
+ return
5961
+ _locks_audit(args.file, res, project_path, args.note)
5962
+ if res["was_locked"]:
5963
+ print(f"[OK] Broke the lease on {res['relpath']} "
5964
+ f"(was held by {res['previous_owner']}).")
5965
+ print(" The fencing token moved, so the old holder is stale "
5966
+ "even if it thinks it still holds it.")
5967
+ else:
5968
+ print(f"[=] {res['relpath']} was not locked; fencing bumped anyway.")
5969
+ return
5970
+
5971
+ if sub == "sweep":
5972
+ res = store.sweep()
5973
+ print(f"Swept {res['count']} expired lease(s)"
5974
+ + (f": {', '.join(res['expired'])}" if res["expired"] else ""))
5975
+ return
5976
+
5977
+ print("Usage: c3 locks {list,release,force-release,sweep}")
5978
+
5979
+
5980
+ def _locks_audit(target: str, res: dict, project_path: str, note: str) -> None:
5981
+ """Ledger + activity log for a human lease override. Failure-safe."""
5982
+ try:
5983
+ from services.activity_log import ActivityLog
5984
+ ActivityLog(project_path).log("lock_force_release", {
5985
+ "kind": "locks", "relpath": res.get("relpath"),
5986
+ "previous_owner": res.get("previous_owner"), "via": "cli",
5987
+ })
5988
+ except Exception:
5989
+ pass
5990
+ try:
5991
+ from services.edit_ledger import EditLedger
5992
+ EditLedger(project_path).log_edit(
5993
+ file=f"lock://{res.get('relpath', target)}",
5994
+ change_type="lock_force_release",
5995
+ summary=f"force-released lease on {res.get('relpath', target)}"
5996
+ + (f" — {note}" if note else ""),
5997
+ tags=["locks", "force_release"],
5998
+ detail={"kind": "locks", "previous_owner": res.get("previous_owner"),
5999
+ "was_locked": res.get("was_locked"), "note": note},
6000
+ )
6001
+ except Exception:
6002
+ pass
6003
+
6004
+
5926
6005
  def cmd_access(args):
5927
6006
  """Access Guard rule management — human-only mutation surface (spec §1)."""
5928
6007
  sub = getattr(args, "access_cmd", None)
5929
6008
  if not sub:
5930
- print("Usage: c3 access {list,add,remove,check,mask} [args]")
6009
+ print("Usage: c3 access {list,add,remove,check,mask,builtin} [args]")
5931
6010
  print(" c3 access mask {add,rm,status,activate,preview} [args]")
6011
+ print(" c3 access builtin {disable,enable} <glob>")
5932
6012
  return
5933
6013
 
5934
6014
  project_path = getattr(args, "project_path", ".") or "."
@@ -5943,6 +6023,8 @@ def cmd_access(args):
5943
6023
  _access_cmd_check(args, project_path)
5944
6024
  elif sub == "mask":
5945
6025
  _access_cmd_mask(args, project_path)
6026
+ elif sub == "builtin":
6027
+ _access_cmd_builtin(args, project_path)
5946
6028
  else:
5947
6029
  print(f"Unknown access subcommand: {sub}")
5948
6030
 
@@ -5998,6 +6080,21 @@ def _access_cmd_list(args, project_path: str) -> None:
5998
6080
  print(" [warn] access section invalid — scope fails closed "
5999
6081
  "(deny-all); fix config.json 'access' by hand")
6000
6082
  if scope == "builtin":
6083
+ off = sec.get("disabled") or []
6084
+ if off:
6085
+ print(" DISABLED by you (not enforced):")
6086
+ for glob in off:
6087
+ print(f" {'off':<10} {glob}")
6088
+ print(" re-enable: c3 access builtin enable <glob>")
6089
+ can = [g for g in (sec.get("disableable") or [])
6090
+ if access_guard._norm_builtin(g) not in set(off)]
6091
+ if can:
6092
+ print(" disableable (currently on): "
6093
+ + ", ".join(can))
6094
+ print(" disable: c3 access builtin disable <glob>")
6095
+ if sec.get("absolute"):
6096
+ print(" absolute (credential vault, cannot be disabled): "
6097
+ + ", ".join(sec["absolute"]))
6001
6098
  print(" spelling rules (deny by how a path is written, no glob):")
6002
6099
  for name, why in access_guard.SYNTHETIC_RULES:
6003
6100
  print(f" {name:<18} {why}")
@@ -6010,6 +6107,58 @@ def _access_cmd_list(args, project_path: str) -> None:
6010
6107
  print(access_guard.COVERAGE_MATRIX)
6011
6108
 
6012
6109
 
6110
+ def _access_cmd_builtin(args, project_path: str) -> None:
6111
+ """Switch a Tier-1 builtin off or back on. Human-only; always global scope.
6112
+
6113
+ Disabling asks for typed confirmation unless --yes: these guards are what
6114
+ stop an agent rewriting its own hooks, settings or git history, and the
6115
+ consequence deserves a beat of friction.
6116
+ """
6117
+ from services import access_guard
6118
+
6119
+ action = getattr(args, "builtin_cmd", None)
6120
+ glob = getattr(args, "glob", None)
6121
+ if action not in ("disable", "enable") or not glob:
6122
+ print("Usage: c3 access builtin {disable,enable} <glob>")
6123
+ print(" disableable: "
6124
+ + ", ".join(access_guard.DISABLEABLE_BUILTINS))
6125
+ return
6126
+
6127
+ disabling = action == "disable"
6128
+ if disabling and not getattr(args, "yes", False):
6129
+ print(f"About to STOP enforcing the builtin guard on: {glob}")
6130
+ print(" While off, any agent with C3 tools can write those paths.")
6131
+ if glob.endswith("settings*.json") or ".claude" in glob:
6132
+ print(" This is the file that configures the agent itself — hooks,")
6133
+ print(" permissions, model. An agent could rewrite its own rules.")
6134
+ reply = input("Type the glob again to confirm: ").strip()
6135
+ if reply != glob:
6136
+ print("[abort] Not confirmed; nothing changed.")
6137
+ return
6138
+
6139
+ try:
6140
+ result = access_guard.set_builtin_disabled(glob, disabling)
6141
+ except ValueError as exc:
6142
+ print(f"[error] {exc}")
6143
+ return
6144
+
6145
+ _access_audit(f"builtin_{action}", result["glob"], "builtin", "global",
6146
+ project_path)
6147
+ if not result["changed"]:
6148
+ state = "already disabled" if disabling else "already enforced"
6149
+ print(f"[=] {result['glob']} — {state}")
6150
+ return
6151
+ if disabling:
6152
+ print(f"[OK] Builtin '{result['glob']}' DISABLED (global scope).")
6153
+ print(" Re-enable with: c3 access builtin enable "
6154
+ f"{result['glob']}")
6155
+ else:
6156
+ print(f"[OK] Builtin '{result['glob']}' re-enforced.")
6157
+ if not result["attested"]:
6158
+ print(" [warn] keyring attestation could not be cleared; the "
6159
+ "builtin is enforced anyway (config entry removed).")
6160
+
6161
+
6013
6162
  def _access_cmd_add(args, project_path: str) -> None:
6014
6163
  from services import access_guard
6015
6164
 
@@ -7583,6 +7732,7 @@ def main():
7583
7732
  "jira": cmd_jira,
7584
7733
  "creds": cmd_creds,
7585
7734
  "access": cmd_access,
7735
+ "locks": cmd_locks,
7586
7736
  "oracle": cmd_oracle,
7587
7737
  "upgrade": cmd_upgrade,
7588
7738
  }
@@ -447,6 +447,30 @@ def build_parser(version: str, parse_cli_ide_arg):
447
447
  cr_import.add_argument("--overwrite", action="store_true", help="Replace entries already registered in the target scope")
448
448
  cr_import.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
449
449
 
450
+ # ── Agent Locks (docs/agent-locks.md) ───────────────────────────────
451
+ # force-release is human-only: it bumps the fencing counter so a holder
452
+ # that comes back is stale by construction. Agents get c3_locks instead,
453
+ # which deliberately has no force action.
454
+ p_locks = subparsers.add_parser(
455
+ "locks", help="Agent leases — see who holds which file, release a stuck one")
456
+ locks_subs = p_locks.add_subparsers(dest="locks_cmd")
457
+
458
+ lk_list = locks_subs.add_parser("list", help="Show active leases")
459
+ lk_list.add_argument("--path", dest="project_path", default=".")
460
+
461
+ lk_rel = locks_subs.add_parser("release", help="Release leases held by a session")
462
+ lk_rel.add_argument("--session", required=True, help="session_id to release")
463
+ lk_rel.add_argument("--path", dest="project_path", default=".")
464
+
465
+ lk_force = locks_subs.add_parser(
466
+ "force-release", help="Break one lease regardless of holder (audited)")
467
+ lk_force.add_argument("file", help="Project-relative path to unlock")
468
+ lk_force.add_argument("--note", default="", help="Why — recorded in the ledger")
469
+ lk_force.add_argument("--path", dest="project_path", default=".")
470
+
471
+ lk_sweep = locks_subs.add_parser("sweep", help="Drop expired leases now")
472
+ lk_sweep.add_argument("--path", dest="project_path", default=".")
473
+
450
474
  # ── Access Guard (v2.62.0) ──────────────────────────────────────────
451
475
  # Human-only mutation surface (frozen spec docs/access-guard.md §1):
452
476
  # rule changes happen here or in the UI tab, never via an agent tool.
@@ -483,6 +507,24 @@ def build_parser(version: str, parse_cli_ide_arg):
483
507
  help="Operation to evaluate (default: read)")
484
508
  ac_check.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
485
509
 
510
+ # ── Builtin opt-out (two-key) ───────────────────────────────────────
511
+ # Builtins are on by default. Switching one off needs a config entry AND
512
+ # a keyring attestation, so an agent that writes config.json alone still
513
+ # cannot loosen the guard. Global scope only — project scopes may only
514
+ # ever tighten. The credential-vault builtins are never disableable.
515
+ ac_builtin = access_subs.add_parser(
516
+ "builtin", help="Disable or re-enable a built-in guard (global, needs confirmation)")
517
+ builtin_subs = ac_builtin.add_subparsers(dest="builtin_cmd")
518
+ for _name, _help in (("disable", "Stop enforcing a built-in guard"),
519
+ ("enable", "Re-enforce a built-in guard")):
520
+ _p = builtin_subs.add_parser(_name, help=_help)
521
+ _p.add_argument("glob", help="One of: **/.env*, **/.c3/**, **/.claude/settings*.json, **/.git/**")
522
+ _p.add_argument("--path", dest="project_path", default=".",
523
+ help="Project directory used for the audit log (default: current)")
524
+ if _name == "disable":
525
+ _p.add_argument("--yes", action="store_true",
526
+ help="Skip the typed confirmation (scripts/CI)")
527
+
486
528
  # ── Mask Guard (v2.63.0, docs/mask-guard.md) ────────────────────────
487
529
  # Masking exposes a path but transforms what the agent sees. Rules are
488
530
  # human-only, like the rest of Access Guard.
@@ -335,6 +335,7 @@ _HUB_JS_FILES = [
335
335
  "hub_ui/components/drill_panel.js",
336
336
  "hub_ui/components/drill_views.js",
337
337
  "hub_ui/components/hub_credentials.js",
338
+ "hub_ui/components/hub_locks.js",
338
339
  "hub_ui/components/drill_subprojects.js",
339
340
  "hub_ui/components/drill_health.js",
340
341
  "hub_ui/components/drill_tasks.js",
@@ -433,8 +434,9 @@ def api_hub_config_set():
433
434
  cfg["projects_view"] = projects_view
434
435
  if "main_view" in data:
435
436
  main_view = str(data["main_view"]).strip().lower()
436
- if main_view not in {"projects", "board", "creds"}:
437
- return jsonify({"error": "main_view must be 'projects', 'board' or 'creds'"}), 400
437
+ if main_view not in {"projects", "board", "creds", "locks"}:
438
+ return jsonify({"error": "main_view must be 'projects', 'board', "
439
+ "'creds' or 'locks'"}), 400
438
440
  cfg["main_view"] = main_view
439
441
  if "oracle_url" in data:
440
442
  cfg["oracle_url"] = str(data["oracle_url"]).strip()
@@ -2039,6 +2041,96 @@ def api_hub_credentials_overview():
2039
2041
  return jsonify({"global": {"entries": global_out}, "projects": projects_out})
2040
2042
 
2041
2043
 
2044
+ # ── Agent Locks (hub) ────────────────────────────────────────────────────────
2045
+ # Read + one human override. force-release is here and in `c3 locks`, never in
2046
+ # the c3_locks agent tool: it bumps the fencing counter so a holder that comes
2047
+ # back is stale by construction, which is a decision for a person.
2048
+
2049
+
2050
+ @app.route("/api/hub/locks/overview", methods=["GET"])
2051
+ def api_hub_locks_overview():
2052
+ """Cross-project lease snapshot for the Locks tab.
2053
+
2054
+ Per-row isolation like /api/hub/credentials/overview: one unreadable
2055
+ project must not blank the page. A project we cannot read reports
2056
+ ``error``/``initialized`` rather than an empty lease list — "0 leases"
2057
+ would claim the repo is clear when we simply do not know.
2058
+ """
2059
+ from services import agent_locks as al
2060
+
2061
+ rows, total = [], 0
2062
+ for p in _pm().list_projects():
2063
+ ppath = str(p.get("path") or "")
2064
+ row = {"name": p.get("name") or "", "path": ppath, "initialized": True,
2065
+ "error": None, "enabled": True, "mode": "advisory",
2066
+ "locks": [], "count": 0, "fencing": 0}
2067
+ try:
2068
+ if not (Path(ppath) / ".c3").is_dir():
2069
+ row["initialized"] = False
2070
+ else:
2071
+ cfg = al.config(ppath)
2072
+ row["enabled"] = cfg["enabled"]
2073
+ row["mode"] = cfg["mode"]
2074
+ snap = al.store_for(ppath).snapshot()
2075
+ row["locks"] = snap["locks"]
2076
+ row["count"] = snap["count"]
2077
+ row["fencing"] = snap["fencing"]
2078
+ total += snap["count"]
2079
+ except Exception as e:
2080
+ row["error"] = str(e)
2081
+ rows.append(row)
2082
+ return jsonify({"projects": rows, "total": total,
2083
+ # Surfaced so the UI can state its own limits instead of
2084
+ # implying a lease covers everything (spec §9).
2085
+ "coverage_note": (
2086
+ "Leases gate C3 tool surfaces only. A raw shell "
2087
+ "redirect, a non-Claude agent, or a human in an editor "
2088
+ "is not covered.")})
2089
+
2090
+
2091
+ @app.route("/api/projects/locks/force-release", methods=["POST"])
2092
+ def api_projects_locks_force_release():
2093
+ """Break one lease regardless of holder. Human-only, audited on the target."""
2094
+ from services import agent_locks as al
2095
+
2096
+ data = request.get_json(force=True) or {}
2097
+ path = (data.get("path") or "").strip()
2098
+ relpath = (data.get("relpath") or "").strip()
2099
+ note = (data.get("note") or "").strip()
2100
+ if not path or not relpath:
2101
+ return jsonify({"error": "path and relpath are required"}), 400
2102
+ try:
2103
+ resolved = _resolve_project_path(path)
2104
+ except ValueError as e:
2105
+ return jsonify({"error": str(e)}), 404
2106
+
2107
+ res = al.store_for(resolved).force_release(relpath, by="hub", note=note)
2108
+ if not res.get("forced"):
2109
+ return jsonify({"error": res.get("error", "force-release failed"),
2110
+ "reason": res.get("reason", "")}), 400
2111
+
2112
+ try:
2113
+ from services.activity_log import ActivityLog
2114
+ ActivityLog(resolved).log("lock_force_release", {
2115
+ "kind": "locks", "relpath": res.get("relpath"),
2116
+ "previous_owner": res.get("previous_owner"), "via": "hub"})
2117
+ except Exception:
2118
+ pass
2119
+ try:
2120
+ from services.edit_ledger import EditLedger
2121
+ EditLedger(resolved).log_edit(
2122
+ file=f"lock://{res.get('relpath', relpath)}",
2123
+ change_type="lock_force_release",
2124
+ summary=f"force-released lease on {res.get('relpath', relpath)}"
2125
+ + (f" — {note}" if note else ""),
2126
+ tags=["locks", "force_release"],
2127
+ detail={"kind": "locks", "previous_owner": res.get("previous_owner"),
2128
+ "was_locked": res.get("was_locked"), "note": note})
2129
+ except Exception:
2130
+ pass
2131
+ return jsonify(res)
2132
+
2133
+
2042
2134
  @app.route("/api/projects/config", methods=["PUT"])
2043
2135
  def api_projects_config_put():
2044
2136
  """Whitelisted section write: deep-merge, atomic replace, audited on the target."""
@@ -17,7 +17,7 @@ function App() {
17
17
  const [version, setVersion] = useState('');
18
18
  const [projects, setProjects] = useState([]);
19
19
  const [loaded, setLoaded] = useState(false);
20
- const [mainView, setMainView] = useState('projects'); // projects | board | creds
20
+ const [mainView, setMainView] = useState('projects'); // projects | board | creds | locks
21
21
  const [filter, setFilter] = useState('all'); // all | active | idle | tag:<x>
22
22
  const [search, setSearch] = useState('');
23
23
  const [view, setView] = useState('list'); // list | grid
@@ -44,7 +44,7 @@ function App() {
44
44
  if (cfg.projects_view === 'grid') setView('grid');
45
45
  if (cfg.sidebar_collapsed != null) setSidebarCollapsed(!!cfg.sidebar_collapsed);
46
46
  if (cfg.sidebar_group) setFilter(cfg.sidebar_group);
47
- if (cfg.main_view === 'board' || cfg.main_view === 'creds') setMainView(cfg.main_view);
47
+ if (['board', 'creds', 'locks'].includes(cfg.main_view)) setMainView(cfg.main_view);
48
48
  } catch { }
49
49
  try { const v = await api.get('/api/version'); setVersion(v.c3_version || ''); } catch { }
50
50
  }, []);
@@ -114,6 +114,8 @@ function App() {
114
114
  <TaskBoard projects={projects} onOpenDrill={openDrill} />
115
115
  ) : mainView === 'creds' ? (
116
116
  <HubCredentials projects={projects} onOpenDrill={openDrill} />
117
+ ) : mainView === 'locks' ? (
118
+ <HubLocks projects={projects} onOpenDrill={openDrill} />
117
119
  ) : (
118
120
  <React.Fragment>
119
121
  <SummaryBar projects={projects} search={search} setSearch={setSearch}