code-context-control 2.126.1__tar.gz → 2.127.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 (526) hide show
  1. {code_context_control-2.126.1 → code_context_control-2.127.0}/PKG-INFO +1 -1
  2. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/c3.py +37 -2
  3. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/commands/parser.py +12 -0
  4. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_server.py +37 -0
  5. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_access.js +111 -11
  6. {code_context_control-2.126.1 → code_context_control-2.127.0}/code_context_control.egg-info/PKG-INFO +1 -1
  7. {code_context_control-2.126.1 → code_context_control-2.127.0}/code_context_control.egg-info/SOURCES.txt +3 -0
  8. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/mobile_api.py +72 -1
  9. {code_context_control-2.126.1 → code_context_control-2.127.0}/pyproject.toml +1 -1
  10. code_context_control-2.127.0/services/override_costs.py +183 -0
  11. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_override_routes.py +73 -0
  12. code_context_control-2.127.0/tests/test_mobile_override_costs.py +252 -0
  13. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mobile_override_routes.py +49 -0
  14. code_context_control-2.127.0/tests/test_override_costs.py +320 -0
  15. {code_context_control-2.126.1 → code_context_control-2.127.0}/LICENSE +0 -0
  16. {code_context_control-2.126.1 → code_context_control-2.127.0}/README.md +0 -0
  17. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/__init__.py +0 -0
  18. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/_hook_utils.py +0 -0
  19. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/_shell_writes.py +0 -0
  20. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/commands/__init__.py +0 -0
  21. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/commands/common.py +0 -0
  22. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/docs.html +0 -0
  23. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/edits.html +0 -0
  24. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/access.html +0 -0
  25. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/bitbucket.html +0 -0
  26. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/credentials.html +0 -0
  27. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/getting-started.html +0 -0
  28. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/index.html +0 -0
  29. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/masking.html +0 -0
  30. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/oracle.html +0 -0
  31. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/shared.css +0 -0
  32. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/tools.html +0 -0
  33. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/guide/workflow.html +0 -0
  34. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_access_guard.py +0 -0
  35. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_artifact.py +0 -0
  36. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_auto_snapshot.py +0 -0
  37. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_c3_signal.py +0 -0
  38. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_c3read.py +0 -0
  39. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_codex_lifecycle.py +0 -0
  40. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_dispatch.py +0 -0
  41. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_edit_ledger.py +0 -0
  42. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_edit_unlock.py +0 -0
  43. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_filter.py +0 -0
  44. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_ghost_files.py +0 -0
  45. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_pretool_enforce.py +0 -0
  46. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_prompt_recall.py +0 -0
  47. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_read.py +0 -0
  48. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_session_end.py +0 -0
  49. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_session_open.py +0 -0
  50. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_session_stats.py +0 -0
  51. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hook_terse_advisor.py +0 -0
  52. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/app.js +0 -0
  53. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/add_project.js +0 -0
  54. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/config_editor.js +0 -0
  55. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  56. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/drill_health.js +0 -0
  57. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/drill_panel.js +0 -0
  58. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  59. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  60. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/drill_views.js +0 -0
  61. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/global_search.js +0 -0
  62. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_ci.js +0 -0
  63. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  64. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  65. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  66. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_locks.js +0 -0
  67. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/hub_tokens.js +0 -0
  68. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  69. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/modals.js +0 -0
  70. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/project_card.js +0 -0
  71. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/project_tree.js +0 -0
  72. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/session_drawer.js +0 -0
  73. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/settings_modal.js +0 -0
  74. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/sidebar.js +0 -0
  75. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/summary_bar.js +0 -0
  76. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/task_board.js +0 -0
  77. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/toasts.js +0 -0
  78. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/components/topbar.js +0 -0
  79. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui/state.js +0 -0
  80. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/hub_ui.html +0 -0
  81. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/mcp_proxy.py +0 -0
  82. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/mcp_server.py +0 -0
  83. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/progress.py +0 -0
  84. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/server.py +0 -0
  85. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/__init__.py +0 -0
  86. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/_grants.py +0 -0
  87. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/_helpers.py +0 -0
  88. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/agent.py +0 -0
  89. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/artifacts.py +0 -0
  90. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/bitbucket.py +0 -0
  91. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/ci.py +0 -0
  92. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/compress.py +0 -0
  93. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/credentials.py +0 -0
  94. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/delegate.py +0 -0
  95. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/edit.py +0 -0
  96. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/edit_verify.py +0 -0
  97. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/edits.py +0 -0
  98. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/federate.py +0 -0
  99. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/filter.py +0 -0
  100. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/impact.py +0 -0
  101. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/jira.py +0 -0
  102. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/locks.py +0 -0
  103. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/memory.py +0 -0
  104. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/override.py +0 -0
  105. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/project.py +0 -0
  106. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/read.py +0 -0
  107. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/search.py +0 -0
  108. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/session.py +0 -0
  109. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/shell.py +0 -0
  110. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/shell_job.py +0 -0
  111. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/shell_nudge.py +0 -0
  112. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/shell_parsers.py +0 -0
  113. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/shell_render.py +0 -0
  114. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/status.py +0 -0
  115. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/tasks.py +0 -0
  116. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/tools/validate.py +0 -0
  117. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/api.js +0 -0
  118. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/app.js +0 -0
  119. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/access.js +0 -0
  120. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/bitbucket.js +0 -0
  121. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/chat.js +0 -0
  122. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/credentials.js +0 -0
  123. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/dashboard.js +0 -0
  124. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/edits.js +0 -0
  125. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/enforcement.js +0 -0
  126. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/instructions.js +0 -0
  127. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/jira.js +0 -0
  128. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/memory.js +0 -0
  129. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/sessions.js +0 -0
  130. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/settings.js +0 -0
  131. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/sidebar.js +0 -0
  132. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/components/tasks.js +0 -0
  133. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/icons.js +0 -0
  134. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/pm_shared.js +0 -0
  135. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/shared.js +0 -0
  136. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui/theme.js +0 -0
  137. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui.html +0 -0
  138. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui_legacy.html +0 -0
  139. {code_context_control-2.126.1 → code_context_control-2.127.0}/cli/ui_nano.html +0 -0
  140. {code_context_control-2.126.1 → code_context_control-2.127.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  141. {code_context_control-2.126.1 → code_context_control-2.127.0}/code_context_control.egg-info/entry_points.txt +0 -0
  142. {code_context_control-2.126.1 → code_context_control-2.127.0}/code_context_control.egg-info/requires.txt +0 -0
  143. {code_context_control-2.126.1 → code_context_control-2.127.0}/code_context_control.egg-info/top_level.txt +0 -0
  144. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/__init__.py +0 -0
  145. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/codex_patch.py +0 -0
  146. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/config.py +0 -0
  147. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/host.py +0 -0
  148. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/ide.py +0 -0
  149. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/mcp_toml.py +0 -0
  150. {code_context_control-2.126.1 → code_context_control-2.127.0}/core/web_security.py +0 -0
  151. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/__init__.py +0 -0
  152. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/config.py +0 -0
  153. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/listeners.py +0 -0
  154. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/mcp_oracle.py +0 -0
  155. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/oracle_server.py +0 -0
  156. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/oracle_ui.html +0 -0
  157. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/__init__.py +0 -0
  158. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/activity_reporter.py +0 -0
  159. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/api_auth.py +0 -0
  160. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/c3_bridge.py +0 -0
  161. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/chat_engine.py +0 -0
  162. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/chat_poll.py +0 -0
  163. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/chat_store.py +0 -0
  164. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/client_tokens.py +0 -0
  165. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/cross_memory.py +0 -0
  166. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/discovery_audit.py +0 -0
  167. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/federated_graph.py +0 -0
  168. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/health_checker.py +0 -0
  169. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/insight_engine.py +0 -0
  170. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/local_session.py +0 -0
  171. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/memory_reader.py +0 -0
  172. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/memory_writer.py +0 -0
  173. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/project_scanner.py +0 -0
  174. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/review_agent.py +0 -0
  175. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/tool_executor.py +0 -0
  176. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/services/tool_registry.py +0 -0
  177. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/activity.js +0 -0
  178. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/agents.js +0 -0
  179. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/app.js +0 -0
  180. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/busy.js +0 -0
  181. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/chat/conversations.js +0 -0
  182. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/chat/input.js +0 -0
  183. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/chat/markdown.js +0 -0
  184. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/chat/send.js +0 -0
  185. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/chat/stream_renderer.js +0 -0
  186. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/chat/toolbar.js +0 -0
  187. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/core.js +0 -0
  188. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/crossgraph.js +0 -0
  189. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/header.js +0 -0
  190. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/insights.js +0 -0
  191. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/projects.js +0 -0
  192. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/qrcode.js +0 -0
  193. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/settings.js +0 -0
  194. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/suggestions.js +0 -0
  195. {code_context_control-2.126.1 → code_context_control-2.127.0}/oracle/ui/theme_tabs.js +0 -0
  196. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/__init__.py +0 -0
  197. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/access_guard.py +0 -0
  198. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/access_telemetry.py +0 -0
  199. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/activity_log.py +0 -0
  200. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/agent_base.py +0 -0
  201. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/agent_locks.py +0 -0
  202. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/agents.py +0 -0
  203. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/artifact_defs.py +0 -0
  204. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/artifact_store.py +0 -0
  205. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/atomic_json.py +0 -0
  206. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/auto_memory.py +0 -0
  207. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/background_service.py +0 -0
  208. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/__init__.py +0 -0
  209. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/external/__init__.py +0 -0
  210. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/external/aider_polyglot.py +0 -0
  211. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/external/swe_bench.py +0 -0
  212. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/map_eval.py +0 -0
  213. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/search_eval.py +0 -0
  214. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bench/shell_eval.py +0 -0
  215. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/benchmark_dashboard.py +0 -0
  216. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bitbucket_client.py +0 -0
  217. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/bitbucket_credentials.py +0 -0
  218. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_act.py +0 -0
  219. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_cache.py +0 -0
  220. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_expr.py +0 -0
  221. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_failures.py +0 -0
  222. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_github.py +0 -0
  223. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_impact.py +0 -0
  224. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_intel.py +0 -0
  225. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_runner.py +0 -0
  226. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ci_workflow.py +0 -0
  227. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/circuit_breaker.py +0 -0
  228. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/claude_md.py +0 -0
  229. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/codex_integration.py +0 -0
  230. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/codex_transcript.py +0 -0
  231. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/compressor.py +0 -0
  232. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/context_snapshot.py +0 -0
  233. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/conversation_store.py +0 -0
  234. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/cred_audit.py +0 -0
  235. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/cred_telemetry.py +0 -0
  236. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/credential_store.py +0 -0
  237. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/dir_map.py +0 -0
  238. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/doc_index.py +0 -0
  239. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/e2e_benchmark.py +0 -0
  240. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/e2e_evaluator.py +0 -0
  241. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/e2e_tasks.py +0 -0
  242. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/edit_ledger.py +0 -0
  243. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/embedding_index.py +0 -0
  244. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/enforcement_policy.py +0 -0
  245. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/error_reporting.py +0 -0
  246. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/file_map.py +0 -0
  247. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/file_memory.py +0 -0
  248. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/git_context.py +0 -0
  249. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/host_sessions.py +0 -0
  250. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/hub_service.py +0 -0
  251. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/index_store.py +0 -0
  252. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/indexer.py +0 -0
  253. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/jira_client.py +0 -0
  254. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/jira_cloud.py +0 -0
  255. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/jira_credentials.py +0 -0
  256. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/jira_data_center.py +0 -0
  257. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/jira_links.py +0 -0
  258. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/lexical_index.py +0 -0
  259. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/mask_activation.py +0 -0
  260. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/mask_mirror.py +0 -0
  261. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/mask_presets.py +0 -0
  262. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory.py +0 -0
  263. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory_consolidator.py +0 -0
  264. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory_distiller.py +0 -0
  265. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory_graph.py +0 -0
  266. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory_grounder.py +0 -0
  267. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory_queue.py +0 -0
  268. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/memory_scorer.py +0 -0
  269. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/metrics.py +0 -0
  270. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/notifications.py +0 -0
  271. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ollama_bridge.py +0 -0
  272. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ollama_client.py +0 -0
  273. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/ollama_credentials.py +0 -0
  274. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/oracle_service.py +0 -0
  275. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/output_filter.py +0 -0
  276. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/override_grants.py +0 -0
  277. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/override_policy.py +0 -0
  278. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/override_requests.py +0 -0
  279. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/override_wake.py +0 -0
  280. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/parser.py +0 -0
  281. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/project_manager.py +0 -0
  282. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/project_runtime.py +0 -0
  283. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/protocol.py +0 -0
  284. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/proxy_state.py +0 -0
  285. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/repo_map.py +0 -0
  286. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/repo_shape.py +0 -0
  287. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/reranker.py +0 -0
  288. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/retention.py +0 -0
  289. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/retrieval.py +0 -0
  290. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/retrieval_broker.py +0 -0
  291. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/router.py +0 -0
  292. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/runtime.py +0 -0
  293. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/scanner.py +0 -0
  294. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/session_benchmark.py +0 -0
  295. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/session_manager.py +0 -0
  296. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/session_preloader.py +0 -0
  297. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/shell_jobs.py +0 -0
  298. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/shell_output.py +0 -0
  299. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/subprojects.py +0 -0
  300. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/task_store.py +0 -0
  301. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/telemetry.py +0 -0
  302. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/text_index.py +0 -0
  303. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/time_tracker.py +0 -0
  304. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/tool_classifier.py +0 -0
  305. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/transcript_index.py +0 -0
  306. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/validation_cache.py +0 -0
  307. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/vector_store.py +0 -0
  308. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/watcher.py +0 -0
  309. {code_context_control-2.126.1 → code_context_control-2.127.0}/services/win_subprocess.py +0 -0
  310. {code_context_control-2.126.1 → code_context_control-2.127.0}/setup.cfg +0 -0
  311. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_access_builtin_optout.py +0 -0
  312. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_access_guard.py +0 -0
  313. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_access_guard_meta.py +0 -0
  314. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_access_guard_shell_project.py +0 -0
  315. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_access_guard_surfaces.py +0 -0
  316. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_access_guard_wiring.py +0 -0
  317. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_activity_reporter.py +0 -0
  318. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_agent_locks.py +0 -0
  319. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_aider_polyglot.py +0 -0
  320. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_antigravity_transition.py +0 -0
  321. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_artifact_store.py +0 -0
  322. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_artifact_tool.py +0 -0
  323. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_atomic_json.py +0 -0
  324. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_background_service.py +0 -0
  325. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  326. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_bitbucket_client.py +0 -0
  327. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_bitbucket_config_fallback.py +0 -0
  328. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_bitbucket_credentials.py +0 -0
  329. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_bitbucket_tool.py +0 -0
  330. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_builtin_modes.py +0 -0
  331. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  332. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_c3_shell.py +0 -0
  333. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_chat_poll.py +0 -0
  334. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_act.py +0 -0
  335. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_cache.py +0 -0
  336. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_expr.py +0 -0
  337. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_impact.py +0 -0
  338. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_intel.py +0 -0
  339. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_runner.py +0 -0
  340. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ci_workflow.py +0 -0
  341. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_circuit_breaker.py +0 -0
  342. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_claude_md_merge.py +0 -0
  343. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_claude_md_updater.py +0 -0
  344. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_cli_smoke.py +0 -0
  345. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_codex_mcp_transport.py +0 -0
  346. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_codex_native.py +0 -0
  347. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_compressor_large_file.py +0 -0
  348. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_confirm_guard.py +0 -0
  349. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_confirm_guard_wiring.py +0 -0
  350. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_cooccurrence_bounds.py +0 -0
  351. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_cred_audit.py +0 -0
  352. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_cred_telemetry.py +0 -0
  353. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_credential_login_kind.py +0 -0
  354. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_credential_store.py +0 -0
  355. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_credential_ui_parity.py +0 -0
  356. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_credentials_routes.py +0 -0
  357. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_credentials_tool.py +0 -0
  358. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_creds_cli_smoke.py +0 -0
  359. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_delegate_cascade.py +0 -0
  360. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_delegate_version_probe.py +0 -0
  361. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_dir_map_c3.py +0 -0
  362. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_e2e_benchmark.py +0 -0
  363. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_edit_ledger_deadline.py +0 -0
  364. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_edit_ledger_hook.py +0 -0
  365. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_edit_locking.py +0 -0
  366. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_edit_normalization.py +0 -0
  367. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_edit_verify.py +0 -0
  368. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_embedding_index_deadlock.py +0 -0
  369. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_enforcement_flip.py +0 -0
  370. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_enforcement_policy.py +0 -0
  371. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_enforcement_routes.py +0 -0
  372. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_env_parser.py +0 -0
  373. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
  374. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_federated_graph.py +0 -0
  375. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_file_map_c1.py +0 -0
  376. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_filter_backoff.py +0 -0
  377. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ghost_files.py +0 -0
  378. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ghost_generation.py +0 -0
  379. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_git_branch_awareness.py +0 -0
  380. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_access_guard.py +0 -0
  381. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_codex_compat.py +0 -0
  382. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_dispatch.py +0 -0
  383. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_pretool_enforce.py +0 -0
  384. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_prompt_recall.py +0 -0
  385. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_session_end.py +0 -0
  386. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_smoke.py +0 -0
  387. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_state.py +0 -0
  388. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hook_utf8_stdio.py +0 -0
  389. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_credentials_route.py +0 -0
  390. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_credentials_routes_write.py +0 -0
  391. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_enforcement_routes.py +0 -0
  392. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_inspect_api.py +0 -0
  393. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_locks_routes.py +0 -0
  394. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_oracle_service_routes.py +0 -0
  395. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_server_smoke.py +0 -0
  396. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_hub_subproject_links.py +0 -0
  397. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ide_workflow_adaptation.py +0 -0
  398. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_index_cap_not_hardcoded.py +0 -0
  399. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_init_clear_preserves_user_content.py +0 -0
  400. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_init_scan.py +0 -0
  401. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_install_mcp_entrypoint.py +0 -0
  402. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_cli_smoke.py +0 -0
  403. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_client.py +0 -0
  404. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_config_fallback.py +0 -0
  405. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_credentials.py +0 -0
  406. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_links.py +0 -0
  407. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_routes.py +0 -0
  408. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_jira_tool.py +0 -0
  409. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_large_files_c4.py +0 -0
  410. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_lazy_store_init.py +0 -0
  411. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_map_eval.py +0 -0
  412. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_map_telemetry_c0.py +0 -0
  413. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mask_guard.py +0 -0
  414. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mask_routes.py +0 -0
  415. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mask_surfaces.py +0 -0
  416. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mcp_host_guard.py +0 -0
  417. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mcp_memory_timeout.py +0 -0
  418. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mcp_server_smoke.py +0 -0
  419. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mcp_toml.py +0 -0
  420. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_memory_distiller.py +0 -0
  421. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_memory_graph_api.py +0 -0
  422. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_memory_queue.py +0 -0
  423. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_memory_system.py +0 -0
  424. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mobile_api.py +0 -0
  425. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mobile_clients.py +0 -0
  426. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mobile_extras.py +0 -0
  427. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mobile_jobs_ci.py +0 -0
  428. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_mobile_security_api.py +0 -0
  429. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_no_stale_model_pins.py +0 -0
  430. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_notification_dedup.py +0 -0
  431. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_notification_discipline.py +0 -0
  432. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_notification_kinds.py +0 -0
  433. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ollama_credentials.py +0 -0
  434. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_api_auth.py +0 -0
  435. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_apikey_api.py +0 -0
  436. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_c3_bridge.py +0 -0
  437. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_chat_engine.py +0 -0
  438. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_chat_store.py +0 -0
  439. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_discovery_api.py +0 -0
  440. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_discovery_audit.py +0 -0
  441. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_health_probe.py +0 -0
  442. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_local_auth.py +0 -0
  443. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_loopback.py +0 -0
  444. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_ollama_bridge.py +0 -0
  445. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_scanner_cache.py +0 -0
  446. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_security_fixes.py +0 -0
  447. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_session_bootstrap.py +0 -0
  448. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_subproject_awareness.py +0 -0
  449. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_oracle_ui_bundle.py +0 -0
  450. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_output_filter.py +0 -0
  451. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_override_grants.py +0 -0
  452. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_override_grants_mcp.py +0 -0
  453. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_override_requests.py +0 -0
  454. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_override_wake.py +0 -0
  455. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_permissions.py +0 -0
  456. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_pm_api.py +0 -0
  457. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_project_manager.py +0 -0
  458. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_project_manager_merge.py +0 -0
  459. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_project_tool.py +0 -0
  460. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_read_coercion.py +0 -0
  461. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_read_edit_parity.py +0 -0
  462. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_related_facts.py +0 -0
  463. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_repo_map.py +0 -0
  464. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_repo_shape.py +0 -0
  465. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_response_boilerplate.py +0 -0
  466. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_retention.py +0 -0
  467. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_review_digest.py +0 -0
  468. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_eval.py +0 -0
  469. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_p1.py +0 -0
  470. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_p2.py +0 -0
  471. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_p2b.py +0 -0
  472. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_p3.py +0 -0
  473. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_p4.py +0 -0
  474. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_search_p5.py +0 -0
  475. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_service_durability.py +0 -0
  476. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_session_benchmark.py +0 -0
  477. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_session_budget.py +0 -0
  478. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_budget_s1.py +0 -0
  479. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_creds.py +0 -0
  480. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_eval.py +0 -0
  481. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_jobs_s3.py +0 -0
  482. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_nudge_s4.py +0 -0
  483. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_output.py +0 -0
  484. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_parsers_s2.py +0 -0
  485. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_robustness.py +0 -0
  486. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_telemetry_s0.py +0 -0
  487. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_write_ledger.py +0 -0
  488. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_shell_writes.py +0 -0
  489. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_subproject_clear_scope.py +0 -0
  490. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_subproject_depth_consumers.py +0 -0
  491. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_subproject_exclusion.py +0 -0
  492. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_subproject_federation.py +0 -0
  493. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_subproject_linkage_api.py +0 -0
  494. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_subprojects.py +0 -0
  495. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_swe_bench.py +0 -0
  496. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_task_store.py +0 -0
  497. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_task_tool.py +0 -0
  498. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_time_tracker.py +0 -0
  499. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_token_telemetry.py +0 -0
  500. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_token_tracking.py +0 -0
  501. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_tool_registry.py +0 -0
  502. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_ui_jsx_syntax.py +0 -0
  503. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_upgrade_and_version.py +0 -0
  504. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_validate.py +0 -0
  505. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_vault_write_guard.py +0 -0
  506. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_version_sync.py +0 -0
  507. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_web_security.py +0 -0
  508. {code_context_control-2.126.1 → code_context_control-2.127.0}/tests/test_windows_reliability.py +0 -0
  509. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/__init__.py +0 -0
  510. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/backend.py +0 -0
  511. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/main.py +0 -0
  512. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/__init__.py +0 -0
  513. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/benchmark_view.py +0 -0
  514. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/claudemd_view.py +0 -0
  515. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/compress_view.py +0 -0
  516. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/index_view.py +0 -0
  517. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/init_view.py +0 -0
  518. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/mcp_view.py +0 -0
  519. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/optimize_view.py +0 -0
  520. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/pipe_view.py +0 -0
  521. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/projects_view.py +0 -0
  522. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/search_view.py +0 -0
  523. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/session_view.py +0 -0
  524. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/stats.py +0 -0
  525. {code_context_control-2.126.1 → code_context_control-2.127.0}/tui/screens/ui_view.py +0 -0
  526. {code_context_control-2.126.1 → code_context_control-2.127.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.126.1
3
+ Version: 2.127.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.126.1"
95
+ __version__ = "2.127.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -6968,8 +6968,10 @@ def cmd_override(args):
6968
6968
  """
6969
6969
  sub = getattr(args, "override_cmd", None)
6970
6970
  if not sub:
6971
- print("Usage: c3 override <policy|grant|list|revoke|check|sweep> ...")
6971
+ print("Usage: c3 override <policy|grant|list|revoke|check|sweep|"
6972
+ "requests|approve|deny|costs> ...")
6972
6973
  print(" c3 override policy # what is escalatable right now")
6974
+ print(" c3 override costs # which rules keep holding the agent")
6973
6975
  return
6974
6976
 
6975
6977
  from services import override_grants as og
@@ -6998,6 +7000,39 @@ def cmd_override(args):
6998
7000
  _override_requests(args, project_path)
6999
7001
  elif sub in ("approve", "deny"):
7000
7002
  _override_decide(args, sub, project_path)
7003
+ elif sub == "costs":
7004
+ _override_costs(args, project_path)
7005
+
7006
+
7007
+ def _override_costs(args, project_path: str) -> None:
7008
+ """`c3 override costs` — which rules keep holding the agent (§11 T5)."""
7009
+ from services import override_costs as ocost
7010
+
7011
+ days = max(1, int(getattr(args, "days", None) or ocost.DEFAULT_DAYS))
7012
+ everywhere = bool(getattr(args, "all_projects", False))
7013
+ rows = ocost.rule_costs(project_path=None if everywhere else project_path,
7014
+ days=days)
7015
+ print_header(f"Override costs — last {days} day(s)"
7016
+ + ("" if everywhere else f" · {Path(project_path).name}"))
7017
+ if not rows:
7018
+ print(" (no requests in the window)")
7019
+ return
7020
+ width = max(len(r["rule"]) for r in rows)
7021
+ print(f" {'held':>4} {'ok':>3} {'no':>3} {'exp':>3} {'wait':>4} "
7022
+ f"{'rule':<{width}} suggestion")
7023
+ for r in rows:
7024
+ line = (f" {r['count']:>4} {r['approved']:>3} {r['denied']:>3} "
7025
+ f"{r['expired']:>3} {r['pending']:>4} {r['rule']:<{width}} "
7026
+ f"{r['suggestion']}")
7027
+ if r["count"] >= ocost.NUDGE_THRESHOLD:
7028
+ line += " <- costing you"
7029
+ print(line)
7030
+ if everywhere:
7031
+ print(f" {'':22s} {r['project_path']}")
7032
+ print("\n held = requests filed; ok/no/exp/wait = approved/denied/"
7033
+ "expired/still pending (withdrawn counts in held only).")
7034
+ print(" A rule you keep approving is friction: edit it with `c3 access`. "
7035
+ "A rule you keep denying is working — mute the session instead.")
7001
7036
 
7002
7037
 
7003
7038
  def _override_requests(args, project_path: str) -> None:
@@ -779,6 +779,18 @@ def build_parser(version: str, parse_cli_ide_arg):
779
779
  ov_deny.add_argument("--path", dest="project_path", default=".",
780
780
  help="Project directory (default: current)")
781
781
 
782
+ # Costs: which rules keep asking (spec §11 Threat 5, v2.127.0). A read
783
+ # over the request store — it decides nothing and edits no rule.
784
+ ov_costs = override_subs.add_parser(
785
+ "costs", help="Which rules held the agent most, and how you answered"
786
+ )
787
+ ov_costs.add_argument("--days", type=int, default=7,
788
+ help="Trailing window in days (default 7)")
789
+ ov_costs.add_argument("--all", dest="all_projects", action="store_true",
790
+ help="Every project, not just this one")
791
+ ov_costs.add_argument("--path", dest="project_path", default=".",
792
+ help="Project directory (default: current)")
793
+
782
794
  # ── Tool discipline / enforcement mode (v2.66.0) ────────────────────
783
795
  # LAYER C: how hard C3 pushes the agent toward c3_* tools. Distinct from
784
796
  # `c3 access` (path policy — a security boundary) and from
@@ -3215,6 +3215,43 @@ def api_hub_overrides():
3215
3215
  "limit": limit})
3216
3216
 
3217
3217
 
3218
+ @app.route("/api/hub/overrides/costs", methods=["GET"])
3219
+ def api_hub_override_costs():
3220
+ """Per-(project, rule) request counts over a trailing window (§11 T5).
3221
+
3222
+ The "this rule is costing you" strip. Query: path (optional — omit for
3223
+ every project in the store; the hub is this machine's own surface and
3224
+ does not filter to a registry), days (1..30, default 7). Response:
3225
+ {days, threshold, rules: [...], count, project} with the row shape of
3226
+ ``services.override_costs.FIELDS``; ``threshold`` is the count at which
3227
+ the UI says something, so the strip and the desktop tray agree on it.
3228
+ Registered before the POST-only ``<request_id>`` route so a GET on
3229
+ ``costs`` can never fall through to a 405 there.
3230
+ """
3231
+ from services import override_costs as ocost
3232
+ project_path = ""
3233
+ raw_project = (request.args.get("path") or "").strip()
3234
+ if raw_project:
3235
+ try:
3236
+ project_path = str(_resolve_project_path(raw_project))
3237
+ except ValueError as e:
3238
+ return jsonify({"error": str(e)}), 404
3239
+ try:
3240
+ days = int(request.args.get("days") or ocost.DEFAULT_DAYS)
3241
+ except (TypeError, ValueError):
3242
+ days = ocost.DEFAULT_DAYS
3243
+ days = max(1, min(ocost.MAX_DAYS, days))
3244
+ try:
3245
+ rules = ocost.rule_costs(project_path=project_path or None, days=days)
3246
+ except Exception as exc:
3247
+ return jsonify({"error": str(exc)}), 500
3248
+ for r in rules:
3249
+ r["project_name"] = Path(str(r.get("project_path") or ".")).name
3250
+ return jsonify({"days": days, "threshold": ocost.NUDGE_THRESHOLD,
3251
+ "rules": rules, "count": len(rules),
3252
+ "project": project_path})
3253
+
3254
+
3218
3255
  @app.route("/api/hub/overrides/<request_id>", methods=["POST"])
3219
3256
  def api_hub_override_decide(request_id):
3220
3257
  """Approve (minting a grant) or deny one request. decided_by='desktop'.
@@ -185,11 +185,79 @@ function AccRequestCard({ row, busy, onDecide, onTypedApprove, onRuleApprove })
185
185
  );
186
186
  }
