code-context-control 2.91.0__tar.gz → 2.92.1__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 (452) hide show
  1. {code_context_control-2.91.0/code_context_control.egg-info → code_context_control-2.92.1}/PKG-INFO +1 -1
  2. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/_hook_utils.py +38 -0
  3. code_context_control-2.92.1/cli/_shell_writes.py +120 -0
  4. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/c3.py +257 -49
  5. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/oracle.html +2 -2
  6. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_c3_signal.py +5 -1
  7. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_dispatch.py +4 -0
  8. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_edit_ledger.py +86 -0
  9. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_edit_unlock.py +8 -0
  10. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_pretool_enforce.py +217 -1
  11. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_server.py +43 -1
  12. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/topbar.js +4 -1
  13. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/mcp_server.py +9 -1
  14. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/compress.py +2 -1
  15. {code_context_control-2.91.0 → code_context_control-2.92.1/code_context_control.egg-info}/PKG-INFO +1 -1
  16. {code_context_control-2.91.0 → code_context_control-2.92.1}/code_context_control.egg-info/SOURCES.txt +7 -0
  17. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/oracle_server.py +15 -2
  18. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/oracle_ui.html +31 -0
  19. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/local_session.py +72 -8
  20. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/chat/send.js +6 -1
  21. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/core.js +39 -0
  22. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/header.js +13 -1
  23. {code_context_control-2.91.0 → code_context_control-2.92.1}/pyproject.toml +1 -1
  24. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/claude_md.py +38 -0
  25. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/enforcement_policy.py +9 -3
  26. code_context_control-2.92.1/services/repo_shape.py +129 -0
  27. code_context_control-2.92.1/tests/test_failed_calls_do_not_unlock.py +124 -0
  28. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_codex_compat.py +2 -2
  29. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_dispatch.py +4 -1
  30. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_pretool_enforce.py +175 -0
  31. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_oracle_service_routes.py +56 -0
  32. code_context_control-2.92.1/tests/test_init_clear_preserves_user_content.py +236 -0
  33. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_session_bootstrap.py +69 -0
  34. code_context_control-2.92.1/tests/test_repo_shape.py +204 -0
  35. code_context_control-2.92.1/tests/test_shell_write_ledger.py +111 -0
  36. code_context_control-2.92.1/tests/test_shell_writes.py +84 -0
  37. {code_context_control-2.91.0 → code_context_control-2.92.1}/LICENSE +0 -0
  38. {code_context_control-2.91.0 → code_context_control-2.92.1}/README.md +0 -0
  39. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/__init__.py +0 -0
  40. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/commands/__init__.py +0 -0
  41. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/commands/common.py +0 -0
  42. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/commands/parser.py +0 -0
  43. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/docs.html +0 -0
  44. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/edits.html +0 -0
  45. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/access.html +0 -0
  46. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/bitbucket.html +0 -0
  47. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/credentials.html +0 -0
  48. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/getting-started.html +0 -0
  49. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/index.html +0 -0
  50. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/masking.html +0 -0
  51. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/shared.css +0 -0
  52. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/tools.html +0 -0
  53. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/guide/workflow.html +0 -0
  54. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_access_guard.py +0 -0
  55. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_artifact.py +0 -0
  56. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_auto_snapshot.py +0 -0
  57. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_c3read.py +0 -0
  58. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_filter.py +0 -0
  59. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_ghost_files.py +0 -0
  60. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_prompt_recall.py +0 -0
  61. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_read.py +0 -0
  62. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_session_stats.py +0 -0
  63. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hook_terse_advisor.py +0 -0
  64. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/app.js +0 -0
  65. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/add_project.js +0 -0
  66. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/config_editor.js +0 -0
  67. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/drill_artifacts.js +0 -0
  68. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/drill_health.js +0 -0
  69. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/drill_panel.js +0 -0
  70. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/drill_subprojects.js +0 -0
  71. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/drill_tasks.js +0 -0
  72. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/drill_views.js +0 -0
  73. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/global_search.js +0 -0
  74. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/hub_ci.js +0 -0
  75. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/hub_credentials.js +0 -0
  76. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/hub_enforcement.js +0 -0
  77. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/hub_locks.js +0 -0
  78. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/mcp_manager.js +0 -0
  79. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/modals.js +0 -0
  80. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/project_card.js +0 -0
  81. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/project_tree.js +0 -0
  82. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/session_drawer.js +0 -0
  83. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/settings_modal.js +0 -0
  84. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/sidebar.js +0 -0
  85. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/summary_bar.js +0 -0
  86. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/task_board.js +0 -0
  87. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/components/toasts.js +0 -0
  88. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui/state.js +0 -0
  89. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/hub_ui.html +0 -0
  90. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/mcp_proxy.py +0 -0
  91. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/progress.py +0 -0
  92. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/server.py +0 -0
  93. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/__init__.py +0 -0
  94. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/_grants.py +0 -0
  95. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/_helpers.py +0 -0
  96. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/agent.py +0 -0
  97. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/artifacts.py +0 -0
  98. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/bitbucket.py +0 -0
  99. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/ci.py +0 -0
  100. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/credentials.py +0 -0
  101. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/delegate.py +0 -0
  102. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/edit.py +0 -0
  103. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/edit_verify.py +0 -0
  104. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/edits.py +0 -0
  105. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/federate.py +0 -0
  106. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/filter.py +0 -0
  107. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/impact.py +0 -0
  108. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/jira.py +0 -0
  109. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/locks.py +0 -0
  110. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/memory.py +0 -0
  111. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/override.py +0 -0
  112. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/project.py +0 -0
  113. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/read.py +0 -0
  114. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/search.py +0 -0
  115. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/session.py +0 -0
  116. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/shell.py +0 -0
  117. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/status.py +0 -0
  118. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/tasks.py +0 -0
  119. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/tools/validate.py +0 -0
  120. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/api.js +0 -0
  121. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/app.js +0 -0
  122. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/access.js +0 -0
  123. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/bitbucket.js +0 -0
  124. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/chat.js +0 -0
  125. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/credentials.js +0 -0
  126. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/dashboard.js +0 -0
  127. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/edits.js +0 -0
  128. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/enforcement.js +0 -0
  129. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/instructions.js +0 -0
  130. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/jira.js +0 -0
  131. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/memory.js +0 -0
  132. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/sessions.js +0 -0
  133. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/settings.js +0 -0
  134. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/sidebar.js +0 -0
  135. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/components/tasks.js +0 -0
  136. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/icons.js +0 -0
  137. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/pm_shared.js +0 -0
  138. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/shared.js +0 -0
  139. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui/theme.js +0 -0
  140. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui.html +0 -0
  141. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui_legacy.html +0 -0
  142. {code_context_control-2.91.0 → code_context_control-2.92.1}/cli/ui_nano.html +0 -0
  143. {code_context_control-2.91.0 → code_context_control-2.92.1}/code_context_control.egg-info/dependency_links.txt +0 -0
  144. {code_context_control-2.91.0 → code_context_control-2.92.1}/code_context_control.egg-info/entry_points.txt +0 -0
  145. {code_context_control-2.91.0 → code_context_control-2.92.1}/code_context_control.egg-info/requires.txt +0 -0
  146. {code_context_control-2.91.0 → code_context_control-2.92.1}/code_context_control.egg-info/top_level.txt +0 -0
  147. {code_context_control-2.91.0 → code_context_control-2.92.1}/core/__init__.py +0 -0
  148. {code_context_control-2.91.0 → code_context_control-2.92.1}/core/config.py +0 -0
  149. {code_context_control-2.91.0 → code_context_control-2.92.1}/core/ide.py +0 -0
  150. {code_context_control-2.91.0 → code_context_control-2.92.1}/core/mcp_toml.py +0 -0
  151. {code_context_control-2.91.0 → code_context_control-2.92.1}/core/web_security.py +0 -0
  152. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/__init__.py +0 -0
  153. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/config.py +0 -0
  154. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/mcp_oracle.py +0 -0
  155. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/__init__.py +0 -0
  156. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/activity_reporter.py +0 -0
  157. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/api_auth.py +0 -0
  158. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/c3_bridge.py +0 -0
  159. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/chat_engine.py +0 -0
  160. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/chat_poll.py +0 -0
  161. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/chat_store.py +0 -0
  162. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/cross_memory.py +0 -0
  163. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/discovery_audit.py +0 -0
  164. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/federated_graph.py +0 -0
  165. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/health_checker.py +0 -0
  166. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/insight_engine.py +0 -0
  167. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/memory_reader.py +0 -0
  168. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/memory_writer.py +0 -0
  169. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/mobile_api.py +0 -0
  170. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/project_scanner.py +0 -0
  171. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/review_agent.py +0 -0
  172. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/tool_executor.py +0 -0
  173. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/services/tool_registry.py +0 -0
  174. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/activity.js +0 -0
  175. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/agents.js +0 -0
  176. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/app.js +0 -0
  177. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/busy.js +0 -0
  178. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/chat/conversations.js +0 -0
  179. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/chat/input.js +0 -0
  180. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/chat/markdown.js +0 -0
  181. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/chat/stream_renderer.js +0 -0
  182. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/chat/toolbar.js +0 -0
  183. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/crossgraph.js +0 -0
  184. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/insights.js +0 -0
  185. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/projects.js +0 -0
  186. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/qrcode.js +0 -0
  187. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/settings.js +0 -0
  188. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/suggestions.js +0 -0
  189. {code_context_control-2.91.0 → code_context_control-2.92.1}/oracle/ui/theme_tabs.js +0 -0
  190. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/__init__.py +0 -0
  191. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/access_guard.py +0 -0
  192. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/access_telemetry.py +0 -0
  193. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/activity_log.py +0 -0
  194. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/agent_base.py +0 -0
  195. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/agent_locks.py +0 -0
  196. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/agents.py +0 -0
  197. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/artifact_defs.py +0 -0
  198. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/artifact_store.py +0 -0
  199. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/auto_memory.py +0 -0
  200. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/background_service.py +0 -0
  201. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/bench/__init__.py +0 -0
  202. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/bench/external/__init__.py +0 -0
  203. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/bench/external/aider_polyglot.py +0 -0
  204. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/bench/external/swe_bench.py +0 -0
  205. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/benchmark_dashboard.py +0 -0
  206. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/bitbucket_client.py +0 -0
  207. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/bitbucket_credentials.py +0 -0
  208. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_act.py +0 -0
  209. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_cache.py +0 -0
  210. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_expr.py +0 -0
  211. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_failures.py +0 -0
  212. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_github.py +0 -0
  213. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_impact.py +0 -0
  214. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_intel.py +0 -0
  215. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_runner.py +0 -0
  216. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ci_workflow.py +0 -0
  217. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/circuit_breaker.py +0 -0
  218. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/compressor.py +0 -0
  219. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/context_snapshot.py +0 -0
  220. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/conversation_store.py +0 -0
  221. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/cred_telemetry.py +0 -0
  222. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/credential_store.py +0 -0
  223. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/doc_index.py +0 -0
  224. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/e2e_benchmark.py +0 -0
  225. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/e2e_evaluator.py +0 -0
  226. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/e2e_tasks.py +0 -0
  227. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/edit_ledger.py +0 -0
  228. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/embedding_index.py +0 -0
  229. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/error_reporting.py +0 -0
  230. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/file_memory.py +0 -0
  231. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/git_context.py +0 -0
  232. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/hub_service.py +0 -0
  233. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/indexer.py +0 -0
  234. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/jira_client.py +0 -0
  235. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/jira_cloud.py +0 -0
  236. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/jira_credentials.py +0 -0
  237. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/jira_data_center.py +0 -0
  238. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/jira_links.py +0 -0
  239. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/mask_activation.py +0 -0
  240. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/mask_mirror.py +0 -0
  241. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/mask_presets.py +0 -0
  242. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory.py +0 -0
  243. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory_consolidator.py +0 -0
  244. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory_distiller.py +0 -0
  245. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory_graph.py +0 -0
  246. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory_grounder.py +0 -0
  247. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory_queue.py +0 -0
  248. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/memory_scorer.py +0 -0
  249. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/metrics.py +0 -0
  250. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/notifications.py +0 -0
  251. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ollama_bridge.py +0 -0
  252. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ollama_client.py +0 -0
  253. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/ollama_credentials.py +0 -0
  254. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/oracle_service.py +0 -0
  255. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/output_filter.py +0 -0
  256. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/override_grants.py +0 -0
  257. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/override_policy.py +0 -0
  258. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/override_requests.py +0 -0
  259. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/override_wake.py +0 -0
  260. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/parser.py +0 -0
  261. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/project_manager.py +0 -0
  262. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/project_runtime.py +0 -0
  263. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/protocol.py +0 -0
  264. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/proxy_state.py +0 -0
  265. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/repo_map.py +0 -0
  266. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/retention.py +0 -0
  267. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/retrieval_broker.py +0 -0
  268. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/router.py +0 -0
  269. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/runtime.py +0 -0
  270. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/scanner.py +0 -0
  271. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/session_benchmark.py +0 -0
  272. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/session_manager.py +0 -0
  273. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/session_preloader.py +0 -0
  274. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/subprojects.py +0 -0
  275. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/task_store.py +0 -0
  276. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/telemetry.py +0 -0
  277. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/text_index.py +0 -0
  278. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/time_tracker.py +0 -0
  279. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/tool_classifier.py +0 -0
  280. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/transcript_index.py +0 -0
  281. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/validation_cache.py +0 -0
  282. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/vector_store.py +0 -0
  283. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/watcher.py +0 -0
  284. {code_context_control-2.91.0 → code_context_control-2.92.1}/services/win_subprocess.py +0 -0
  285. {code_context_control-2.91.0 → code_context_control-2.92.1}/setup.cfg +0 -0
  286. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_access_builtin_optout.py +0 -0
  287. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_access_guard.py +0 -0
  288. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_access_guard_meta.py +0 -0
  289. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_access_guard_shell_project.py +0 -0
  290. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_access_guard_surfaces.py +0 -0
  291. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_access_guard_wiring.py +0 -0
  292. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_activity_reporter.py +0 -0
  293. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_agent_locks.py +0 -0
  294. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_aider_polyglot.py +0 -0
  295. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_antigravity_transition.py +0 -0
  296. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_artifact_store.py +0 -0
  297. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_artifact_tool.py +0 -0
  298. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_background_service.py +0 -0
  299. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_bitbucket_cli_smoke.py +0 -0
  300. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_bitbucket_client.py +0 -0
  301. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_bitbucket_config_fallback.py +0 -0
  302. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_bitbucket_credentials.py +0 -0
  303. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_bitbucket_tool.py +0 -0
  304. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_c3_bridge_project_artifacts.py +0 -0
  305. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_c3_shell.py +0 -0
  306. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_chat_poll.py +0 -0
  307. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_act.py +0 -0
  308. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_cache.py +0 -0
  309. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_expr.py +0 -0
  310. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_impact.py +0 -0
  311. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_intel.py +0 -0
  312. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_runner.py +0 -0
  313. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ci_workflow.py +0 -0
  314. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_circuit_breaker.py +0 -0
  315. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_claude_md_merge.py +0 -0
  316. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_cli_smoke.py +0 -0
  317. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_compressor_large_file.py +0 -0
  318. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_cred_telemetry.py +0 -0
  319. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_credential_login_kind.py +0 -0
  320. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_credential_store.py +0 -0
  321. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_credential_ui_parity.py +0 -0
  322. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_credentials_routes.py +0 -0
  323. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_credentials_tool.py +0 -0
  324. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_creds_cli_smoke.py +0 -0
  325. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_delegate_cascade.py +0 -0
  326. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_delegate_version_probe.py +0 -0
  327. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_e2e_benchmark.py +0 -0
  328. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_edit_ledger_deadline.py +0 -0
  329. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_edit_ledger_hook.py +0 -0
  330. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_edit_locking.py +0 -0
  331. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_edit_normalization.py +0 -0
  332. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_edit_verify.py +0 -0
  333. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_embedding_index_deadlock.py +0 -0
  334. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_enforcement_flip.py +0 -0
  335. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_enforcement_policy.py +0 -0
  336. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_enforcement_routes.py +0 -0
  337. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_federated_graph.py +0 -0
  338. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_filter_backoff.py +0 -0
  339. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ghost_files.py +0 -0
  340. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ghost_generation.py +0 -0
  341. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_git_branch_awareness.py +0 -0
  342. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_access_guard.py +0 -0
  343. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_prompt_recall.py +0 -0
  344. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_smoke.py +0 -0
  345. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_state.py +0 -0
  346. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hook_utf8_stdio.py +0 -0
  347. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_credentials_route.py +0 -0
  348. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_credentials_routes_write.py +0 -0
  349. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_enforcement_routes.py +0 -0
  350. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_inspect_api.py +0 -0
  351. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_locks_routes.py +0 -0
  352. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_server_smoke.py +0 -0
  353. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_hub_subproject_links.py +0 -0
  354. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ide_workflow_adaptation.py +0 -0
  355. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_init_scan.py +0 -0
  356. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_install_mcp_entrypoint.py +0 -0
  357. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_cli_smoke.py +0 -0
  358. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_client.py +0 -0
  359. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_config_fallback.py +0 -0
  360. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_credentials.py +0 -0
  361. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_links.py +0 -0
  362. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_routes.py +0 -0
  363. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_jira_tool.py +0 -0
  364. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_lazy_store_init.py +0 -0
  365. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mask_guard.py +0 -0
  366. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mask_routes.py +0 -0
  367. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mask_surfaces.py +0 -0
  368. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mcp_host_guard.py +0 -0
  369. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mcp_memory_timeout.py +0 -0
  370. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mcp_server_smoke.py +0 -0
  371. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mcp_toml.py +0 -0
  372. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_memory_distiller.py +0 -0
  373. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_memory_graph_api.py +0 -0
  374. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_memory_queue.py +0 -0
  375. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_memory_system.py +0 -0
  376. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mobile_api.py +0 -0
  377. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mobile_extras.py +0 -0
  378. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mobile_override_routes.py +0 -0
  379. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_mobile_security_api.py +0 -0
  380. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_no_stale_model_pins.py +0 -0
  381. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_notification_dedup.py +0 -0
  382. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_notification_discipline.py +0 -0
  383. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_ollama_credentials.py +0 -0
  384. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_api_auth.py +0 -0
  385. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_apikey_api.py +0 -0
  386. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_c3_bridge.py +0 -0
  387. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_chat_engine.py +0 -0
  388. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_chat_store.py +0 -0
  389. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_discovery_api.py +0 -0
  390. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_discovery_audit.py +0 -0
  391. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_health_probe.py +0 -0
  392. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_local_auth.py +0 -0
  393. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_ollama_bridge.py +0 -0
  394. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_scanner_cache.py +0 -0
  395. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_security_fixes.py +0 -0
  396. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_subproject_awareness.py +0 -0
  397. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_oracle_ui_bundle.py +0 -0
  398. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_output_filter.py +0 -0
  399. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_override_grants.py +0 -0
  400. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_override_grants_mcp.py +0 -0
  401. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_override_requests.py +0 -0
  402. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_override_wake.py +0 -0
  403. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_permissions.py +0 -0
  404. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_pm_api.py +0 -0
  405. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_project_manager.py +0 -0
  406. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_project_manager_merge.py +0 -0
  407. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_project_tool.py +0 -0
  408. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_read_coercion.py +0 -0
  409. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_read_edit_parity.py +0 -0
  410. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_related_facts.py +0 -0
  411. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_repo_map.py +0 -0
  412. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_response_boilerplate.py +0 -0
  413. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_retention.py +0 -0
  414. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_review_digest.py +0 -0
  415. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_service_durability.py +0 -0
  416. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_session_benchmark.py +0 -0
  417. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_session_budget.py +0 -0
  418. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_shell_creds.py +0 -0
  419. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_shell_robustness.py +0 -0
  420. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_subproject_exclusion.py +0 -0
  421. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_subproject_federation.py +0 -0
  422. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_subprojects.py +0 -0
  423. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_swe_bench.py +0 -0
  424. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_task_store.py +0 -0
  425. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_task_tool.py +0 -0
  426. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_time_tracker.py +0 -0
  427. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_token_telemetry.py +0 -0
  428. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_tool_registry.py +0 -0
  429. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_upgrade_and_version.py +0 -0
  430. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_validate.py +0 -0
  431. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_vault_write_guard.py +0 -0
  432. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_version_sync.py +0 -0
  433. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_web_security.py +0 -0
  434. {code_context_control-2.91.0 → code_context_control-2.92.1}/tests/test_windows_reliability.py +0 -0
  435. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/__init__.py +0 -0
  436. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/backend.py +0 -0
  437. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/main.py +0 -0
  438. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/__init__.py +0 -0
  439. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/benchmark_view.py +0 -0
  440. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/claudemd_view.py +0 -0
  441. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/compress_view.py +0 -0
  442. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/index_view.py +0 -0
  443. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/init_view.py +0 -0
  444. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/mcp_view.py +0 -0
  445. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/optimize_view.py +0 -0
  446. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/pipe_view.py +0 -0
  447. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/projects_view.py +0 -0
  448. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/search_view.py +0 -0
  449. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/session_view.py +0 -0
  450. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/stats.py +0 -0
  451. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/screens/ui_view.py +0 -0
  452. {code_context_control-2.91.0 → code_context_control-2.92.1}/tui/theme.tcss +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.91.0
