code-context-control 2.124.0__tar.gz → 2.126.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 (523) hide show
  1. {code_context_control-2.124.0/code_context_control.egg-info → code_context_control-2.126.1}/PKG-INFO +2 -2
  2. {code_context_control-2.124.0 → code_context_control-2.126.1}/README.md +1 -1
  3. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/_hook_utils.py +34 -0
  4. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/c3.py +23 -1
  5. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_dispatch.py +12 -3
  6. code_context_control-2.126.1/cli/hook_session_end.py +103 -0
  7. code_context_control-2.126.1/cli/hook_session_open.py +97 -0
  8. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/mcp_server.py +114 -1
  9. {code_context_control-2.124.0 → code_context_control-2.126.1/code_context_control.egg-info}/PKG-INFO +2 -2
  10. {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/SOURCES.txt +10 -0
  11. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/config.py +5 -0
  12. code_context_control-2.126.1/oracle/listeners.py +210 -0
  13. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/oracle_server.py +88 -2
  14. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/oracle_ui.html +9 -3
  15. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/chat_poll.py +8 -3
  16. code_context_control-2.126.1/oracle/services/client_tokens.py +239 -0
  17. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/mobile_api.py +362 -20
  18. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/app.js +1 -1
  19. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/settings.js +75 -19
  20. {code_context_control-2.124.0 → code_context_control-2.126.1}/pyproject.toml +1 -1
  21. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_runner.py +32 -0
  22. code_context_control-2.126.1/services/host_sessions.py +95 -0
  23. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/notifications.py +31 -0
  24. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/shell_jobs.py +93 -1
  25. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_codex_compat.py +11 -0
  26. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_dispatch.py +9 -0
  27. code_context_control-2.126.1/tests/test_hook_session_end.py +291 -0
  28. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_api.py +85 -1
  29. code_context_control-2.126.1/tests/test_mobile_clients.py +543 -0
  30. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_extras.py +4 -2
  31. code_context_control-2.126.1/tests/test_mobile_jobs_ci.py +327 -0
  32. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_override_routes.py +35 -0
  33. code_context_control-2.126.1/tests/test_notification_kinds.py +294 -0
  34. code_context_control-2.126.1/tests/test_oracle_loopback.py +269 -0
  35. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_jobs_s3.py +4 -1
  36. {code_context_control-2.124.0 → code_context_control-2.126.1}/LICENSE +0 -0
  37. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/__init__.py +0 -0
  38. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/_shell_writes.py +0 -0
  39. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/commands/__init__.py +0 -0
  40. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/commands/common.py +0 -0
  41. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/commands/parser.py +0 -0
  42. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/docs.html +0 -0
  43. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/edits.html +0 -0
  44. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/access.html +0 -0
  45. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/bitbucket.html +0 -0
  46. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/credentials.html +0 -0
  47. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/getting-started.html +0 -0
  48. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/index.html +0 -0
  49. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/masking.html +0 -0
  50. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/oracle.html +0 -0
  51. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/shared.css +0 -0
  52. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/tools.html +0 -0
  53. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/guide/workflow.html +0 -0
  54. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_access_guard.py +0 -0
  55. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_artifact.py +0 -0
  56. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_auto_snapshot.py +0 -0
  57. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_c3_signal.py +0 -0
  58. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_c3read.py +0 -0
  59. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_codex_lifecycle.py +0 -0
  60. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_edit_ledger.py +0 -0
  61. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_edit_unlock.py +0 -0
  62. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_filter.py +0 -0
  63. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_ghost_files.py +0 -0
  64. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_pretool_enforce.py +0 -0
  65. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_prompt_recall.py +0 -0
  66. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_read.py +0 -0
  67. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_session_stats.py +0 -0
  68. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hook_terse_advisor.py +0 -0
  69. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_server.py +0 -0
  70. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/app.js +0 -0
  71. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/add_project.js +0 -0
  72. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/config_editor.js +0 -0
  73. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_artifacts.js +0 -0
  74. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_health.js +0 -0
  75. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_panel.js +0 -0
  76. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_subprojects.js +0 -0
  77. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_tasks.js +0 -0
  78. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/drill_views.js +0 -0
  79. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/global_search.js +0 -0
  80. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_access.js +0 -0
  81. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_ci.js +0 -0
  82. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_cred_audit.js +0 -0
  83. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_credentials.js +0 -0
  84. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_enforcement.js +0 -0
  85. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_locks.js +0 -0
  86. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/hub_tokens.js +0 -0
  87. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/mcp_manager.js +0 -0
  88. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/modals.js +0 -0
  89. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/project_card.js +0 -0
  90. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/project_tree.js +0 -0
  91. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/session_drawer.js +0 -0
  92. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/settings_modal.js +0 -0
  93. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/sidebar.js +0 -0
  94. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/summary_bar.js +0 -0
  95. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/task_board.js +0 -0
  96. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/toasts.js +0 -0
  97. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/components/topbar.js +0 -0
  98. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui/state.js +0 -0
  99. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/hub_ui.html +0 -0
  100. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/mcp_proxy.py +0 -0
  101. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/progress.py +0 -0
  102. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/server.py +0 -0
  103. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/__init__.py +0 -0
  104. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/_grants.py +0 -0
  105. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/_helpers.py +0 -0
  106. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/agent.py +0 -0
  107. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/artifacts.py +0 -0
  108. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/bitbucket.py +0 -0
  109. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/ci.py +0 -0
  110. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/compress.py +0 -0
  111. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/credentials.py +0 -0
  112. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/delegate.py +0 -0
  113. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/edit.py +0 -0
  114. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/edit_verify.py +0 -0
  115. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/edits.py +0 -0
  116. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/federate.py +0 -0
  117. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/filter.py +0 -0
  118. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/impact.py +0 -0
  119. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/jira.py +0 -0
  120. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/locks.py +0 -0
  121. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/memory.py +0 -0
  122. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/override.py +0 -0
  123. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/project.py +0 -0
  124. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/read.py +0 -0
  125. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/search.py +0 -0
  126. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/session.py +0 -0
  127. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell.py +0 -0
  128. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_job.py +0 -0
  129. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_nudge.py +0 -0
  130. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_parsers.py +0 -0
  131. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/shell_render.py +0 -0
  132. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/status.py +0 -0
  133. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/tasks.py +0 -0
  134. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/tools/validate.py +0 -0
  135. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/api.js +0 -0
  136. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/app.js +0 -0
  137. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/access.js +0 -0
  138. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/bitbucket.js +0 -0
  139. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/chat.js +0 -0
  140. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/credentials.js +0 -0
  141. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/dashboard.js +0 -0
  142. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/edits.js +0 -0
  143. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/enforcement.js +0 -0
  144. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/instructions.js +0 -0
  145. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/jira.js +0 -0
  146. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/memory.js +0 -0
  147. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/sessions.js +0 -0
  148. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/settings.js +0 -0
  149. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/sidebar.js +0 -0
  150. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/components/tasks.js +0 -0
  151. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/icons.js +0 -0
  152. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/pm_shared.js +0 -0
  153. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/shared.js +0 -0
  154. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui/theme.js +0 -0
  155. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui.html +0 -0
  156. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui_legacy.html +0 -0
  157. {code_context_control-2.124.0 → code_context_control-2.126.1}/cli/ui_nano.html +0 -0
  158. {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/dependency_links.txt +0 -0
  159. {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/entry_points.txt +0 -0
  160. {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/requires.txt +0 -0
  161. {code_context_control-2.124.0 → code_context_control-2.126.1}/code_context_control.egg-info/top_level.txt +0 -0
  162. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/__init__.py +0 -0
  163. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/codex_patch.py +0 -0
  164. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/config.py +0 -0
  165. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/host.py +0 -0
  166. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/ide.py +0 -0
  167. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/mcp_toml.py +0 -0
  168. {code_context_control-2.124.0 → code_context_control-2.126.1}/core/web_security.py +0 -0
  169. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/__init__.py +0 -0
  170. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/mcp_oracle.py +0 -0
  171. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/__init__.py +0 -0
  172. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/activity_reporter.py +0 -0
  173. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/api_auth.py +0 -0
  174. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/c3_bridge.py +0 -0
  175. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/chat_engine.py +0 -0
  176. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/chat_store.py +0 -0
  177. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/cross_memory.py +0 -0
  178. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/discovery_audit.py +0 -0
  179. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/federated_graph.py +0 -0
  180. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/health_checker.py +0 -0
  181. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/insight_engine.py +0 -0
  182. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/local_session.py +0 -0
  183. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/memory_reader.py +0 -0
  184. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/memory_writer.py +0 -0
  185. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/project_scanner.py +0 -0
  186. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/review_agent.py +0 -0
  187. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/tool_executor.py +0 -0
  188. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/services/tool_registry.py +0 -0
  189. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/activity.js +0 -0
  190. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/agents.js +0 -0
  191. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/busy.js +0 -0
  192. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/conversations.js +0 -0
  193. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/input.js +0 -0
  194. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/markdown.js +0 -0
  195. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/send.js +0 -0
  196. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/stream_renderer.js +0 -0
  197. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/chat/toolbar.js +0 -0
  198. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/core.js +0 -0
  199. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/crossgraph.js +0 -0
  200. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/header.js +0 -0
  201. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/insights.js +0 -0
  202. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/projects.js +0 -0
  203. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/qrcode.js +0 -0
  204. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/suggestions.js +0 -0
  205. {code_context_control-2.124.0 → code_context_control-2.126.1}/oracle/ui/theme_tabs.js +0 -0
  206. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/__init__.py +0 -0
  207. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/access_guard.py +0 -0
  208. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/access_telemetry.py +0 -0
  209. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/activity_log.py +0 -0
  210. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/agent_base.py +0 -0
  211. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/agent_locks.py +0 -0
  212. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/agents.py +0 -0
  213. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/artifact_defs.py +0 -0
  214. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/artifact_store.py +0 -0
  215. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/atomic_json.py +0 -0
  216. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/auto_memory.py +0 -0
  217. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/background_service.py +0 -0
  218. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/__init__.py +0 -0
  219. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/external/__init__.py +0 -0
  220. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/external/aider_polyglot.py +0 -0
  221. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/external/swe_bench.py +0 -0
  222. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/map_eval.py +0 -0
  223. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/search_eval.py +0 -0
  224. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bench/shell_eval.py +0 -0
  225. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/benchmark_dashboard.py +0 -0
  226. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bitbucket_client.py +0 -0
  227. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/bitbucket_credentials.py +0 -0
  228. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_act.py +0 -0
  229. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_cache.py +0 -0
  230. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_expr.py +0 -0
  231. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_failures.py +0 -0
  232. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_github.py +0 -0
  233. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_impact.py +0 -0
  234. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_intel.py +0 -0
  235. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ci_workflow.py +0 -0
  236. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/circuit_breaker.py +0 -0
  237. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/claude_md.py +0 -0
  238. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/codex_integration.py +0 -0
  239. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/codex_transcript.py +0 -0
  240. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/compressor.py +0 -0
  241. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/context_snapshot.py +0 -0
  242. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/conversation_store.py +0 -0
  243. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/cred_audit.py +0 -0
  244. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/cred_telemetry.py +0 -0
  245. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/credential_store.py +0 -0
  246. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/dir_map.py +0 -0
  247. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/doc_index.py +0 -0
  248. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/e2e_benchmark.py +0 -0
  249. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/e2e_evaluator.py +0 -0
  250. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/e2e_tasks.py +0 -0
  251. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/edit_ledger.py +0 -0
  252. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/embedding_index.py +0 -0
  253. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/enforcement_policy.py +0 -0
  254. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/error_reporting.py +0 -0
  255. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/file_map.py +0 -0
  256. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/file_memory.py +0 -0
  257. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/git_context.py +0 -0
  258. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/hub_service.py +0 -0
  259. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/index_store.py +0 -0
  260. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/indexer.py +0 -0
  261. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_client.py +0 -0
  262. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_cloud.py +0 -0
  263. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_credentials.py +0 -0
  264. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_data_center.py +0 -0
  265. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/jira_links.py +0 -0
  266. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/lexical_index.py +0 -0
  267. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/mask_activation.py +0 -0
  268. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/mask_mirror.py +0 -0
  269. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/mask_presets.py +0 -0
  270. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory.py +0 -0
  271. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_consolidator.py +0 -0
  272. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_distiller.py +0 -0
  273. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_graph.py +0 -0
  274. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_grounder.py +0 -0
  275. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_queue.py +0 -0
  276. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/memory_scorer.py +0 -0
  277. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/metrics.py +0 -0
  278. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ollama_bridge.py +0 -0
  279. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ollama_client.py +0 -0
  280. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/ollama_credentials.py +0 -0
  281. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/oracle_service.py +0 -0
  282. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/output_filter.py +0 -0
  283. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_grants.py +0 -0
  284. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_policy.py +0 -0
  285. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_requests.py +0 -0
  286. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/override_wake.py +0 -0
  287. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/parser.py +0 -0
  288. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/project_manager.py +0 -0
  289. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/project_runtime.py +0 -0
  290. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/protocol.py +0 -0
  291. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/proxy_state.py +0 -0
  292. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/repo_map.py +0 -0
  293. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/repo_shape.py +0 -0
  294. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/reranker.py +0 -0
  295. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/retention.py +0 -0
  296. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/retrieval.py +0 -0
  297. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/retrieval_broker.py +0 -0
  298. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/router.py +0 -0
  299. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/runtime.py +0 -0
  300. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/scanner.py +0 -0
  301. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/session_benchmark.py +0 -0
  302. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/session_manager.py +0 -0
  303. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/session_preloader.py +0 -0
  304. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/shell_output.py +0 -0
  305. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/subprojects.py +0 -0
  306. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/task_store.py +0 -0
  307. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/telemetry.py +0 -0
  308. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/text_index.py +0 -0
  309. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/time_tracker.py +0 -0
  310. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/tool_classifier.py +0 -0
  311. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/transcript_index.py +0 -0
  312. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/validation_cache.py +0 -0
  313. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/vector_store.py +0 -0
  314. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/watcher.py +0 -0
  315. {code_context_control-2.124.0 → code_context_control-2.126.1}/services/win_subprocess.py +0 -0
  316. {code_context_control-2.124.0 → code_context_control-2.126.1}/setup.cfg +0 -0
  317. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_builtin_optout.py +0 -0
  318. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard.py +0 -0
  319. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_meta.py +0 -0
  320. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_shell_project.py +0 -0
  321. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_surfaces.py +0 -0
  322. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_access_guard_wiring.py +0 -0
  323. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_activity_reporter.py +0 -0
  324. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_agent_locks.py +0 -0
  325. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_aider_polyglot.py +0 -0
  326. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_antigravity_transition.py +0 -0
  327. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_artifact_store.py +0 -0
  328. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_artifact_tool.py +0 -0
  329. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_atomic_json.py +0 -0
  330. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_background_service.py +0 -0
  331. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_cli_smoke.py +0 -0
  332. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_client.py +0 -0
  333. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_config_fallback.py +0 -0
  334. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_credentials.py +0 -0
  335. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_bitbucket_tool.py +0 -0
  336. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_builtin_modes.py +0 -0
  337. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_c3_bridge_project_artifacts.py +0 -0
  338. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_c3_shell.py +0 -0
  339. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_chat_poll.py +0 -0
  340. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_act.py +0 -0
  341. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_cache.py +0 -0
  342. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_expr.py +0 -0
  343. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_impact.py +0 -0
  344. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_intel.py +0 -0
  345. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_runner.py +0 -0
  346. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ci_workflow.py +0 -0
  347. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_circuit_breaker.py +0 -0
  348. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_claude_md_merge.py +0 -0
  349. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_claude_md_updater.py +0 -0
  350. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cli_smoke.py +0 -0
  351. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_codex_mcp_transport.py +0 -0
  352. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_codex_native.py +0 -0
  353. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_compressor_large_file.py +0 -0
  354. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_confirm_guard.py +0 -0
  355. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_confirm_guard_wiring.py +0 -0
  356. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cooccurrence_bounds.py +0 -0
  357. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cred_audit.py +0 -0
  358. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_cred_telemetry.py +0 -0
  359. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credential_login_kind.py +0 -0
  360. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credential_store.py +0 -0
  361. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credential_ui_parity.py +0 -0
  362. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credentials_routes.py +0 -0
  363. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_credentials_tool.py +0 -0
  364. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_creds_cli_smoke.py +0 -0
  365. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_delegate_cascade.py +0 -0
  366. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_delegate_version_probe.py +0 -0
  367. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_dir_map_c3.py +0 -0
  368. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_e2e_benchmark.py +0 -0
  369. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_ledger_deadline.py +0 -0
  370. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_ledger_hook.py +0 -0
  371. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_locking.py +0 -0
  372. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_normalization.py +0 -0
  373. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_edit_verify.py +0 -0
  374. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_embedding_index_deadlock.py +0 -0
  375. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_enforcement_flip.py +0 -0
  376. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_enforcement_policy.py +0 -0
  377. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_enforcement_routes.py +0 -0
  378. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_env_parser.py +0 -0
  379. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_failed_calls_do_not_unlock.py +0 -0
  380. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_federated_graph.py +0 -0
  381. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_file_map_c1.py +0 -0
  382. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_filter_backoff.py +0 -0
  383. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ghost_files.py +0 -0
  384. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ghost_generation.py +0 -0
  385. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_git_branch_awareness.py +0 -0
  386. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_access_guard.py +0 -0
  387. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_pretool_enforce.py +0 -0
  388. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_prompt_recall.py +0 -0
  389. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_smoke.py +0 -0
  390. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_state.py +0 -0
  391. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hook_utf8_stdio.py +0 -0
  392. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_credentials_route.py +0 -0
  393. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_credentials_routes_write.py +0 -0
  394. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_enforcement_routes.py +0 -0
  395. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_inspect_api.py +0 -0
  396. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_locks_routes.py +0 -0
  397. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_oracle_service_routes.py +0 -0
  398. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_override_routes.py +0 -0
  399. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_server_smoke.py +0 -0
  400. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_hub_subproject_links.py +0 -0
  401. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ide_workflow_adaptation.py +0 -0
  402. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_index_cap_not_hardcoded.py +0 -0
  403. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_init_clear_preserves_user_content.py +0 -0
  404. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_init_scan.py +0 -0
  405. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_install_mcp_entrypoint.py +0 -0
  406. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_cli_smoke.py +0 -0
  407. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_client.py +0 -0
  408. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_config_fallback.py +0 -0
  409. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_credentials.py +0 -0
  410. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_links.py +0 -0
  411. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_routes.py +0 -0
  412. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_jira_tool.py +0 -0
  413. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_large_files_c4.py +0 -0
  414. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_lazy_store_init.py +0 -0
  415. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_map_eval.py +0 -0
  416. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_map_telemetry_c0.py +0 -0
  417. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mask_guard.py +0 -0
  418. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mask_routes.py +0 -0
  419. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mask_surfaces.py +0 -0
  420. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_host_guard.py +0 -0
  421. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_memory_timeout.py +0 -0
  422. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_server_smoke.py +0 -0
  423. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mcp_toml.py +0 -0
  424. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_distiller.py +0 -0
  425. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_graph_api.py +0 -0
  426. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_queue.py +0 -0
  427. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_memory_system.py +0 -0
  428. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_mobile_security_api.py +0 -0
  429. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_no_stale_model_pins.py +0 -0
  430. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_notification_dedup.py +0 -0
  431. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_notification_discipline.py +0 -0
  432. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ollama_credentials.py +0 -0
  433. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_api_auth.py +0 -0
  434. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_apikey_api.py +0 -0
  435. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_c3_bridge.py +0 -0
  436. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_chat_engine.py +0 -0
  437. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_chat_store.py +0 -0
  438. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_discovery_api.py +0 -0
  439. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_discovery_audit.py +0 -0
  440. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_health_probe.py +0 -0
  441. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_local_auth.py +0 -0
  442. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_ollama_bridge.py +0 -0
  443. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_scanner_cache.py +0 -0
  444. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_security_fixes.py +0 -0
  445. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_session_bootstrap.py +0 -0
  446. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_subproject_awareness.py +0 -0
  447. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_oracle_ui_bundle.py +0 -0
  448. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_output_filter.py +0 -0
  449. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_grants.py +0 -0
  450. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_grants_mcp.py +0 -0
  451. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_requests.py +0 -0
  452. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_override_wake.py +0 -0
  453. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_permissions.py +0 -0
  454. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_pm_api.py +0 -0
  455. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_project_manager.py +0 -0
  456. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_project_manager_merge.py +0 -0
  457. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_project_tool.py +0 -0
  458. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_read_coercion.py +0 -0
  459. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_read_edit_parity.py +0 -0
  460. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_related_facts.py +0 -0
  461. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_repo_map.py +0 -0
  462. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_repo_shape.py +0 -0
  463. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_response_boilerplate.py +0 -0
  464. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_retention.py +0 -0
  465. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_review_digest.py +0 -0
  466. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_eval.py +0 -0
  467. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p1.py +0 -0
  468. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p2.py +0 -0
  469. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p2b.py +0 -0
  470. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p3.py +0 -0
  471. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p4.py +0 -0
  472. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_search_p5.py +0 -0
  473. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_service_durability.py +0 -0
  474. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_session_benchmark.py +0 -0
  475. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_session_budget.py +0 -0
  476. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_budget_s1.py +0 -0
  477. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_creds.py +0 -0
  478. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_eval.py +0 -0
  479. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_nudge_s4.py +0 -0
  480. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_output.py +0 -0
  481. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_parsers_s2.py +0 -0
  482. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_robustness.py +0 -0
  483. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_telemetry_s0.py +0 -0
  484. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_write_ledger.py +0 -0
  485. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_shell_writes.py +0 -0
  486. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_clear_scope.py +0 -0
  487. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_depth_consumers.py +0 -0
  488. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_exclusion.py +0 -0
  489. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_federation.py +0 -0
  490. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subproject_linkage_api.py +0 -0
  491. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_subprojects.py +0 -0
  492. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_swe_bench.py +0 -0
  493. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_task_store.py +0 -0
  494. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_task_tool.py +0 -0
  495. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_time_tracker.py +0 -0
  496. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_token_telemetry.py +0 -0
  497. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_token_tracking.py +0 -0
  498. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_tool_registry.py +0 -0
  499. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_ui_jsx_syntax.py +0 -0
  500. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_upgrade_and_version.py +0 -0
  501. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_validate.py +0 -0
  502. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_vault_write_guard.py +0 -0
  503. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_version_sync.py +0 -0
  504. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_web_security.py +0 -0
  505. {code_context_control-2.124.0 → code_context_control-2.126.1}/tests/test_windows_reliability.py +0 -0
  506. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/__init__.py +0 -0
  507. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/backend.py +0 -0
  508. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/main.py +0 -0
  509. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/__init__.py +0 -0
  510. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/benchmark_view.py +0 -0
  511. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/claudemd_view.py +0 -0
  512. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/compress_view.py +0 -0
  513. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/index_view.py +0 -0
  514. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/init_view.py +0 -0
  515. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/mcp_view.py +0 -0
  516. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/optimize_view.py +0 -0
  517. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/pipe_view.py +0 -0
  518. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/projects_view.py +0 -0
  519. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/search_view.py +0 -0
  520. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/session_view.py +0 -0
  521. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/stats.py +0 -0
  522. {code_context_control-2.124.0 → code_context_control-2.126.1}/tui/screens/ui_view.py +0 -0
  523. {code_context_control-2.124.0 → code_context_control-2.126.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.124.0
3
+ Version: 2.126.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
@@ -380,7 +380,7 @@ C3 also records real per-tool usage to `.c3/tool_telemetry.jsonl`, so estimates
380
380
  ## Security & privacy
381
381
 
382
382
  - **All web servers bind `127.0.0.1` by default** and are guarded against browser-based attacks even on loopback — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface is opt-in and warned at startup. *(Hardening added in v2.33.0.)*
383
- - **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires the **Discovery Bearer token on every method, GETs included**, validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (QR code carrying URL + token). Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
383
+ - **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires a **Bearer token on every method, GETs included** — the Discovery token, or (v2.125.0+) a **per-client token**: one credential per paired device, stored hashed in `~/.c3/oracle/clients.json`, revocable one at a time, and carrying a kind (`mobile` or `desk`) that override decisions are audited under. It validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (the QR carries the URL and a freshly minted per-device token; a legacy Discovery-token code is one button away). A same-machine client such as C3 Desk pairs itself with `POST /api/mobile/clients` and the owner-only `~/.c3/oracle/bootstrap.key`. Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`; with such a bind the Oracle also listens on `127.0.0.1` (`loopback_listener`, default on) so local clients are not refused. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
384
384
  - **The mobile gateway never returns a credential value.** It has no reveal route by design: entries cross the wire through an allowlist serializer, and a value can only be identified by its length and an on-demand fingerprint. Two further levers ship **off** — `mobile_creds_agent_readable_raise` (raising `agent_readable` from the phone) and `mobile_access_global_scope` (machine-wide access rules) — because each exceeds what a leaked Bearer token could otherwise reach. Deliberately absent from the surface: bulk `.env` import, denial-counter clearing, `set_builtin_disabled`, and the raw-content access preview.
385
385
  - **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`; even then request bodies, local variables, and prompts are stripped.
386
386
  - **LLM memory distillation is local-first.** Cloud distillation (v2.51.0) is off by default and opt-in per project.
@@ -314,7 +314,7 @@ C3 also records real per-tool usage to `.c3/tool_telemetry.jsonl`, so estimates
314
314
  ## Security & privacy
315
315
 
316
316
  - **All web servers bind `127.0.0.1` by default** and are guarded against browser-based attacks even on loopback — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface is opt-in and warned at startup. *(Hardening added in v2.33.0.)*
317
- - **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires the **Discovery Bearer token on every method, GETs included**, validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (QR code carrying URL + token). Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
317
+ - **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires a **Bearer token on every method, GETs included** — the Discovery token, or (v2.125.0+) a **per-client token**: one credential per paired device, stored hashed in `~/.c3/oracle/clients.json`, revocable one at a time, and carrying a kind (`mobile` or `desk`) that override decisions are audited under. It validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (the QR carries the URL and a freshly minted per-device token; a legacy Discovery-token code is one button away). A same-machine client such as C3 Desk pairs itself with `POST /api/mobile/clients` and the owner-only `~/.c3/oracle/bootstrap.key`. Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`; with such a bind the Oracle also listens on `127.0.0.1` (`loopback_listener`, default on) so local clients are not refused. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
318
318
  - **The mobile gateway never returns a credential value.** It has no reveal route by design: entries cross the wire through an allowlist serializer, and a value can only be identified by its length and an on-demand fingerprint. Two further levers ship **off** — `mobile_creds_agent_readable_raise` (raising `agent_readable` from the phone) and `mobile_access_global_scope` (machine-wide access rules) — because each exceeds what a leaked Bearer token could otherwise reach. Deliberately absent from the surface: bulk `.env` import, denial-counter clearing, `set_builtin_disabled`, and the raw-content access preview.
319
319
  - **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`; even then request bodies, local variables, and prompts are stripped.
320
320
  - **LLM memory distillation is local-first.** Cloud distillation (v2.51.0) is off by default and opt-in per project.
@@ -500,6 +500,40 @@ def record_json_unlocks(
500
500
  pass
501
501
 
502
502
 
503
+ _PROJECT_WALK_UP_LEVELS = 4
504
+
505
+
506
+ def find_project(payload: dict, project_path=None) -> Path | None:
507
+ """The nearest ancestor (≤ 4 levels) of ``project_path`` / ``payload.cwd``
508
+ that owns a ``.c3`` directory, or None.
509
+
510
+ Claude Code runs hooks from the project root, Codex passes ``--project``;
511
+ either way the payload's ``cwd`` may be a subdirectory (a session opened
512
+ in ``src/``). The walk is lexical on purpose — no path canonicalisation
513
+ happens here (see tests/test_access_guard_meta.py).
514
+ """
515
+ candidates = []
516
+ if project_path:
517
+ candidates.append(Path(str(project_path)))
518
+ cwd = payload.get("cwd") if isinstance(payload, dict) else None
519
+ if cwd:
520
+ candidates.append(Path(str(cwd)))
521
+ if not candidates:
522
+ candidates.append(Path.cwd())
523
+ for base in candidates:
524
+ node = base
525
+ for _ in range(_PROJECT_WALK_UP_LEVELS):
526
+ try:
527
+ if (node / ".c3").is_dir():
528
+ return node
529
+ except OSError:
530
+ break
531
+ if node.parent == node:
532
+ break
533
+ node = node.parent
534
+ return None
535
+
536
+
503
537
  def emit_additional_context(text: str, is_gemini: bool) -> None:
504
538
  """Write additionalContext JSON to stdout in the correct format for the IDE."""
505
539
  if is_gemini:
@@ -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.124.0"
95
+ __version__ = "2.126.1"
96
96
 
97
97
 
98
98
  def _compress_file_cli(compressor, path, mode="smart", **kw):
@@ -5558,6 +5558,8 @@ def cmd_install_mcp(args):
5558
5558
  hook_posttool_cmd = f"{_dispatch_base} posttool"
5559
5559
  hook_stop_cmd = f"{_dispatch_base} stop"
5560
5560
  hook_prompt_cmd = f"{_dispatch_base} prompt"
5561
+ hook_start_cmd = f"{_dispatch_base} start"
5562
+ hook_end_cmd = f"{_dispatch_base} end"
5561
5563
 
5562
5564
  shell_matcher = "Bash"
5563
5565
  read_matcher = "Read"
@@ -5696,6 +5698,25 @@ def cmd_install_mcp(args):
5696
5698
  )
5697
5699
  settings.setdefault("hooks", {})[prompt_event] = existing_prompt
5698
5700
 
5701
+ # ── SessionStart / SessionEnd hooks (v2.126.0: session_open /
5702
+ # session_end activity rows + `session` notifications, the join key
5703
+ # a desktop client needs). Same merge discipline: replace only C3's
5704
+ # own dispatcher entries, keep user-added ones. SessionStart's
5705
+ # matcher is the payload `source` (startup|resume|clear|compact);
5706
+ # empty matches all — the hook itself ignores `compact`.
5707
+ for _lifecycle_event, _lifecycle_cmd in (
5708
+ ("SessionStart", hook_start_cmd),
5709
+ ("SessionEnd", hook_end_cmd),
5710
+ ):
5711
+ _kept = [
5712
+ h for h in settings.get("hooks", {}).get(_lifecycle_event, [])
5713
+ if not _is_c3_prompt_hook(h)
5714
+ ]
5715
+ _kept.append(
5716
+ {"matcher": "", "hooks": [{"type": "command", "command": _lifecycle_cmd}]}
5717
+ )
5718
+ settings.setdefault("hooks", {})[_lifecycle_event] = _kept
5719
+
5699
5720
  # Claude Code only: enable MCP server prompt settings
5700
5721
  if profile.name == "claude-code":
5701
5722
  settings["enableAllProjectMcpServers"] = True
@@ -5742,6 +5763,7 @@ def cmd_install_mcp(args):
5742
5763
  print(f" Hooks ({hook_event}): dispatcher (1 spawn/event) — filter/ghost/read-guard/ledger/unlock/signal via cli/hook_dispatch.py posttool")
5743
5764
  print(f" Hooks ({pre_event}): dispatcher — {read_matcher}/{grep_matcher}/{glob_matcher}/{edit_matcher}/{write_matcher} (c3 enforcement)")
5744
5765
  print(" Hooks (Stop): dispatcher — session_stats + auto_snapshot + terse_advisor")
5766
+ print(" Hooks (SessionStart/SessionEnd): dispatcher — session_open / session_end rows + session notifications")
5745
5767
  if profile.name == "claude-code":
5746
5768
  print(" Claude MCP prompt settings enabled for this project")
5747
5769
  if perm_tier and profile.name == "claude-code":
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  """Per-event hook dispatcher: ONE process per Claude Code / Gemini hook event.
3
3
 
4
- Usage: python hook_dispatch.py <pretool|posttool|stop|prompt>
4
+ Usage: python hook_dispatch.py <pretool|posttool|stop|prompt|start|compact|end>
5
5
 
6
6
  Before v2.42 every hook was registered as its own "cmd /c python <hook>.py"
7
7
  subprocess, so a single native Read fired up to three interpreter spawns
@@ -167,8 +167,17 @@ def _routes(event: str, raw_tool: str, norm_tool: str, host: str = HOST_CLAUDE):
167
167
  yield "hook_terse_advisor"
168
168
  elif event == "prompt":
169
169
  yield "hook_prompt_recall"
170
- elif event in ("start", "compact", "end") and host == HOST_CODEX:
171
- yield "hook_codex_lifecycle"
170
+ elif event in ("start", "compact", "end"):
171
+ # Codex's thread-bound handoff runs first (it may return context on
172
+ # SessionStart); the session bookkeeping below is host-agnostic and
173
+ # returns nothing (v2.126.0: session_open / session_end rows + the
174
+ # `session` notifications a desktop client wakes on).
175
+ if host == HOST_CODEX:
176
+ yield "hook_codex_lifecycle"
177
+ if event == "start":
178
+ yield "hook_session_open"
179
+ elif event == "end":
180
+ yield "hook_session_end"
172
181
 
173
182
 
174
183
  _RUN_CACHE: dict = {}
@@ -0,0 +1,103 @@
1
+ """SessionEnd hook: record that a host session ended (D0b, v2.126.0).
2
+
3
+ Claude Code's ``SessionEnd`` event delivers on stdin::
4
+
5
+ {
6
+ "session_id": "<Claude Code UUID>",
7
+ "transcript_path": "...",
8
+ "cwd": "...",
9
+ "hook_event_name": "SessionEnd",
10
+ "reason": "clear" | "logout" | "prompt_input_exit" | "other"
11
+ }
12
+
13
+ Codex's ``SessionEnd`` carries its thread id in the same ``session_id``
14
+ field; the dispatcher routes both here (``hook_dispatch._routes``, event
15
+ ``end``).
16
+
17
+ Why this exists: this repo's activity log held 525 ``session_start`` rows
18
+ and 14 ``session_save`` rows — ``session_save`` is only written when a human
19
+ ends a session from the hub, so for a client the end of a conversation was
20
+ invisible. Two records fix that:
21
+
22
+ - ``{type: "session_end", session_id: <C3 id if known>, host_session_id,
23
+ reason, source}`` appended to ``.c3/activity_log.jsonl``. The C3 id comes
24
+ from the link file the MCP server wrote at session start
25
+ (``services.host_sessions``); it is ``""`` when the server never learned
26
+ the host id.
27
+ - a ``session`` notification (``kind="session"``, ``ref_id=host id``,
28
+ severity ``info``, title ``Session ended <short id>``) in
29
+ ``.c3/notifications.jsonl`` — the write that wakes a ``/feed?wait=``
30
+ client.
31
+
32
+ Runs in a short-lived subprocess with a few seconds of budget; every step is
33
+ best-effort and nothing here can fail the session that is already ending.
34
+ """
35
+ from __future__ import annotations
36
+
37
+ import sys
38
+ from pathlib import Path
39
+
40
+ sys.path.insert(0, str(Path(__file__).parent.parent))
41
+
42
+ from cli._hook_utils import detect_host, find_project, log_hook_error # noqa: E402
43
+
44
+ SHORT_ID_CHARS = 8
45
+
46
+
47
+ def short_id(session_id: str) -> str:
48
+ return str(session_id or "")[:SHORT_ID_CHARS] or "?"
49
+
50
+
51
+ def run(payload: dict, project_path: Path | None = None):
52
+ """Core logic — importable by the dispatcher and tests. Returns None."""
53
+ project = find_project(payload, project_path)
54
+ if project is None:
55
+ return None
56
+ host = detect_host(payload)
57
+ host_sid = str(payload.get("session_id") or "").strip()
58
+ reason = str(payload.get("reason") or "").strip()
59
+ c3_sid = ""
60
+ try:
61
+ from services.host_sessions import linked_c3_session_id
62
+ c3_sid = linked_c3_session_id(project, host, host_sid)
63
+ except Exception:
64
+ c3_sid = ""
65
+ try:
66
+ from services.activity_log import ActivityLog
67
+ ActivityLog(str(project)).log("session_end", {
68
+ "session_id": c3_sid,
69
+ "host_session_id": host_sid,
70
+ "reason": reason,
71
+ "source": host,
72
+ })
73
+ except Exception as exc:
74
+ log_hook_error("hook_session_end", exc)
75
+ try:
76
+ from services.notifications import notify
77
+ notify(project, agent="session", severity="info",
78
+ title=f"Session ended {short_id(host_sid)}",
79
+ message=(f"{host} session {host_sid or '?'} ended"
80
+ + (f" ({reason})" if reason else "")
81
+ + (f"; C3 session {c3_sid}" if c3_sid else "")),
82
+ kind="session", ref_id=host_sid)
83
+ except Exception:
84
+ pass
85
+ return None
86
+
87
+
88
+ def main() -> None:
89
+ import json
90
+ try:
91
+ data = json.load(sys.stdin)
92
+ except Exception as exc:
93
+ log_hook_error("hook_session_end", exc)
94
+ sys.exit(0)
95
+ try:
96
+ run(data)
97
+ except Exception as exc:
98
+ log_hook_error("hook_session_end", exc)
99
+ sys.exit(0)
100
+
101
+
102
+ if __name__ == "__main__":
103
+ main()
@@ -0,0 +1,97 @@
1
+ """SessionStart hook: record that a host session opened (D0b, v2.126.0).
2
+
3
+ Claude Code's ``SessionStart`` event delivers on stdin::
4
+
5
+ {
6
+ "session_id": "<Claude Code UUID>",
7
+ "transcript_path": "...",
8
+ "cwd": "...",
9
+ "hook_event_name": "SessionStart",
10
+ "source": "startup" | "resume" | "clear" | "compact"
11
+ }
12
+
13
+ Codex's ``SessionStart`` carries its thread id in the same ``session_id``
14
+ field and no ``source``; the dispatcher routes both here (event ``start``).
15
+
16
+ Records:
17
+
18
+ - ``{type: "session_open", host_session_id, source: <host>, start_source}``
19
+ in ``.c3/activity_log.jsonl``. ``source`` is the HOST (``claude`` /
20
+ ``codex`` / ``gemini``), matching ``session_end``; the payload's own
21
+ ``source`` (startup / resume / clear) is kept as ``start_source``.
22
+ - a ``session`` notification (``kind="session"``, ``ref_id=host id``,
23
+ ``info``, title ``Session started <short id>``).
24
+
25
+ ``source: "compact"`` writes NOTHING: a compaction is the same session and
26
+ the same MCP process, and a "Session started" toast on every compaction
27
+ would teach the user to ignore the real ones.
28
+
29
+ The MCP server's own ``session_start`` row is untouched — it carries the C3
30
+ id and, when the host put its id in the environment, ``host_session_id``
31
+ too. This hook is what lets a client see the session before the runtime has
32
+ finished starting (~seconds), and it is the row the desktop's "MCP failed to
33
+ connect" sentinel starts its 30 s clock from.
34
+
35
+ Returns None always: SessionStart hook stdout becomes model context, and
36
+ this hook has nothing to tell the model.
37
+ """
38
+ from __future__ import annotations
39
+
40
+ import sys
41
+ from pathlib import Path
42
+
43
+ sys.path.insert(0, str(Path(__file__).parent.parent))
44
+
45
+ from cli._hook_utils import detect_host, find_project, log_hook_error # noqa: E402
46
+ from cli.hook_session_end import short_id # noqa: E402
47
+
48
+ _SILENT_SOURCES = {"compact"}
49
+
50
+
51
+ def run(payload: dict, project_path: Path | None = None):
52
+ """Core logic — importable by the dispatcher and tests. Returns None."""
53
+ start_source = str(payload.get("source") or "").strip().lower()
54
+ if start_source in _SILENT_SOURCES:
55
+ return None
56
+ project = find_project(payload, project_path)
57
+ if project is None:
58
+ return None
59
+ host = detect_host(payload)
60
+ host_sid = str(payload.get("session_id") or "").strip()
61
+ try:
62
+ from services.activity_log import ActivityLog
63
+ ActivityLog(str(project)).log("session_open", {
64
+ "host_session_id": host_sid,
65
+ "source": host,
66
+ "start_source": start_source,
67
+ })
68
+ except Exception as exc:
69
+ log_hook_error("hook_session_open", exc)
70
+ try:
71
+ from services.notifications import notify
72
+ notify(project, agent="session", severity="info",
73
+ title=f"Session started {short_id(host_sid)}",
74
+ message=(f"{host} session {host_sid or '?'} started"
75
+ + (f" ({start_source})" if start_source else "")),
76
+ kind="session", ref_id=host_sid)
77
+ except Exception:
78
+ pass
79
+ return None
80
+
81
+
82
+ def main() -> None:
83
+ import json
84
+ try:
85
+ data = json.load(sys.stdin)
86
+ except Exception as exc:
87
+ log_hook_error("hook_session_open", exc)
88
+ sys.exit(0)
89
+ try:
90
+ run(data)
91
+ except Exception as exc:
92
+ log_hook_error("hook_session_open", exc)
93
+ sys.exit(0)
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()
@@ -100,6 +100,92 @@ def _build_instructions(ide_name: str) -> str:
100
100
  )
101
101
 
102
102
 
103
+ # ── Host session id (the join key between hook rows and MCP rows) ──────────
104
+ # The PreToolUse hooks write .c3/enforcement_state.json with `session_id` =
105
+ # the host's id for the session that just called. When the host also put its
106
+ # id in this process's environment (CLAUDE_CODE_SESSION_ID / CODEX_THREAD_ID)
107
+ # the SessionManager already carries it and no file is read. Otherwise the
108
+ # state file is consulted at most once per _HOST_SID_TTL_S — a tool call is
109
+ # far hotter than that, and a per-call read would be a stat+parse on every
110
+ # c3_* invocation for a value that changes once per session.
111
+ _HOST_SID_TTL_S = 5.0
112
+ _host_sid_cache = {"value": "", "read_at": 0.0, "linked": ""}
113
+ _host_sid_lock = threading.Lock()
114
+
115
+
116
+ def _host_session_id(svc) -> str:
117
+ """The host session id for this process, or ``""`` when nobody knows it."""
118
+ try:
119
+ session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
120
+ env_sid = str(session.get("host_session_id") or "").strip()
121
+ except Exception:
122
+ env_sid = ""
123
+ if env_sid:
124
+ _link_host_session(svc, env_sid)
125
+ return env_sid
126
+ now = time.monotonic()
127
+ with _host_sid_lock:
128
+ if now - _host_sid_cache["read_at"] < _HOST_SID_TTL_S:
129
+ return _host_sid_cache["value"]
130
+ _host_sid_cache["read_at"] = now
131
+ value = ""
132
+ try:
133
+ import json as _json
134
+
135
+ from cli._hook_utils import ENFORCEMENT_STATE_FILE
136
+ state_path = Path(svc.project_path) / ENFORCEMENT_STATE_FILE
137
+ if state_path.is_file():
138
+ data = _json.loads(state_path.read_text(encoding="utf-8"))
139
+ if isinstance(data, dict):
140
+ value = str(data.get("session_id") or "").strip()
141
+ except Exception:
142
+ value = ""
143
+ with _host_sid_lock:
144
+ _host_sid_cache["value"] = value
145
+ if value:
146
+ _link_host_session(svc, value)
147
+ return value
148
+
149
+
150
+ def _link_host_session(svc, host_sid: str) -> None:
151
+ """Write the host→C3 link file once per distinct host id (services.host_sessions)."""
152
+ with _host_sid_lock:
153
+ if _host_sid_cache["linked"] == host_sid:
154
+ return
155
+ _host_sid_cache["linked"] = host_sid
156
+ try:
157
+ session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
158
+ c3_id = str(session.get("id") or "")
159
+ if c3_id:
160
+ from services.host_sessions import write_link
161
+ write_link(svc.project_path, getattr(svc, "ide_name", "") or _IDE_NAME, host_sid, c3_id)
162
+ except Exception:
163
+ pass
164
+
165
+
166
+ def _notify_mcp_ready(svc) -> None:
167
+ """``kind="mcp"`` / ``C3 connected`` — the runtime is ready to serve (D0b).
168
+
169
+ ref_id is the C3 session id, the same value ``session_start`` carries;
170
+ the host id rides in the message when known. Best-effort: a notification
171
+ failure must never keep the server from serving.
172
+ """
173
+ try:
174
+ session = getattr(getattr(svc, "session_mgr", None), "current_session", None) or {}
175
+ c3_id = str(session.get("id") or "")
176
+ host_sid = _host_session_id(svc)
177
+ short = (host_sid or c3_id)[:8] or "?"
178
+ from services.notifications import notify
179
+ notify(svc.project_path, agent="c3", severity="info",
180
+ title=f"C3 connected {short}",
181
+ message=(f"C3 {C3_VERSION} MCP runtime ready for {_IDE_NAME}"
182
+ f" (session {c3_id}"
183
+ + (f", host {host_sid}" if host_sid else "") + ")"),
184
+ kind="mcp", ref_id=c3_id)
185
+ except Exception:
186
+ pass
187
+
188
+
103
189
  @asynccontextmanager
104
190
  async def lifespan(server):
105
191
  """Initialize all services, auto-start session, start file watcher."""
@@ -223,9 +309,16 @@ async def lifespan(server):
223
309
  services.auto_memory = AutoMemory(services.memory, services.session_mgr, auto_mem_cfg)
224
310
 
225
311
  if services.session_mgr.current_session:
312
+ # host_session_id (the Claude Code UUID / Codex thread id) joins this
313
+ # row to the hooks' session_open / session_end rows, which only know
314
+ # the host id. Absent when the host did not put its id in the
315
+ # environment; the link file below is written lazily in that case
316
+ # the first time a hook reveals it (see _host_session_id).
317
+ _host_sid = _host_session_id(services)
226
318
  services.activity_log.log("session_start", {
227
319
  "session_id": services.session_mgr.current_session["id"],
228
320
  "source_system": started_session.get("source_system", ""),
321
+ **({"host_session_id": _host_sid} if _host_sid else {}),
229
322
  })
230
323
 
231
324
  # Auto-restore latest snapshot if recent (< 30 min).
@@ -288,6 +381,12 @@ async def lifespan(server):
288
381
  )
289
382
  _t.Thread(target=_bg_validation_sweep, daemon=True, name="c3-validate-sweep").start()
290
383
 
384
+ # Runtime is ready to serve: say so where a client can hear it. A desktop
385
+ # "MCP failed to connect" sentinel keys on a session_open with no `mcp`
386
+ # notification within 30 s, so this must be the LAST thing before the
387
+ # handshake proceeds and must never be skipped on a partial init.
388
+ _notify_mcp_ready(services)
389
+
291
390
  try:
292
391
  yield services
293
392
  finally:
@@ -430,8 +529,22 @@ def _finalize_response(ctx: Context, tool_name: str, args: dict,
430
529
  call_ok = not _failed(response)
431
530
  except Exception:
432
531
  call_ok = True
532
+ # Both session ids on every tool_call row (D0b): C3's own id joins the
533
+ # row to session_start / the saved session file, the host id joins it to
534
+ # the hooks' session_open / session_end rows. Either may be absent.
535
+ _ids: dict = {}
536
+ try:
537
+ _c3_sid = str((svc.session_mgr.current_session or {}).get("id") or "")
538
+ if _c3_sid:
539
+ _ids["session_id"] = _c3_sid
540
+ _host_sid = _host_session_id(svc)
541
+ if _host_sid:
542
+ _ids["host_session_id"] = _host_sid
543
+ except Exception:
544
+ pass
433
545
  svc.activity_log.log("tool_call", {"tool": tool_name, "args": args,
434
- "result_summary": summary, "ok": call_ok})
546
+ "result_summary": summary, "ok": call_ok,
547
+ **_ids})
435
548
  tracker = getattr(svc, "time_tracker", None)
436
549
  if tracker is not None:
437
550
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.124.0
3
+ Version: 2.126.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
@@ -380,7 +380,7 @@ C3 also records real per-tool usage to `.c3/tool_telemetry.jsonl`, so estimates
380
380
  ## Security & privacy
381
381
 
382
382
  - **All web servers bind `127.0.0.1` by default** and are guarded against browser-based attacks even on loopback — a Host-header allowlist (defeats DNS rebinding) plus an Origin/Referer check on every request (defeats cross-origin CSRF), with scoped, non-wildcard CORS. There is still **no user authentication**, so do not expose these servers to an untrusted network without auth/TLS in front. Binding to a non-loopback interface is opt-in and warned at startup. *(Hardening added in v2.33.0.)*
383
- - **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires the **Discovery Bearer token on every method, GETs included**, validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (QR code carrying URL + token). Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
383
+ - **Mobile gateway (`/api/mobile/*`)** — the Oracle exposes a companion-app surface for the C3 mobile app: merged cross-project feed, project overview, PM board read/write, digest, notification ack, plus the security surface (credential vault, Access Guard rules and masks, tool discipline). Unlike the legacy Oracle GETs it requires a **Bearer token on every method, GETs included** — the Discovery token, or (v2.125.0+) a **per-client token**: one credential per paired device, stored hashed in `~/.c3/oracle/clients.json`, revocable one at a time, and carrying a kind (`mobile` or `desk`) that override decisions are audited under. It validates every project path against the registry, and audits every write to the project's activity log and edit ledger. Pair the app from Oracle Settings → *Mobile app* (the QR carries the URL and a freshly minted per-device token; a legacy Discovery-token code is one button away). A same-machine client such as C3 Desk pairs itself with `POST /api/mobile/clients` and the owner-only `~/.c3/oracle/bootstrap.key`. Remote reachability is the same recipe as the Discovery API: set `bind_host` to the Tailscale/LAN interface IP (avoid `0.0.0.0`) and list that address in `allowed_hosts`, both in `~/.c3/oracle/config.json`; with such a bind the Oracle also listens on `127.0.0.1` (`loopback_listener`, default on) so local clients are not refused. Disable the whole surface with `"mobile_api_enabled": false`, or any subsystem with `mobile_credentials_enabled` / `mobile_access_enabled` / their `_write` twins.
384
384
  - **The mobile gateway never returns a credential value.** It has no reveal route by design: entries cross the wire through an allowlist serializer, and a value can only be identified by its length and an on-demand fingerprint. Two further levers ship **off** — `mobile_creds_agent_readable_raise` (raising `agent_readable` from the phone) and `mobile_access_global_scope` (machine-wide access rules) — because each exceeds what a leaked Bearer token could otherwise reach. Deliberately absent from the surface: bulk `.env` import, denial-counter clearing, `set_builtin_disabled`, and the raw-content access preview.
385
385
  - **No telemetry by default.** The OSS package collects nothing. Opt-in Sentry crash reporting requires the `[telemetry]` extra plus both `SENTRY_DSN` and `C3_TELEMETRY_OPT_IN=1`; even then request bodies, local variables, and prompts are stripped.
386
386
  - **LLM memory distillation is local-first.** Cloud distillation (v2.51.0) is off by default and opt-in per project.
@@ -21,6 +21,8 @@ cli/hook_ghost_files.py
21
21
  cli/hook_pretool_enforce.py
22
22
  cli/hook_prompt_recall.py
23
23
  cli/hook_read.py
24
+ cli/hook_session_end.py
25
+ cli/hook_session_open.py
24
26
  cli/hook_session_stats.py
25
27
  cli/hook_terse_advisor.py
26
28
  cli/hub_server.py
@@ -141,6 +143,7 @@ core/mcp_toml.py
141
143
  core/web_security.py
142
144
  oracle/__init__.py
143
145
  oracle/config.py
146
+ oracle/listeners.py
144
147
  oracle/mcp_oracle.py
145
148
  oracle/oracle_server.py
146
149
  oracle/oracle_ui.html
@@ -151,6 +154,7 @@ oracle/services/c3_bridge.py
151
154
  oracle/services/chat_engine.py
152
155
  oracle/services/chat_poll.py
153
156
  oracle/services/chat_store.py
157
+ oracle/services/client_tokens.py
154
158
  oracle/services/cross_memory.py
155
159
  oracle/services/discovery_audit.py
156
160
  oracle/services/federated_graph.py
@@ -229,6 +233,7 @@ services/error_reporting.py
229
233
  services/file_map.py
230
234
  services/file_memory.py
231
235
  services/git_context.py
236
+ services/host_sessions.py
232
237
  services/hub_service.py
233
238
  services/index_store.py
234
239
  services/indexer.py
@@ -370,6 +375,7 @@ tests/test_hook_codex_compat.py
370
375
  tests/test_hook_dispatch.py
371
376
  tests/test_hook_pretool_enforce.py
372
377
  tests/test_hook_prompt_recall.py
378
+ tests/test_hook_session_end.py
373
379
  tests/test_hook_smoke.py
374
380
  tests/test_hook_state.py
375
381
  tests/test_hook_utf8_stdio.py
@@ -410,12 +416,15 @@ tests/test_memory_graph_api.py
410
416
  tests/test_memory_queue.py
411
417
  tests/test_memory_system.py
412
418
  tests/test_mobile_api.py
419
+ tests/test_mobile_clients.py
413
420
  tests/test_mobile_extras.py
421
+ tests/test_mobile_jobs_ci.py
414
422
  tests/test_mobile_override_routes.py
415
423
  tests/test_mobile_security_api.py
416
424
  tests/test_no_stale_model_pins.py
417
425
  tests/test_notification_dedup.py
418
426
  tests/test_notification_discipline.py
427
+ tests/test_notification_kinds.py
419
428
  tests/test_ollama_credentials.py
420
429
  tests/test_oracle_api_auth.py
421
430
  tests/test_oracle_apikey_api.py
@@ -426,6 +435,7 @@ tests/test_oracle_discovery_api.py
426
435
  tests/test_oracle_discovery_audit.py
427
436
  tests/test_oracle_health_probe.py
428
437
  tests/test_oracle_local_auth.py
438
+ tests/test_oracle_loopback.py
429
439
  tests/test_oracle_ollama_bridge.py
430
440
  tests/test_oracle_scanner_cache.py
431
441
  tests/test_oracle_security_fixes.py
@@ -11,6 +11,11 @@ DEFAULTS = {
11
11
  "port": 3331,
12
12
  # ── Discovery API (external LLM tool surface, v2.32.0) ──
13
13
  "bind_host": "127.0.0.1", # loopback only by default (was 0.0.0.0)
14
+ # When bind_host is a specific non-loopback address (a Tailscale / LAN
15
+ # IP), ALSO serve the same app on 127.0.0.1 so same-machine clients (the
16
+ # desk tray client, `c3 oracle open`, curl) are not refused. No effect on
17
+ # a loopback or wildcard bind. See oracle/listeners.py.
18
+ "loopback_listener": True,
14
19
  "api_enabled": True, # expose /api/discovery/* REST surface
15
20
  "api_require_auth": True, # require Bearer token on /api/discovery/*
16
21
  "api_max_tier": "action", # cap exposed tools: "read" | "action"