code-context-control 2.96.1__tar.gz → 2.101.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 (467) hide show
  1. {code_context_control-2.96.1/code_context_control.egg-info → code_context_control-2.101.0}/PKG-INFO +1 -1
  2. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/c3.py +78 -5
  3. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/commands/parser.py +22 -3
  4. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_access_guard.py +27 -0
  5. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_server.py +207 -0
  6. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/app.js +3 -1
  7. code_context_control-2.101.0/cli/hub_ui/components/hub_access.js +353 -0
  8. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/topbar.js +1 -1
  9. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/server.py +26 -1
  10. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/_grants.py +25 -0
  11. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/edit.py +7 -1
  12. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/override.py +9 -0
  13. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/read.py +7 -1
  14. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/shell.py +25 -1
  15. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/status.py +2 -1
  16. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/access.js +63 -6
  17. {code_context_control-2.96.1 → code_context_control-2.101.0/code_context_control.egg-info}/PKG-INFO +1 -1
  18. {code_context_control-2.96.1 → code_context_control-2.101.0}/code_context_control.egg-info/SOURCES.txt +4 -0
  19. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/mobile_api.py +2 -1
  20. {code_context_control-2.96.1 → code_context_control-2.101.0}/pyproject.toml +1 -1
  21. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/access_guard.py +386 -95
  22. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/artifact_store.py +5 -1
  23. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/claude_md.py +2 -1
  24. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/override_grants.py +35 -2
  25. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/override_policy.py +45 -7
  26. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/override_requests.py +36 -4
  27. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_access_guard_meta.py +40 -0
  28. code_context_control-2.101.0/tests/test_builtin_modes.py +358 -0
  29. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_c3_shell.py +77 -0
  30. code_context_control-2.101.0/tests/test_confirm_guard.py +386 -0
  31. code_context_control-2.101.0/tests/test_hub_override_routes.py +222 -0
  32. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_override_grants.py +11 -2
  33. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_override_requests.py +14 -0
  34. {code_context_control-2.96.1 → code_context_control-2.101.0}/LICENSE +0 -0
  35. {code_context_control-2.96.1 → code_context_control-2.101.0}/README.md +0 -0
  36. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/__init__.py +0 -0
  37. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/_hook_utils.py +0 -0
  38. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/_shell_writes.py +0 -0
  39. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/commands/__init__.py +0 -0
  40. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/commands/common.py +0 -0
  41. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/docs.html +0 -0
  42. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/edits.html +0 -0
  43. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/access.html +0 -0
  44. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/bitbucket.html +0 -0
  45. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/credentials.html +0 -0
  46. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/getting-started.html +0 -0
  47. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/index.html +0 -0
  48. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/masking.html +0 -0
  49. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/oracle.html +0 -0
  50. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/shared.css +0 -0
  51. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/tools.html +0 -0
  52. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/guide/workflow.html +0 -0
  53. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_artifact.py +0 -0
  54. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_auto_snapshot.py +0 -0
  55. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_c3_signal.py +0 -0
  56. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_c3read.py +0 -0
  57. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_dispatch.py +0 -0
  58. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_edit_ledger.py +0 -0
  59. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_edit_unlock.py +0 -0
  60. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_filter.py +0 -0
  61. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_ghost_files.py +0 -0
  62. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_pretool_enforce.py +0 -0
  63. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_prompt_recall.py +0 -0
  64. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_read.py +0 -0
  65. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_session_stats.py +0 -0
  66. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hook_terse_advisor.py +0 -0
  67. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/add_project.js +0 -0
  68. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/config_editor.js +0 -0
  69. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/drill_artifacts.js +0 -0
  70. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/drill_health.js +0 -0
  71. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/drill_panel.js +0 -0
  72. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/drill_subprojects.js +0 -0
  73. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/drill_tasks.js +0 -0
  74. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/drill_views.js +0 -0
  75. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/global_search.js +0 -0
  76. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/hub_ci.js +0 -0
  77. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  78. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/hub_credentials.js +0 -0
  79. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/hub_enforcement.js +0 -0
  80. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/hub_locks.js +0 -0
  81. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/hub_tokens.js +0 -0
  82. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/mcp_manager.js +0 -0
  83. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/modals.js +0 -0
  84. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/project_card.js +0 -0
  85. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/project_tree.js +0 -0
  86. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/session_drawer.js +0 -0
  87. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/settings_modal.js +0 -0
  88. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/sidebar.js +0 -0
  89. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/summary_bar.js +0 -0
  90. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/task_board.js +0 -0
  91. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/components/toasts.js +0 -0
  92. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui/state.js +0 -0
  93. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/hub_ui.html +0 -0
  94. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/mcp_proxy.py +0 -0
  95. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/mcp_server.py +0 -0
  96. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/progress.py +0 -0
  97. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/__init__.py +0 -0
  98. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/_helpers.py +0 -0
  99. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/agent.py +0 -0
  100. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/artifacts.py +0 -0
  101. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/bitbucket.py +0 -0
  102. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/ci.py +0 -0
  103. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/compress.py +0 -0
  104. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/credentials.py +0 -0
  105. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/delegate.py +0 -0
  106. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/edit_verify.py +0 -0
  107. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/edits.py +0 -0
  108. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/federate.py +0 -0
  109. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/filter.py +0 -0
  110. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/impact.py +0 -0
  111. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/jira.py +0 -0
  112. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/locks.py +0 -0
  113. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/memory.py +0 -0
  114. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/project.py +0 -0
  115. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/search.py +0 -0
  116. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/session.py +0 -0
  117. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/tasks.py +0 -0
  118. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/tools/validate.py +0 -0
  119. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/api.js +0 -0
  120. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/app.js +0 -0
  121. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/bitbucket.js +0 -0
  122. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/chat.js +0 -0
  123. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/credentials.js +0 -0
  124. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/dashboard.js +0 -0
  125. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/edits.js +0 -0
  126. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/enforcement.js +0 -0
  127. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/instructions.js +0 -0
  128. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/jira.js +0 -0
  129. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/memory.js +0 -0
  130. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/sessions.js +0 -0
  131. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/settings.js +0 -0
  132. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/sidebar.js +0 -0
  133. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/components/tasks.js +0 -0
  134. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/icons.js +0 -0
  135. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/pm_shared.js +0 -0
  136. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/shared.js +0 -0
  137. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui/theme.js +0 -0
  138. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui.html +0 -0
  139. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui_legacy.html +0 -0
  140. {code_context_control-2.96.1 → code_context_control-2.101.0}/cli/ui_nano.html +0 -0
  141. {code_context_control-2.96.1 → code_context_control-2.101.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  142. {code_context_control-2.96.1 → code_context_control-2.101.0}/code_context_control.egg-info/entry_points.txt +0 -0
  143. {code_context_control-2.96.1 → code_context_control-2.101.0}/code_context_control.egg-info/requires.txt +0 -0
  144. {code_context_control-2.96.1 → code_context_control-2.101.0}/code_context_control.egg-info/top_level.txt +0 -0
  145. {code_context_control-2.96.1 → code_context_control-2.101.0}/core/__init__.py +0 -0
  146. {code_context_control-2.96.1 → code_context_control-2.101.0}/core/config.py +0 -0
  147. {code_context_control-2.96.1 → code_context_control-2.101.0}/core/ide.py +0 -0
  148. {code_context_control-2.96.1 → code_context_control-2.101.0}/core/mcp_toml.py +0 -0
  149. {code_context_control-2.96.1 → code_context_control-2.101.0}/core/web_security.py +0 -0
  150. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/__init__.py +0 -0
  151. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/config.py +0 -0
  152. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/mcp_oracle.py +0 -0
  153. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/oracle_server.py +0 -0
  154. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/oracle_ui.html +0 -0
  155. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/__init__.py +0 -0
  156. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/activity_reporter.py +0 -0
  157. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/api_auth.py +0 -0
  158. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/c3_bridge.py +0 -0
  159. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/chat_engine.py +0 -0
  160. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/chat_poll.py +0 -0
  161. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/chat_store.py +0 -0
  162. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/cross_memory.py +0 -0
  163. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/discovery_audit.py +0 -0
  164. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/federated_graph.py +0 -0
  165. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/health_checker.py +0 -0
  166. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/insight_engine.py +0 -0
  167. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/local_session.py +0 -0
  168. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/memory_reader.py +0 -0
  169. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/memory_writer.py +0 -0
  170. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/project_scanner.py +0 -0
  171. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/review_agent.py +0 -0
  172. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/tool_executor.py +0 -0
  173. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/services/tool_registry.py +0 -0
  174. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/activity.js +0 -0
  175. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/agents.js +0 -0
  176. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/app.js +0 -0
  177. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/busy.js +0 -0
  178. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/chat/conversations.js +0 -0
  179. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/chat/input.js +0 -0
  180. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/chat/markdown.js +0 -0
  181. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/chat/send.js +0 -0
  182. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/chat/stream_renderer.js +0 -0
  183. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/chat/toolbar.js +0 -0
  184. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/core.js +0 -0
  185. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/crossgraph.js +0 -0
  186. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/header.js +0 -0
  187. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/insights.js +0 -0
  188. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/projects.js +0 -0
  189. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/qrcode.js +0 -0
  190. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/settings.js +0 -0
  191. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/suggestions.js +0 -0
  192. {code_context_control-2.96.1 → code_context_control-2.101.0}/oracle/ui/theme_tabs.js +0 -0
  193. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/__init__.py +0 -0
  194. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/access_telemetry.py +0 -0
  195. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/activity_log.py +0 -0
  196. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/agent_base.py +0 -0
  197. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/agent_locks.py +0 -0
  198. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/agents.py +0 -0
  199. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/artifact_defs.py +0 -0
  200. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/auto_memory.py +0 -0
  201. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/background_service.py +0 -0
  202. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/bench/__init__.py +0 -0
  203. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/bench/external/__init__.py +0 -0
  204. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/bench/external/aider_polyglot.py +0 -0
  205. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/bench/external/swe_bench.py +0 -0
  206. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/benchmark_dashboard.py +0 -0
  207. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/bitbucket_client.py +0 -0
  208. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/bitbucket_credentials.py +0 -0
  209. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_act.py +0 -0
  210. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_cache.py +0 -0
  211. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_expr.py +0 -0
  212. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_failures.py +0 -0
  213. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_github.py +0 -0
  214. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_impact.py +0 -0
  215. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_intel.py +0 -0
  216. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_runner.py +0 -0
  217. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ci_workflow.py +0 -0
  218. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/circuit_breaker.py +0 -0
  219. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/compressor.py +0 -0
  220. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/context_snapshot.py +0 -0
  221. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/conversation_store.py +0 -0
  222. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/cred_audit.py +0 -0
  223. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/cred_telemetry.py +0 -0
  224. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/credential_store.py +0 -0
  225. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/doc_index.py +0 -0
  226. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/e2e_benchmark.py +0 -0
  227. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/e2e_evaluator.py +0 -0
  228. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/e2e_tasks.py +0 -0
  229. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/edit_ledger.py +0 -0
  230. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/embedding_index.py +0 -0
  231. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/enforcement_policy.py +0 -0
  232. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/error_reporting.py +0 -0
  233. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/file_memory.py +0 -0
  234. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/git_context.py +0 -0
  235. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/hub_service.py +0 -0
  236. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/indexer.py +0 -0
  237. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/jira_client.py +0 -0
  238. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/jira_cloud.py +0 -0
  239. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/jira_credentials.py +0 -0
  240. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/jira_data_center.py +0 -0
  241. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/jira_links.py +0 -0
  242. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/mask_activation.py +0 -0
  243. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/mask_mirror.py +0 -0
  244. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/mask_presets.py +0 -0
  245. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory.py +0 -0
  246. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory_consolidator.py +0 -0
  247. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory_distiller.py +0 -0
  248. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory_graph.py +0 -0
  249. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory_grounder.py +0 -0
  250. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory_queue.py +0 -0
  251. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/memory_scorer.py +0 -0
  252. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/metrics.py +0 -0
  253. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/notifications.py +0 -0
  254. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ollama_bridge.py +0 -0
  255. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ollama_client.py +0 -0
  256. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/ollama_credentials.py +0 -0
  257. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/oracle_service.py +0 -0
  258. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/output_filter.py +0 -0
  259. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/override_wake.py +0 -0
  260. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/parser.py +0 -0
  261. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/project_manager.py +0 -0
  262. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/project_runtime.py +0 -0
  263. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/protocol.py +0 -0
  264. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/proxy_state.py +0 -0
  265. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/repo_map.py +0 -0
  266. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/repo_shape.py +0 -0
  267. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/retention.py +0 -0
  268. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/retrieval_broker.py +0 -0
  269. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/router.py +0 -0
  270. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/runtime.py +0 -0
  271. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/scanner.py +0 -0
  272. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/session_benchmark.py +0 -0
  273. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/session_manager.py +0 -0
  274. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/session_preloader.py +0 -0
  275. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/subprojects.py +0 -0
  276. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/task_store.py +0 -0
  277. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/telemetry.py +0 -0
  278. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/text_index.py +0 -0
  279. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/time_tracker.py +0 -0
  280. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/tool_classifier.py +0 -0
  281. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/transcript_index.py +0 -0
  282. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/validation_cache.py +0 -0
  283. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/vector_store.py +0 -0
  284. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/watcher.py +0 -0
  285. {code_context_control-2.96.1 → code_context_control-2.101.0}/services/win_subprocess.py +0 -0
  286. {code_context_control-2.96.1 → code_context_control-2.101.0}/setup.cfg +0 -0
  287. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_access_builtin_optout.py +0 -0
  288. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_access_guard.py +0 -0
  289. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_access_guard_shell_project.py +0 -0
  290. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_access_guard_surfaces.py +0 -0
  291. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_access_guard_wiring.py +0 -0
  292. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_activity_reporter.py +0 -0
  293. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_agent_locks.py +0 -0
  294. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_aider_polyglot.py +0 -0
  295. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_antigravity_transition.py +0 -0
  296. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_artifact_store.py +0 -0
  297. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_artifact_tool.py +0 -0
  298. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_background_service.py +0 -0
  299. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_bitbucket_cli_smoke.py +0 -0
  300. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_bitbucket_client.py +0 -0
  301. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_bitbucket_config_fallback.py +0 -0
  302. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_bitbucket_credentials.py +0 -0
  303. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_bitbucket_tool.py +0 -0
  304. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_c3_bridge_project_artifacts.py +0 -0
  305. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_chat_poll.py +0 -0
  306. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_act.py +0 -0
  307. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_cache.py +0 -0
  308. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_expr.py +0 -0
  309. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_impact.py +0 -0
  310. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_intel.py +0 -0
  311. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_runner.py +0 -0
  312. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ci_workflow.py +0 -0
  313. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_circuit_breaker.py +0 -0
  314. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_claude_md_merge.py +0 -0
  315. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_cli_smoke.py +0 -0
  316. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_compressor_large_file.py +0 -0
  317. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_cooccurrence_bounds.py +0 -0
  318. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_cred_audit.py +0 -0
  319. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_cred_telemetry.py +0 -0
  320. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_credential_login_kind.py +0 -0
  321. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_credential_store.py +0 -0
  322. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_credential_ui_parity.py +0 -0
  323. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_credentials_routes.py +0 -0
  324. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_credentials_tool.py +0 -0
  325. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_creds_cli_smoke.py +0 -0
  326. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_delegate_cascade.py +0 -0
  327. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_delegate_version_probe.py +0 -0
  328. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_e2e_benchmark.py +0 -0
  329. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_edit_ledger_deadline.py +0 -0
  330. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_edit_ledger_hook.py +0 -0
  331. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_edit_locking.py +0 -0
  332. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_edit_normalization.py +0 -0
  333. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_edit_verify.py +0 -0
  334. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_embedding_index_deadlock.py +0 -0
  335. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_enforcement_flip.py +0 -0
  336. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_enforcement_policy.py +0 -0
  337. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_enforcement_routes.py +0 -0
  338. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_env_parser.py +0 -0
  339. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_failed_calls_do_not_unlock.py +0 -0
  340. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_federated_graph.py +0 -0
  341. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_filter_backoff.py +0 -0
  342. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ghost_files.py +0 -0
  343. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ghost_generation.py +0 -0
  344. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_git_branch_awareness.py +0 -0
  345. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_access_guard.py +0 -0
  346. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_codex_compat.py +0 -0
  347. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_dispatch.py +0 -0
  348. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_pretool_enforce.py +0 -0
  349. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_prompt_recall.py +0 -0
  350. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_smoke.py +0 -0
  351. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_state.py +0 -0
  352. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hook_utf8_stdio.py +0 -0
  353. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_credentials_route.py +0 -0
  354. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_credentials_routes_write.py +0 -0
  355. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_enforcement_routes.py +0 -0
  356. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_inspect_api.py +0 -0
  357. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_locks_routes.py +0 -0
  358. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_oracle_service_routes.py +0 -0
  359. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_server_smoke.py +0 -0
  360. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_hub_subproject_links.py +0 -0
  361. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ide_workflow_adaptation.py +0 -0
  362. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_init_clear_preserves_user_content.py +0 -0
  363. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_init_scan.py +0 -0
  364. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_install_mcp_entrypoint.py +0 -0
  365. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_cli_smoke.py +0 -0
  366. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_client.py +0 -0
  367. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_config_fallback.py +0 -0
  368. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_credentials.py +0 -0
  369. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_links.py +0 -0
  370. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_routes.py +0 -0
  371. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_jira_tool.py +0 -0
  372. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_lazy_store_init.py +0 -0
  373. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mask_guard.py +0 -0
  374. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mask_routes.py +0 -0
  375. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mask_surfaces.py +0 -0
  376. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mcp_host_guard.py +0 -0
  377. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mcp_memory_timeout.py +0 -0
  378. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mcp_server_smoke.py +0 -0
  379. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mcp_toml.py +0 -0
  380. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_memory_distiller.py +0 -0
  381. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_memory_graph_api.py +0 -0
  382. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_memory_queue.py +0 -0
  383. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_memory_system.py +0 -0
  384. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mobile_api.py +0 -0
  385. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mobile_extras.py +0 -0
  386. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mobile_override_routes.py +0 -0
  387. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_mobile_security_api.py +0 -0
  388. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_no_stale_model_pins.py +0 -0
  389. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_notification_dedup.py +0 -0
  390. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_notification_discipline.py +0 -0
  391. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ollama_credentials.py +0 -0
  392. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_api_auth.py +0 -0
  393. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_apikey_api.py +0 -0
  394. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_c3_bridge.py +0 -0
  395. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_chat_engine.py +0 -0
  396. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_chat_store.py +0 -0
  397. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_discovery_api.py +0 -0
  398. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_discovery_audit.py +0 -0
  399. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_health_probe.py +0 -0
  400. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_local_auth.py +0 -0
  401. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_ollama_bridge.py +0 -0
  402. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_scanner_cache.py +0 -0
  403. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_security_fixes.py +0 -0
  404. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_session_bootstrap.py +0 -0
  405. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_subproject_awareness.py +0 -0
  406. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_oracle_ui_bundle.py +0 -0
  407. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_output_filter.py +0 -0
  408. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_override_grants_mcp.py +0 -0
  409. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_override_wake.py +0 -0
  410. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_permissions.py +0 -0
  411. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_pm_api.py +0 -0
  412. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_project_manager.py +0 -0
  413. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_project_manager_merge.py +0 -0
  414. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_project_tool.py +0 -0
  415. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_read_coercion.py +0 -0
  416. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_read_edit_parity.py +0 -0
  417. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_related_facts.py +0 -0
  418. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_repo_map.py +0 -0
  419. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_repo_shape.py +0 -0
  420. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_response_boilerplate.py +0 -0
  421. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_retention.py +0 -0
  422. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_review_digest.py +0 -0
  423. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_service_durability.py +0 -0
  424. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_session_benchmark.py +0 -0
  425. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_session_budget.py +0 -0
  426. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_shell_creds.py +0 -0
  427. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_shell_robustness.py +0 -0
  428. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_shell_write_ledger.py +0 -0
  429. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_shell_writes.py +0 -0
  430. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_subproject_clear_scope.py +0 -0
  431. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_subproject_depth_consumers.py +0 -0
  432. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_subproject_exclusion.py +0 -0
  433. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_subproject_federation.py +0 -0
  434. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_subproject_linkage_api.py +0 -0
  435. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_subprojects.py +0 -0
  436. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_swe_bench.py +0 -0
  437. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_task_store.py +0 -0
  438. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_task_tool.py +0 -0
  439. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_time_tracker.py +0 -0
  440. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_token_telemetry.py +0 -0
  441. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_token_tracking.py +0 -0
  442. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_tool_registry.py +0 -0
  443. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_ui_jsx_syntax.py +0 -0
  444. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_upgrade_and_version.py +0 -0
  445. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_validate.py +0 -0
  446. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_vault_write_guard.py +0 -0
  447. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_version_sync.py +0 -0
  448. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_web_security.py +0 -0
  449. {code_context_control-2.96.1 → code_context_control-2.101.0}/tests/test_windows_reliability.py +0 -0
  450. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/__init__.py +0 -0
  451. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/backend.py +0 -0
  452. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/main.py +0 -0
  453. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/__init__.py +0 -0
  454. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/benchmark_view.py +0 -0
  455. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/claudemd_view.py +0 -0
  456. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/compress_view.py +0 -0
  457. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/index_view.py +0 -0
  458. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/init_view.py +0 -0
  459. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/mcp_view.py +0 -0
  460. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/optimize_view.py +0 -0
  461. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/pipe_view.py +0 -0
  462. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/projects_view.py +0 -0
  463. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/search_view.py +0 -0
  464. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/session_view.py +0 -0
  465. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/stats.py +0 -0
  466. {code_context_control-2.96.1 → code_context_control-2.101.0}/tui/screens/ui_view.py +0 -0
  467. {code_context_control-2.96.1 → code_context_control-2.101.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.96.1
3
+ Version: 2.101.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.96.1"
95
+ __version__ = "2.101.0"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -7266,7 +7266,8 @@ def _access_cmd_list(args, project_path: str) -> None:
7266
7266
  "project": ".c3/config.json"}
7267
7267
  for scope in ("builtin", "global", "project"):
7268
7268
  sec = scopes.get(scope) or {}
7269
- rules = [(k, g) for k in ("deny", "read_only") for g in sec.get(k, [])]
7269
+ rules = [(k, g) for k in ("deny", "read_only", "confirm")
7270
+ for g in sec.get(k, [])]
7270
7271
  masks = sec.get("mask") or []
7271
7272
  print(f"[{scope}] ({notes[scope]}) — {len(rules) + len(masks)} rule(s)")
7272
7273
  for kind, glob in rules:
@@ -7286,12 +7287,22 @@ def _access_cmd_list(args, project_path: str) -> None:
7286
7287
  for glob in off:
7287
7288
  print(f" {'off':<10} {glob}")
7288
7289
  print(" re-enable: c3 access builtin enable <glob>")
7290
+ moded = {g: m for g, m in (sec.get("modes") or {}).items()
7291
+ if m not in ("default", "allow")}
7292
+ if moded:
7293
+ print(" MODE set by you (departs from the shipped default):")
7294
+ for glob, m in sorted(moded.items()):
7295
+ print(f" {m:<10} {glob}")
7296
+ print(" reset: c3 access builtin mode <glob> default")
7289
7297
  can = [g for g in (sec.get("disableable") or [])
7290
- if access_guard._norm_builtin(g) not in set(off)]
7298
+ if access_guard._norm_builtin(g) not in set(off)
7299
+ and access_guard._norm_builtin(g) not in moded]
7291
7300
  if can:
