code-context-control 2.73.0__tar.gz → 2.74.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 (411) hide show
  1. {code_context_control-2.73.0/code_context_control.egg-info → code_context_control-2.74.0}/PKG-INFO +1 -1
  2. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/c3.py +1 -1
  3. {code_context_control-2.73.0 → code_context_control-2.74.0/code_context_control.egg-info}/PKG-INFO +1 -1
  4. {code_context_control-2.73.0 → code_context_control-2.74.0}/pyproject.toml +1 -1
  5. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/access_guard.py +38 -10
  6. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/notifications.py +22 -1
  7. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/override_requests.py +6 -0
  8. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_override_requests.py +125 -0
  9. {code_context_control-2.73.0 → code_context_control-2.74.0}/LICENSE +0 -0
  10. {code_context_control-2.73.0 → code_context_control-2.74.0}/README.md +0 -0
  11. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/__init__.py +0 -0
  12. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/_hook_utils.py +0 -0
  13. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/commands/__init__.py +0 -0
  14. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/commands/common.py +0 -0
  15. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/commands/parser.py +0 -0
  16. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/docs.html +0 -0
  17. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/edits.html +0 -0
  18. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/access.html +0 -0
  19. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/bitbucket.html +0 -0
  20. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/credentials.html +0 -0
  21. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/getting-started.html +0 -0
  22. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/index.html +0 -0
  23. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/masking.html +0 -0
  24. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/oracle.html +0 -0
  25. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/shared.css +0 -0
  26. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/tools.html +0 -0
  27. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/guide/workflow.html +0 -0
  28. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_access_guard.py +0 -0
  29. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_artifact.py +0 -0
  30. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_auto_snapshot.py +0 -0
  31. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_c3_signal.py +0 -0
  32. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_c3read.py +0 -0
  33. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_dispatch.py +0 -0
  34. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_edit_ledger.py +0 -0
  35. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_edit_unlock.py +0 -0
  36. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_filter.py +0 -0
  37. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_ghost_files.py +0 -0
  38. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_pretool_enforce.py +0 -0
  39. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_prompt_recall.py +0 -0
  40. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_read.py +0 -0
  41. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_session_stats.py +0 -0
  42. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hook_terse_advisor.py +0 -0
  43. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_server.py +0 -0
  44. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/app.js +0 -0
  45. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/add_project.js +0 -0
  46. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/config_editor.js +0 -0
  47. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  48. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/drill_health.js +0 -0
  49. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/drill_panel.js +0 -0
  50. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  51. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  52. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/drill_views.js +0 -0
  53. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/global_search.js +0 -0
  54. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  55. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  56. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/hub_locks.js +0 -0
  57. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  58. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/modals.js +0 -0
  59. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/project_card.js +0 -0
  60. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/project_tree.js +0 -0
  61. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/session_drawer.js +0 -0
  62. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/settings_modal.js +0 -0
  63. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/sidebar.js +0 -0
  64. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/summary_bar.js +0 -0
  65. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/task_board.js +0 -0
  66. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/toasts.js +0 -0
  67. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/components/topbar.js +0 -0
  68. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui/state.js +0 -0
  69. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/hub_ui.html +0 -0
  70. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/mcp_proxy.py +0 -0
  71. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/mcp_server.py +0 -0
  72. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/progress.py +0 -0
  73. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/server.py +0 -0
  74. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/__init__.py +0 -0
  75. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/_grants.py +0 -0
  76. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/_helpers.py +0 -0
  77. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/agent.py +0 -0
  78. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/artifacts.py +0 -0
  79. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/bitbucket.py +0 -0
  80. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/compress.py +0 -0
  81. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/credentials.py +0 -0
  82. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/delegate.py +0 -0
  83. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/edit.py +0 -0
  84. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/edits.py +0 -0
  85. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/federate.py +0 -0
  86. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/filter.py +0 -0
  87. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/impact.py +0 -0
  88. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/jira.py +0 -0
  89. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/locks.py +0 -0
  90. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/memory.py +0 -0
  91. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/override.py +0 -0
  92. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/project.py +0 -0
  93. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/read.py +0 -0
  94. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/search.py +0 -0
  95. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/session.py +0 -0
  96. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/shell.py +0 -0
  97. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/status.py +0 -0
  98. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/tasks.py +0 -0
  99. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/tools/validate.py +0 -0
  100. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/api.js +0 -0
  101. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/app.js +0 -0
  102. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/access.js +0 -0
  103. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/bitbucket.js +0 -0
  104. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/chat.js +0 -0
  105. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/credentials.js +0 -0
  106. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/dashboard.js +0 -0
  107. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/edits.js +0 -0
  108. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/enforcement.js +0 -0
  109. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/instructions.js +0 -0
  110. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/jira.js +0 -0
  111. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/memory.js +0 -0
  112. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/sessions.js +0 -0
  113. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/settings.js +0 -0
  114. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/sidebar.js +0 -0
  115. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/components/tasks.js +0 -0
  116. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/icons.js +0 -0
  117. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/pm_shared.js +0 -0
  118. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/shared.js +0 -0
  119. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui/theme.js +0 -0
  120. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui.html +0 -0
  121. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui_legacy.html +0 -0
  122. {code_context_control-2.73.0 → code_context_control-2.74.0}/cli/ui_nano.html +0 -0
  123. {code_context_control-2.73.0 → code_context_control-2.74.0}/code_context_control.egg-info/SOURCES.txt +0 -0
  124. {code_context_control-2.73.0 → code_context_control-2.74.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  125. {code_context_control-2.73.0 → code_context_control-2.74.0}/code_context_control.egg-info/entry_points.txt +0 -0
  126. {code_context_control-2.73.0 → code_context_control-2.74.0}/code_context_control.egg-info/requires.txt +0 -0
  127. {code_context_control-2.73.0 → code_context_control-2.74.0}/code_context_control.egg-info/top_level.txt +0 -0
  128. {code_context_control-2.73.0 → code_context_control-2.74.0}/core/__init__.py +0 -0
  129. {code_context_control-2.73.0 → code_context_control-2.74.0}/core/config.py +0 -0
  130. {code_context_control-2.73.0 → code_context_control-2.74.0}/core/ide.py +0 -0
  131. {code_context_control-2.73.0 → code_context_control-2.74.0}/core/mcp_toml.py +0 -0
  132. {code_context_control-2.73.0 → code_context_control-2.74.0}/core/web_security.py +0 -0
  133. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/__init__.py +0 -0
  134. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/config.py +0 -0
  135. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/mcp_oracle.py +0 -0
  136. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/oracle_server.py +0 -0
  137. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/oracle_ui.html +0 -0
  138. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/__init__.py +0 -0
  139. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/activity_reporter.py +0 -0
  140. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/api_auth.py +0 -0
  141. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/c3_bridge.py +0 -0
  142. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/chat_engine.py +0 -0
  143. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/chat_store.py +0 -0
  144. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/cross_memory.py +0 -0
  145. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/discovery_audit.py +0 -0
  146. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/federated_graph.py +0 -0
  147. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/health_checker.py +0 -0
  148. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/insight_engine.py +0 -0
  149. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/local_session.py +0 -0
  150. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/memory_reader.py +0 -0
  151. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/memory_writer.py +0 -0
  152. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/mobile_api.py +0 -0
  153. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/project_scanner.py +0 -0
  154. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/review_agent.py +0 -0
  155. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/tool_executor.py +0 -0
  156. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/services/tool_registry.py +0 -0
  157. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/activity.js +0 -0
  158. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/agents.js +0 -0
  159. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/app.js +0 -0
  160. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/busy.js +0 -0
  161. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/chat/conversations.js +0 -0
  162. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/chat/input.js +0 -0
  163. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/chat/markdown.js +0 -0
  164. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/chat/send.js +0 -0
  165. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/chat/stream_renderer.js +0 -0
  166. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/chat/toolbar.js +0 -0
  167. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/core.js +0 -0
  168. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/crossgraph.js +0 -0
  169. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/header.js +0 -0
  170. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/insights.js +0 -0
  171. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/projects.js +0 -0
  172. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/qrcode.js +0 -0
  173. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/settings.js +0 -0
  174. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/suggestions.js +0 -0
  175. {code_context_control-2.73.0 → code_context_control-2.74.0}/oracle/ui/theme_tabs.js +0 -0
  176. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/__init__.py +0 -0
  177. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/access_telemetry.py +0 -0
  178. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/activity_log.py +0 -0
  179. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/agent_base.py +0 -0
  180. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/agent_locks.py +0 -0
  181. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/agents.py +0 -0
  182. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/artifact_defs.py +0 -0
  183. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/artifact_store.py +0 -0
  184. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/auto_memory.py +0 -0
  185. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/bench/__init__.py +0 -0
  186. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/bench/external/__init__.py +0 -0
  187. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/bench/external/aider_polyglot.py +0 -0
  188. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/bench/external/swe_bench.py +0 -0
  189. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/benchmark_dashboard.py +0 -0
  190. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/bitbucket_client.py +0 -0
  191. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/bitbucket_credentials.py +0 -0
  192. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/circuit_breaker.py +0 -0
  193. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/claude_md.py +0 -0
  194. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/compressor.py +0 -0
  195. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/context_snapshot.py +0 -0
  196. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/conversation_store.py +0 -0
  197. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/credential_store.py +0 -0
  198. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/doc_index.py +0 -0
  199. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/e2e_benchmark.py +0 -0
  200. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/e2e_evaluator.py +0 -0
  201. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/e2e_tasks.py +0 -0
  202. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/edit_ledger.py +0 -0
  203. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/embedding_index.py +0 -0
  204. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/enforcement_policy.py +0 -0
  205. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/error_reporting.py +0 -0
  206. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/file_memory.py +0 -0
  207. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/git_context.py +0 -0
  208. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/hub_service.py +0 -0
  209. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/indexer.py +0 -0
  210. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/jira_client.py +0 -0
  211. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/jira_cloud.py +0 -0
  212. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/jira_credentials.py +0 -0
  213. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/jira_data_center.py +0 -0
  214. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/jira_links.py +0 -0
  215. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/mask_activation.py +0 -0
  216. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/mask_mirror.py +0 -0
  217. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/mask_presets.py +0 -0
  218. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory.py +0 -0
  219. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory_consolidator.py +0 -0
  220. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory_distiller.py +0 -0
  221. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory_graph.py +0 -0
  222. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory_grounder.py +0 -0
  223. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory_queue.py +0 -0
  224. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/memory_scorer.py +0 -0
  225. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/metrics.py +0 -0
  226. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/ollama_bridge.py +0 -0
  227. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/ollama_client.py +0 -0
  228. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/ollama_credentials.py +0 -0
  229. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/output_filter.py +0 -0
  230. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/override_grants.py +0 -0
  231. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/override_policy.py +0 -0
  232. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/override_wake.py +0 -0
  233. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/parser.py +0 -0
  234. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/project_manager.py +0 -0
  235. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/project_runtime.py +0 -0
  236. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/protocol.py +0 -0
  237. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/proxy_state.py +0 -0
  238. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/repo_map.py +0 -0
  239. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/retention.py +0 -0
  240. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/retrieval_broker.py +0 -0
  241. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/router.py +0 -0
  242. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/runtime.py +0 -0
  243. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/scanner.py +0 -0
  244. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/session_benchmark.py +0 -0
  245. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/session_manager.py +0 -0
  246. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/session_preloader.py +0 -0
  247. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/subprojects.py +0 -0
  248. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/task_store.py +0 -0
  249. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/telemetry.py +0 -0
  250. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/text_index.py +0 -0
  251. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/time_tracker.py +0 -0
  252. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/tool_classifier.py +0 -0
  253. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/transcript_index.py +0 -0
  254. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/validation_cache.py +0 -0
  255. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/vector_store.py +0 -0
  256. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/watcher.py +0 -0
  257. {code_context_control-2.73.0 → code_context_control-2.74.0}/services/win_subprocess.py +0 -0
  258. {code_context_control-2.73.0 → code_context_control-2.74.0}/setup.cfg +0 -0
  259. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_access_builtin_optout.py +0 -0
  260. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_access_guard.py +0 -0
  261. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_access_guard_meta.py +0 -0
  262. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_access_guard_shell_project.py +0 -0
  263. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_access_guard_surfaces.py +0 -0
  264. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_access_guard_wiring.py +0 -0
  265. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_activity_reporter.py +0 -0
  266. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_agent_locks.py +0 -0
  267. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_aider_polyglot.py +0 -0
  268. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_antigravity_transition.py +0 -0
  269. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_artifact_store.py +0 -0
  270. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_artifact_tool.py +0 -0
  271. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  272. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_bitbucket_client.py +0 -0
  273. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_bitbucket_config_fallback.py +0 -0
  274. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_bitbucket_credentials.py +0 -0
  275. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_bitbucket_tool.py +0 -0
  276. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  277. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_c3_shell.py +0 -0
  278. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_circuit_breaker.py +0 -0
  279. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_claude_md_merge.py +0 -0
  280. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_cli_smoke.py +0 -0
  281. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_compressor_large_file.py +0 -0
  282. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_credential_store.py +0 -0
  283. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_credentials_routes.py +0 -0
  284. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_credentials_tool.py +0 -0
  285. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_creds_cli_smoke.py +0 -0
  286. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_delegate_cascade.py +0 -0
  287. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_delegate_version_probe.py +0 -0
  288. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_e2e_benchmark.py +0 -0
  289. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_edit_ledger_hook.py +0 -0
  290. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_edit_locking.py +0 -0
  291. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_edit_normalization.py +0 -0
  292. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_embedding_index_deadlock.py +0 -0
  293. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_enforcement_flip.py +0 -0
  294. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_enforcement_policy.py +0 -0
  295. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_enforcement_routes.py +0 -0
  296. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_federated_graph.py +0 -0
  297. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_filter_backoff.py +0 -0
  298. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_ghost_files.py +0 -0
  299. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_ghost_generation.py +0 -0
  300. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_git_branch_awareness.py +0 -0
  301. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_access_guard.py +0 -0
  302. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_dispatch.py +0 -0
  303. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_pretool_enforce.py +0 -0
  304. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_prompt_recall.py +0 -0
  305. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_smoke.py +0 -0
  306. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_state.py +0 -0
  307. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hook_utf8_stdio.py +0 -0
  308. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_credentials_route.py +0 -0
  309. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_credentials_routes_write.py +0 -0
  310. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_enforcement_routes.py +0 -0
  311. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_inspect_api.py +0 -0
  312. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_locks_routes.py +0 -0
  313. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_server_smoke.py +0 -0
  314. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_hub_subproject_links.py +0 -0
  315. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_ide_workflow_adaptation.py +0 -0
  316. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_init_scan.py +0 -0
  317. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_install_mcp_entrypoint.py +0 -0
  318. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_cli_smoke.py +0 -0
  319. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_client.py +0 -0
  320. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_config_fallback.py +0 -0
  321. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_credentials.py +0 -0
  322. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_links.py +0 -0
  323. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_routes.py +0 -0
  324. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_jira_tool.py +0 -0
  325. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_lazy_store_init.py +0 -0
  326. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mask_guard.py +0 -0
  327. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mask_routes.py +0 -0
  328. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mask_surfaces.py +0 -0
  329. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mcp_host_guard.py +0 -0
  330. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mcp_memory_timeout.py +0 -0
  331. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mcp_server_smoke.py +0 -0
  332. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mcp_toml.py +0 -0
  333. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_memory_distiller.py +0 -0
  334. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_memory_graph_api.py +0 -0
  335. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_memory_queue.py +0 -0
  336. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_memory_system.py +0 -0
  337. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mobile_api.py +0 -0
  338. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mobile_override_routes.py +0 -0
  339. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_mobile_security_api.py +0 -0
  340. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_no_stale_model_pins.py +0 -0
  341. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_notification_dedup.py +0 -0
  342. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_notification_discipline.py +0 -0
  343. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_ollama_credentials.py +0 -0
  344. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_api_auth.py +0 -0
  345. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_apikey_api.py +0 -0
  346. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_c3_bridge.py +0 -0
  347. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_chat_engine.py +0 -0
  348. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_chat_store.py +0 -0
  349. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_discovery_api.py +0 -0
  350. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_discovery_audit.py +0 -0
  351. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_local_auth.py +0 -0
  352. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_ollama_bridge.py +0 -0
  353. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_scanner_cache.py +0 -0
  354. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_security_fixes.py +0 -0
  355. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_session_bootstrap.py +0 -0
  356. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_subproject_awareness.py +0 -0
  357. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_oracle_ui_bundle.py +0 -0
  358. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_output_filter.py +0 -0
  359. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_override_grants.py +0 -0
  360. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_override_grants_mcp.py +0 -0
  361. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_override_wake.py +0 -0
  362. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_permissions.py +0 -0
  363. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_pm_api.py +0 -0
  364. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_project_manager.py +0 -0
  365. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_project_manager_merge.py +0 -0
  366. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_project_tool.py +0 -0
  367. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_read_coercion.py +0 -0
  368. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_read_edit_parity.py +0 -0
  369. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_related_facts.py +0 -0
  370. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_repo_map.py +0 -0
  371. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_response_boilerplate.py +0 -0
  372. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_retention.py +0 -0
  373. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_review_digest.py +0 -0
  374. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_service_durability.py +0 -0
  375. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_session_benchmark.py +0 -0
  376. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_session_budget.py +0 -0
  377. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_shell_creds.py +0 -0
  378. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_shell_robustness.py +0 -0
  379. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_subproject_exclusion.py +0 -0
  380. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_subproject_federation.py +0 -0
  381. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_subprojects.py +0 -0
  382. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_swe_bench.py +0 -0
  383. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_task_store.py +0 -0
  384. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_task_tool.py +0 -0
  385. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_time_tracker.py +0 -0
  386. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_token_telemetry.py +0 -0
  387. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_tool_registry.py +0 -0
  388. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_upgrade_and_version.py +0 -0
  389. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_validate.py +0 -0
  390. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_vault_write_guard.py +0 -0
  391. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_version_sync.py +0 -0
  392. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_web_security.py +0 -0
  393. {code_context_control-2.73.0 → code_context_control-2.74.0}/tests/test_windows_reliability.py +0 -0
  394. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/__init__.py +0 -0
  395. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/backend.py +0 -0
  396. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/main.py +0 -0
  397. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/__init__.py +0 -0
  398. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/benchmark_view.py +0 -0
  399. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/claudemd_view.py +0 -0
  400. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/compress_view.py +0 -0
  401. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/index_view.py +0 -0
  402. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/init_view.py +0 -0
  403. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/mcp_view.py +0 -0
  404. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/optimize_view.py +0 -0
  405. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/pipe_view.py +0 -0
  406. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/projects_view.py +0 -0
  407. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/search_view.py +0 -0
  408. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/session_view.py +0 -0
  409. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/stats.py +0 -0
  410. {code_context_control-2.73.0 → code_context_control-2.74.0}/tui/screens/ui_view.py +0 -0
  411. {code_context_control-2.73.0 → code_context_control-2.74.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.73.0
3
+ Version: 2.74.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.73.0"
95
+ __version__ = "2.74.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.73.0
3
+ Version: 2.74.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.73.0"
7
+ version = "2.74.0"
8
8
  description = "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."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -709,11 +709,12 @@ def _override_offer(denial: Denial, path, operation: str, tool: str) -> str:
709
709
  that can never be escalated: an agent must not learn from a refusal that
710
710
  a request surface exists for the credential vault (§6).
711
711
 
712
- Restricted to the hook surface on purpose. The offer promises that a human
713
- 'yes' makes the retry work, and today only the PreToolUse gates consult
714
- grants — the ``c3_*`` content surfaces do not (see §13, phase P2a). An
715
- offer on a surface that would still refuse after approval is worse than
716
- no offer.
712
+ Restricted to the hook surface on purpose see ``refusal``. The rule was
713
+ written when only the PreToolUse gates consulted grants; P2a taught the
714
+ ``c3_*`` content surfaces to consult them too, so extending the offer to
715
+ the MCP surface is now defensible. It is deliberately NOT done here: that
716
+ is a separate, wider change (every c3_* refusal grows a line) and belongs
717
+ in its own review, not smuggled in beside a fix for the branch ordering.
717
718
  """
718
719
  try:
719
720
  from services import override_policy as _op # noqa: PLC0415 — cycle
@@ -738,7 +739,26 @@ def refusal(denial: Denial, path, operation: str, *, surface: str = "mcp",
738
739
  the agent it may ASK (docs/override-requests.md §6). The pinned strings
739
740
  above are unchanged: the append is absent unless the project opted in,
740
741
  which is off by default.
742
+
743
+ The append happens HERE, once, for every kind — not inside a branch. It
744
+ used to live at the tail of the deny branch, which sits below the mask and
745
+ read-only early returns, so those two kinds could never carry an offer on
746
+ any surface even though `rule_class_for_denial` marks both escalatable.
747
+ `access_readonly` was the only layer anyone had turned on, so in practice
748
+ the invitation half of Override Requests had never fired once.
741
749
  """
750
+ body = _refusal_body(denial, path, operation, surface=surface,
751
+ tool=tool, project=project)
752
+ # Hook only, still: the offer promises that a 'yes' makes the retry work,
753
+ # and the proxy surface answers for a DIFFERENT project's policy.
754
+ if surface == "hook":
755
+ return body + _override_offer(denial, path, operation, tool)
756
+ return body
757
+
758
+
759
+ def _refusal_body(denial: Denial, path, operation: str, *, surface: str,
760
+ tool: str, project: str) -> str:
761
+ """The pinned string itself, with no override append."""
742
762
  p, glob, scope = _cap(path), denial.rule, denial.scope
743
763
  if denial.kind == _KIND_MASK:
744
764
  if operation in ("write", "create", "delete"):
@@ -762,12 +782,20 @@ def refusal(denial: Denial, path, operation: str, *, surface: str = "mcp",
762
782
  "`c3 access list` or the Access tab."
763
783
  )
764
784
  if denial.kind == _KIND_READ_ONLY:
785
+ # `{operation}`, not a hardcoded "write". A read-only rule blocks the
786
+ # whole write class, and for a file that does not exist yet the tools
787
+ # call that operation `create`. Saying "write" told the agent to ask
788
+ # the user to approve `op='write'`, the approval was minted for
789
+ # `write`, and the grant matcher — which compares op exactly — then
790
+ # refused the `create` the tool actually attempted. A real approval
791
+ # was spent and silently discarded (§4 near_miss).
765
792
  return (
766
- f"{TAG_READ_ONLY} write denied for {p} by Access Guard rule "
793
+ f"{TAG_READ_ONLY} {operation} denied for {p} by Access Guard rule "
767
794
  f"'{glob}' ({scope} scope). The effective policy is read-only; "
768
- "reads are evaluated separately. Do not retry the write. Mark "
769
- "the affected step blocked and continue with unaffected files; "
770
- "report the skip. Rules: `c3 access list` or the Access tab."
795
+ f"reads are evaluated separately. Do not retry the {operation}. "
796
+ "Mark the affected step blocked and continue with unaffected "
797
+ "files; report the skip. Rules: `c3 access list` or the Access "
798
+ "tab."
771
799
  )
772
800
  if surface == "hook":
773
801
  return (
@@ -776,7 +804,7 @@ def refusal(denial: Denial, path, operation: str, *, surface: str = "mcp",
776
804
  "decision, not a transient error — do not retry through another "
777
805
  "tool or the shell. Mark the affected step blocked and continue "
778
806
  "with unaffected files. Rules: `c3 access list`."
779
- ) + _override_offer(denial, path, operation, tool)
807
+ )
780
808
  if surface == "proxy":
781
809
  return (
782
810
  f"{TAG_DENIED} {operation} denied for {p} through project "
@@ -43,7 +43,8 @@ class NotificationStore:
43
43
  self._collapsed = False
44
44
 
45
45
  def add(self, agent: str, severity: str, title: str, message: str,
46
- ai_enhanced: bool = False, replace_if_unacked: bool = False) -> dict | None:
46
+ ai_enhanced: bool = False, replace_if_unacked: bool = False,
47
+ kind: str = "", ref_id: str = "") -> dict | None:
47
48
  """Append a notification. Dedup: an identical (agent, title, message)
48
49
  that is still unacknowledged collapses into the existing record — its
49
50
  ``count`` is bumped and ``last_seen`` refreshed instead of appending a
@@ -54,6 +55,13 @@ class NotificationStore:
54
55
  already exists, update its message/severity in-place (bumping
55
56
  count/last_seen) instead of appending a new entry. Use for
56
57
  high-frequency agents (budget, index, key-file drift) to prevent pile-up.
58
+ kind: machine-readable class for clients that ROUTE on a tap rather
59
+ than parse the title — 'override' for an approval request. Omitted
60
+ from the record when empty, so every existing producer and every
61
+ stored line is unchanged.
62
+ ref_id: the id of the thing the notification is ABOUT (e.g. the
63
+ override request), which is not the notification's own ``id``.
64
+ A client needs both: ``id`` to acknowledge, ``ref_id`` to navigate.
57
65
  Returns the entry if written/updated, None if deduped.
58
66
  """
59
67
  with self._lock:
@@ -75,6 +83,13 @@ class NotificationStore:
75
83
  existing["last_seen"] = now.isoformat()
76
84
  existing["count"] = _entry_count(existing) + 1
77
85
  existing["ai_enhanced"] = ai_enhanced
86
+ # Refresh the routing fields too: an in-place update
87
+ # keeps the record but the thing it points AT may have
88
+ # changed (a new request id under the same title).
89
+ if kind:
90
+ existing["kind"] = kind
91
+ if ref_id:
92
+ existing["ref_id"] = ref_id
78
93
  self._write_all(entries)
79
94
  return existing
80
95
  # Same notification still pending — collapse into the
@@ -108,6 +123,12 @@ class NotificationStore:
108
123
  "acknowledged": False,
109
124
  "ai_enhanced": ai_enhanced,
110
125
  }
126
+ # Additive only: absent keys rather than empty ones, so a client
127
+ # can test presence and old lines stay byte-identical in shape.
128
+ if kind:
129
+ entry["kind"] = kind
130
+ if ref_id:
131
+ entry["ref_id"] = ref_id
111
132
  with open(self._file, "a", encoding="utf-8") as f:
112
133
  f.write(json.dumps(entry) + "\n")
113
134
  return entry
@@ -420,6 +420,12 @@ def _notify(project_path: str, row: dict, policy) -> None:
420
420
  f"{Path(row['path']).name}?",
421
421
  message=(f"Blocked by rule {row['rule']} ({row['rule_class']}). "
422
422
  f"Approve once: c3 override approve {row['id']}"),
423
+ # A phone routes on these, not on the title. Without them a tap
424
+ # opens the app and drops the user wherever they were last —
425
+ # which, for the one notification that exists to be answered, is
426
+ # the same as not delivering it (§9).
427
+ kind="override",
428
+ ref_id=row["id"],
423
429
  )
