code-context-control 2.92.0__tar.gz → 2.92.2__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.92.0/code_context_control.egg-info → code_context_control-2.92.2}/PKG-INFO +1 -1
  2. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/_hook_utils.py +38 -0
  3. code_context_control-2.92.2/cli/_shell_writes.py +120 -0
  4. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/c3.py +1 -1
  5. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_c3_signal.py +5 -1
  6. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_dispatch.py +4 -0
  7. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_edit_ledger.py +86 -0
  8. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_edit_unlock.py +8 -0
  9. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_pretool_enforce.py +69 -1
  10. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/mcp_server.py +9 -1
  11. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/compress.py +2 -1
  12. {code_context_control-2.92.0 → code_context_control-2.92.2/code_context_control.egg-info}/PKG-INFO +1 -1
  13. {code_context_control-2.92.0 → code_context_control-2.92.2}/code_context_control.egg-info/SOURCES.txt +4 -0
  14. {code_context_control-2.92.0 → code_context_control-2.92.2}/pyproject.toml +1 -1
  15. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/bench/external/swe_bench.py +3 -1
  16. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/doc_index.py +1 -1
  17. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/indexer.py +3 -2
  18. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/protocol.py +1 -1
  19. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/scanner.py +2 -1
  20. code_context_control-2.92.2/tests/test_failed_calls_do_not_unlock.py +124 -0
  21. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_codex_compat.py +2 -2
  22. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_dispatch.py +4 -1
  23. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_pretool_enforce.py +52 -0
  24. code_context_control-2.92.2/tests/test_shell_write_ledger.py +111 -0
  25. code_context_control-2.92.2/tests/test_shell_writes.py +84 -0
  26. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_windows_reliability.py +65 -1
  27. {code_context_control-2.92.0 → code_context_control-2.92.2}/LICENSE +0 -0
  28. {code_context_control-2.92.0 → code_context_control-2.92.2}/README.md +0 -0
  29. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/__init__.py +0 -0
  30. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/commands/__init__.py +0 -0
  31. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/commands/common.py +0 -0
  32. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/commands/parser.py +0 -0
  33. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/docs.html +0 -0
  34. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/edits.html +0 -0
  35. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/access.html +0 -0
  36. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/bitbucket.html +0 -0
  37. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/credentials.html +0 -0
  38. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/getting-started.html +0 -0
  39. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/index.html +0 -0
  40. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/masking.html +0 -0
  41. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/oracle.html +0 -0
  42. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/shared.css +0 -0
  43. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/tools.html +0 -0
  44. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/guide/workflow.html +0 -0
  45. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_access_guard.py +0 -0
  46. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_artifact.py +0 -0
  47. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_auto_snapshot.py +0 -0
  48. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_c3read.py +0 -0
  49. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_filter.py +0 -0
  50. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_ghost_files.py +0 -0
  51. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_prompt_recall.py +0 -0
  52. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_read.py +0 -0
  53. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_session_stats.py +0 -0
  54. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hook_terse_advisor.py +0 -0
  55. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_server.py +0 -0
  56. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/app.js +0 -0
  57. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/add_project.js +0 -0
  58. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/config_editor.js +0 -0
  59. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/drill_artifacts.js +0 -0
  60. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/drill_health.js +0 -0
  61. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/drill_panel.js +0 -0
  62. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/drill_subprojects.js +0 -0
  63. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/drill_tasks.js +0 -0
  64. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/drill_views.js +0 -0
  65. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/global_search.js +0 -0
  66. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/hub_ci.js +0 -0
  67. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/hub_credentials.js +0 -0
  68. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/hub_enforcement.js +0 -0
  69. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/hub_locks.js +0 -0
  70. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/mcp_manager.js +0 -0
  71. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/modals.js +0 -0
  72. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/project_card.js +0 -0
  73. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/project_tree.js +0 -0
  74. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/session_drawer.js +0 -0
  75. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/settings_modal.js +0 -0
  76. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/sidebar.js +0 -0
  77. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/summary_bar.js +0 -0
  78. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/task_board.js +0 -0
  79. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/toasts.js +0 -0
  80. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/components/topbar.js +0 -0
  81. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui/state.js +0 -0
  82. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/hub_ui.html +0 -0
  83. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/mcp_proxy.py +0 -0
  84. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/progress.py +0 -0
  85. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/server.py +0 -0
  86. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/__init__.py +0 -0
  87. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/_grants.py +0 -0
  88. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/_helpers.py +0 -0
  89. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/agent.py +0 -0
  90. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/artifacts.py +0 -0
  91. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/bitbucket.py +0 -0
  92. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/ci.py +0 -0
  93. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/credentials.py +0 -0
  94. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/delegate.py +0 -0
  95. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/edit.py +0 -0
  96. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/edit_verify.py +0 -0
  97. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/edits.py +0 -0
  98. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/federate.py +0 -0
  99. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/filter.py +0 -0
  100. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/impact.py +0 -0
  101. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/jira.py +0 -0
  102. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/locks.py +0 -0
  103. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/memory.py +0 -0
  104. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/override.py +0 -0
  105. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/project.py +0 -0
  106. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/read.py +0 -0
  107. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/search.py +0 -0
  108. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/session.py +0 -0
  109. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/shell.py +0 -0
  110. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/status.py +0 -0
  111. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/tasks.py +0 -0
  112. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/tools/validate.py +0 -0
  113. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/api.js +0 -0
  114. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/app.js +0 -0
  115. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/access.js +0 -0
  116. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/bitbucket.js +0 -0
  117. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/chat.js +0 -0
  118. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/credentials.js +0 -0
  119. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/dashboard.js +0 -0
  120. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/edits.js +0 -0
  121. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/enforcement.js +0 -0
  122. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/instructions.js +0 -0
  123. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/jira.js +0 -0
  124. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/memory.js +0 -0
  125. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/sessions.js +0 -0
  126. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/settings.js +0 -0
  127. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/sidebar.js +0 -0
  128. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/components/tasks.js +0 -0
  129. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/icons.js +0 -0
  130. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/pm_shared.js +0 -0
  131. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/shared.js +0 -0
  132. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui/theme.js +0 -0
  133. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui.html +0 -0
  134. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui_legacy.html +0 -0
  135. {code_context_control-2.92.0 → code_context_control-2.92.2}/cli/ui_nano.html +0 -0
  136. {code_context_control-2.92.0 → code_context_control-2.92.2}/code_context_control.egg-info/dependency_links.txt +0 -0
  137. {code_context_control-2.92.0 → code_context_control-2.92.2}/code_context_control.egg-info/entry_points.txt +0 -0
  138. {code_context_control-2.92.0 → code_context_control-2.92.2}/code_context_control.egg-info/requires.txt +0 -0
  139. {code_context_control-2.92.0 → code_context_control-2.92.2}/code_context_control.egg-info/top_level.txt +0 -0
  140. {code_context_control-2.92.0 → code_context_control-2.92.2}/core/__init__.py +0 -0
  141. {code_context_control-2.92.0 → code_context_control-2.92.2}/core/config.py +0 -0
  142. {code_context_control-2.92.0 → code_context_control-2.92.2}/core/ide.py +0 -0
  143. {code_context_control-2.92.0 → code_context_control-2.92.2}/core/mcp_toml.py +0 -0
  144. {code_context_control-2.92.0 → code_context_control-2.92.2}/core/web_security.py +0 -0
  145. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/__init__.py +0 -0
  146. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/config.py +0 -0
  147. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/mcp_oracle.py +0 -0
  148. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/oracle_server.py +0 -0
  149. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/oracle_ui.html +0 -0
  150. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/__init__.py +0 -0
  151. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/activity_reporter.py +0 -0
  152. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/api_auth.py +0 -0
  153. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/c3_bridge.py +0 -0
  154. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/chat_engine.py +0 -0
  155. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/chat_poll.py +0 -0
  156. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/chat_store.py +0 -0
  157. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/cross_memory.py +0 -0
  158. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/discovery_audit.py +0 -0
  159. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/federated_graph.py +0 -0
  160. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/health_checker.py +0 -0
  161. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/insight_engine.py +0 -0
  162. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/local_session.py +0 -0
  163. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/memory_reader.py +0 -0
  164. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/memory_writer.py +0 -0
  165. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/mobile_api.py +0 -0
  166. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/project_scanner.py +0 -0
  167. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/review_agent.py +0 -0
  168. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/tool_executor.py +0 -0
  169. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/services/tool_registry.py +0 -0
  170. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/activity.js +0 -0
  171. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/agents.js +0 -0
  172. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/app.js +0 -0
  173. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/busy.js +0 -0
  174. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/chat/conversations.js +0 -0
  175. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/chat/input.js +0 -0
  176. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/chat/markdown.js +0 -0
  177. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/chat/send.js +0 -0
  178. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/chat/stream_renderer.js +0 -0
  179. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/chat/toolbar.js +0 -0
  180. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/core.js +0 -0
  181. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/crossgraph.js +0 -0
  182. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/header.js +0 -0
  183. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/insights.js +0 -0
  184. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/projects.js +0 -0
  185. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/qrcode.js +0 -0
  186. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/settings.js +0 -0
  187. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/suggestions.js +0 -0
  188. {code_context_control-2.92.0 → code_context_control-2.92.2}/oracle/ui/theme_tabs.js +0 -0
  189. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/__init__.py +0 -0
  190. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/access_guard.py +0 -0
  191. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/access_telemetry.py +0 -0
  192. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/activity_log.py +0 -0
  193. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/agent_base.py +0 -0
  194. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/agent_locks.py +0 -0
  195. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/agents.py +0 -0
  196. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/artifact_defs.py +0 -0
  197. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/artifact_store.py +0 -0
  198. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/auto_memory.py +0 -0
  199. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/background_service.py +0 -0
  200. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/bench/__init__.py +0 -0
  201. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/bench/external/__init__.py +0 -0
  202. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/bench/external/aider_polyglot.py +0 -0
  203. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/benchmark_dashboard.py +0 -0
  204. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/bitbucket_client.py +0 -0
  205. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/bitbucket_credentials.py +0 -0
  206. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_act.py +0 -0
  207. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_cache.py +0 -0
  208. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_expr.py +0 -0
  209. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_failures.py +0 -0
  210. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_github.py +0 -0
  211. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_impact.py +0 -0
  212. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_intel.py +0 -0
  213. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_runner.py +0 -0
  214. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ci_workflow.py +0 -0
  215. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/circuit_breaker.py +0 -0
  216. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/claude_md.py +0 -0
  217. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/compressor.py +0 -0
  218. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/context_snapshot.py +0 -0
  219. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/conversation_store.py +0 -0
  220. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/cred_telemetry.py +0 -0
  221. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/credential_store.py +0 -0
  222. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/e2e_benchmark.py +0 -0
  223. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/e2e_evaluator.py +0 -0
  224. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/e2e_tasks.py +0 -0
  225. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/edit_ledger.py +0 -0
  226. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/embedding_index.py +0 -0
  227. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/enforcement_policy.py +0 -0
  228. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/error_reporting.py +0 -0
  229. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/file_memory.py +0 -0
  230. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/git_context.py +0 -0
  231. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/hub_service.py +0 -0
  232. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/jira_client.py +0 -0
  233. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/jira_cloud.py +0 -0
  234. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/jira_credentials.py +0 -0
  235. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/jira_data_center.py +0 -0
  236. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/jira_links.py +0 -0
  237. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/mask_activation.py +0 -0
  238. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/mask_mirror.py +0 -0
  239. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/mask_presets.py +0 -0
  240. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory.py +0 -0
  241. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory_consolidator.py +0 -0
  242. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory_distiller.py +0 -0
  243. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory_graph.py +0 -0
  244. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory_grounder.py +0 -0
  245. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory_queue.py +0 -0
  246. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/memory_scorer.py +0 -0
  247. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/metrics.py +0 -0
  248. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/notifications.py +0 -0
  249. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ollama_bridge.py +0 -0
  250. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ollama_client.py +0 -0
  251. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/ollama_credentials.py +0 -0
  252. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/oracle_service.py +0 -0
  253. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/output_filter.py +0 -0
  254. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/override_grants.py +0 -0
  255. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/override_policy.py +0 -0
  256. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/override_requests.py +0 -0
  257. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/override_wake.py +0 -0
  258. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/parser.py +0 -0
  259. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/project_manager.py +0 -0
  260. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/project_runtime.py +0 -0
  261. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/proxy_state.py +0 -0
  262. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/repo_map.py +0 -0
  263. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/repo_shape.py +0 -0
  264. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/retention.py +0 -0
  265. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/retrieval_broker.py +0 -0
  266. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/router.py +0 -0
  267. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/runtime.py +0 -0
  268. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/session_benchmark.py +0 -0
  269. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/session_manager.py +0 -0
  270. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/session_preloader.py +0 -0
  271. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/subprojects.py +0 -0
  272. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/task_store.py +0 -0
  273. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/telemetry.py +0 -0
  274. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/text_index.py +0 -0
  275. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/time_tracker.py +0 -0
  276. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/tool_classifier.py +0 -0
  277. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/transcript_index.py +0 -0
  278. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/validation_cache.py +0 -0
  279. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/vector_store.py +0 -0
  280. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/watcher.py +0 -0
  281. {code_context_control-2.92.0 → code_context_control-2.92.2}/services/win_subprocess.py +0 -0
  282. {code_context_control-2.92.0 → code_context_control-2.92.2}/setup.cfg +0 -0
  283. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_access_builtin_optout.py +0 -0
  284. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_access_guard.py +0 -0
  285. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_access_guard_meta.py +0 -0
  286. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_access_guard_shell_project.py +0 -0
  287. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_access_guard_surfaces.py +0 -0
  288. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_access_guard_wiring.py +0 -0
  289. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_activity_reporter.py +0 -0
  290. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_agent_locks.py +0 -0
  291. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_aider_polyglot.py +0 -0
  292. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_antigravity_transition.py +0 -0
  293. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_artifact_store.py +0 -0
  294. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_artifact_tool.py +0 -0
  295. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_background_service.py +0 -0
  296. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_bitbucket_cli_smoke.py +0 -0
  297. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_bitbucket_client.py +0 -0
  298. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_bitbucket_config_fallback.py +0 -0
  299. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_bitbucket_credentials.py +0 -0
  300. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_bitbucket_tool.py +0 -0
  301. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_c3_bridge_project_artifacts.py +0 -0
  302. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_c3_shell.py +0 -0
  303. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_chat_poll.py +0 -0
  304. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_act.py +0 -0
  305. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_cache.py +0 -0
  306. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_expr.py +0 -0
  307. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_impact.py +0 -0
  308. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_intel.py +0 -0
  309. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_runner.py +0 -0
  310. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ci_workflow.py +0 -0
  311. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_circuit_breaker.py +0 -0
  312. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_claude_md_merge.py +0 -0
  313. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_cli_smoke.py +0 -0
  314. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_compressor_large_file.py +0 -0
  315. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_cred_telemetry.py +0 -0
  316. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_credential_login_kind.py +0 -0
  317. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_credential_store.py +0 -0
  318. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_credential_ui_parity.py +0 -0
  319. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_credentials_routes.py +0 -0
  320. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_credentials_tool.py +0 -0
  321. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_creds_cli_smoke.py +0 -0
  322. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_delegate_cascade.py +0 -0
  323. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_delegate_version_probe.py +0 -0
  324. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_e2e_benchmark.py +0 -0
  325. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_edit_ledger_deadline.py +0 -0
  326. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_edit_ledger_hook.py +0 -0
  327. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_edit_locking.py +0 -0
  328. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_edit_normalization.py +0 -0
  329. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_edit_verify.py +0 -0
  330. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_embedding_index_deadlock.py +0 -0
  331. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_enforcement_flip.py +0 -0
  332. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_enforcement_policy.py +0 -0
  333. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_enforcement_routes.py +0 -0
  334. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_federated_graph.py +0 -0
  335. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_filter_backoff.py +0 -0
  336. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ghost_files.py +0 -0
  337. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ghost_generation.py +0 -0
  338. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_git_branch_awareness.py +0 -0
  339. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_access_guard.py +0 -0
  340. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_prompt_recall.py +0 -0
  341. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_smoke.py +0 -0
  342. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_state.py +0 -0
  343. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hook_utf8_stdio.py +0 -0
  344. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_credentials_route.py +0 -0
  345. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_credentials_routes_write.py +0 -0
  346. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_enforcement_routes.py +0 -0
  347. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_inspect_api.py +0 -0
  348. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_locks_routes.py +0 -0
  349. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_oracle_service_routes.py +0 -0
  350. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_server_smoke.py +0 -0
  351. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_hub_subproject_links.py +0 -0
  352. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ide_workflow_adaptation.py +0 -0
  353. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_init_clear_preserves_user_content.py +0 -0
  354. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_init_scan.py +0 -0
  355. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_install_mcp_entrypoint.py +0 -0
  356. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_cli_smoke.py +0 -0
  357. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_client.py +0 -0
  358. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_config_fallback.py +0 -0
  359. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_credentials.py +0 -0
  360. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_links.py +0 -0
  361. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_routes.py +0 -0
  362. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_jira_tool.py +0 -0
  363. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_lazy_store_init.py +0 -0
  364. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mask_guard.py +0 -0
  365. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mask_routes.py +0 -0
  366. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mask_surfaces.py +0 -0
  367. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mcp_host_guard.py +0 -0
  368. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mcp_memory_timeout.py +0 -0
  369. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mcp_server_smoke.py +0 -0
  370. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mcp_toml.py +0 -0
  371. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_memory_distiller.py +0 -0
  372. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_memory_graph_api.py +0 -0
  373. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_memory_queue.py +0 -0
  374. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_memory_system.py +0 -0
  375. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mobile_api.py +0 -0
  376. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mobile_extras.py +0 -0
  377. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mobile_override_routes.py +0 -0
  378. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_mobile_security_api.py +0 -0
  379. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_no_stale_model_pins.py +0 -0
  380. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_notification_dedup.py +0 -0
  381. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_notification_discipline.py +0 -0
  382. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_ollama_credentials.py +0 -0
  383. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_api_auth.py +0 -0
  384. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_apikey_api.py +0 -0
  385. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_c3_bridge.py +0 -0
  386. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_chat_engine.py +0 -0
  387. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_chat_store.py +0 -0
  388. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_discovery_api.py +0 -0
  389. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_discovery_audit.py +0 -0
  390. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_health_probe.py +0 -0
  391. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_local_auth.py +0 -0
  392. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_ollama_bridge.py +0 -0
  393. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_scanner_cache.py +0 -0
  394. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_security_fixes.py +0 -0
  395. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_session_bootstrap.py +0 -0
  396. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_subproject_awareness.py +0 -0
  397. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_oracle_ui_bundle.py +0 -0
  398. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_output_filter.py +0 -0
  399. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_override_grants.py +0 -0
  400. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_override_grants_mcp.py +0 -0
  401. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_override_requests.py +0 -0
  402. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_override_wake.py +0 -0
  403. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_permissions.py +0 -0
  404. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_pm_api.py +0 -0
  405. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_project_manager.py +0 -0
  406. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_project_manager_merge.py +0 -0
  407. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_project_tool.py +0 -0
  408. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_read_coercion.py +0 -0
  409. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_read_edit_parity.py +0 -0
  410. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_related_facts.py +0 -0
  411. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_repo_map.py +0 -0
  412. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_repo_shape.py +0 -0
  413. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_response_boilerplate.py +0 -0
  414. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_retention.py +0 -0
  415. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_review_digest.py +0 -0
  416. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_service_durability.py +0 -0
  417. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_session_benchmark.py +0 -0
  418. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_session_budget.py +0 -0
  419. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_shell_creds.py +0 -0
  420. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_shell_robustness.py +0 -0
  421. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_subproject_exclusion.py +0 -0
  422. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_subproject_federation.py +0 -0
  423. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_subprojects.py +0 -0
  424. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_swe_bench.py +0 -0
  425. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_task_store.py +0 -0
  426. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_task_tool.py +0 -0
  427. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_time_tracker.py +0 -0
  428. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_token_telemetry.py +0 -0
  429. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_tool_registry.py +0 -0
  430. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_upgrade_and_version.py +0 -0
  431. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_validate.py +0 -0
  432. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_vault_write_guard.py +0 -0
  433. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_version_sync.py +0 -0
  434. {code_context_control-2.92.0 → code_context_control-2.92.2}/tests/test_web_security.py +0 -0
  435. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/__init__.py +0 -0
  436. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/backend.py +0 -0
  437. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/main.py +0 -0
  438. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/__init__.py +0 -0
  439. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/benchmark_view.py +0 -0
  440. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/claudemd_view.py +0 -0
  441. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/compress_view.py +0 -0
  442. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/index_view.py +0 -0
  443. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/init_view.py +0 -0
  444. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/mcp_view.py +0 -0
  445. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/optimize_view.py +0 -0
  446. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/pipe_view.py +0 -0
  447. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/projects_view.py +0 -0
  448. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/search_view.py +0 -0
  449. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/session_view.py +0 -0
  450. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/stats.py +0 -0
  451. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/screens/ui_view.py +0 -0
  452. {code_context_control-2.92.0 → code_context_control-2.92.2}/tui/theme.tcss +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.92.0