7292
7301
  print(" disableable (currently on): "
7293
7302
  + ", ".join(can))
7294
- print(" disable: c3 access builtin disable <glob>")
7303
+ print(" disable: c3 access builtin disable <glob> · "
7304
+ "granular: c3 access builtin mode <glob> "
7305
+ "{deny,confirm,allow}")
7295
7306
  if sec.get("absolute"):
7296
7307
  print(" absolute (credential vault, cannot be disabled): "
7297
7308
  + ", ".join(sec["absolute"]))
@@ -7318,12 +7329,17 @@ def _access_cmd_builtin(args, project_path: str) -> None:
7318
7329
 
7319
7330
  action = getattr(args, "builtin_cmd", None)
7320
7331
  glob = getattr(args, "glob", None)
7321
- if action not in ("disable", "enable") or not glob:
7332
+ if action not in ("disable", "enable", "mode") or not glob:
7322
7333
  print("Usage: c3 access builtin {disable,enable} <glob>")
7334
+ print(" c3 access builtin mode <glob> {deny,confirm,allow,default}")
7323
7335
  print(" disableable: "
7324
7336
  + ", ".join(access_guard.DISABLEABLE_BUILTINS))
7325
7337
  return
7326
7338
 
7339
+ if action == "mode":
7340
+ _access_cmd_builtin_mode(args, glob, project_path)
7341
+ return
7342
+
7327
7343
  disabling = action == "disable"