187
187
 
188
+ // ── "Costing you" — the §11 Threat 5 nudge ─────────────────────────────────
189
+ // One row per rule that held at least `threshold` times in the window. The
190
+ // count is the argument: a rule the user keeps approving is friction, and a
191
+ // rule they keep denying is doing its job against an agent that will not
192
+ // stop asking. Either way the fix is the RULE, not the next card — so the
193
+ // only affordance is "open the rule", which jumps to it in the policy matrix
194
+ // below. The strip never approves anything and never edits policy; it says
195
+ // the number out loud, which is the mitigation the spec asks for.
196
+ function accSamePath(a, b) {
197
+ const norm = (p) => String(p || '').replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase();
198
+ return norm(a) === norm(b);
199
+ }
200
+
201
+ function AccCostStrip({ onOpenRule }) {
202
+ const [data, setData] = useState(null);
203
+
204
+ const load = useCallback(async () => {
205
+ try {
206
+ setData(await api.get('/api/hub/overrides/costs?days=7'));
207
+ } catch { /* keep the last good strip */ }
208
+ }, []);
209
+
210
+ useEffect(() => { load(); }, [load]);
211
+ usePoll(load, 15000);
212
+
213
+ if (!data) return null;
214
+ const threshold = Number(data.threshold) || 3;
215
+ const rows = (data.rules || []).filter(r => (Number(r.count) || 0) >= threshold);
216
+ if (rows.length === 0) return null;
217
+ return (
218
+ <div style={{
219
+ background: T.surface, border: `1px solid ${T.warn}`, borderRadius: 10,
220
+ padding: '10px 14px',
221
+ }}>
222
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', marginBottom: 4 }}>
223
+ <span style={{ fontSize: 12.5, fontWeight: 700, color: T.warn }}>Costing you</span>
224
+ <span style={{ fontSize: 11, color: T.textDim }}>
225
+ rules that held {threshold}+ times in the last {data.days} days — fix the
226
+ rule, not the next card
227
+ </span>
228
+ </div>
229
+ {rows.map(r => (
230
+ <div key={`${r.project_path}|${r.rule}`} style={{
231
+ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap',
232
+ padding: '4px 0', fontSize: 11.5, color: T.textMuted,
233
+ }}>
234
+ <span className="mono" title={r.project_path} style={{
235
+ fontSize: 10.5, padding: '2px 7px', borderRadius: 4,
236
+ background: T.surfaceAlt, color: T.textMuted,
237
+ }}>{r.project_name || r.project_path}</span>
238
+ <span>
239
+ <b className="mono" style={{ color: T.text }}>{r.rule}</b>
240
+ {' '}held {r.count}× this week ({r.approved} approved) — {r.suggestion}
241
+ </span>
242
+ <div style={{ flex: 1 }} />
243
+ <Btn variant="ghost" onClick={() => onOpenRule(r)}
244
+ style={{ padding: '4px 10px' }}>Open rule</Btn>
245
+ </div>
246
+ ))}
247
+ </div>
248
+ );
249
+ }
250
+
188
251
  // ── Read-only per-project policy matrix ────────────────────────────────────
