code-context-control 2.61.2__tar.gz → 2.62.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 (369) hide show
  1. {code_context_control-2.61.2 → code_context_control-2.62.0}/PKG-INFO +40 -1
  2. {code_context_control-2.61.2 → code_context_control-2.62.0}/README.md +39 -0
  3. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/_hook_utils.py +22 -1
  4. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/c3.py +135 -5
  5. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/commands/parser.py +36 -0
  6. code_context_control-2.62.0/cli/guide/access.html +288 -0
  7. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/bitbucket.html +1 -0
  8. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/credentials.html +1 -0
  9. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/getting-started.html +1 -0
  10. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/index.html +9 -0
  11. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/oracle.html +1 -0
  12. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/tools.html +1 -0
  13. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/workflow.html +1 -0
  14. code_context_control-2.62.0/cli/hook_access_guard.py +119 -0
  15. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_dispatch.py +35 -3
  16. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_pretool_enforce.py +14 -2
  17. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_server.py +6 -2
  18. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/mcp_server.py +7 -3
  19. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/server.py +107 -1
  20. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/artifacts.py +8 -1
  21. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/compress.py +18 -1
  22. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/delegate.py +60 -1
  23. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/edit.py +11 -0
  24. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/filter.py +8 -0
  25. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/impact.py +20 -0
  26. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/project.py +88 -0
  27. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/read.py +12 -0
  28. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/search.py +51 -16
  29. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/shell.py +131 -0
  30. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/status.py +31 -1
  31. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/validate.py +13 -0
  32. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/app.js +4 -0
  33. code_context_control-2.62.0/cli/ui/components/access.js +332 -0
  34. {code_context_control-2.61.2 → code_context_control-2.62.0}/code_context_control.egg-info/PKG-INFO +40 -1
  35. {code_context_control-2.61.2 → code_context_control-2.62.0}/code_context_control.egg-info/SOURCES.txt +10 -0
  36. {code_context_control-2.61.2 → code_context_control-2.62.0}/pyproject.toml +1 -1
  37. code_context_control-2.62.0/services/access_guard.py +573 -0
  38. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/artifact_store.py +19 -0
  39. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/compressor.py +10 -1
  40. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/scanner.py +45 -0
  41. code_context_control-2.62.0/tests/test_access_guard.py +293 -0
  42. code_context_control-2.62.0/tests/test_access_guard_meta.py +155 -0
  43. code_context_control-2.62.0/tests/test_access_guard_shell_project.py +379 -0
  44. code_context_control-2.62.0/tests/test_access_guard_surfaces.py +335 -0
  45. code_context_control-2.62.0/tests/test_access_guard_wiring.py +330 -0
  46. code_context_control-2.62.0/tests/test_hook_access_guard.py +184 -0
  47. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hook_dispatch.py +6 -4
  48. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hook_pretool_enforce.py +1 -1
  49. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hook_smoke.py +2 -2
  50. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hook_state.py +4 -3
  51. {code_context_control-2.61.2 → code_context_control-2.62.0}/LICENSE +0 -0
  52. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/__init__.py +0 -0
  53. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/commands/__init__.py +0 -0
  54. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/commands/common.py +0 -0
  55. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/docs.html +0 -0
  56. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/edits.html +0 -0
  57. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/guide/shared.css +0 -0
  58. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_artifact.py +0 -0
  59. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_auto_snapshot.py +0 -0
  60. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_c3_signal.py +0 -0
  61. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_c3read.py +0 -0
  62. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_edit_ledger.py +0 -0
  63. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_edit_unlock.py +0 -0
  64. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_filter.py +0 -0
  65. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_ghost_files.py +0 -0
  66. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_prompt_recall.py +0 -0
  67. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_read.py +0 -0
  68. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_session_stats.py +0 -0
  69. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hook_terse_advisor.py +0 -0
  70. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub.html +0 -0
  71. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/app.js +0 -0
  72. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/add_project.js +0 -0
  73. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/config_editor.js +0 -0
  74. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  75. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/drill_health.js +0 -0
  76. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/drill_panel.js +0 -0
  77. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  78. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  79. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/drill_views.js +0 -0
  80. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/global_search.js +0 -0
  81. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  82. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  83. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/modals.js +0 -0
  84. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/project_card.js +0 -0
  85. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/project_tree.js +0 -0
  86. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/session_drawer.js +0 -0
  87. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/settings_modal.js +0 -0
  88. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/sidebar.js +0 -0
  89. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/summary_bar.js +0 -0
  90. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/task_board.js +0 -0
  91. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/toasts.js +0 -0
  92. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/components/topbar.js +0 -0
  93. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui/state.js +0 -0
  94. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/hub_ui.html +0 -0
  95. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/mcp_proxy.py +0 -0
  96. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/progress.py +0 -0
  97. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/__init__.py +0 -0
  98. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/_helpers.py +0 -0
  99. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/agent.py +0 -0
  100. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/bitbucket.py +0 -0
  101. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/credentials.py +0 -0
  102. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/edits.py +0 -0
  103. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/federate.py +0 -0
  104. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/jira.py +0 -0
  105. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/memory.py +0 -0
  106. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/session.py +0 -0
  107. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/tools/tasks.py +0 -0
  108. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/api.js +0 -0
  109. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/bitbucket.js +0 -0
  110. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/chat.js +0 -0
  111. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/credentials.js +0 -0
  112. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/dashboard.js +0 -0
  113. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/edits.js +0 -0
  114. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/instructions.js +0 -0
  115. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/jira.js +0 -0
  116. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/memory.js +0 -0
  117. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/sessions.js +0 -0
  118. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/settings.js +0 -0
  119. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/sidebar.js +0 -0
  120. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/components/tasks.js +0 -0
  121. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/icons.js +0 -0
  122. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/pm_shared.js +0 -0
  123. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/shared.js +0 -0
  124. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui/theme.js +0 -0
  125. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui.html +0 -0
  126. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui_legacy.html +0 -0
  127. {code_context_control-2.61.2 → code_context_control-2.62.0}/cli/ui_nano.html +0 -0
  128. {code_context_control-2.61.2 → code_context_control-2.62.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  129. {code_context_control-2.61.2 → code_context_control-2.62.0}/code_context_control.egg-info/entry_points.txt +0 -0
  130. {code_context_control-2.61.2 → code_context_control-2.62.0}/code_context_control.egg-info/requires.txt +0 -0
  131. {code_context_control-2.61.2 → code_context_control-2.62.0}/code_context_control.egg-info/top_level.txt +0 -0
  132. {code_context_control-2.61.2 → code_context_control-2.62.0}/core/__init__.py +0 -0
  133. {code_context_control-2.61.2 → code_context_control-2.62.0}/core/config.py +0 -0
  134. {code_context_control-2.61.2 → code_context_control-2.62.0}/core/ide.py +0 -0
  135. {code_context_control-2.61.2 → code_context_control-2.62.0}/core/mcp_toml.py +0 -0
  136. {code_context_control-2.61.2 → code_context_control-2.62.0}/core/web_security.py +0 -0
  137. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/__init__.py +0 -0
  138. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/config.py +0 -0
  139. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/mcp_oracle.py +0 -0
  140. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/oracle_server.py +0 -0
  141. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/oracle_ui.html +0 -0
  142. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/__init__.py +0 -0
  143. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/activity_reporter.py +0 -0
  144. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/api_auth.py +0 -0
  145. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/c3_bridge.py +0 -0
  146. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/chat_engine.py +0 -0
  147. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/chat_store.py +0 -0
  148. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/cross_memory.py +0 -0
  149. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/federated_graph.py +0 -0
  150. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/health_checker.py +0 -0
  151. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/insight_engine.py +0 -0
  152. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/local_session.py +0 -0
  153. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/memory_reader.py +0 -0
  154. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/memory_writer.py +0 -0
  155. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/project_scanner.py +0 -0
  156. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/review_agent.py +0 -0
  157. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/tool_executor.py +0 -0
  158. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/services/tool_registry.py +0 -0
  159. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/activity.js +0 -0
  160. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/agents.js +0 -0
  161. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/app.js +0 -0
  162. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/busy.js +0 -0
  163. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/chat/conversations.js +0 -0
  164. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/chat/input.js +0 -0
  165. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/chat/markdown.js +0 -0
  166. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/chat/send.js +0 -0
  167. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/chat/stream_renderer.js +0 -0
  168. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/chat/toolbar.js +0 -0
  169. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/core.js +0 -0
  170. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/crossgraph.js +0 -0
  171. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/header.js +0 -0
  172. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/insights.js +0 -0
  173. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/projects.js +0 -0
  174. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/settings.js +0 -0
  175. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/suggestions.js +0 -0
  176. {code_context_control-2.61.2 → code_context_control-2.62.0}/oracle/ui/theme_tabs.js +0 -0
  177. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/__init__.py +0 -0
  178. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/activity_log.py +0 -0
  179. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/agent_base.py +0 -0
  180. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/agents.py +0 -0
  181. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/artifact_defs.py +0 -0
  182. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/auto_memory.py +0 -0
  183. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/bench/__init__.py +0 -0
  184. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/bench/external/__init__.py +0 -0
  185. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/bench/external/aider_polyglot.py +0 -0
  186. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/bench/external/swe_bench.py +0 -0
  187. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/benchmark_dashboard.py +0 -0
  188. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/bitbucket_client.py +0 -0
  189. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/bitbucket_credentials.py +0 -0
  190. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/circuit_breaker.py +0 -0
  191. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/claude_md.py +0 -0
  192. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/context_snapshot.py +0 -0
  193. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/conversation_store.py +0 -0
  194. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/credential_store.py +0 -0
  195. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/doc_index.py +0 -0
  196. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/e2e_benchmark.py +0 -0
  197. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/e2e_evaluator.py +0 -0
  198. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/e2e_tasks.py +0 -0
  199. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/edit_ledger.py +0 -0
  200. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/embedding_index.py +0 -0
  201. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/error_reporting.py +0 -0
  202. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/file_memory.py +0 -0
  203. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/git_context.py +0 -0
  204. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/hub_service.py +0 -0
  205. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/indexer.py +0 -0
  206. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/jira_client.py +0 -0
  207. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/jira_cloud.py +0 -0
  208. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/jira_credentials.py +0 -0
  209. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/jira_data_center.py +0 -0
  210. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/jira_links.py +0 -0
  211. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory.py +0 -0
  212. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory_consolidator.py +0 -0
  213. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory_distiller.py +0 -0
  214. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory_graph.py +0 -0
  215. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory_grounder.py +0 -0
  216. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory_queue.py +0 -0
  217. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/memory_scorer.py +0 -0
  218. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/metrics.py +0 -0
  219. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/notifications.py +0 -0
  220. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/ollama_bridge.py +0 -0
  221. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/ollama_client.py +0 -0
  222. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/ollama_credentials.py +0 -0
  223. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/output_filter.py +0 -0
  224. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/parser.py +0 -0
  225. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/project_manager.py +0 -0
  226. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/project_runtime.py +0 -0
  227. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/protocol.py +0 -0
  228. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/proxy_state.py +0 -0
  229. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/repo_map.py +0 -0
  230. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/retention.py +0 -0
  231. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/retrieval_broker.py +0 -0
  232. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/router.py +0 -0
  233. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/runtime.py +0 -0
  234. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/session_benchmark.py +0 -0
  235. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/session_manager.py +0 -0
  236. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/session_preloader.py +0 -0
  237. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/subprojects.py +0 -0
  238. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/task_store.py +0 -0
  239. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/telemetry.py +0 -0
  240. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/text_index.py +0 -0
  241. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/time_tracker.py +0 -0
  242. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/tool_classifier.py +0 -0
  243. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/transcript_index.py +0 -0
  244. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/validation_cache.py +0 -0
  245. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/vector_store.py +0 -0
  246. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/watcher.py +0 -0
  247. {code_context_control-2.61.2 → code_context_control-2.62.0}/services/win_subprocess.py +0 -0
  248. {code_context_control-2.61.2 → code_context_control-2.62.0}/setup.cfg +0 -0
  249. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_activity_reporter.py +0 -0
  250. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_aider_polyglot.py +0 -0
  251. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_antigravity_transition.py +0 -0
  252. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_artifact_store.py +0 -0
  253. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_artifact_tool.py +0 -0
  254. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  255. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_bitbucket_client.py +0 -0
  256. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_bitbucket_config_fallback.py +0 -0
  257. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_bitbucket_credentials.py +0 -0
  258. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_bitbucket_tool.py +0 -0
  259. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  260. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_c3_shell.py +0 -0
  261. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_circuit_breaker.py +0 -0
  262. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_claude_md_merge.py +0 -0
  263. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_cli_smoke.py +0 -0
  264. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_compressor_large_file.py +0 -0
  265. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_credential_store.py +0 -0
  266. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_credentials_routes.py +0 -0
  267. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_credentials_tool.py +0 -0
  268. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_creds_cli_smoke.py +0 -0
  269. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_delegate_cascade.py +0 -0
  270. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_e2e_benchmark.py +0 -0
  271. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_edit_ledger_hook.py +0 -0
  272. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_edit_normalization.py +0 -0
  273. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_enforcement_flip.py +0 -0
  274. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_federated_graph.py +0 -0
  275. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_filter_backoff.py +0 -0
  276. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_ghost_files.py +0 -0
  277. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_ghost_generation.py +0 -0
  278. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_git_branch_awareness.py +0 -0
  279. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hook_prompt_recall.py +0 -0
  280. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hook_utf8_stdio.py +0 -0
  281. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hub_credentials_route.py +0 -0
  282. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hub_credentials_routes_write.py +0 -0
  283. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hub_inspect_api.py +0 -0
  284. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hub_server_smoke.py +0 -0
  285. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_hub_subproject_links.py +0 -0
  286. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_init_scan.py +0 -0
  287. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_install_mcp_entrypoint.py +0 -0
  288. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_cli_smoke.py +0 -0
  289. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_client.py +0 -0
  290. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_config_fallback.py +0 -0
  291. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_credentials.py +0 -0
  292. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_links.py +0 -0
  293. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_routes.py +0 -0
  294. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_jira_tool.py +0 -0
  295. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_lazy_store_init.py +0 -0
  296. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_mcp_host_guard.py +0 -0
  297. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_mcp_memory_timeout.py +0 -0
  298. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_mcp_server_smoke.py +0 -0
  299. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_mcp_toml.py +0 -0
  300. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_memory_distiller.py +0 -0
  301. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_memory_graph_api.py +0 -0
  302. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_memory_queue.py +0 -0
  303. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_memory_system.py +0 -0
  304. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_no_stale_model_pins.py +0 -0
  305. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_notification_dedup.py +0 -0
  306. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_notification_discipline.py +0 -0
  307. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_ollama_credentials.py +0 -0
  308. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_api_auth.py +0 -0
  309. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_apikey_api.py +0 -0
  310. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_c3_bridge.py +0 -0
  311. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_chat_engine.py +0 -0
  312. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_discovery_api.py +0 -0
  313. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_local_auth.py +0 -0
  314. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_ollama_bridge.py +0 -0
  315. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_scanner_cache.py +0 -0
  316. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_security_fixes.py +0 -0
  317. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_subproject_awareness.py +0 -0
  318. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_oracle_ui_bundle.py +0 -0
  319. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_output_filter.py +0 -0
  320. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_permissions.py +0 -0
  321. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_pm_api.py +0 -0
  322. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_project_manager.py +0 -0
  323. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_project_manager_merge.py +0 -0
  324. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_project_tool.py +0 -0
  325. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_read_coercion.py +0 -0
  326. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_read_edit_parity.py +0 -0
  327. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_related_facts.py +0 -0
  328. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_repo_map.py +0 -0
  329. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_response_boilerplate.py +0 -0
  330. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_retention.py +0 -0
  331. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_review_digest.py +0 -0
  332. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_service_durability.py +0 -0
  333. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_session_benchmark.py +0 -0
  334. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_session_budget.py +0 -0
  335. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_shell_creds.py +0 -0
  336. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_shell_robustness.py +0 -0
  337. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_subproject_exclusion.py +0 -0
  338. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_subproject_federation.py +0 -0
  339. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_subprojects.py +0 -0
  340. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_swe_bench.py +0 -0
  341. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_task_store.py +0 -0
  342. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_task_tool.py +0 -0
  343. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_time_tracker.py +0 -0
  344. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_token_telemetry.py +0 -0
  345. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_tool_registry.py +0 -0
  346. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_upgrade_and_version.py +0 -0
  347. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_validate.py +0 -0
  348. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_vault_write_guard.py +0 -0
  349. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_version_sync.py +0 -0
  350. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_web_security.py +0 -0
  351. {code_context_control-2.61.2 → code_context_control-2.62.0}/tests/test_windows_reliability.py +0 -0
  352. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/__init__.py +0 -0
  353. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/backend.py +0 -0
  354. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/main.py +0 -0
  355. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/__init__.py +0 -0
  356. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/benchmark_view.py +0 -0
  357. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/claudemd_view.py +0 -0
  358. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/compress_view.py +0 -0
  359. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/index_view.py +0 -0
  360. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/init_view.py +0 -0
  361. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/mcp_view.py +0 -0
  362. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/optimize_view.py +0 -0
  363. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/pipe_view.py +0 -0
  364. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/projects_view.py +0 -0
  365. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/search_view.py +0 -0
  366. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/session_view.py +0 -0
  367. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/stats.py +0 -0
  368. {code_context_control-2.61.2 → code_context_control-2.62.0}/tui/screens/ui_view.py +0 -0
  369. {code_context_control-2.61.2 → code_context_control-2.62.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.61.2
3
+ Version: 2.62.0
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Copilot, Cursor, Antigravity). Retrieve less, read less, edit safer — version the configs that shape your agent (CLAUDE.md, skills, hooks, MCP), and manage multi-project + sub-project hierarchies from a local hub.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -386,6 +386,45 @@ inbound-only, **no hub route ever returns a stored value** (there is no
386
386
  Full documentation: [`cli/guide/credentials.html`](cli/guide/credentials.html)
387
387
  — open it in the app at `/guide/credentials.html`.
388
388
 
389
+ ### Access Guard (v2.62.0)
390
+
391
+ The Credential Vault protects *values*; **Access Guard** protects *files and
392
+ folders*. Two glob lists in your config mark what an agent must never read
393
+ (`deny`) or never write (`read_only`), and one shared evaluator enforces them
394
+ at every C3 surface — the MCP tools (`c3_read`/`c3_edit`/`c3_search`/…, so
395
+ any agent using C3 is covered), Claude Code's native tools via PreToolUse
396
+ hooks (fail-closed: a broken guard denies writes instead of waving them
397
+ through), and `c3_shell` via a best-effort command scan.
398
+
399
+ ```bash
400
+ c3 access add "secrets/**" --kind deny # never read, never write
401
+ c3 access add "migrations/**" --kind read_only
402
+ c3 access check secrets/key.txt # probe: verdict + matched rule
403
+ ```
404
+
405
+ - **Tighten-only.** No allow list exists; scopes (global `~/.c3` + project
406
+ `.c3`) merge as a union. A cloned repo's config can only add protection,
407
+ never grant itself access.
408
+ - **`deny` means deny-create and deny-enumerate** too: alternate spellings
409
+ are canonicalized before matching, and denied paths never appear in search
410
+ results, maps, or the vector index.
411
+ - **Refusals teach the agent to stop.** Every denial carries a stable
412
+ `[c3-access:*]` tag, the matched rule and scope, and explicit
413
+ do-not-retry guidance — no retry loops, no "file must not exist, let me
414
+ recreate it".
415
+ - **All rule changes are human-only** (Access Guard UI tab or `c3 access`
416
+ CLI), ledger-logged; agents have no mutation surface.
417
+ - **Built-ins always on:** `.env*` files, the credential vault's sidecars,
418
+ and write-denies on `.c3/`, `.claude/settings*.json`, `.git/`, and the
419
+ installed C3 package itself.
420
+ - **Honest coverage:** this guards *cooperative* agents against mistakes and
421
+ prompt-injection. It is not a sandbox — raw shell or direct file access
422
+ outside C3's tools and hooks is not stopped. The guide states exactly
423
+ where each layer holds.
424
+
425
+ Full documentation: [`cli/guide/access.html`](cli/guide/access.html)
426
+ — open it in the app at `/guide/access.html`.
427
+
389
428
  ### Jira — Cloud + Data Center (v2.56.0)
390
429
 
391
430
  `c3_jira` connects to Jira Cloud (REST v3, email + API token) or self-hosted
@@ -323,6 +323,45 @@ inbound-only, **no hub route ever returns a stored value** (there is no
323
323
  Full documentation: [`cli/guide/credentials.html`](cli/guide/credentials.html)
324
324
  — open it in the app at `/guide/credentials.html`.
325
325
 
326
+ ### Access Guard (v2.62.0)
327
+
328
+ The Credential Vault protects *values*; **Access Guard** protects *files and
329
+ folders*. Two glob lists in your config mark what an agent must never read
330
+ (`deny`) or never write (`read_only`), and one shared evaluator enforces them
331
+ at every C3 surface — the MCP tools (`c3_read`/`c3_edit`/`c3_search`/…, so
332
+ any agent using C3 is covered), Claude Code's native tools via PreToolUse
333
+ hooks (fail-closed: a broken guard denies writes instead of waving them
334
+ through), and `c3_shell` via a best-effort command scan.
335
+
336
+ ```bash
337
+ c3 access add "secrets/**" --kind deny # never read, never write
338
+ c3 access add "migrations/**" --kind read_only
339
+ c3 access check secrets/key.txt # probe: verdict + matched rule
340
+ ```
341
+
342
+ - **Tighten-only.** No allow list exists; scopes (global `~/.c3` + project
343
+ `.c3`) merge as a union. A cloned repo's config can only add protection,
344
+ never grant itself access.
345
+ - **`deny` means deny-create and deny-enumerate** too: alternate spellings
346
+ are canonicalized before matching, and denied paths never appear in search
347
+ results, maps, or the vector index.
348
+ - **Refusals teach the agent to stop.** Every denial carries a stable
349
+ `[c3-access:*]` tag, the matched rule and scope, and explicit
350
+ do-not-retry guidance — no retry loops, no "file must not exist, let me
351
+ recreate it".
352
+ - **All rule changes are human-only** (Access Guard UI tab or `c3 access`
353
+ CLI), ledger-logged; agents have no mutation surface.
354
+ - **Built-ins always on:** `.env*` files, the credential vault's sidecars,
355
+ and write-denies on `.c3/`, `.claude/settings*.json`, `.git/`, and the
356
+ installed C3 package itself.
357
+ - **Honest coverage:** this guards *cooperative* agents against mistakes and
358
+ prompt-injection. It is not a sandbox — raw shell or direct file access
359
+ outside C3's tools and hooks is not stopped. The guide states exactly
360
+ where each layer holds.
361
+
362
+ Full documentation: [`cli/guide/access.html`](cli/guide/access.html)
363
+ — open it in the app at `/guide/access.html`.
364
+
326
365
  ### Jira — Cloud + Data Center (v2.56.0)
327
366
 
328
367
  `c3_jira` connects to Jira Cloud (REST v3, email + API token) or self-hosted
@@ -175,6 +175,17 @@ def load_enforcement_state(project_path: Path | None = None, session_id: str = "
175
175
  # session must not grant unlocks (signal files used to survive /clear).
176
176
  if session_id and state.get("session_id") and state["session_id"] != session_id:
177
177
  return _empty_state(session_id)
178
+ # Migrate unlock keys written before canonical_key (raw resolve() form):
179
+ # lookups are canonical now, so re-key at load — old and new forms merge.
180
+ migrated: dict = {}
181
+ for k, cats in state.get("unlocked_files", {}).items():
182
+ try:
183
+ key = canonical_key(k)
184
+ except OSError:
185
+ continue
186
+ merged = set(migrated.get(key, [])) | set(cats)
187
+ migrated[key] = sorted(merged)
188
+ state["unlocked_files"] = migrated
178
189
  return state
179
190
 
180
191
 
@@ -205,6 +216,16 @@ def record_c3_signal(
205
216
  save_enforcement_state(state, project_path)
206
217
 
207
218
 
219
+ def canonical_key(path) -> str:
220
+ """Canonical unlock-map key: resolved, forward-slash, casefolded.
221
+
222
+ Must stay form-identical to services.access_guard.canonicalize()'s canon
223
+ string for existing paths (parity-tested) — the unlock map and the
224
+ access evaluator must never disagree about path identity on Windows.
225
+ """
226
+ return str(Path(path).resolve()).replace("\\", "/").casefold()
227
+
228
+
208
229
  def record_unlocked_files(
209
230
  paths,
210
231
  categories,
@@ -223,7 +244,7 @@ def record_unlocked_files(
223
244
  if not fp:
224
245
  continue
225
246
  try:
226
- normalized = str(Path(fp).resolve())
247
+ normalized = canonical_key(fp)
227
248
  except OSError:
228
249
  continue
229
250
  cats = set(state["unlocked_files"].get(normalized, []))
@@ -92,7 +92,17 @@ 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.61.2"
95
+ __version__ = "2.62.0"
96
+
97
+
98
+ def _compress_file_cli(compressor, path, mode="smart", **kw):
99
+ """compress_file for human-CLI paths: AccessDenied → error dict, not a
100
+ traceback. The refusal text names the rule so the operator can act."""
101
+ from services import access_guard as _ag
102
+ try:
103
+ return compressor.compress_file(path, mode, **kw)
104
+ except _ag.AccessDenied as exc:
105
+ return {"error": exc.message}
96
106
 
97
107
 
98
108
  def _command_deps() -> CommandDeps:
@@ -1338,7 +1348,7 @@ def _benchmark_extract_preview(full_path: Path, compressor: CodeCompressor, patt
1338
1348
  extracted = ""
1339
1349
 
1340
1350
  if ext in code_exts and not pattern:
1341
- result = compressor.compress_file(str(full_path), "smart")
1351
+ result = _compress_file_cli(compressor, str(full_path), "smart")
1342
1352
  extracted = result.get("compressed", "") if "error" not in result else f"Error: {result['error']}"
1343
1353
 
1344
1354
  elif ext == ".jsonl" and not pattern:
@@ -1617,7 +1627,7 @@ def _benchmark_delegate_optional(project_path: Path, sample: list[tuple[Path, st
1617
1627
  "Focus on responsibilities, important functions/classes, and notable dependencies."
1618
1628
  )
1619
1629
 
1620
- compressed_result = compressor.compress_file(str(fpath), "smart")
1630
+ compressed_result = _compress_file_cli(compressor, str(fpath), "smart")
1621
1631
  compressed_context = compressed_result.get("compressed", "") if isinstance(compressed_result, dict) else ""
1622
1632
  if not compressed_context:
1623
1633
  compressed_context = raw_content
@@ -3478,7 +3488,7 @@ def cmd_benchmark(args):
3478
3488
  raw_content = content
3479
3489
  comp_baseline_latencies.append((time.perf_counter() - t_read) * 1000)
3480
3490
  t0 = time.perf_counter()
3481
- result = compressor.compress_file(str(fpath), "smart")
3491
+ result = _compress_file_cli(compressor, str(fpath), "smart")
3482
3492
  comp_c3_latencies.append((time.perf_counter() - t0) * 1000)
3483
3493
  raw_tokens = count_tokens(raw_content)
3484
3494
  comp_orig += raw_tokens
@@ -3544,7 +3554,7 @@ def cmd_benchmark(args):
3544
3554
  tmp.write(raw_extracted)
3545
3555
  tmp_path = tmp.name
3546
3556
  try:
3547
- comp_res = compressor.compress_file(tmp_path, mode="smart")
3557
+ comp_res = _compress_file_cli(compressor, tmp_path, mode="smart")
3548
3558
  extracted_text += comp_res.get("compressed", raw_extracted)
3549
3559
  finally:
3550
3560
  if os.path.exists(tmp_path):
@@ -5203,6 +5213,9 @@ def cmd_install_mcp(args):
5203
5213
  ]
5204
5214
 
5205
5215
  # ── PreToolUse hooks (enforcement — blocks native tools without prior c3_*) ──
5216
+ # Bash/run_shell_command joined in v2.62: the Access Guard sub-hook
5217
+ # scans shell commands (best-effort); without these matchers PreToolUse
5218
+ # simply never fires for shell — proven bypass, see docs/access-guard.md.
5206
5219
  _pre_matcher_names = [
5207
5220
  read_matcher,
5208
5221
  grep_matcher,
@@ -5210,6 +5223,8 @@ def cmd_install_mcp(args):
5210
5223
  edit_matcher,
5211
5224
  write_matcher,
5212
5225
  *extra_edit_matchers,
5226
+ shell_matcher,
5227
+ "run_shell_command",
5213
5228
  ]
5214
5229
  desired_pre_hooks = [
5215
5230
  {"matcher": m, "hooks": [{"type": "command", "command": hook_pretool_cmd}]}
@@ -5899,6 +5914,120 @@ def _creds_cmd_import(args, project_path: str) -> None:
5899
5914
  "(use --overwrite to replace)")
5900
5915
 
5901
5916
 
5917
+ def cmd_access(args):
5918
+ """Access Guard rule management — human-only mutation surface (spec §1)."""
5919
+ sub = getattr(args, "access_cmd", None)
5920
+ if not sub:
5921
+ print("Usage: c3 access {list,add,remove,check} [args]")
5922
+ return
5923
+
5924
+ project_path = getattr(args, "project_path", ".") or "."
5925
+
5926
+ if sub == "list":
5927
+ _access_cmd_list(args, project_path)
5928
+ elif sub == "add":
5929
+ _access_cmd_add(args, project_path)
5930
+ elif sub == "remove":
5931
+ _access_cmd_remove(args, project_path)
5932
+ elif sub == "check":
5933
+ _access_cmd_check(args, project_path)
5934
+ else:
5935
+ print(f"Unknown access subcommand: {sub}")
5936
+
5937
+
5938
+ def _access_scope(args) -> str:
5939
+ return "global" if getattr(args, "use_global", False) else "project"
5940
+
5941
+
5942
+ def _access_audit(action: str, glob: str, kind: str, scope: str,
5943
+ project_path: str) -> None:
5944
+ """Ledger + activity log for CLI rule mutations. Identifiers only; failure-safe."""
5945
+ try:
5946
+ from services.activity_log import ActivityLog
5947
+ ActivityLog(project_path).log("access_action", {
5948
+ "kind": "access", "action": action, "glob": glob,
5949
+ "rule_kind": kind, "scope": scope, "via": "cli",
5950
+ })
5951
+ except Exception:
5952
+ pass
5953
+ try:
5954
+ from services.edit_ledger import EditLedger
5955
+ EditLedger(project_path).log_edit(
5956
+ file=f"access://{glob}", change_type=f"access_{action}",
5957
+ summary=f"{action} {kind} rule '{glob}' ({scope}) via `c3 access`",
5958
+ tags=["access", action],
5959
+ detail={"kind": "access", "action": action, "glob": glob,
5960
+ "rule_kind": kind, "scope": scope},
5961
+ )
5962
+ except Exception:
5963
+ pass
5964
+
5965
+
5966
+ def _access_cmd_list(args, project_path: str) -> None:
5967
+ from services import access_guard
5968
+
5969
+ scopes = access_guard.list_rules(project_path)
5970
+ notes = {"builtin": "built-in, always on",
5971
+ "global": "~/.c3/config.json",
5972
+ "project": ".c3/config.json"}
5973
+ for scope in ("builtin", "global", "project"):
5974
+ sec = scopes.get(scope) or {}
5975
+ rules = [(k, g) for k in ("deny", "read_only") for g in sec.get(k, [])]
5976
+ print(f"[{scope}] ({notes[scope]}) — {len(rules)} rule(s)")
5977
+ for kind, glob in rules:
5978
+ print(f" {kind:<10} {glob}")
5979
+ if sec.get("corrupt"):
5980
+ print(" [warn] access section invalid — scope fails closed "
5981
+ "(deny-all); fix config.json 'access' by hand")
5982
+ print()
5983
+ print(access_guard.COVERAGE_MATRIX)
5984
+
5985
+
5986
+ def _access_cmd_add(args, project_path: str) -> None:
5987
+ from services import access_guard
5988
+
5989
+ scope = _access_scope(args)
5990
+ try:
5991
+ result = access_guard.set_rule(args.glob, args.kind, scope, project_path)
5992
+ except ValueError as exc:
5993
+ print(f"[error] {exc}")
5994
+ return
5995
+ if result["added"]:
5996
+ _access_audit("add", result["glob"], args.kind, scope, project_path)
5997
+ print(f"[OK] Added {args.kind} rule '{result['glob']}' (scope={scope})")
5998
+ else:
5999
+ print(f"[=] Rule already present: '{result['glob']}' "
6000
+ f"({args.kind}, {scope})")
6001
+
6002
+
6003
+ def _access_cmd_remove(args, project_path: str) -> None:
6004
+ from services import access_guard
6005
+
6006
+ scope = _access_scope(args)
6007
+ try:
6008
+ result = access_guard.remove_rule(args.glob, args.kind, scope, project_path)
6009
+ except ValueError as exc:
6010
+ print(f"[error] {exc}")
6011
+ return
6012
+ if result["removed"]:
6013
+ _access_audit("remove", result["glob"], args.kind, scope, project_path)
6014
+ print(f"[OK] Removed {args.kind} rule '{result['glob']}' (scope={scope})")
6015
+ else:
6016
+ print(f"[error] no {args.kind} rule matching '{result['glob']}' "
6017
+ f"in {scope} scope")
6018
+
6019
+
6020
+ def _access_cmd_check(args, project_path: str) -> None:
6021
+ from services import access_guard
6022
+
6023
+ op = getattr(args, "op", "read") or "read"
6024
+ denial = access_guard.check(args.target, op, project_path)
6025
+ if denial is None:
6026
+ print(f"[OK] {op} allowed: {args.target}")
6027
+ else:
6028
+ print(access_guard.refusal(denial, args.target, op))
6029
+
6030
+
5902
6031
  def cmd_jira(args):
5903
6032
  """Jira Cloud / Data Center credential + workspace management."""
5904
6033
  sub = getattr(args, "jira_cmd", None)
@@ -7199,6 +7328,7 @@ def main():
7199
7328
  "bitbucket": cmd_bitbucket,
7200
7329
  "jira": cmd_jira,
7201
7330
  "creds": cmd_creds,
7331
+ "access": cmd_access,
7202
7332
  "oracle": cmd_oracle,
7203
7333
  "upgrade": cmd_upgrade,
7204
7334
  }
@@ -447,6 +447,42 @@ 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
+ # ── Access Guard (v2.62.0) ──────────────────────────────────────────
451
+ # Human-only mutation surface (frozen spec docs/access-guard.md §1):
452
+ # rule changes happen here or in the UI tab, never via an agent tool.
453
+ p_access = subparsers.add_parser(
454
+ "access",
455
+ help="Access Guard — path deny/read-only rules the agent must respect",
456
+ )
457
+ access_subs = p_access.add_subparsers(dest="access_cmd")
458
+
459
+ ac_list = access_subs.add_parser(
460
+ "list", help="Show rules per scope (builtin + global + project) and coverage"
461
+ )
462
+ ac_list.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
463
+
464
+ ac_add = access_subs.add_parser("add", help="Add a rule to the project (or --global) scope")
465
+ ac_add.add_argument("glob", help="POSIX glob (** crosses directories), e.g. 'secrets/**' or '*.pem'")
466
+ ac_add.add_argument("--kind", choices=["deny", "read_only"], required=True,
467
+ help="deny = no read/write/enumerate; read_only = no write")
468
+ ac_add.add_argument("--global", dest="use_global", action="store_true",
469
+ help="Store in the global scope (~/.c3) so every C3 project enforces it")
470
+ ac_add.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
471
+
472
+ ac_remove = access_subs.add_parser("remove", help="Remove a rule from the project (or --global) scope")
473
+ ac_remove.add_argument("glob", help="The stored glob to remove (case-insensitive match)")
474
+ ac_remove.add_argument("--kind", choices=["deny", "read_only"], required=True,
475
+ help="Which rule list the glob lives in")
476
+ ac_remove.add_argument("--global", dest="use_global", action="store_true",
477
+ help="Remove from the global scope (~/.c3)")
478
+ ac_remove.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
479
+
480
+ ac_check = access_subs.add_parser("check", help="Test a path: verdict + matched rule + refusal string")
481
+ ac_check.add_argument("target", help="Path to test (absolute or project-relative)")
482
+ ac_check.add_argument("--op", choices=["read", "write"], default="read",
483
+ help="Operation to evaluate (default: read)")
484
+ ac_check.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
485
+
450
486
  # ── Oracle Discovery API (v2.32.0) ──────────────────────────────────
451
487
  p_oracle = subparsers.add_parser(
452
488
  "oracle",