7328
7344
  if disabling and not getattr(args, "yes", False):
7329
7345
  print(f"About to STOP enforcing the builtin guard on: {glob}")
@@ -7359,6 +7375,63 @@ def _access_cmd_builtin(args, project_path: str) -> None:
7359
7375
  "builtin is enforced anyway (config entry removed).")
7360
7376
 
7361
7377
 
7378
+ _BUILTIN_MODE_HELP = {
7379
+ "deny": "full block — read, write and enumeration all refuse (tightens "
7380
+ "a write-only guard)",
7381
+ "confirm": "each governed operation pauses and files an approval request "
7382
+ "you answer from the Hub, phone, or `c3 override`",
7383
+ "allow": "the guard stops enforcing entirely (same as disable)",
7384
+ "default": "the shipped behaviour",
7385
+ }
7386
+
7387
+
7388
+ def _access_cmd_builtin_mode(args, glob: str, project_path: str) -> None:
7389
+ """`c3 access builtin mode <glob> <mode>` — granular builtin control.
7390
+
7391
+ `deny` and `default` never prompt (tightening / reset). `confirm` and
7392
+ `allow` weaken the guard, so they get the same typed-glob beat of
7393
+ friction as `builtin disable`, unless --yes.
7394
+ """
7395
+ from services import access_guard
7396
+
7397
+ mode = getattr(args, "mode", None)
7398
+ if mode in ("confirm", "allow") and not getattr(args, "yes", False):
7399
+ widening = ("STOP enforcing" if mode == "allow"
7400
+ else "PAUSE (not block) and ask you to approve")
7401
+ print(f"About to make the builtin guard on {glob} {widening}.")
7402
+ if mode == "allow":
7403
+ print(" While off, any agent with C3 tools can touch those paths.")
7404
+ else:
7405
+ print(" Each hit files an Override Request; one tap approves one "
7406
+ "single-use retry.")
7407
+ if glob.endswith("settings*.json") or ".claude" in glob:
7408
+ print(" This guards the file that configures the agent itself — "
7409
+ "hooks, permissions, model.")
7410
+ reply = input("Type the glob again to confirm: ").strip()
7411
+ if reply != glob:
7412
+ print("[abort] Not confirmed; nothing changed.")
7413
+ return
7414
+
7415
+ try:
7416
+ result = access_guard.set_builtin_mode(glob, mode)
7417
+ except ValueError as exc:
7418
+ print(f"[error] {exc}")
7419
+ return
7420
+
7421
+ _access_audit(f"builtin_mode_{result['mode']}", result["glob"],
7422
+ "builtin", "global", project_path)
7423
+ if not result["changed"]:
7424
+ print(f"[=] {result['glob']} — already {result['mode']}")
7425
+ return
7426
+ print(f"[OK] Builtin '{result['glob']}' mode = {result['mode']} "
7427
+ f"(global scope): {_BUILTIN_MODE_HELP[result['mode']]}.")
7428
+ if result["mode"] != "default":
7429
+ print(f" Reset with: c3 access builtin mode {result['glob']} default")
7430
+ if not result["attested"]:
7431
+ print(" [warn] keyring attestation could not be cleared; the "
7432
+ "default is enforced anyway (config entry removed).")
7433
+
7434
+
7362
7435
  def _access_cmd_add(args, project_path: str) -> None:
7363
7436
  from services import access_guard
7364
7437
 
@@ -751,15 +751,19 @@ def build_parser(version: str, parse_cli_ide_arg):
751
751
 
752
752
  ac_add = access_subs.add_parser("add", help="Add a rule to the project (or --global) scope")
753
753
  ac_add.add_argument("glob", help="POSIX glob (** crosses directories), e.g. 'secrets/**' or '*.pem'")
754
- ac_add.add_argument("--kind", choices=["deny", "read_only"], required=True,
755
- help="deny = no read/write/enumerate; read_only = no write")
754
+ ac_add.add_argument("--kind", choices=["deny", "read_only", "confirm"],
755
+ required=True,
756
+ help="deny = no read/write/enumerate; read_only = no "
757
+ "write; confirm = writes pause for your approval "
758
+ "(reads unaffected)")
756
759
  ac_add.add_argument("--global", dest="use_global", action="store_true",
757
760
  help="Store in the global scope (~/.c3) so every C3 project enforces it")
758
761
  ac_add.add_argument("--path", dest="project_path", default=".", help="Project directory (default: current)")
759
762
 
760
763
  ac_remove = access_subs.add_parser("remove", help="Remove a rule from the project (or --global) scope")
761
764
  ac_remove.add_argument("glob", help="The stored glob to remove (case-insensitive match)")