3
+ Version: 2.92.2
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.92.0"
95
+ __version__ = "2.92.2"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -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"
@@ -139,6 +139,9 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
139
139
  """
140
140
  tool_name = normalize_tool_name(payload.get("tool_name", ""))
141
141
 
142
+ if tool_name == "Bash":
143
+ return _run_shell(payload, project_path)
144
+
142
145
  if tool_name not in ("Edit", "Write", "NotebookEdit"):
143
146
  return None
144
147
 
@@ -230,6 +233,89 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
230
233
  }
231
234
 
232
235
 
236
+ # A file named by the command counts as written by it only if it changed
237
+ # this recently — `rm`, a stale name in a quoted string, or a path that was
238
+ # merely mentioned must not become a ledger row.
239
+ _SHELL_WRITE_WINDOW_S = 120
240
+
241
+
242
+ def _run_shell(payload: dict, project_path: Path | None) -> dict | None:
243
+ """After-the-fact ledger rows for files a shell command wrote.
244
+
245
+ Field report 2026-08-22 (ISSUE-1): writes through `python -c`, heredocs
246
+ and `sed -i` never reached the ledger, so the audit trail had holes
247
+ exactly where the agent had gone round the Write block. There is no
248
+ pre-edit snapshot to take here — the command already ran — so the row
249
+ is marked change_type "shell" and carries the command.
250
+ """
251
+ tool_input = payload.get("tool_input", {}) or {}
252
+ cmd = str(tool_input.get("command") or "")
253
+ if not cmd.strip():
254
+ return None
255
+ if project_path is None:
256
+ project_path = Path.cwd()
257
+ c3_dir = project_path / ".c3"
258
+ if not c3_dir.exists():
259
+ return None
260
+ config = load_hybrid_config(str(project_path))
261
+ ledger_cfg = config.get("edit_ledger", {})
262
+ if not ledger_cfg.get("enabled", True):
263
+ return None
264
+ tracking_level = ledger_cfg.get("tracking_level", "standard")
265
+ try:
266
+ from cli._shell_writes import shell_write_targets
267
+ except Exception:
268
+ return None
269
+
270
+ ledger_file = c3_dir / "edit_ledger.jsonl"
271
+ now = datetime.now(timezone.utc)
272
+ root = project_path.resolve()
273
+ logged = []
274
+ for target in shell_write_targets(cmd, str(project_path)):
275
+ p = Path(target)
276
+ try:
277
+ if not p.is_file() or p.suffix.lower() not in EDITABLE_EXTS:
278
+ continue
279
+ rel = str(p.resolve().relative_to(root)).replace("\\", "/")
280
+ if now.timestamp() - p.stat().st_mtime > _SHELL_WRITE_WINDOW_S:
281
+ continue
282
+ except (OSError, ValueError):
283
+ continue
284
+ entry = {
285
+ "id": f"edit_{now.strftime('%Y%m%d_%H%M%S')}_{_next_seq(ledger_file, now):03d}_{uuid.uuid4().hex[:4]}",
286
+ "timestamp": now.isoformat(),
287
+ "session_id": str(payload.get("session_id") or ""),
288
+ "file": rel,
289
+ "change_type": "shell",
290
+ "summary": "shell" if tracking_level == "minimal" else f"shell: {cmd.strip()[:160]}",
291
+ "lines_changed": None,
292
+ "version": _next_version(ledger_file, rel),
293
+ "git": {},
294
+ "diff_summary": "",
295
+ "git_pending": tracking_level != "minimal",
296
+ "tags": ["auto", "shell"] if ledger_cfg.get("auto_tag", True) else ["shell"],
297
+ }
298
+ if tracking_level == "detailed":
299
+ entry["detail"] = {"command": cmd.strip()[:300]}
300
+ with open(ledger_file, "a", encoding="utf-8") as f:
301
+ f.write(json.dumps(entry) + "\n")
302
+ logged.append(f"{rel} {entry['version']}")
303
+ try:
304
+ from services.repo_map import is_structural_change, mark_map_dirty
305
+ if is_structural_change(rel, "shell"):
306
+ mark_map_dirty(project_path, f"shell:{rel}")
307
+ except Exception:
308
+ pass
309
+ if not logged:
310
+ return None
311
+ return {
312
+ "_text": (
313
+ f"[c3:ledger] shell write logged after the fact: {', '.join(logged)} "
314
+ f"— no pre-edit snapshot; prefer c3_edit for file changes."
315
+ )
316
+ }
317
+
318
+
233
319
  def main():
234
320
  ensure_utf8_stdio()
235
321
  try:
@@ -21,6 +21,7 @@ from cli._hook_utils import ( # noqa: E402
21
21
  emit_additional_context,
22
22
  log_hook_error,
23
23
  record_json_unlocks,
24
+ tool_response_failed,
24
25
  )
25
26
 
26
27
  EDITABLE_EXTS = {
@@ -98,6 +99,13 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
98
99
 
99
100
  base = project_path if project_path is not None else Path.cwd()
100
101
 
102
+ # "c3_compress on a path that does not exist" returned an error and still
103
+ # unlocked native Write for that path (field report 2026-08-22, ISSUE-3).
104
+ # An error response gathered no context, so it grants nothing. New files
105
+ # are created through c3_edit(old_string=""), which needs no unlock.
106
+ if tool_response_failed(payload):
107
+ return None
108
+
101
109
  tool_input = payload.get("tool_input", {}) or {}
102
110
  tool_response = payload.get("tool_response", "")
103
111
  if isinstance(tool_response, dict):
@@ -35,6 +35,7 @@ advisory path instead of granting stale unlocks.
35
35
  Supports both Claude Code and Gemini CLI via _hook_utils.
36
36
  """