424
430
  except Exception:
425
431
  pass # a missing notification must never fail the request
@@ -325,5 +325,130 @@ class TestOfferLine(RequestBase):
325
325
  self.assertIn("do not retry through another tool or the shell", text)
326
326
 
327
327
 
328
+ # ── §6 the offer must not depend on WHICH kind denied ──────────────────────
329
+
330
+ class TestOfferReachesEveryEscalatableKind(RequestBase):
331
+ """The bug this class exists for.
332
+
333
+ `refusal()` used to append the offer at the tail of the deny branch, which
334
+ sits *below* the mask and read-only early returns. Both of those kinds map
335
+ to an escalatable layer in `rule_class_for_denial`, so policy said "offer
336
+ this" and the composer structurally could not. `access_readonly` was the
337
+ only layer that had ever been switched on in the wild, which made the
338
+ invitation half of the feature dead on the one path anybody used.
339
+
340
+ These assert on the LAYER, not on a branch, so re-introducing an early
341
+ return in front of the append fails here rather than in production.
342
+ """
343
+
344
+ def _refuse(self, rel, operation, tool="Write"):
345
+ target = self.proj / rel
346
+ target.parent.mkdir(parents=True, exist_ok=True)
347
+ denial = ag.check(str(target), operation, str(self.proj))
348
+ self.assertIsNotNone(denial, f"fixture must deny {rel} on {operation}")
349
+ return denial, ag.refusal(denial, str(target), operation,
350
+ surface="hook", tool=tool)
351
+
352
+ def test_read_only_denial_carries_the_offer(self):
353
+ denial, text = self._refuse("docs/a.md", "write")
354
+ self.assertEqual(denial.kind, "read_only")
355
+ self.assertEqual(opol.rule_class_for_denial(denial),
356
+ opol.LAYER_ACCESS_READONLY)
357
+ self.assertIn(opol.TAG_OFFER, text)
358
+ self.assertIn("action='request'", text)
359
+
360
+ def test_deny_denial_still_carries_the_offer(self):
361
+ denial, text = self._refuse("secrets/other.txt", "read", tool="Read")
362
+ self.assertEqual(denial.kind, "deny")
363
+ self.assertIn(opol.TAG_OFFER, text)
364
+
365
+ def test_every_escalatable_kind_is_offered(self):
366
+ """No kind may be silently unreachable."""
367
+ cases = [("docs/a.md", "write"), ("secrets/other.txt", "read")]
368
+ for rel, operation in cases:
369
+ with self.subTest(path=rel):
370
+ denial, text = self._refuse(rel, operation)
371
+ layer = opol.rule_class_for_denial(denial)
372
+ self.assertIsNotNone(layer)
373
+ self.assertIn(opol.TAG_OFFER, text)
374
+
375
+ def test_offer_still_absent_when_the_layer_is_off(self):
376
+ layers = dict(ALL_LAYERS_ON)
377
+ layers[opol.LAYER_ACCESS_READONLY] = False
378
+ self.write_config(layers=layers)
379
+ _, text = self._refuse("docs/a.md", "write")
380
+ self.assertNotIn(opol.TAG_OFFER, text)
381
+
382
+ def test_offer_absent_on_the_mcp_surface(self):
383
+ denial = ag.check(str(self.proj / "docs" / "a.md"), "write",
384
+ str(self.proj))
385
+ text = ag.refusal(denial, "docs/a.md", "write")
386
+ self.assertNotIn(opol.TAG_OFFER, text)
387
+
388
+
389
+ # ── §4 the refusal must name the operation the caller named ────────────────
390
+
391
+ class TestRefusalNamesTheRealOperation(RequestBase):
392
+ """A read-only refusal that always said "write" cost a real approval.
393
+
394
+ `c3_edit` calls the operation `create` when the file does not exist. The
395
+ agent copied "write" out of the refusal, the human approved `write`, and
396
+ the grant matcher — exact on `op` — refused the `create` that followed.
397
+ """
398
+
399
+ def _text(self, operation):
400
+ target = self.proj / "docs" / "new.md"
401
+ denial = ag.check(str(target), operation, str(self.proj))
402
+ return ag.refusal(denial, str(target), operation)
403
+
404
+ def test_create_is_named_create(self):
405
+ text = self._text("create")
406
+ self.assertIn("create denied", text)
407
+ self.assertNotIn("write denied", text)
408
+ self.assertIn("Do not retry the create", text)
409
+
410
+ def test_write_is_still_named_write(self):
411
+ text = self._text("write")
412
+ self.assertIn("write denied", text)
413
+
414
+ def test_delete_is_named_delete(self):
415
+ self.assertIn("delete denied", self._text("delete"))
416
+
417
+ def test_the_offer_carries_the_same_operation(self):
418
+ target = self.proj / "docs" / "new.md"
419
+ denial = ag.check(str(target), "create", str(self.proj))
420
+ text = ag.refusal(denial, str(target), "create", surface="hook",
421
+ tool="c3_edit")
422
+ self.assertIn("op='create'", text)
423
+ self.assertNotIn("op='write'", text)
424
+
425
+
426
+ # ── §9 the phone routes on the payload, not on the title ───────────────────
427
+
428
+ class TestNotificationPayload(RequestBase):
429
+ def _entries(self):
430
+ raw = (self.proj / ".c3" / "notifications.jsonl").read_text("utf-8")
431
+ return [json.loads(ln) for ln in raw.splitlines() if ln.strip()]
432
+
433
+ def test_request_notification_carries_kind_and_ref_id(self):
434
+ row = self.request()
435
+ entry = next(e for e in self._entries()
436
+ if e.get("title", "").startswith("Approve "))
437
+ self.assertEqual(entry["kind"], "override")
438
+ self.assertEqual(entry["ref_id"], row["id"])
439
+ # The notification's own id stays its own — a client needs both, one
440
+ # to acknowledge and one to navigate.
441
+ self.assertNotEqual(entry["id"], row["id"])
442
+
443
+ def test_other_producers_are_unchanged(self):
444
+ from services.notifications import NotificationStore
445
+ NotificationStore(str(self.proj)).add(
446
+ agent="IndexStaleness", severity="info", title="t", message="m")
447
+ entry = next(e for e in self._entries() if e.get("agent") ==
448
+ "IndexStaleness")
449
+ self.assertNotIn("kind", entry)
450
+ self.assertNotIn("ref_id", entry)
451
+
452
+
328
453
  if __name__ == "__main__":
329
454
  unittest.main()