762
- ac_remove.add_argument("--kind", choices=["deny", "read_only"], required=True,
765
+ ac_remove.add_argument("--kind", choices=["deny", "read_only", "confirm"],
766
+ required=True,
763
767
  help="Which rule list the glob lives in")
764
768
  ac_remove.add_argument("--global", dest="use_global", action="store_true",
765
769
  help="Remove from the global scope (~/.c3)")
@@ -805,6 +809,21 @@ def build_parser(version: str, parse_cli_ide_arg):
805
809
  _p.add_argument("--yes", action="store_true",
806
810
  help="Skip the typed confirmation (scripts/CI)")
807
811
 
812
+ # Granular per-builtin mode (docs/confirm-guard.md §7): deny tightens a
813
+ # write-deny to a full deny, confirm turns the block into a pause that
814
+ # auto-files an approval request, allow switches it off (same two-key
815
+ # construction as disable), default restores the shipped behaviour.
816
+ bm = builtin_subs.add_parser(
817
+ "mode", help="Set a built-in guard to deny | confirm | allow | default")
818
+ bm.add_argument("glob", help="One of: **/.env*, **/.c3/**, **/.claude/settings*.json, **/.git/**")
819
+ bm.add_argument("mode", choices=["deny", "confirm", "allow", "default"],
820
+ help="deny = full block (tighten); confirm = pause for your "
821
+ "approval; allow = off (two-key); default = shipped behaviour")
822
+ bm.add_argument("--path", dest="project_path", default=".",
823
+ help="Project directory used for the audit log (default: current)")
824
+ bm.add_argument("--yes", action="store_true",
825
+ help="Skip the typed confirmation (scripts/CI)")
826
+
808
827
  # ── Mask Guard (v2.63.0, docs/mask-guard.md) ────────────────────────
809
828
  # Masking exposes a path but transforms what the agent sees. Rules are
810
829
  # human-only, like the rest of Access Guard.
@@ -221,6 +221,25 @@ def _override_allows(base: str, denial, *, tool: str, op: str, path: str,
221
221
  return None # fail closed: no grant, ordinary denial
222
222
 
223
223
 
224
+ def _confirm_request(base: str, denial, *, tool: str, op: str, path: str,
225
+ session_id: str) -> tuple:
226
+ """Auto-file an Override Request for a ``confirm`` denial (S8).
227
+
228
+ ``(request_id, note)`` — one of them is always ''. Lazy import, never
229
+ raises: a broken request store degrades to S8's "could not be filed"
230
+ tail, and the hold stands either way (docs/confirm-guard.md §3).
231
+ """
232
+ try:
233
+ from services import override_requests as orq # noqa: PLC0415 — lazy
234
+ row, reason = orq.auto_file(base, denial=denial, tool=tool, op=op,
235
+ path=path, session_id=session_id)
236
+ if row:
237
+ return str(row.get("id") or ""), ""
238
+ return "", reason
239
+ except Exception as exc:
240
+ return "", f"request store unavailable ({exc})"
241
+
242
+
224
243
  def _target(tool_input: dict) -> str:
225
244
  return str(
226
245
  tool_input.get("file_path")
@@ -348,6 +367,14 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
348
367
  if granted:
349
368
  return {"additionalContext": granted}
350
369
  _record(denial, tool, op, fp, base, session_id)
370
+ if denial.kind == "confirm":
371
+ # A confirm hold files its own request (grants were consulted
372
+ # above, so an approved retry lands in the granted branch).
373
+ rid, note = _confirm_request(base, denial, tool=tool, op=op,
374
+ path=fp, session_id=session_id)
375
+ return _deny(ag.refusal(denial, fp, op, surface="hook",
376
+ tool=tool, request_id=rid,
377
+ request_note=note))
351
378
  return _deny(ag.refusal(denial, fp, op, surface="hook", tool=tool))
352
379
  return None
353
380
 
@@ -338,6 +338,7 @@ _HUB_JS_FILES = [
338
338
  "hub_ui/components/hub_cred_audit.js",
339
339
  "hub_ui/components/hub_tokens.js",
340
340
  "hub_ui/components/hub_locks.js",
341
+ "hub_ui/components/hub_access.js",
341
342
  "hub_ui/components/hub_enforcement.js",
342
343
  "hub_ui/components/hub_ci.js",
343
344
  "hub_ui/components/drill_subprojects.js",
@@ -3088,6 +3089,212 @@ def api_projects_config_put():
3088
3089
  return jsonify({"saved": True, "section": section, "config": merged})
3089
3090
 
3090
3091
 
3092
+ # ── Override approvals (hub) — docs/override-requests.md P5 desktop parity ──
3093
+ # The desktop half of the request→grant pipeline. Everything here reads or
3094
+ # decides REQUESTS; grants are only ever minted inside override_requests.decide,
3095
+ # and the typed-confirmation checks in the route exist for the client's
3096
+ # benefit — decide() enforces them again regardless of what this route
3097
+ # believes (same two-places-compute-one-enforces rule as the mobile route).
3098
+
3099
+ _OVERRIDE_ROW_FIELDS = (
3100
+ "id", "project_path", "session_id", "created_at", "expires_at", "status",
3101
+ "layer", "rule", "rule_class", "scope", "tool", "op", "path", "refusal",
3102
+ "justification", "resolved_at", "decided_by", "decision_note",
3103
+ )
3104
+
3105
+
3106
+ def _hub_override_row(row: dict) -> dict:
3107
+ """One request row for the wire. Allowlisted, never the raw dict.
3108
+
3109
+ ``path_key`` stays server-side (grant-matching identity; the UI gets the
3110
+ human-readable ``path``). ``justification`` IS shipped — the UI renders it
3111
+ quoted under the untrusted-input label, never as markup.
3112
+ """
3113
+ out = {k: row.get(k) for k in _OVERRIDE_ROW_FIELDS}
3114
+ for extra in ("grant_id", "grant_mode", "muted"):
3115
+ if row.get(extra) is not None:
3116
+ out[extra] = row.get(extra)
3117
+ return out
3118
+
3119
+
3120
+ def _hub_override_audit(action: str, row: dict, *, confirmed: bool = False,
3121
+ detail_extra: dict | None = None) -> None:
3122
+ """Identifiers and rule globs only — NEVER the justification (untrusted
3123
+ agent text; the activity feed ships verbatim to every client). Mirrors
3124
+ the mobile route's audit shape with via='hub'. Failure-safe."""
3125
+ detail = {"kind": "override", "action": action,
3126
+ "request_id": row.get("id", ""),
3127
+ "session_id": row.get("session_id", ""),
3128
+ "rule": row.get("rule", ""),
3129
+ "rule_class": row.get("rule_class", ""),
3130
+ "tool": row.get("tool", ""), "op": row.get("op", ""),
3131
+ "via": "hub", "confirmed": bool(confirmed)}
3132
+ detail.update(detail_extra or {})
3133
+ project = row.get("project_path") or ""
3134
+ if not project:
3135
+ return
3136
+ try:
3137
+ ActivityLog(str(project)).log("access_action", dict(detail))
3138
+ except Exception:
3139
+ pass
3140
+ try:
3141
+ from services.edit_ledger import EditLedger
3142
+ EditLedger(str(project)).log_edit(
3143
+ file=f"override://{row.get('id', '')}",
3144
+ change_type=f"override_{action}",
3145
+ summary=(f"{action} override {row.get('id', '')} "
3146
+ f"({row.get('rule', '')}) via Hub"),
3147
+ tags=["override", action], detail=dict(detail))
3148
+ except Exception:
3149
+ pass
3150
+
3151
+
3152
+ @app.route("/api/hub/overrides", methods=["GET"])
3153
+ def api_hub_overrides():
3154
+ """Pending + recently-decided requests across every project, newest first.
3155
+
3156
+ The hub is this machine's own surface, so unlike the mobile gateway it
3157
+ does not filter rows to a token's project registry — the store is one file
3158
+ across every project on the box and the hub answers for all of them.
3159
+ Each row carries what the card needs to decide without a second fetch:
3160
+ whether the layer is still escalatable and which typed challenge (if any)
3161
+ an approval demands.
3162
+ """
3163
+ from services import override_policy as opol
3164
+ from services import override_requests as orq
3165
+ project_path = ""
3166
+ raw_project = (request.args.get("path") or "").strip()
3167
+ if raw_project:
3168
+ try:
3169
+ project_path = str(_resolve_project_path(raw_project))
3170
+ except ValueError as e:
3171
+ return jsonify({"error": str(e)}), 404
3172
+ status = (request.args.get("status") or "").strip().lower()
3173
+ try:
3174
+ limit = int(request.args.get("limit") or 50)
3175
+ except (TypeError, ValueError):
3176
+ limit = 50
3177
+ limit = max(1, min(limit, 200))
3178
+ try:
3179
+ rows = orq.list_requests(project_path=project_path, status=status,
3180
+ limit=limit)
3181
+ except Exception as exc:
3182
+ return jsonify({"error": str(exc)}), 500
3183
+
3184
+ out, policies = [], {}
3185
+ for row in rows:
3186
+ proj = str(row.get("project_path") or ".")
3187
+ if proj not in policies:
3188
+ try:
3189
+ policies[proj] = opol.resolve(proj)
3190
+ except Exception:
3191
+ policies[proj] = None
3192
+ policy = policies[proj]
3193
+ rule_class = str(row.get("rule_class") or "")
3194
+ typed = rule_class in opol.TYPED_CONFIRM_LAYERS
3195
+ entry = _hub_override_row(row)
3196
+ entry["needs_typed_confirm"] = typed
3197
+ entry["confirm_with"] = row.get("rule") if typed else ""
3198
+ entry["escalatable"] = bool(policy.escalatable(rule_class)) \
3199
+ if policy is not None else False
3200
+ entry["allow_session_grants"] = bool(policy.allow_session_grants) \
3201
+ if policy is not None else False
3202
+ entry["project_name"] = Path(proj).name
3203
+ out.append(entry)
3204
+ return jsonify({"requests": out, "count": len(out),
3205
+ "project": project_path, "status": status,
3206
+ "limit": limit})
3207
+
3208
+
3209
+ @app.route("/api/hub/overrides/<request_id>", methods=["POST"])
3210
+ def api_hub_override_decide(request_id):
3211
+ """Approve (minting a grant) or deny one request. decided_by='desktop'.
3212
+
3213
+ Body: {decision, confirm?, mode?, note?, mute?, ttl_s?, uses?}.
3214
+ 409 for a request that lapsed while the page was showing it — the card
3215
+ refreshes to the real status instead of silently minting a grant.
3216
+ """
3217
+ from services import override_policy as opol
3218
+ from services import override_requests as orq
3219
+ data = request.get_json(silent=True) or {}
3220
+ decision = str(data.get("decision") or "").strip().lower()
3221
+ if decision not in (orq.DECISION_APPROVE, orq.DECISION_DENY):
3222
+ return jsonify({"error": "decision must be 'approve' or 'deny'"}), 400
3223
+ mode = str(data.get("mode") or orq.MODE_ONCE).strip().lower()
3224
+ if mode not in orq.MODES:
3225
+ return jsonify({"error": f"mode must be one of: "
3226
+ f"{', '.join(orq.MODES)}"}), 400
3227
+
3228
+ row = orq.get(str(request_id))
3229
+ if row is None:
3230
+ return jsonify({"error": "unknown request"}), 404
3231
+ if row.get("status") != orq.STATUS_PENDING:
3232
+ return jsonify({"error": f"request is {row.get('status')}, not pending",
3233
+ "request": _hub_override_row(row)}), 409
3234
+
3235
+ rule_class = str(row.get("rule_class") or "")
3236
+ confirm = data.get("confirm")
3237
+ if (decision == orq.DECISION_APPROVE
3238
+ and rule_class in opol.TYPED_CONFIRM_LAYERS
3239
+ and confirm != row.get("rule")):
3240
+ return jsonify({
3241
+ "error": f"approving an {rule_class} request needs the rule "
3242
+ "glob retyped by hand",
3243
+ "needs_confirmation": True,
3244
+ "confirm_with": row.get("rule"),
3245
+ }), 400
3246
+
3247
+ try:
3248
+ ttl_s = int(data["ttl_s"]) if data.get("ttl_s") is not None else None
3249
+ uses = int(data["uses"]) if data.get("uses") is not None else None
3250
+ except (TypeError, ValueError):
3251
+ return jsonify({"error": "ttl_s and uses must be integers"}), 400
3252
+
3253
+ try:
3254
+ result = orq.decide(
3255
+ str(request_id), decision, uses=uses, ttl_s=ttl_s,
3256
+ note=str(data.get("note") or ""), decided_by="desktop",
3257
+ confirm=confirm, mode=mode, mute=bool(data.get("mute")))
3258
+ except orq.OverrideError as exc:
3259
+ _hub_override_audit(f"{decision}_refused", row)
3260
+ return jsonify({"error": str(exc)}), 400
3261
+ except Exception as exc:
3262
+ return jsonify({"error": str(exc)}), 500
3263
+
3264
+ _hub_override_audit(decision, result,
3265
+ confirmed=rule_class in opol.TYPED_CONFIRM_LAYERS,
3266
+ detail_extra={"mode": mode,
3267
+ "grant_id": result.get("grant_id", "")})
3268
+ return jsonify({"request": _hub_override_row(result),
3269
+ "decision": decision})
3270
+
3271
+
3272
+ @app.route("/api/hub/access", methods=["GET"])
3273
+ def api_hub_access():
3274
+ """Effective Access Guard rules + override policy for one project.
3275
+
3276
+ Read-only companion to the approvals list: the per-project mode matrix
3277
+ the tab renders under the pending cards. Rule MUTATION stays on the
3278
+ per-project server and the CLI — this route never writes.
3279
+ """
3280
+ from services import access_guard
3281
+ from services import override_policy as opol
3282
+ raw = (request.args.get("path") or "").strip()
3283
+ if not raw:
3284
+ return jsonify({"error": "path is required"}), 400
3285
+ try:
3286
+ resolved = _resolve_project_path(raw)
3287
+ except ValueError as e:
3288
+ return jsonify({"error": str(e)}), 404
3289
+ try:
3290
+ rules = access_guard.list_rules(str(resolved))
3291
+ policy = opol.resolve(str(resolved)).as_dict()
3292
+ except Exception as exc:
3293
+ return jsonify({"error": str(exc)}), 500
3294
+ return jsonify({"path": str(resolved), "rules": rules,
3295
+ "policy": policy})
3296
+
3297
+
3091
3298
  # ── Project management: tasks / milestones / notes (v2.45.0) ──────────────
3092
3299
  # Direct TaskStore per request (reload-per-op store — no runtime build needed
3093
3300
  # for mutations); every write audited to the target project's activity log.
@@ -44,7 +44,7 @@ function App() {
44
44
  if (cfg.projects_view === 'grid') setView('grid');
45
45
  if (cfg.sidebar_collapsed != null) setSidebarCollapsed(!!cfg.sidebar_collapsed);
46
46
  if (cfg.sidebar_group) setFilter(cfg.sidebar_group);
47
- if (['board', 'ci', 'creds', 'locks', 'enforce'].includes(cfg.main_view)) setMainView(cfg.main_view);
47
+ if (['board', 'ci', 'creds', 'tokens', 'locks', 'access', 'enforce'].includes(cfg.main_view)) setMainView(cfg.main_view);
48
48
  } catch { }
49
49
  try { const v = await api.get('/api/version'); setVersion(v.c3_version || ''); } catch { }
50
50
  }, []);
@@ -120,6 +120,8 @@ function App() {
120
120
  <HubTokens projects={projects} onOpenDrill={openDrill} />
121
121
  ) : mainView === 'locks' ? (
122
122
  <HubLocks projects={projects} onOpenDrill={openDrill} />
123
+ ) : mainView === 'access' ? (
124
+ <HubAccess projects={projects} />
123
125
  ) : mainView === 'enforce' ? (
124
126
  <HubEnforcement projects={projects} onOpenDrill={openDrill} />
125
127
  ) : (