37
37
  import json
38
+ import os
38
39
  import re
39
40
  import sys
40
41
  from datetime import datetime, timezone
@@ -54,8 +55,17 @@ from _hook_utils import ( # noqa: E402
54
55
  log_hook_error,
55
56
  normalize_tool_name,
56
57
  record_unlocked_files,
58
+ response_text_failed,
57
59
  )
58
60
 
61
+ try:
62
+ from _shell_writes import shell_write_targets
63
+ except Exception: # pragma: no cover - package-style import (tests, dispatcher)
64
+ try:
65
+ from cli._shell_writes import shell_write_targets
66
+ except Exception:
67
+ shell_write_targets = None
68
+
59
69
  try:
60
70
  from services import access_telemetry, enforcement_policy
61
71
  except Exception: # pragma: no cover — degrade to hardcoded strict behavior
@@ -142,7 +152,8 @@ _REDIRECTS = {
142
152
  ),
143
153
  "Write": (
144
154
  "Use c3_edit(file_path='...', old_string='...', new_string='...', summary='...') "
145
- "for file modifications. For new files, use native Write only after c3_search/c3_compress."
155
+ "for file modifications. For a NEW file, c3_edit(file_path='...', old_string='', "
156
+ "new_string='<content>') creates it and logs it."
146
157
  ),