3
+ Version: 2.92.1
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
@@ -7,6 +7,7 @@ All hook reads/writes of enforcement state MUST go through this module.
7
7
  """
8
8
  import json
9
9
  import os
10
+ import re
10
11
  import sys
11
12
  import traceback
12
13
  from datetime import datetime, timezone
@@ -440,6 +441,43 @@ def get_tool_output(data: dict) -> tuple:
440
441
  return resp if isinstance(resp, str) else "", False
441
442
 
442
443
 
444
+ # A c3 tool that failed did not read, search or edit anything, so its
445
+ # completion is not evidence that c3 was used (field report 2026-08-22,
446
+ # ISSUE-3: c3_compress on a missing path -> "Error: File not found" -> the
447
+ # sticky unlock and the signal both fired -> native Write allowed). Tools
448
+ # report failure as a leading "Error" / "[<tool>:error]" line, the masked-path
449
+ # refusal tag, or an MCP isError flag.
450
+ _FAILED_RESPONSE_RE = re.compile(
451
+ r"^\s*(?:Error\b|\[[a-z0-9_\-]+:error\]|\[c3-mask:unsupported\])", re.IGNORECASE)
452
+
453
+
454
+ def response_text_failed(text) -> bool:
455
+ """True when a c3 tool's response text reads as a failure."""
456
+ return bool(_FAILED_RESPONSE_RE.match(str(text or "")))
457
+
458
+
459
+ def tool_response_failed(data: dict) -> bool:
460
+ """True when the PostToolUse payload carries a failed c3 tool response.
461
+
462
+ Handles Claude Code's plain string, an MCP-style dict with ``isError`` /
463
+ ``content`` parts, a bare list of parts, and Gemini's ``llmContent``.
464
+ """
465
+ resp = data.get("tool_response")
466
+ if isinstance(resp, dict):
467
+ if resp.get("isError") is True or resp.get("is_error") is True:
468
+ return True
469
+ content = resp.get("content")
470
+ if isinstance(content, list):
471
+ text = "\n".join((p.get("text") or "") for p in content if isinstance(p, dict))
472
+ return response_text_failed(text)
473
+ text, _ = get_tool_output(data)
474
+ return response_text_failed(text)
475
+ if isinstance(resp, list):
476
+ text = "\n".join((p.get("text") or "") if isinstance(p, dict) else str(p) for p in resp)
477
+ return response_text_failed(text)
478
+ return response_text_failed(resp if isinstance(resp, str) else "")
479
+
480
+
443
481
  def get_tool_input_path(data: dict) -> str:
444
482
  """Extract file path from tool_input, handling Claude (file_path),
445
483
  Gemini (path), and NotebookEdit (notebook_path)."""
@@ -0,0 +1,120 @@
1
+ """Best-effort extraction of the files a shell command writes.
2
+
3
+ Field report 2026-08-22, ISSUE-1's buried finding: ``Bash`` sits in the
4
+ PreToolUse matcher, but tool discipline never looked at what a shell
5
+ command does to files. An inline ``python -c`` write, ``cat > f <<EOF`` and
6
+ ``sed -i`` were never nudged toward c3_edit and never reached the ledger,
7
+ so every agent that met a blocked ``Write`` simply went round it. This
8
+ module is the one place that answers "which files does this command
9
+ probably write?" for both the PreToolUse nudge (hook_pretool_enforce) and
10
+ the after-the-fact ledger entry (hook_edit_ledger).
11
+
12
+ Deliberately conservative, like the access guard's shell scan: a missed
13
+ target costs one missing advisory line and one missing ledger row; a false
14
+ target costs a misleading hint, so tokens that are shell syntax, streams
15
+ (``/dev/null``, ``&1``) or pip-style ``>=`` version specs are skipped.
16
+ Paths resolve against the directory the command runs in, following ``cd``.
17
+ Never raises.
18
+ """
19
+ from __future__ import annotations
20
+
21
+ import os
22
+ import re
23
+ from pathlib import Path
24
+
25
+ _SEGMENT_SPLIT = re.compile(r"&&|\|\||[;\n]")
26
+ _CD_RE = re.compile(r"""^\s*cd\s+(?:/d\s+)?(?P<dir>"[^"]+"|'[^']+'|\S+)\s*$""", re.IGNORECASE)
27
+ # `>` / `>>` / `>|` preceded by whitespace or line start (so `foo>=3.0` is not a redirect).
28
+ _REDIRECT_RE = re.compile(r"""(?:^|\s)\d?>{1,2}\|?\s*(?P<t>"[^"]+"|'[^']+'|\S+)""")
29
+ _TEE_RE = re.compile(r"""(?:^|\|)\s*tee\s+(?:-[a-zA-Z]+\s+)*(?P<t>"[^"]+"|'[^']+'|\S+)""")
30
+ _SED_INPLACE_RE = re.compile(r"""(?:^|\s)sed\s+(?P<rest>.*)$""")
31
+ _PY_OPEN_RE = re.compile(r"""open\(\s*(?P<q>['"])(?P<t>[^'"]+)(?P=q)\s*,\s*['"][wax]""")
32
+ _PY_WRITE_TEXT_RE = re.compile(r"""Path\(\s*(?P<q>['"])(?P<t>[^'"]+)(?P=q)\s*\)\s*\.write_(?:text|bytes)\(""")
33
+ _FILE_CMDS = {"cp", "mv", "touch", "rm", "install"}
34
+ _STREAMS = {"/dev/null", "/dev/stdout", "/dev/stderr", "nul", "&1", "&2", "-"}
35
+ _SYNTAX = set("$`(){}|<>*?")
36
+ MAX_TARGETS = 20
37
+
38
+
39
+ def _clean(tok: str) -> str:
40
+ return tok.strip().strip("\"'`;,")
41
+
42
+
43
+ def _skip(tok: str) -> bool:
44
+ if not tok or tok.startswith("-") or tok.startswith("=") or tok in _STREAMS:
45
+ return True
46
+ if tok.lower() in _STREAMS or tok.startswith("&"):
47
+ return True
48
+ return bool(_SYNTAX & set(tok))
49
+
50
+
51
+ def _segment_targets(segment: str) -> list[str]:
52
+ out: list[str] = []
53
+ for m in _REDIRECT_RE.finditer(segment):
54
+ out.append(_clean(m.group("t")))
55
+ for m in _TEE_RE.finditer(segment):
56
+ out.append(_clean(m.group("t")))
57
+ for m in _PY_OPEN_RE.finditer(segment):
58
+ out.append(m.group("t"))
59
+ for m in _PY_WRITE_TEXT_RE.finditer(segment):
60
+ out.append(m.group("t"))
61
+ words = [w for w in re.split(r"\s+", segment.strip()) if w]
62
+ if words:
63
+ head = words[0].rsplit("/", 1)[-1].lower()
64
+ args = [_clean(w) for w in words[1:] if not w.startswith("-")]
65
+ if head in ("cp", "mv", "install") and len(args) >= 2:
66
+ out.append(args[-1])
67
+ elif head in ("touch", "rm") and args:
68
+ out.extend(args)
69
+ elif head == "sed":
70
+ flags = [w for w in words[1:] if w.startswith("-")]
71
+ if any(f.startswith("-i") or f == "--in-place" for f in flags):
72
+ # last non-flag, non-script argument(s): the files
73
+ files = [a for a in args if not (a.startswith("s/") or a.startswith("s|") or "/" in a and a.count("/") >= 2 and a.startswith("s"))]
74
+ out.extend(files[-2:] if files else [])
75
+ return [t for t in out if not _skip(t)]
76
+
77
+
78
+ def _cd_target(segment: str, cwd: str) -> str | None:
79
+ m = _CD_RE.match(segment)
80
+ if not m:
81
+ return None
82
+ target = m.group("dir").strip("\"'")
83
+ try:
84
+ return target if os.path.isabs(target) else os.path.normpath(os.path.join(cwd, target))
85
+ except (OSError, ValueError):
86
+ return None
87
+
88
+
89
+ def shell_write_targets(cmd: str, cwd: str) -> list[str]:
90
+ """Absolute paths the command probably writes, in order, de-duplicated.
91
+
92
+ ``cwd`` is the directory the command runs in (the project root for
93
+ Claude Code hooks). Relative targets resolve against it, and a ``cd``
94
+ segment moves it for the segments that follow.
95
+ """
96
+ found: list[str] = []
97
+ seen: set[str] = set()
98
+ here = cwd
99
+ try:
100
+ for segment in _SEGMENT_SPLIT.split(cmd or ""):
101
+ for tok in _segment_targets(segment):
102
+ if re.match(r"^/[a-z]/", tok): # MSYS /c/foo -> C:/foo
103
+ tok = f"{tok[1]}:{tok[2:]}"
104
+ try:
105
+ p = Path(tok) if os.path.isabs(tok) else Path(here) / tok
106
+ key = os.path.normcase(os.path.normpath(str(p)))
107
+ except (OSError, ValueError):
108
+ continue
109
+ if key in seen:
110
+ continue
111
+ seen.add(key)
112
+ found.append(str(p))
113
+ if len(found) >= MAX_TARGETS:
114
+ return found
115
+ moved = _cd_target(segment, here)
116
+ if moved is not None:
117
+ here = moved
118
+ except Exception:
119
+ return found
120
+ return found
@@ -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.91.0"
95
+ __version__ = "2.92.1"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -845,7 +845,8 @@ def _prompt_memory_llm(project_path: str) -> None:
845
845
  + ("cloud + local fallback." if section["cloud_enabled"] else "local only (private)."))