189
- function AccRulesPanel({ projects }) {
252
+ // `focus` ({path, rule, seq}) comes from the cost strip's "Open rule": the
253
+ // panel switches to that project, scrolls itself into view and outlines the
254
+ // chip whose glob is the rule. A synthetic rule (discipline / shell) has no
255
+ // chip, so the scroll alone is the answer there.
256
+ function AccRulesPanel({ projects, focus }) {
190
257
  const [path, setPath] = useState('');
191
258
  const [data, setData] = useState(null);
192
259
  const [err, setErr] = useState('');
260
+ const panelRef = useRef(null);
193
261
 
194
262
  const load = useCallback(async (p) => {
195
263
  if (!p) { setData(null); setErr(''); return; }
@@ -199,10 +267,28 @@ function AccRulesPanel({ projects }) {
199
267
  } catch (e) { setData(null); setErr(apiErr(e)); }
200
268
  }, []);
201
269
 
270
+ // Deliberately keyed on `focus` alone: `projects` is rebuilt by the hub's
271
+ // own poll, and re-running this on every poll would re-scroll the page
272
+ // under the user every few seconds.
273
+ useEffect(() => {
274
+ if (!focus || !focus.path) return;
275
+ // Prefer the hub's own spelling of the project so the <select> shows it;
276
+ // the store's spelling still loads when the project is not registered.
277
+ const known = (projects || []).find(p => accSamePath(p.path, focus.path));
278
+ const target = known ? known.path : focus.path;
279
+ setPath(target);
280
+ load(target);
281
+ const el = panelRef.current;
282
+ if (el && typeof el.scrollIntoView === 'function') {
283
+ el.scrollIntoView({ behavior: 'smooth', block: 'start' });
284
+ }
285
+ }, [focus]); // eslint-disable-line react-hooks/exhaustive-deps
286
+
287
+ const hot = focus && focus.rule ? String(focus.rule) : '';
202
288
  const scopes = (data && data.rules) || {};
203
289
  const layerRows = data && data.policy ? Object.entries(data.policy.layers || {}) : [];
204
290
  return (
205
- <div style={{
291
+ <div ref={panelRef} style={{
206
292
  background: T.surface, border: `1px solid ${T.border}`, borderRadius: 10,
207
293
  padding: '12px 16px',
208
294
  }}>
@@ -249,14 +335,21 @@ function AccRulesPanel({ projects }) {
249
335
  <div style={{ fontSize: 11.5, color: T.textDim }}>no rules</div>
250
336
  ) : (
251
337
  <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
252
- {rows.map(([kind, glob], i) => (
253
- <span key={i} className="mono" style={{
254
- fontSize: 11, padding: '2px 8px', borderRadius: 4,
255
- color: ACC_KIND_COLOR(kind),
256
- background: `${ACC_KIND_COLOR(kind)}18`,
257
- border: `1px solid ${ACC_KIND_COLOR(kind)}44`,
258
- }} title={kind}>{kind}: {glob}</span>
259
- ))}
338
+ {rows.map(([kind, glob], i) => {
339
+ const lit = hot && glob === hot;
340
+ return (
341
+ <span key={i} className="mono" style={{
342
+ fontSize: 11, padding: '2px 8px', borderRadius: 4,
343
+ color: ACC_KIND_COLOR(kind),
344
+ background: `${ACC_KIND_COLOR(kind)}18`,
345
+ border: `1px solid ${ACC_KIND_COLOR(kind)}44`,
346
+ outline: lit ? `2px solid ${T.warn}` : 'none',
347
+ outlineOffset: lit ? 2 : 0,
348
+ }} title={lit ? `${kind} — this rule is costing you` : kind}>
349
+ {kind}: {glob}
350
+ </span>
351
+ );
352
+ })}
260
353
  </div>
261
354
  )}
262
355
  {scope === 'builtin' && (sec.disabled || []).length > 0 && (
@@ -395,6 +488,11 @@ function HubAccess({ projects }) {
395
488
  const [chip, setChip] = useState('pending');
396
489
  const [busyId, setBusyId] = useState('');
397
490
  const [confirmSpec, setConfirmSpec] = useState(null);
491
+ // `seq` makes a second click on the same rule re-fire the panel's effect.
492
+ const [ruleFocus, setRuleFocus] = useState(null);
493
+ const openRule = (r) => setRuleFocus({
494
+ path: r.project_path, rule: r.rule, seq: Date.now(),
495
+ });
398
496
 
399
497
  const load = useCallback(async () => {
400
498
  try {
@@ -459,6 +557,8 @@ function HubAccess({ projects }) {
459
557
  ))}
460
558
  </div>
461
559
 
560
+ <AccCostStrip onOpenRule={openRule} />
561
+
462
562
  {!loaded ? (
463
563
  <div style={{ fontSize: 12, color: T.textDim }}>Loading…</div>
464
564
  ) : rows.length === 0 ? (
@@ -479,7 +579,7 @@ function HubAccess({ projects }) {
479
579
  )}
480
580
 
481
581
  <AccGrantsPanel projects={projects} />
482
- <AccRulesPanel projects={projects} />
582
+ <AccRulesPanel projects={projects} focus={ruleFocus} />
483
583
  {confirmSpec && (
484
584
  <CredConfirm spec={confirmSpec} onClose={() => setConfirmSpec(null)} />
485
585
  )}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.126.1
3
+ Version: 2.127.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
@@ -260,6 +260,7 @@ services/ollama_client.py
260
260
  services/ollama_credentials.py
261
261
  services/oracle_service.py
262
262
  services/output_filter.py
263
+ services/override_costs.py
263
264
  services/override_grants.py
264
265
  services/override_policy.py
265
266
  services/override_requests.py
@@ -419,6 +420,7 @@ tests/test_mobile_api.py
419
420
  tests/test_mobile_clients.py
420
421
  tests/test_mobile_extras.py
421
422
  tests/test_mobile_jobs_ci.py
423
+ tests/test_mobile_override_costs.py
422
424
  tests/test_mobile_override_routes.py
423
425
  tests/test_mobile_security_api.py
424
426
  tests/test_no_stale_model_pins.py
@@ -443,6 +445,7 @@ tests/test_oracle_session_bootstrap.py
443
445
  tests/test_oracle_subproject_awareness.py
444
446
  tests/test_oracle_ui_bundle.py
445
447
  tests/test_output_filter.py
448
+ tests/test_override_costs.py
446
449
  tests/test_override_grants.py
447
450
  tests/test_override_grants_mcp.py
448
451
  tests/test_override_requests.py
@@ -71,6 +71,11 @@ from services.atomic_json import write_json_atomic
71
71
  # reports the caller as `client: {kind, client_id}`, and override
72
72
  # decisions are attributed to that kind ("desk" for the tray client,
73
73
  # "mobile" for a phone or the legacy Discovery token).
74
+ # 5 (unchanged, additive, v2.127.0): `override_costs` capability and
75
+ # GET /overrides/costs — per-(project, rule) request counts over a
76
+ # trailing window, the "this rule is costing you" nudge (D3a). The
77
+ # /overrides/<id> detail also carries `allow_session_grants`,
78
+ # `max_ttl_s` and `session_confirm` at the top level.
74
79
  API_VERSION = 5
75
80
 
76
81
  CAPABILITIES = [
@@ -79,7 +84,7 @@ CAPABILITIES = [
79
84
  "credentials", "credentials_write",
80
85
  "access", "access_write",
81
86
  "enforcement", "enforcement_write",
82
- "override", "override_write",
87
+ "override", "override_write", "override_costs",
83
88
  "edits", "locks", "status",
84
89
  "insights", "insights_write",
85
90
  "suggestions", "suggestions_write",
@@ -103,6 +108,9 @@ _CAPABILITY_SWITCHES = {
103
108
  "enforcement_write": "mobile_access_write",
104
109
  "override": "mobile_override_enabled",
105
110
  "override_write": "mobile_override_write",
111
+ # The cost view is a read over the same store the inbox serves, so it
112
+ # goes dark with the inbox rather than carrying a switch of its own.
113
+ "override_costs": "mobile_override_enabled",
106
114
  # The ops reads (edits, locks, status, insights, suggestions, review) are
107
115
  # deliberately absent: they expose nothing the feed does not already, so
108
116
  # gating them would only cost a client a capability probe. Only the two
@@ -2439,6 +2447,60 @@ def _write_override_section(project: Path, section: dict) -> dict:
2439
2447
  return block
2440
2448
 
2441
2449
 
2450
+ def _days_arg(default: int, ceiling: int) -> int:
2451
+ """``?days=`` clamped to ``[1, ceiling]``; garbage reads as the default.
2452
+
2453
+ A clamp rather than a 400 because the value only sizes a window — a
2454
+ client asking for a quarter gets the month it is allowed, and the answer
2455
+ echoes the window actually used so it can say so.
2456
+ """
2457
+ try:
2458
+ want = int(request.args.get("days", default))
2459
+ except (TypeError, ValueError):
2460
+ want = default
2461
+ return max(1, min(ceiling, want))
2462
+
2463
+
2464
+ @bp.route("/overrides/costs", methods=["GET"])
2465
+ def mobile_overrides_costs():
2466
+ """Per-(project, rule) request counts over a trailing window (§11 T5).
2467
+
2468
+ The "this rule is costing you" number. Query: project (optional — omit
2469
+ for every project this gateway serves), days (1..30, default 7).
2470
+ Response: {days, rules: [{project_path, rule, rule_class, layer, count,
2471
+ approved, denied, expired, pending, last_at, suggestion}], count,
2472
+ project}. Rows sort by count desc then last_at desc; the desktop shows
2473
+ `suggestion` verbatim and nudges at count >= 3.
2474
+
2475
+ Registered BEFORE `/overrides/<id>` for the same reason `policy` is: the
2476
+ ordering is explicit so `costs` can never become a request id.
2477
+ """
2478
+ gate = _feature_or_404("override_costs")
2479
+ if gate:
2480
+ return gate
2481
+ from services import override_costs as ocost
2482
+ raw_project = (request.args.get("project") or "").strip()
2483
+ project_path = ""
2484
+ if raw_project:
2485
+ resolved, err = _project_or_404(raw_project)
2486
+ if err:
2487
+ return err
2488
+ project_path = str(resolved)
2489
+ days = _days_arg(ocost.DEFAULT_DAYS, ocost.MAX_DAYS)
2490
+ try:
2491
+ rules = ocost.rule_costs(project_path=project_path or None, days=days)
2492
+ except Exception as exc:
2493
+ return _svc_error(exc)
2494
+ if not project_path:
2495
+ # Same rule as /overrides and /jobs: the store is one file for the
2496
+ # whole machine, and a cross-project view must not name a project
2497
+ # this token cannot otherwise see.
2498
+ rules = [r for r in rules
2499
+ if _resolve_registered(str(r.get("project_path") or "")) is not None]
2500
+ return jsonify({"days": days, "rules": rules, "count": len(rules),
2501
+ "project": project_path})
2502
+
2503
+
2442
2504
  @bp.route("/overrides/<request_id>", methods=["GET"])
2443
2505
  def mobile_override_get(request_id):
2444
2506
  """One request, full context."""
@@ -2481,6 +2543,15 @@ def mobile_override_get(request_id):
2481
2543
  "confirm_with": (
2482
2544
  row.get("rule") if str(row.get("rule_class") or "")
2483
2545
  in opol.TYPED_CONFIRM_LAYERS else ""),
2546
+ # Top-level as well as under `policy` (v2.127.0): what a session-grant
2547
+ # button needs, in one fetch — whether the switch is on, how long the
2548
+ # grant would last, and the literal the client must send as
2549
+ # `confirm` (`decide()` demands it on the layers that are otherwise
2550
+ # one-tap). Duplicated on purpose: a client should not need the
2551
+ # policy dict's shape to draw one button.
2552
+ "allow_session_grants": bool(policy.allow_session_grants),
2553
+ "max_ttl_s": int(policy.max_ttl_s),
2554
+ "session_confirm": orq.CONFIRM_SESSION,
2484
2555
  })
2485
2556
 
2486
2557
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.126.1"
7
+ version = "2.127.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"
@@ -0,0 +1,183 @@
1
+ """Override costs — the "this rule is costing you" nudge (spec §11 Threat 5).
2
+
3
+ The request store answers "what is waiting?"; nothing answered "which rule
4
+ keeps asking?". On 2026-09-06 one session filed six holds on
5
+ ``**/.claude/skills/**`` for ONE file in 65 minutes — four approved by hand,
6
+ two lost to the TTL — and every surface rendered each card as if it were the
7
+ first. Approval fatigue is the threat §11 calls "the real one", and its
8
+ mitigation is a number: how often a rule held, and how the human answered.
9
+
10
+ This module is that number. It is a READ-ONLY fold over
11
+ ``~/.c3/oracle/override_requests.json`` grouped by ``(project_path, rule)``
12
+ over a trailing window — never a decision, never a mutation, not even the
13
+ store's own lazy expiry flip (a lapsed pending row is *counted* as expired
14
+ against the supplied clock; flipping it on disk stays with the readers that
15
+ already do so). A corrupt or missing store reads as no rows, which is the
16
+ honest answer for a nudge: silence, not a crash in a route or a tray.
17
+
18
+ Consumers: ``GET /api/mobile/overrides/costs`` (desktop tray nudge),
19
+ ``GET /api/hub/overrides/costs`` (Hub "Costing you" strip),
20
+ ``c3 override costs``. The desktop shows ``suggestion`` verbatim, so its
21
+ three values are part of the wire contract.
22
+ """
23
+ from __future__ import annotations
24
+
25
+ from datetime import datetime, timedelta
26
+
27
+ from services import override_grants as og
28
+ from services import override_requests as orq
29
+
30
+ #: Window defaults. ``MAX_DAYS`` is the remote ceiling (the gateway clamps
31
+ #: to it); the CLI may ask for more, because a person at the keyboard asking
32
+ #: for a quarter's history is not a phone hammering the store.
33
+ DEFAULT_DAYS = 7
34
+ MAX_DAYS = 30
35
+
36
+ #: How many holds per rule per window before a surface should say something.
37
+ #: Shared by the desktop client (hard-coded there to the same value) and the
38
+ #: Hub strip; a rule that held twice is a coincidence, three times is a cost.
39
+ NUDGE_THRESHOLD = 3
40
+
41
+ #: The one-line verdicts. The desktop renders them verbatim — change the
42
+ #: wording here and the tray changes with it, so treat them as contract.
43
+ SUGGEST_ALLOW = "convert to allow"
44
+ SUGGEST_TIGHTEN = "tighten or deny"
45
+ SUGGEST_REVIEW = "review"
46
+
47
+ #: Output row shape, in order. ``count`` is EVERY request in the window
48
+ #: (withdrawn included); the four buckets are the human-visible outcomes and
49
+ #: deliberately leave ``withdrawn`` out — the agent cancelling its own
50
+ #: question says nothing about whether the rule costs the user anything.
51
+ FIELDS = (
52
+ "project_path", "rule", "rule_class", "layer",
53
+ "count", "approved", "denied", "expired", "pending",
54
+ "last_at", "suggestion",
55
+ )
56
+
57
+
58
+ def suggestion(approved: int, denied: int) -> str:
59
+ """The verdict for one rule's window.
60
+
61
+ ``convert to allow`` — the user keeps saying yes and has never said no;
62
+ the rule is friction, not protection, for this project. ``tighten or
63
+ deny`` — the user has said no at least twice; the rule is doing its job
64
+ and the agent should stop asking, or the rule should be narrower so the
65
+ legitimate case stops tripping it. Anything else is ``review``.
66
+ """
67
+ if denied >= 2:
68
+ return SUGGEST_TIGHTEN
69
+ if approved >= 3 and denied == 0:
70
+ return SUGGEST_ALLOW
71
+ return SUGGEST_REVIEW
72
+
73
+
74
+ def _effective_status(row: dict, at: datetime) -> str:
75
+ """A pending row past its ``expires_at`` IS expired, whether or not a
76
+ writer has flipped it yet. Evaluated against the caller's clock so a
77
+ fixed ``now`` in a test sees the same answer the live store would."""
78
+ status = str(row.get("status") or "")
79
+ if status == orq.STATUS_PENDING:
80
+ exp = og.parse_ts(row.get("expires_at"))
81
+ if exp is None or at >= exp:
82
+ return orq.STATUS_EXPIRED
83
+ return status
84
+
85
+
86
+ def _project_key(raw: str, cache: dict) -> str:
87
+ """Grouping identity for a project path — same canonicaliser
88
+ ``list_requests`` filters with, so a row spelled ``Y:/Projects/X`` and a
89
+ filter spelled ``y:\\projects\\x`` land in one group. Empty stays empty:
90
+ ``path_key('')`` would resolve to the CWD and silently adopt orphan rows."""
91
+ raw = str(raw or "")
92
+ if not raw:
93
+ return ""
94
+ if raw not in cache:
95
+ try:
96
+ cache[raw] = og.path_key(raw) or raw.replace("\\", "/").lower()
97
+ except Exception:
98
+ cache[raw] = raw.replace("\\", "/").lower()
99
+ return cache[raw]
100
+
101
+
102
+ def _load_rows() -> list:
103
+ """Every request row, or ``[]`` — a nudge must never raise."""
104
+ try:
105
+ rows = orq.load()
106
+ except Exception:
107
+ return []
108
+ return [r for r in rows if isinstance(r, dict)]
109
+
110
+
111
+ def rule_costs(project_path: str | None = None, days: int = DEFAULT_DAYS,
112
+ now: datetime | None = None) -> list:
113
+ """Per-``(project_path, rule)`` request counts over the trailing window.
114
+
115
+ ``project_path`` narrows to one project (any spelling); ``None`` / ``""``
116
+ means every project in the store — callers serving a token MUST filter
117
+ the result to what that token may see (the store is one file for the
118
+ whole machine). ``days`` is the window length in days, floor 1; the
119
+ window is ``[now - days, now]`` on ``created_at``. ``now`` defaults to
120
+ the wall clock.
121
+
122
+ Returns a list of dicts with exactly :data:`FIELDS`, sorted by ``count``
123
+ descending then ``last_at`` descending. Never raises on store trouble.
124
+ """
125
+ at = now or og.now()
126
+ try:
127
+ span = max(1, int(days))
128
+ except (TypeError, ValueError):
129
+ span = DEFAULT_DAYS
130
+ since = at - timedelta(days=span)
131
+
132
+ cache: dict = {}
133
+ want = _project_key(project_path or "", cache) if project_path else ""
134
+
135
+ groups: dict = {}
136
+ for row in _load_rows():
137
+ created = og.parse_ts(row.get("created_at"))
138
+ if created is None or created < since or created > at:
139
+ continue
140
+ proj_key = _project_key(row.get("project_path", ""), cache)
141
+ if want and proj_key != want:
142
+ continue
143
+ rule = str(row.get("rule") or "")
144
+ key = (proj_key, rule)
145
+ grp = groups.get(key)
146
+ if grp is None:
147
+ grp = groups[key] = {
148
+ "project_path": str(row.get("project_path") or ""),
149
+ "rule": rule,
150
+ "rule_class": str(row.get("rule_class") or ""),
151
+ "layer": str(row.get("layer") or ""),
152
+ "count": 0, "approved": 0, "denied": 0,
153
+ "expired": 0, "pending": 0,
154
+ "last_at": "", "_last_dt": None,
155
+ }
156
+ grp["count"] += 1
157
+ status = _effective_status(row, at)
158
+ if status in ("approved", "denied", "expired", "pending"):
159
+ grp[status] += 1
160
+ if grp["_last_dt"] is None or created > grp["_last_dt"]:
161
+ grp["_last_dt"] = created
162
+ grp["last_at"] = str(row.get("created_at") or "")
163
+ # The newest row is the most honest source for the labels — a
164
+ # rule reclassified mid-window reports what it is NOW.
165
+ grp["rule_class"] = str(row.get("rule_class") or grp["rule_class"])
166
+ grp["layer"] = str(row.get("layer") or grp["layer"])
167
+ grp["project_path"] = str(row.get("project_path") or grp["project_path"])
168
+
169
+ out = []
170
+ for grp in groups.values():
171
+ grp["suggestion"] = suggestion(grp["approved"], grp["denied"])
172
+ out.append(grp)
173
+ # count desc, then most recent first. Every group has a `_last_dt` (the
174
+ # first row that opened it set one), so the fallback never fires; it is
175
+ # there so a sort key can never be None.
176
+ out.sort(key=lambda g: (-g["count"],
177
+ -(g["_last_dt"] or since).timestamp()))
178
+ return [{k: grp[k] for k in FIELDS} for grp in out]
179
+
180
+
181
+ def costing(rules: list, threshold: int = NUDGE_THRESHOLD) -> list:
182
+ """The subset a surface should actually nudge about."""
183
+ return [r for r in rules if int(r.get("count") or 0) >= threshold]