147
158
  }
148
159
 
@@ -313,6 +324,11 @@ def _check_c3_used(
313
324
  tool = entry.get("tool", "")
314
325
  if tool not in allowed:
315
326
  continue
327
+ # ISSUE-3: the log used to count a call that returned "Error: File
328
+ # not found" as "c3 was used". Newer entries carry ok=False; older
329
+ # ones are judged by the summary text.
330
+ if entry.get("ok") is False or response_text_failed(entry.get("result_summary") or ""):
331
+ continue
316
332
 
317
333
  if native_target:
318
334
  grant = _C3_GRANTS.get(tool, required_cat)
@@ -514,6 +530,9 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
514
530
  """
515
531
  tool_name = normalize_tool_name(payload.get("tool_name", ""))
516
532
 
533
+ if tool_name == "Bash":
534
+ return _shell_advisory(payload, project_path)
535
+
517
536
  if tool_name not in _PREREQS:
518
537
  return None # Not a tool we enforce — pass through
519
538
 
@@ -617,6 +636,55 @@ def run(payload: dict, project_path: Path | None = None) -> dict | None:
617
636
  }, policy)
618
637
 
619
638
 
639
+ def _shell_advisory(payload: dict, project_path: Path | None) -> dict | None:
640
+ """Bash is the escape hatch tool discipline never looked at (field
641
+ report 2026-08-22, ISSUE-1's buried finding): an inline ``python -c`` write
642
+ or a heredoc was never nudged toward c3_edit and never snapshotted. It
643
+ is NOT denied — blocking shell writes outright would break far more
644
+ legitimate work than it protects — it gets the advisory hint that names
645
+ the files, in strict and advisory modes alike, and hook_edit_ledger
646
+ records the writes after the fact. A fresh write-class c3 signal
647
+ (c3_edit just ran) means the agent is already on the c3 path: silent.
648
+ """
649
+ if shell_write_targets is None:
650
+ return None
651
+ tool_input = payload.get("tool_input", {}) or {}
652
+ cmd = str(tool_input.get("command") or "")
653
+ if not cmd.strip():
654
+ return None
655
+ base = project_path if project_path is not None else Path.cwd()
656
+ policy = _resolve_policy(base)
657
+ mode = getattr(policy, "mode", None) or "strict"
658
+ if mode == "off":
659
+ return _policy_warnings(policy)
660
+ targets = [t for t in shell_write_targets(cmd, str(base))
661
+ if not _outside_project(base, {"file_path": t})]
662
+ if not targets:
663
+ return _policy_warnings(policy)
664
+ session_id = str(payload.get("session_id") or "")
665
+ state = load_enforcement_state(base, session_id=session_id)
666
+ ttl_s = getattr(policy, "signal_ttl_s", _SIGNAL_MAX_AGE_SECS)
667
+ recent, _read_unlocked, signal_tool = _check_signal(state, ttl_s)
668
+ if recent and signal_tool in _PREREQS["Write"]:
669
+ return _policy_warnings(policy)
670
+ shown = []
671
+ for t in targets[:3]:
672
+ try: # display only; no path resolution here (canonical_key owns that)
673
+ shown.append(os.path.relpath(t, str(base)).replace("\\", "/"))
674
+ except (OSError, ValueError):
675
+ shown.append(t)
676
+ more = f" (+{len(targets) - 3} more)" if len(targets) > 3 else ""
677
+ return _with_warnings({
678
+ "additionalContext": (
679
+ f"[c3:hint] This shell command looks like it writes {', '.join(shown)}{more}. "
680
+ f"Shell writes bypass c3_edit: no pre-edit snapshot, and the ledger can only "
681
+ f"record them after the fact as `shell` changes. Prefer "
682
+ f"c3_edit(file_path='...', old_string='...', new_string='...') — old_string='' "
683
+ f"creates a file. (advisory: shell is never blocked)"
684
+ )
685
+ }, policy)
686
+
687
+
620
688
  def _record_block(tool_name: str, tool_input: dict, session_id: str,
621
689
  base: Path) -> None:
622
690
  """Log a discipline block so `c3 access stats` can show what it costs."""
@@ -415,7 +415,15 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
415
415
  svc.activity_log.log("budget_auto_reset", {"gap_seconds": gap_reset_seconds})
416
416
 
417
417
  svc.session_mgr.log_tool_call(tool_name, args, summary)
418
- svc.activity_log.log("tool_call", {"tool": tool_name, "args": args, "result_summary": summary})
418
+ # ok=False lets hook_pretool_enforce's activity scan skip a failed call
419
+ # (ISSUE-3: "Error: File not found" used to count as "c3 was used").
420
+ try:
421
+ from cli._hook_utils import response_text_failed as _failed
422
+ call_ok = not _failed(response)
423
+ except Exception:
424
+ call_ok = True
425
+ svc.activity_log.log("tool_call", {"tool": tool_name, "args": args,
426
+ "result_summary": summary, "ok": call_ok})
419
427
  tracker = getattr(svc, "time_tracker", None)
420
428
  if tracker is not None:
421
429
  try:
@@ -147,7 +147,8 @@ def _compress_single(file_path: str, mode: str, svc, finalize, maybe_facts) -> s
147
147
 
148
148
  if mode in ("map", "dense_map"):
149
149
  if not full.exists():
150
- return "[file_map:error] not found"
150
+ return ("[file_map:error] not found. To create a new file use "
151
+ "c3_edit(file_path=..., old_string='', new_string=<content>).")
151
152
  rel = str(full.resolve().relative_to(Path(svc.project_path).resolve())).replace("\\", "/")
152
153
  queued = svc.file_memory.drain_queue()
153
154
  completed = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.92.0
3
+ Version: 2.92.2
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
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  cli/__init__.py
5
5
  cli/_hook_utils.py
6
+ cli/_shell_writes.py
6
7
  cli/c3.py
7
8
  cli/docs.html
8
9
  cli/edits.html
@@ -321,6 +322,7 @@ tests/test_embedding_index_deadlock.py
321
322
  tests/test_enforcement_flip.py
322
323
  tests/test_enforcement_policy.py
323
324
  tests/test_enforcement_routes.py
325
+ tests/test_failed_calls_do_not_unlock.py
324
326
  tests/test_federated_graph.py
325
327
  tests/test_filter_backoff.py
326
328
  tests/test_ghost_files.py
@@ -411,6 +413,8 @@ tests/test_session_benchmark.py
411
413
  tests/test_session_budget.py
412
414
  tests/test_shell_creds.py
413
415
  tests/test_shell_robustness.py
416
+ tests/test_shell_write_ledger.py
417
+ tests/test_shell_writes.py
414
418
  tests/test_subproject_exclusion.py
415
419
  tests/test_subproject_federation.py
416
420
  tests/test_subprojects.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "code-context-control"
7
- version = "2.92.0"
7
+ version = "2.92.2"
8
8
  description = "Local MCP code-intelligence for AI coding tools: surgical search/read/edit, agent-config version history, path-level access + masking guards, and a multi-project hub."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -446,7 +446,9 @@ def evaluate_with_docker(
446
446
  "--timeout", str(timeout),
447
447
  ]
448
448
  try:
449
- subprocess.run(cmd, check=True, timeout=timeout * len(list(predictions_path.read_text().splitlines())))
449
+ n_predictions = len(
450
+ predictions_path.read_text(encoding="utf-8").splitlines())
451
+ subprocess.run(cmd, check=True, timeout=timeout * n_predictions)
450
452
  except Exception as e:
451
453
  return {"error": str(e)}
452
454
 
@@ -113,7 +113,7 @@ class DocIndex:
113
113
  except Exception:
114
114
  pass
115
115
  try:
116
- content = fpath.read_text(errors="replace")
116
+ content = fpath.read_text(encoding="utf-8", errors="replace")
117
117
  except Exception:
118
118
  continue
119
119
 
@@ -30,7 +30,7 @@ def _masked_content(fpath, project_path):
30
30
  if v.denial:
31
31
  return None
32
32
  if not v.masked:
33
- return fpath.read_text(errors="replace")
33
+ return fpath.read_text(encoding="utf-8", errors="replace")
34
34
  try:
35
35
  return mask_mirror.render_for_path(fpath, project_path).text
36
36
  except Exception:
@@ -187,7 +187,8 @@ class CodeIndex:
187
187
  # (docs/mask-guard.md §6, row 2). Skip it instead.
188
188
  continue
189
189
  else:
190
- content = fpath.read_text(errors='replace')
190
+ content = fpath.read_text(encoding='utf-8',
191
+ errors='replace')
191
192
  except Exception:
192
193
  continue
193
194
 
@@ -261,7 +261,7 @@ class CompressionProtocol:
261
261
  if _sub_excluded(fpath):
262
262
  continue
263
263
  try:
264
- content = fpath.read_text(errors='replace')
264
+ content = fpath.read_text(encoding='utf-8', errors='replace')
265
265
  except Exception:
266
266
  continue
267
267
  _accumulate(content)
@@ -43,7 +43,8 @@ def gitignore_dir_patterns(root) -> tuple:
43
43
  names: set = set()
44
44
  patterns: list = []
45
45
  try:
46
- text = (Path(root) / '.gitignore').read_text(errors='replace')
46
+ text = (Path(root) / '.gitignore').read_text(encoding='utf-8',
47
+ errors='replace')
47
48
  except OSError:
48
49
  return names, patterns
49
50
  for line in text.splitlines():