846
846
 
847
847
 
848
- def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "direct") -> tuple[str, bool]:
848
+ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "direct",
849
+ shape=None) -> tuple[str, bool]:
849
850
  """Run guided post-init setup steps for Git and MCP."""
850
851
  chosen_ide = _select_init_ide(ide_name or "auto")
851
852
  save_config({"ide": chosen_ide}, project_path)
@@ -916,7 +917,7 @@ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "di
916
917
  )
917
918
  include_wildcard = bool(wildcard_choice and wildcard_choice.startswith("Yes"))
918
919
 
919
- chosen_enforcement = _prompt_enforcement(chosen_tier)
920
+ chosen_enforcement = _prompt_enforcement(chosen_tier, shape=shape)
920
921
 
921
922
  _run_install_mcp(project_path, chosen_ide, mcp_mode=mcp_mode,
922
923
  permissions=chosen_tier, include_mcp_wildcard=include_wildcard,
@@ -924,9 +925,70 @@ def _prompt_init_steps(project_path: str, ide_name: str, default_mode: str = "di
924
925
  return chosen_ide, True
925
926
 
926
927
 
927
- def _prompt_enforcement(chosen_tier: str | None) -> str | None:
928
+ def _assess_repo_shape(project_path: str):
929
+ """Measure the project (services.repo_shape). None when it cannot be measured."""
930
+ try:
931
+ from services import repo_shape
932
+ return repo_shape.assess(project_path)
933
+ except Exception:
934
+ _log.debug("repo shape assessment failed", exc_info=True)
935
+ return None
936
+
937
+
938
+ def _apply_repo_shape_default(project_path: str, explicit_enforcement: str | None = None,
939
+ shape=None) -> None:
940
+ """Say what kind of project this is, and default a prose one to ``advisory``.
941
+
942
+ Field report 2026-08-22: a 636-file project, ~95% Markdown and .docx,
943
+ where every symbol-aware C3 tool had nothing to act on and strict
944
+ discipline was paid on every turn until C3 was uninstalled. The shape
945
+ is printed for every project; the default is written only for the prose
946
+ kind, only over a tier-derived or unset mode (never over ``c3 enforce``
947
+ or ``--enforcement``), with provenance ``set_by: repo-shape`` so
948
+ ``c3 enforce`` shows where it came from, and with the way back printed.
949
+ """
950
+ try:
951
+ from services import enforcement_policy as ep
952
+ from services import repo_shape
953
+ except Exception:
954
+ return
955
+ if shape is None:
956
+ shape = _assess_repo_shape(project_path)
957
+ if shape is None or shape.kind == repo_shape.KIND_EMPTY:
958
+ return
959
+ print(f"\n Repo shape: {shape.describe()}")
960
+ mode = repo_shape.recommended_mode(shape)
961
+ if not mode:
962
+ return
963
+ if explicit_enforcement:
964
+ print(f" Prose-heavy, but --enforcement {explicit_enforcement} was given — leaving it as set.")
965
+ return
966
+ current = ep.resolve(project_path)
967
+ if current.set_by == ep.SET_BY_USER:
968
+ print(f" Prose-heavy; tool discipline stays '{current.mode}' (your choice).")
969
+ return
970
+ if current.mode == mode:
971
+ print(f" Prose-heavy; tool discipline is already '{mode}'.")
972
+ return
973
+ try:
974
+ result = ep.set_mode(mode, project_path, set_by=ep.SET_BY_SHAPE, scope="project")
975
+ except ValueError:
976
+ return
977
+ if result.get("deferred"):
978
+ return
979
+ print(" [!] This is a documentation project: C3's symbol-aware tools (compress/read/impact/")
980
+ print(f" validate/CI) have little to act on here, so tool discipline is set to '{mode}' —")
981
+ print(" native Edit/Write are allowed with a nudge and the edit ledger still records them.")
982
+ print(" `c3 enforce strict` restores the hard block; `c3 enforce` shows the setting.")
983
+
984
+
985
+ def _prompt_enforcement(chosen_tier: str | None, shape=None) -> str | None:
928
986
  """Step 5/5 — tool discipline. Returns an explicit mode, or None to derive.
929
987
 
988
+ ``shape`` (services.repo_shape.RepoShape) moves the suggested default to
989
+ ``advisory`` for a documentation project and says why, so the user is
990
+ not asked to guess what C3's symbol tools will do with 600 Markdown files.
991
+
930
992
  Asked separately from the permission tier because it answers a genuinely
931
993
  different question: the tier controls what the IDE will let the agent call,
932
994
  this controls how hard C3's own hook pushes it toward c3_* tools. Users hit
@@ -938,8 +1000,18 @@ def _prompt_enforcement(chosen_tier: str | None) -> str | None:
938
1000
  return None
939
1001
 
940
1002
  default_mode = ep.derive_from_tier(chosen_tier) if chosen_tier else ep.MODE_ADVISORY
1003
+ suggested_by = "Your permission tier suggests"
1004
+ try:
1005
+ from services import repo_shape
1006
+ shape_mode = repo_shape.recommended_mode(shape) if shape is not None else None
1007
+ except Exception:
1008
+ shape_mode = None
1009
+ if shape_mode:
1010
+ default_mode = shape_mode
1011
+ suggested_by = ("This is a documentation project — C3's symbol tools have "
1012
+ "little to act on here. Suggested")
941
1013
  print()
942
- print(f" (Your permission tier suggests: {default_mode})")
1014
+ print(f" ({suggested_by}: {default_mode})")
943
1015
  choice = _prompt_choice(
944
1016
  "Step 5/5 — Tool discipline: how hard should C3 push toward c3_* tools?",
945
1017
  [
@@ -1085,6 +1157,7 @@ def cmd_init(args):
1085
1157
  if not c3_dir.exists() or not (c3_dir / "config.json").exists():
1086
1158
  print_header(f"Initializing C3 for: {project_path}")
1087
1159
  _do_init(project_path, ide_name=requested_ide, no_embed=no_embed)
1160
+ shape = _assess_repo_shape(project_path)
1088
1161
  try:
1089
1162
  from services.project_manager import ProjectManager
1090
1163
  ProjectManager().add_project(project_path)
@@ -1101,7 +1174,11 @@ def cmd_init(args):
1101
1174
  enforcement=getattr(args, "enforcement", None),
1102
1175
  )
1103
1176
  else:
1104
- _prompt_init_steps(project_path, requested_ide, default_mode=getattr(args, "mcp_mode", "direct"))
1177
+ _prompt_init_steps(project_path, requested_ide,
1178
+ default_mode=getattr(args, "mcp_mode", "direct"), shape=shape)
1179
+ _apply_repo_shape_default(project_path,
1180
+ explicit_enforcement=getattr(args, "enforcement", None),
1181
+ shape=shape)
1105
1182
  # Detect Codex CLI availability
1106
1183
  try:
1107
1184
  from cli.tools.delegate import check_codex
@@ -1285,11 +1362,7 @@ def cmd_init(args):
1285
1362
  if c3_dir.exists():
1286
1363
  shutil.rmtree(c3_dir)
1287
1364
  print(" Deleted .c3/")
1288
- for filename, _ in _instruction_documents_for_project():
1289
- p = Path(project_path) / filename
1290
- if p.exists():
1291
- p.unlink()
1292
- print(f" Deleted {filename}")
1365
+ _remove_c3_instruction_docs(project_path)
1293
1366
  print("\n[OK] C3 project files removed.")
1294
1367
  return
1295
1368
 
@@ -1361,9 +1434,10 @@ def cmd_init(args):
1361
1434
 
1362
1435
  elif selected.startswith("Wipe"):
1363
1436
  confirm = input(
1364
- "\n WARNING: This will permanently delete .c3/ and all project\n"
1365
- " instruction files (CLAUDE.md, GEMINI.md, AGENTS.md), and remove\n"
1366
- " C3 MCP configurations from your IDE. Type 'yes' to confirm: "
1437
+ "\n WARNING: This will permanently delete .c3/, remove C3's managed\n"
1438
+ " block from CLAUDE.md / AGENTS.md / GEMINI.md (a file is deleted only\n"
1439
+ " when nothing else is in it), and remove C3 MCP configurations from\n"
1440
+ " your IDE. Type 'yes' to confirm: "
1367
1441
  ).strip().lower()
1368
1442
  if confirm != "yes":
1369
1443
  print(" Wipe cancelled.")
@@ -1375,11 +1449,7 @@ def cmd_init(args):
1375
1449
  shutil.rmtree(c3_dir)
1376
1450
  print(" Deleted .c3/")
1377
1451
 
1378
- for filename, _ in _instruction_documents_for_project():
1379
- p = Path(project_path) / filename
1380
- if p.exists():
1381
- p.unlink()
1382
- print(f" Deleted {filename}")
1452
+ _remove_c3_instruction_docs(project_path)
1383
1453
 
1384
1454
  print("\n[OK] C3 project files removed.")
1385
1455
 
@@ -4555,6 +4625,115 @@ def _ensure_global_session_fallbacks(server_script: str, c3_mcp_exe: str | None
4555
4625
  print(f"Warning: Could not update {antigravity_path} (global fallback skipped)")
4556
4626
 
4557
4627
 
4628
+ # Every hook script C3 has ever registered in a settings file — the v2.42+
4629
+ # dispatcher plus the pre-v2.42 per-hook scripts — so uninstall recognises an
4630
+ # entry written by any C3 version. A user hook is anything not naming one.
4631
+ _C3_HOOK_SCRIPTS = (
4632
+ "hook_dispatch.py",
4633
+ "hook_access_guard.py", "hook_artifact.py", "hook_auto_snapshot.py",
4634
+ "hook_c3_signal.py", "hook_c3read.py", "hook_edit_ledger.py",
4635
+ "hook_edit_unlock.py", "hook_filter.py", "hook_ghost_files.py",
4636
+ "hook_pretool_enforce.py", "hook_prompt_recall.py", "hook_read.py",
4637
+ "hook_session_stats.py", "hook_terse_advisor.py",
4638
+ )
4639
+
4640
+
4641
+ def _is_c3_hook_command(command) -> bool:
4642
+ return any(script in str(command or "") for script in _C3_HOOK_SCRIPTS)
4643
+
4644
+
4645
+ def _is_c3_permission(rule) -> bool:
4646
+ """``mcp__c3__<tool>``, ``mcp__c3__*``, or the bare ``mcp__c3`` server grant."""
4647
+ r = str(rule or "").strip()
4648
+ return r == "mcp__c3" or r.startswith("mcp__c3__")
4649
+
4650
+
4651
+ def _c3_references_in_settings(settings: dict) -> list:
4652
+ """Every C3-owned entry present in a settings dict: hook commands (named
4653
+ by event) and permission rules. Used to decide whether there is anything
4654
+ to remove and, after writing, to check that it was actually removed."""
4655
+ refs: list = []
4656
+ hooks = settings.get("hooks")
4657
+ if isinstance(hooks, dict):
4658
+ for event, groups in hooks.items():
4659
+ for group in groups or []:
4660
+ if not isinstance(group, dict):
4661
+ continue
4662
+ for hk in group.get("hooks") or []:
4663
+ if isinstance(hk, dict) and _is_c3_hook_command(hk.get("command")):
4664
+ refs.append(f"hooks.{event}")
4665
+ perms = settings.get("permissions")
4666
+ if isinstance(perms, dict):
4667
+ for key in ("allow", "deny", "ask"):
4668
+ for rule in perms.get(key) or []:
4669
+ if _is_c3_permission(rule):
4670
+ refs.append(f"permissions.{key}:{rule}")
4671
+ if "c3" in (settings.get("enabledMcpjsonServers") or []):
4672
+ refs.append("enabledMcpjsonServers:c3")
4673
+ return refs
4674
+
4675
+
4676
+ def _strip_c3_from_settings(settings: dict) -> dict:
4677
+ """Remove every C3-owned entry from a Claude Code settings dict (in place,
4678
+ and returned). Touches ONLY what C3 wrote: hook entries whose command runs
4679
+ a C3 hook script — any event, any matcher; the previous cleanup looked at
4680
+ three PostToolUse matchers from the pre-v2.42 layout and nothing else, so
4681
+ PreToolUse/Stop/UserPromptSubmit and the whole ``permissions.allow`` list
4682
+ survived an "uninstall" — plus ``mcp__c3__*`` permission rules and the
4683
+ ``c3`` MCP-server enablement. User hooks, user permission rules and every
4684
+ other key are left exactly as found; containers emptied by the removal
4685
+ are dropped so a file C3 created alone ends up empty (and the caller
4686
+ deletes it) rather than as ``{"hooks": {}}``.
4687
+ """
4688
+ hooks = settings.get("hooks")
4689
+ if isinstance(hooks, dict):
4690
+ for event in list(hooks.keys()):
4691
+ kept_groups = []
4692
+ for group in hooks.get(event) or []:
4693
+ if not isinstance(group, dict):
4694
+ kept_groups.append(group)
4695
+ continue
4696
+ entries = group.get("hooks") or []
4697
+ if not any(isinstance(hk, dict) and _is_c3_hook_command(hk.get("command"))
4698
+ for hk in entries):
4699
+ kept_groups.append(group) # not ours — untouched
4700
+ continue
4701
+ kept = [hk for hk in entries
4702
+ if not (isinstance(hk, dict) and _is_c3_hook_command(hk.get("command")))]
4703
+ if kept:
4704
+ group = dict(group)
4705
+ group["hooks"] = kept
4706
+ kept_groups.append(group)
4707
+ if kept_groups:
4708
+ hooks[event] = kept_groups
4709
+ else:
4710
+ del hooks[event]
4711
+ if not hooks:
4712
+ del settings["hooks"]
4713
+
4714
+ perms = settings.get("permissions")
4715
+ if isinstance(perms, dict):
4716
+ for key in ("allow", "deny", "ask"):
4717
+ rules = perms.get(key)
4718
+ if isinstance(rules, list) and any(_is_c3_permission(r) for r in rules):
4719
+ kept_rules = [r for r in rules if not _is_c3_permission(r)]
4720
+ if kept_rules:
4721
+ perms[key] = kept_rules
4722
+ else:
4723
+ del perms[key]
4724
+ if not perms:
4725
+ del settings["permissions"]
4726
+
4727
+ enabled = settings.get("enabledMcpjsonServers")
4728
+ if isinstance(enabled, list) and "c3" in enabled:
4729
+ enabled = [s for s in enabled if s != "c3"]
4730
+ if enabled:
4731
+ settings["enabledMcpjsonServers"] = enabled
4732
+ else:
4733
+ del settings["enabledMcpjsonServers"]
4734
+ return settings
4735
+
4736
+
4558
4737
  def _uninstall_mcp_all(project_path: str, include_global: bool = True):
4559
4738
  """Remove C3 MCP server configurations from all supported IDEs.
4560
4739
 
@@ -4658,37 +4837,28 @@ def _uninstall_mcp_all(project_path: str, include_global: bool = True):
4658
4837
  with open(settings_path, 'r', encoding="utf-8") as f:
4659
4838
  settings = json.load(f)
4660
4839
 
4661
- # Remove hooks
4662
- hooks = settings.get("hooks", {}).get("PostToolUse", [])
4663
- new_hooks = []
4664
- c3_hook_files = {"hook_filter.py", "hook_read.py", "hook_c3read.py", "hook_dispatch.py"}
4665
- for h in hooks:
4666
- if h.get("matcher") in ("Bash", "Read", "mcp__c3__c3_read"):
4667
- h["hooks"] = [hook for hook in h.get("hooks", [])
4668
- if not any(f in hook.get("command", "") for f in c3_hook_files)]
4669
- if h["hooks"]:
4670
- new_hooks.append(h)
4671
- else:
4672
- new_hooks.append(h)
4673
-
4674
- if new_hooks:
4675
- settings["hooks"]["PostToolUse"] = new_hooks
4676
- elif "hooks" in settings and "PostToolUse" in settings["hooks"]:
4677
- del settings["hooks"]["PostToolUse"]
4678
- if not settings["hooks"]:
4679
- del settings["hooks"]
4680
-
4681
- # Remove enabled server
4682
- if "enabledMcpjsonServers" in settings and "c3" in settings["enabledMcpjsonServers"]:
4683
- settings["enabledMcpjsonServers"].remove("c3")
4684
-
4685
- if not settings:
4686
- settings_path.unlink()
4687
- print(f" Deleted empty {settings_path}")
4840
+ before = _c3_references_in_settings(settings)
4841
+ if not before:
4842
+ print(f" No C3 entries in {settings_path}")
4688
4843
  else:
4689
- with open(settings_path, 'w', encoding="utf-8") as f:
4690
- json.dump(settings, f, indent=2)
4691
- print(f" Removed C3 hooks/settings from {settings_path}")
4844
+ settings = _strip_c3_from_settings(settings)
4845
+ if not settings:
4846
+ settings_path.unlink()
4847
+ print(f" Deleted empty {settings_path}")
4848
+ else:
4849
+ with open(settings_path, 'w', encoding="utf-8") as f:
4850
+ json.dump(settings, f, indent=2)
4851
+ # Postcondition: re-read what is on disk and report
4852
+ # what is true, not what was attempted.
4853
+ with open(settings_path, 'r', encoding="utf-8") as f:
4854
+ remaining = _c3_references_in_settings(json.load(f))
4855
+ if remaining:
4856
+ shown = ", ".join(remaining[:5]) + (" ..." if len(remaining) > 5 else "")
4857
+ print(f" [!] C3 entries remain in {settings_path} "
4858
+ f"({len(remaining)}): {shown}")
4859
+ else:
4860
+ print(f" Removed C3 hooks/settings from {settings_path} "
4861
+ f"({len(before)} entries)")
4692
4862
  except Exception as e:
4693
4863
  print(f" Warning: Could not update {settings_path}: {e}")
4694
4864
 
@@ -4872,6 +5042,44 @@ def _instruction_documents_for_project() -> list[tuple[str, str]]:
4872
5042
  ]
4873
5043
 
4874
5044
 
5045
+ def _remove_c3_instruction_docs(project_path: str) -> None:
5046
+ """Take C3's managed block OUT of every instruction doc it ever wrote.
5047
+
5048
+ Uninstall counterpart of ``_sync_project_instruction_docs``. Before
5049
+ v2.92 this was a bare ``unlink()`` of CLAUDE.md / AGENTS.md / GEMINI.md —
5050
+ which, in a project whose CLAUDE.md also carried another tool's managed
5051
+ block (``<!-- YEP:BEGIN -->``) or the user's own notes, destroyed content
5052
+ C3 never owned, with no warning and no way back unless git had it.
5053
+ Same rule every regeneration path already follows: C3 owns its slice,
5054
+ everything outside the markers is preserved. A file is deleted only when
5055
+ the block was all there was.
5056
+ """
5057
+ from services.claude_md import strip_c3_block
5058
+
5059
+ for filename, _ in _instruction_documents_for_project():
5060
+ p = Path(project_path) / filename
5061
+ if not p.exists():
5062
+ continue
5063
+ try:
5064
+ existing = p.read_text(encoding="utf-8", errors="replace")
5065
+ except OSError as exc:
5066
+ print(f" Warning: Could not read {filename}: {exc}")
5067
+ continue
5068
+ remainder = strip_c3_block(existing)
5069
+ if remainder is None:
5070
+ print(f" Kept {filename} (no C3 block in it — not ours to delete)")
5071
+ elif remainder.strip():
5072
+ try:
5073
+ p.write_text(remainder, encoding="utf-8")
5074
+ except OSError as exc:
5075
+ print(f" Warning: Could not update {filename}: {exc}")
5076
+ continue
5077
+ print(f" Removed C3 block from {filename} (kept the rest of the file)")
5078
+ else:
5079
+ p.unlink()
5080
+ print(f" Deleted {filename}")
5081
+
5082
+
4875
5083
  _LEGACY_INSTRUCTION_DOCS = ("GEMINI.md",) # Gemini CLI profile removed in v2.52
4876
5084
 
4877
5085
 
@@ -330,10 +330,10 @@ curl -X POST \
330
330
  <tr><td><code>c3 oracle serve --install</code></td> <td>Register the Oracle as a login/startup service — no terminal window — and start it now. Windows: Task Scheduler (Run-key fallback); macOS: launchd; Linux: systemd user unit</td></tr>
331
331
  <tr><td><code>c3 oracle serve --uninstall</code></td> <td>Remove the startup registration (a running Oracle keeps running)</td></tr>
332
332
  <tr><td><code>c3 oracle serve --status</code></td> <td>Installed? Running? Port, bind host, URL, and the launcher log path</td></tr>
333
- <tr><td><code>c3 oracle open</code></td> <td>Sign in to a running dashboard via a single-use URL</td></tr>
333
+ <tr><td><code>c3 oracle open</code></td> <td>Sign in to a running dashboard via a single-use URL (the hub's <strong>Open Oracle</strong> button does the same thing)</td></tr>
334
334
  </tbody>
335
335
  </table>
336
- <p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">The Hub exposes the same controls under <strong>Settings → Oracle service</strong> (Install / Uninstall / Start / Stop / Open). Starting the Oracle from there also fills in the Hub's <em>Oracle URL</em> when it is empty, so the Open Oracle button appears in the top bar.</p>
336
+ <p style="font-size: 12px; color: var(--text-dim); margin: 8px 0 0;">The Hub exposes the same controls under <strong>Settings → Oracle service</strong> (Install / Uninstall / Start / Stop / Open). Starting the Oracle from there also fills in the Hub's <em>Oracle URL</em> when it is empty, so the Open Oracle button appears in the top bar. That button opens a <strong>signed-in</strong> dashboard: it redeems the Oracle's owner-only bootstrap key for you. Reaching the dashboard by pasting its URL instead leaves it read-only — the page renders and the header looks healthy, but chat, Save and Test Ollama answer <code>401 unauthorized</code>.</p>
337
337
  </section>
338
338
 
339
339
  <hr class="divider">
@@ -26,7 +26,7 @@ from pathlib import Path
26
26
 
27
27
  sys.path.insert(0, str(Path(__file__).parent.parent))
28
28
 
29
- from cli._hook_utils import log_hook_error, record_c3_signal # noqa: E402
29
+ from cli._hook_utils import log_hook_error, record_c3_signal, tool_response_failed # noqa: E402
30
30
 
31
31
  # Tools that unlock generic read operations (Grep/Glob without a file path)
32
32
  _READ_UNLOCK_TOOLS = {"c3_search", "c3_compress", "c3_filter", "c3_read", "c3_impact", "c3_validate"}
@@ -45,6 +45,10 @@ def run(payload: dict, project_path: Path | None = None):
45
45
  if not short_name.startswith("c3_"):
46
46
  return None
47
47
 
48
+ # A failed call read nothing and edited nothing: no signal (ISSUE-3).
49
+ if tool_response_failed(payload):
50
+ return None
51
+
48
52
  record_c3_signal(
49
53
  short_name,
50
54
  short_name in _READ_UNLOCK_TOOLS,
@@ -152,6 +152,10 @@ def _routes(event: str, raw_tool: str, norm_tool: str, host: str = HOST_CLAUDE):
152
152
  yield "hook_artifact"
153
153
  if raw_tool in _GHOST_TOOLS:
154
154
  yield "hook_ghost_files"
155
+ # Shell file writes land in the ledger after the fact (after the
156
+ # ghost sweep, so a 0-byte redirect artifact is never logged).
157
+ if norm_tool == "Bash":
158
+ yield "hook_edit_ledger"
155
159
  elif event == "stop":
156
160
  yield "hook_session_stats"
157
161
  yield "hook_auto_snapshot"