code-context-control 2.30.0__tar.gz → 2.32.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 (196) hide show
  1. {code_context_control-2.30.0/code_context_control.egg-info → code_context_control-2.32.1}/PKG-INFO +4 -3
  2. {code_context_control-2.30.0 → code_context_control-2.32.1}/README.md +3 -2
  3. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/c3.py +58 -1
  4. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/commands/parser.py +21 -0
  5. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/docs.html +1 -1
  6. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/mcp_server.py +59 -0
  7. code_context_control-2.32.1/cli/tools/project.py +287 -0
  8. {code_context_control-2.30.0 → code_context_control-2.32.1/code_context_control.egg-info}/PKG-INFO +4 -3
  9. {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/SOURCES.txt +11 -0
  10. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/config.py +7 -0
  11. code_context_control-2.32.1/oracle/mcp_oracle.py +146 -0
  12. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/oracle.html +130 -2
  13. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/oracle_server.py +210 -3
  14. code_context_control-2.32.1/oracle/services/api_auth.py +120 -0
  15. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/chat_engine.py +9 -0
  16. code_context_control-2.32.1/oracle/services/tool_executor.py +30 -0
  17. code_context_control-2.32.1/oracle/services/tool_registry.py +412 -0
  18. {code_context_control-2.30.0 → code_context_control-2.32.1}/pyproject.toml +1 -1
  19. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/claude_md.py +1 -0
  20. code_context_control-2.32.1/services/project_runtime.py +291 -0
  21. code_context_control-2.32.1/tests/test_oracle_api_auth.py +94 -0
  22. code_context_control-2.32.1/tests/test_oracle_apikey_api.py +101 -0
  23. code_context_control-2.32.1/tests/test_oracle_discovery_api.py +100 -0
  24. code_context_control-2.32.1/tests/test_project_tool.py +287 -0
  25. code_context_control-2.32.1/tests/test_tool_registry.py +91 -0
  26. {code_context_control-2.30.0 → code_context_control-2.32.1}/LICENSE +0 -0
  27. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/__init__.py +0 -0
  28. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/_hook_utils.py +0 -0
  29. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/commands/__init__.py +0 -0
  30. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/commands/common.py +0 -0
  31. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/edits.html +0 -0
  32. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_auto_snapshot.py +0 -0
  33. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_c3_signal.py +0 -0
  34. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_c3read.py +0 -0
  35. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_edit_ledger.py +0 -0
  36. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_edit_unlock.py +0 -0
  37. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_filter.py +0 -0
  38. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_ghost_files.py +0 -0
  39. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_pretool_enforce.py +0 -0
  40. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_read.py +0 -0
  41. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_session_stats.py +0 -0
  42. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_terse_advisor.py +0 -0
  43. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hub.html +0 -0
  44. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hub_server.py +0 -0
  45. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/mcp_proxy.py +0 -0
  46. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/server.py +0 -0
  47. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/__init__.py +0 -0
  48. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/_helpers.py +0 -0
  49. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/agent.py +0 -0
  50. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/bitbucket.py +0 -0
  51. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/compress.py +0 -0
  52. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/delegate.py +0 -0
  53. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/edit.py +0 -0
  54. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/edits.py +0 -0
  55. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/filter.py +0 -0
  56. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/impact.py +0 -0
  57. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/memory.py +0 -0
  58. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/read.py +0 -0
  59. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/search.py +0 -0
  60. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/session.py +0 -0
  61. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/shell.py +0 -0
  62. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/status.py +0 -0
  63. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/validate.py +0 -0
  64. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/api.js +0 -0
  65. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/app.js +0 -0
  66. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/bitbucket.js +0 -0
  67. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/chat.js +0 -0
  68. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/dashboard.js +0 -0
  69. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/edits.js +0 -0
  70. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/instructions.js +0 -0
  71. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/memory.js +0 -0
  72. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/sessions.js +0 -0
  73. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/settings.js +0 -0
  74. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/sidebar.js +0 -0
  75. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/icons.js +0 -0
  76. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/shared.js +0 -0
  77. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/theme.js +0 -0
  78. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui.html +0 -0
  79. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui_legacy.html +0 -0
  80. {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui_nano.html +0 -0
  81. {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/dependency_links.txt +0 -0
  82. {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/entry_points.txt +0 -0
  83. {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/requires.txt +0 -0
  84. {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/top_level.txt +0 -0
  85. {code_context_control-2.30.0 → code_context_control-2.32.1}/core/__init__.py +0 -0
  86. {code_context_control-2.30.0 → code_context_control-2.32.1}/core/config.py +0 -0
  87. {code_context_control-2.30.0 → code_context_control-2.32.1}/core/ide.py +0 -0
  88. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/__init__.py +0 -0
  89. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/__init__.py +0 -0
  90. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/c3_bridge.py +0 -0
  91. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/chat_store.py +0 -0
  92. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/cross_memory.py +0 -0
  93. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/federated_graph.py +0 -0
  94. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/health_checker.py +0 -0
  95. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/insight_engine.py +0 -0
  96. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/memory_reader.py +0 -0
  97. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/memory_writer.py +0 -0
  98. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/ollama_bridge.py +0 -0
  99. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/project_scanner.py +0 -0
  100. {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/review_agent.py +0 -0
  101. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/__init__.py +0 -0
  102. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/activity_log.py +0 -0
  103. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/agent_base.py +0 -0
  104. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/agents.py +0 -0
  105. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/auto_memory.py +0 -0
  106. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/__init__.py +0 -0
  107. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/external/__init__.py +0 -0
  108. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/external/aider_polyglot.py +0 -0
  109. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/external/swe_bench.py +0 -0
  110. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/benchmark_dashboard.py +0 -0
  111. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bitbucket_client.py +0 -0
  112. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bitbucket_credentials.py +0 -0
  113. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/compressor.py +0 -0
  114. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/context_snapshot.py +0 -0
  115. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/conversation_store.py +0 -0
  116. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/doc_index.py +0 -0
  117. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/e2e_benchmark.py +0 -0
  118. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/e2e_evaluator.py +0 -0
  119. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/e2e_tasks.py +0 -0
  120. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/edit_ledger.py +0 -0
  121. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/embedding_index.py +0 -0
  122. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/error_reporting.py +0 -0
  123. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/file_memory.py +0 -0
  124. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/hub_service.py +0 -0
  125. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/indexer.py +0 -0
  126. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory.py +0 -0
  127. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_consolidator.py +0 -0
  128. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_graph.py +0 -0
  129. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_grounder.py +0 -0
  130. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_scorer.py +0 -0
  131. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/metrics.py +0 -0
  132. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/notifications.py +0 -0
  133. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/ollama_client.py +0 -0
  134. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/output_filter.py +0 -0
  135. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/parser.py +0 -0
  136. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/project_manager.py +0 -0
  137. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/protocol.py +0 -0
  138. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/proxy_state.py +0 -0
  139. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/retrieval_broker.py +0 -0
  140. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/router.py +0 -0
  141. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/runtime.py +0 -0
  142. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/session_benchmark.py +0 -0
  143. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/session_manager.py +0 -0
  144. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/session_preloader.py +0 -0
  145. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/text_index.py +0 -0
  146. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/tool_classifier.py +0 -0
  147. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/transcript_index.py +0 -0
  148. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/validation_cache.py +0 -0
  149. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/vector_store.py +0 -0
  150. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/version_tracker.py +0 -0
  151. {code_context_control-2.30.0 → code_context_control-2.32.1}/services/watcher.py +0 -0
  152. {code_context_control-2.30.0 → code_context_control-2.32.1}/setup.cfg +0 -0
  153. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_aider_polyglot.py +0 -0
  154. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_cli_smoke.py +0 -0
  155. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_client.py +0 -0
  156. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_credentials.py +0 -0
  157. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_tool.py +0 -0
  158. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_c3_shell.py +0 -0
  159. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_cli_smoke.py +0 -0
  160. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_e2e_benchmark.py +0 -0
  161. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_edit_normalization.py +0 -0
  162. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_enforcement_flip.py +0 -0
  163. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_federated_graph.py +0 -0
  164. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_ghost_files.py +0 -0
  165. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_hub_server_smoke.py +0 -0
  166. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_mcp_server_smoke.py +0 -0
  167. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_memory_graph_api.py +0 -0
  168. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_memory_system.py +0 -0
  169. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_notification_discipline.py +0 -0
  170. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_output_filter.py +0 -0
  171. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_permissions.py +0 -0
  172. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_project_manager.py +0 -0
  173. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_project_manager_merge.py +0 -0
  174. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_session_benchmark.py +0 -0
  175. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_session_budget.py +0 -0
  176. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_swe_bench.py +0 -0
  177. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_validate.py +0 -0
  178. {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_windows_reliability.py +0 -0
  179. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/__init__.py +0 -0
  180. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/backend.py +0 -0
  181. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/main.py +0 -0
  182. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/__init__.py +0 -0
  183. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/benchmark_view.py +0 -0
  184. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/claudemd_view.py +0 -0
  185. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/compress_view.py +0 -0
  186. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/index_view.py +0 -0
  187. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/init_view.py +0 -0
  188. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/mcp_view.py +0 -0
  189. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/optimize_view.py +0 -0
  190. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/pipe_view.py +0 -0
  191. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/projects_view.py +0 -0
  192. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/search_view.py +0 -0
  193. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/session_view.py +0 -0
  194. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/stats.py +0 -0
  195. {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/ui_view.py +0 -0
  196. {code_context_control-2.30.0 → code_context_control-2.32.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.30.0
3
+ Version: 2.32.1
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -228,7 +228,7 @@ Per-project knobs for everything: budget thresholds, feature flag mode, edit led
228
228
 
229
229
  ## The MCP tool suite
230
230
 
231
- C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
231
+ C3 exposes 16 tools as a native MCP server. Your IDE calls them directly:
232
232
 
233
233
  | Tool | What it does |
234
234
  |---|---|
@@ -247,8 +247,9 @@ C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
247
247
  | `c3_agent` | Multi-step agentic workflows (review, investigate, refactor) |
248
248
  | `c3_edits` | Edit-ledger queries + version diffs + restore points |
249
249
  | `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
250
+ | `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
250
251
 
251
- Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket`).
252
+ Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket` / `c3_project`).
252
253
 
253
254
  ### Bitbucket Data Center / Server (v2.30.0)
254
255
 
@@ -166,7 +166,7 @@ Per-project knobs for everything: budget thresholds, feature flag mode, edit led
166
166
 
167
167
  ## The MCP tool suite
168
168
 
169
- C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
169
+ C3 exposes 16 tools as a native MCP server. Your IDE calls them directly:
170
170
 
171
171
  | Tool | What it does |
172
172
  |---|---|
@@ -185,8 +185,9 @@ C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
185
185
  | `c3_agent` | Multi-step agentic workflows (review, investigate, refactor) |
186
186
  | `c3_edits` | Edit-ledger queries + version diffs + restore points |
187
187
  | `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
188
+ | `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
188
189
 
189
- Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket`).
190
+ Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket` / `c3_project`).
190
191
 
191
192
  ### Bitbucket Data Center / Server (v2.30.0)
192
193
 
@@ -85,7 +85,7 @@ console = Console() if HAS_RICH else None
85
85
  # Config
86
86
  CONFIG_DIR = ".c3"
87
87
  CONFIG_FILE = ".c3/config.json"
88
- __version__ = "2.30.0"
88
+ __version__ = "2.32.1"
89
89
 
90
90
 
91
91
  def _command_deps() -> CommandDeps:
@@ -239,6 +239,7 @@ _C3_MCP_ALLOW = [
239
239
  "mcp__c3__c3_memory", "mcp__c3__c3_validate", "mcp__c3__c3_edit",
240
240
  "mcp__c3__c3_agent", "mcp__c3__c3_delegate", "mcp__c3__c3_edits",
241
241
  "mcp__c3__c3_impact", "mcp__c3__c3_shell", "mcp__c3__c3_bitbucket",
242
+ "mcp__c3__c3_project",
242
243
  ]
243
244
 
244
245
  # Obsolete MCP tool names from earlier C3 versions. `c3 permissions clean`
@@ -4492,6 +4493,7 @@ back to native tools as the task progresses.
4492
4493
  - **Memory**: `c3_memory(action='recall')` — full recall. `index` + `fetch` for token-efficient two-step retrieval
4493
4494
  - **Delegate**: `c3_delegate(task, backend='ollama|codex|gemini|claude|auto')` — offload to other models
4494
4495
  - **Bitbucket** (v2.30.0+, when `c3 bitbucket login` has run): `c3_bitbucket(action='list_prs|get_pr|merge_pr|...')` — self-hosted Bitbucket Data Center / Server. Token in OS keyring; mutating actions auto-log to the edit ledger.
4496
+ - **Cross-project** (v2.31.0+): `c3_project(action='list|scan|search|read|edit|...', project='<name|path>')` — discover and operate on OTHER c3-installed projects. Reads run freely; writes (edit/shell/memory) need `allow_write=true`.
4495
4497
 
4496
4498
  ## Self-Check
4497
4499
  If you haven't called a c3_* tool in several turns during active development, re-engage
@@ -5556,6 +5558,60 @@ def _bb_cmd_set_default(args, project_path: str) -> None:
5556
5558
  print(f"[OK] Default repo: {args.project}/{args.repo}")
5557
5559
 
5558
5560
 
5561
+ def cmd_oracle(args):
5562
+ """Oracle Discovery API key + connection management."""
5563
+ sub = getattr(args, "oracle_cmd", None)
5564
+ if sub != "api":
5565
+ print("Usage: c3 oracle api {info,key,rotate,clear}")
5566
+ return
5567
+
5568
+ from oracle.config import load_config
5569
+ from oracle.mcp_oracle import mcp_url
5570
+ from oracle.services import api_auth
5571
+
5572
+ action = getattr(args, "action", "info") or "info"
5573
+
5574
+ if action == "rotate":
5575
+ print("Rotated. New Discovery API key:")
5576
+ print(f" {api_auth.rotate()}")
5577
+ return
5578
+ if action == "clear":
5579
+ removed = api_auth.clear()
5580
+ print("Discovery API key cleared." if removed else "No stored Discovery API key to clear.")
5581
+ return
5582
+
5583
+ key = api_auth.get_or_create_key()
5584
+ if action == "key":
5585
+ print(key)
5586
+ return
5587
+
5588
+ cfg = load_config()
5589
+ host = cfg.get("bind_host", "127.0.0.1")
5590
+ disp_host = "127.0.0.1" if host in ("0.0.0.0", "") else host
5591
+ rest_port = getattr(args, "port", None) or cfg.get("port", 3331)
5592
+ mcp_port = getattr(args, "mcp_port", None) or cfg.get("mcp_port", 3332)
5593
+ rest_base = f"http://{disp_host}:{rest_port}/api/discovery"
5594
+ url = mcp_url(host, mcp_port)
5595
+
5596
+ print("[oracle:api]")
5597
+ print(f" REST base : {rest_base}")
5598
+ print(f" OpenAPI : {rest_base}/openapi.json")
5599
+ print(f" MCP URL : {url}")
5600
+ print(f" Auth : Bearer {key}")
5601
+ print()
5602
+ print(" Claude .mcp.json entry:")
5603
+ snippet = {
5604
+ "mcpServers": {
5605
+ "c3-oracle": {
5606
+ "type": "http",
5607
+ "url": url,
5608
+ "headers": {"Authorization": f"Bearer {key}"},
5609
+ }
5610
+ }
5611
+ }
5612
+ print(json.dumps(snippet, indent=2))
5613
+
5614
+
5559
5615
  def cmd_projects(args):
5560
5616
  """Manage the global C3 project registry."""
5561
5617
  from services.project_manager import ProjectManager
@@ -6308,6 +6364,7 @@ def main():
6308
6364
  "projects": cmd_projects,
6309
6365
  "hub": cmd_hub,
6310
6366
  "bitbucket": cmd_bitbucket,
6367
+ "oracle": cmd_oracle,
6311
6368
  }
6312
6369
 
6313
6370
  cmd_func = commands.get(args.command)
@@ -322,4 +322,25 @@ def build_parser(version: str, parse_cli_ide_arg):
322
322
  bb_default.add_argument("--repo", required=True, help="Repository slug")
323
323
  bb_default.add_argument("project_path", nargs="?", default=".")
324
324
 
325
+ # ── Oracle Discovery API (v2.32.0) ──────────────────────────────────
326
+ p_oracle = subparsers.add_parser(
327
+ "oracle",
328
+ help="Oracle Discovery API key + connection management",
329
+ )
330
+ or_subs = p_oracle.add_subparsers(dest="oracle_cmd")
331
+ or_api = or_subs.add_parser(
332
+ "api",
333
+ help="Show connection info / manage the Discovery API key",
334
+ )
335
+ or_api.add_argument(
336
+ "action",
337
+ nargs="?",
338
+ default="info",
339
+ choices=["info", "key", "rotate", "clear"],
340
+ help="info (default): print REST+MCP URLs and a .mcp.json snippet; "
341
+ "key: print the token; rotate: replace it; clear: delete it",
342
+ )
343
+ or_api.add_argument("--port", type=int, default=None, help="Override REST port in printed info")
344
+ or_api.add_argument("--mcp-port", type=int, default=None, help="Override MCP port in printed info")
345
+
325
346
  return parser
@@ -1148,7 +1148,7 @@ python cli/c3.py install-mcp . gemini</code></pre>
1148
1148
 
1149
1149
  <!-- ─── MCP Tools ───────────────────── -->
1150
1150
  <h2 id="mcp-tools">MCP Tools Reference</h2>
1151
- <p>C3 exposes 15 MCP tools. All core tools work without Ollama; delegate requires it. The Bitbucket integration is optional and activated via <code>c3 bitbucket login</code>.</p>
1151
+ <p>C3 exposes 16 MCP tools. All core tools work without Ollama; delegate requires it. The Bitbucket integration is optional and activated via <code>c3 bitbucket login</code>.</p>
1152
1152
 
1153
1153
  <h3>Discovery &amp; Compression</h3>
1154
1154
  <table>
@@ -699,6 +699,65 @@ async def c3_bitbucket(
699
699
  )
700
700
 
701
701
 
702
+ @mcp.tool()
703
+ async def c3_project(
704
+ action: str,
705
+ project: str = "",
706
+ query: str = "",
707
+ file_path: str = "",
708
+ symbols: Any = None,
709
+ lines: Any = None,
710
+ mode: str = "map",
711
+ view: str = "health",
712
+ top_k: int = 5,
713
+ max_tokens: int = 1200,
714
+ search_action: str = "code",
715
+ mem_action: str = "recall",
716
+ fact: str = "",
717
+ category: str = "",
718
+ fact_id: str = "",
719
+ edits_action: str = "history",
720
+ file: str = "",
721
+ tag: str = "",
722
+ limit: int = 50,
723
+ target: str = "",
724
+ old_string: str = "",
725
+ new_string: str = "",
726
+ summary: str = "",
727
+ edits: str = "",
728
+ replace_all: bool = False,
729
+ tags: str = "",
730
+ cmd: str = "",
731
+ timeout: int = 60,
732
+ scan_roots: str = "",
733
+ allow_write: bool = False,
734
+ ctx: Context = None,
735
+ ) -> str:
736
+ """CROSS-PROJECT — run C3 against OTHER c3-installed projects (read-only safe in plan mode).
737
+ Discover: list (registry), scan (registry+filesystem), info, register, unregister.
738
+ Read : search, read, compress, status, memory, impact, edits, validate, filter.
739
+ Write : edit, shell, memory(add/update/delete) — require allow_write=true; logged to that project's ledger.
740
+ project = registered name OR absolute path (.c3 required). list/scan need no project.
741
+ search_action/mem_action/edits_action pick the sub-op for those verbs."""
742
+ svc = _svc(ctx)
743
+
744
+ def finalize(fname, fargs, fresp, fsumm, **kw):
745
+ return _finalize_response(ctx, fname, fargs, fresp, fsumm, **kw)
746
+
747
+ from cli.tools.project import handle_project
748
+ return await asyncio.to_thread(
749
+ handle_project, action, svc, finalize,
750
+ project=project, query=query, file_path=file_path, symbols=symbols,
751
+ lines=lines, mode=mode, view=view, top_k=top_k, max_tokens=max_tokens,
752
+ search_action=search_action, mem_action=mem_action, fact=fact,
753
+ category=category, fact_id=fact_id, edits_action=edits_action, file=file,
754
+ tag=tag, limit=limit, target=target, old_string=old_string,
755
+ new_string=new_string, summary=summary, edits=edits,
756
+ replace_all=replace_all, tags=tags, cmd=cmd, timeout=timeout,
757
+ scan_roots=scan_roots, allow_write=allow_write,
758
+ )
759
+
760
+
702
761
  def main() -> None:
703
762
  """Entry-point for the ``c3-mcp`` console script."""
704
763
  from services import error_reporting
@@ -0,0 +1,287 @@
1
+ """c3_project tool -- run C3 against OTHER c3-installed projects.
2
+
3
+ Discovery and read ops run freely against any registered/.c3 project. Write ops
4
+ (``edit``, ``shell``, and memory mutations) require ``allow_write=True`` and are
5
+ recorded on the *target* project (its edit ledger + activity log), so a foreign
6
+ mutation leaves an audit trail in the project it touched.
7
+
8
+ The heavy lifting reuses the existing per-tool handlers unchanged -- only the
9
+ ``svc`` (a ``C3Runtime``) differs, supplied by the shared foreign-runtime cache.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import asyncio
14
+ from pathlib import Path
15
+
16
+ from services.project_runtime import (
17
+ discover_projects,
18
+ resolve_project,
19
+ shared_cache,
20
+ )
21
+
22
+ # Memory sub-actions that mutate the target project's fact store.
23
+ _MEMORY_WRITE = {"add", "update", "delete", "consolidate", "consolidate_deep", "ground"}
24
+ # Dispatch verbs that mutate the target project.
25
+ _WRITE_OPS = {"edit", "shell"}
26
+ _DISCOVERY_OPS = {"list", "scan", "info", "register", "unregister"}
27
+ _READ_OPS = {
28
+ "search", "read", "compress", "status", "memory",
29
+ "impact", "edits", "validate", "filter",
30
+ }
31
+
32
+
33
+ def _foreign_finalize(_name, _args, resp, _summ="", **_kw):
34
+ """No-op finalize for proxied calls.
35
+
36
+ The home session's finalize wraps the whole ``c3_project`` response, so the
37
+ inner handlers must not also charge budget / log against either session.
38
+ """
39
+ return resp
40
+
41
+
42
+ def _foreign_facts(*_a, **_kw):
43
+ return ""
44
+
45
+
46
+ def _runtime_for(path: str):
47
+ """Indirection point (monkeypatched in tests) -> foreign ``C3Runtime``."""
48
+ return shared_cache().get(path)
49
+
50
+
51
+ # ── Discovery renderers ────────────────────────────────────────────────────
52
+
53
+
54
+ def _render_discovery(scan_roots_csv: str, do_scan: bool) -> str:
55
+ roots = [r.strip() for r in (scan_roots_csv or "").split(",") if r.strip()] or None
56
+ data = discover_projects(scan_roots=roots, scan=do_scan)
57
+ reg = data["registered"]
58
+ unreg = data["unregistered"]
59
+
60
+ out = [f"Registered C3 projects ({len(reg)}):"]
61
+ if not reg:
62
+ out.append(" (none -- c3_project(action='register', project='<path>') to add one)")
63
+ for p in reg:
64
+ flag = "" if p["accessible"] else " [MISSING]"
65
+ out.append(f" - {p['name']:<28} {p['ide']:<12} {p['path']}{flag}")
66
+
67
+ if do_scan:
68
+ out.append("")
69
+ out.append(f"Unregistered .c3 projects found nearby ({len(unreg)}):")
70
+ if not unreg:
71
+ out.append(" (none found near registered projects)")
72
+ for p in unreg:
73
+ out.append(f" - {p['name']:<28} {'':<12} {p['path']}")
74
+ if unreg:
75
+ out.append("")
76
+ out.append("Register one: c3_project(action='register', project='<path>')")
77
+ return "\n".join(out)
78
+
79
+
80
+ def _render_info(project: str) -> str:
81
+ try:
82
+ resolved = resolve_project(project)
83
+ except ValueError as e:
84
+ return f"[c3_project:error] {e}"
85
+ p = Path(resolved["path"])
86
+ out = [
87
+ f"Project: {resolved['name']}",
88
+ f" path : {resolved['path']}",
89
+ f" .c3 present : {(p / '.c3').is_dir()}",
90
+ f" accessible : {p.is_dir()}",
91
+ ]
92
+ try:
93
+ from services.project_manager import ProjectManager
94
+
95
+ details = ProjectManager().get_project_details(resolved["path"]) or {}
96
+ for key in ("ide", "c3_version", "facts_count", "last_session", "active"):
97
+ if key in details and details[key] not in (None, ""):
98
+ out.append(f" {key:<11} : {details[key]}")
99
+ except Exception:
100
+ pass
101
+ return "\n".join(out)
102
+
103
+
104
+ def _do_register(project: str) -> str:
105
+ if not (project or "").strip():
106
+ return "[c3_project:error] register requires project='<path>'."
107
+ path = Path(project).expanduser()
108
+ if not path.exists():
109
+ return f"[c3_project:error] Path does not exist: {project}"
110
+ if not (path / ".c3").is_dir():
111
+ return (
112
+ f"[c3_project:error] No .c3 directory in {path}. "
113
+ "Run 'c3 init' there first."
114
+ )
115
+ from services.project_manager import ProjectManager
116
+
117
+ entry = ProjectManager().add_project(str(path.resolve()))
118
+ return f"Registered: {entry['name']} ({entry['path']})"
119
+
120
+
121
+ def _do_unregister(project: str) -> str:
122
+ try:
123
+ resolved = resolve_project(project)
124
+ except ValueError as e:
125
+ return f"[c3_project:error] {e}"
126
+ from services.project_manager import ProjectManager
127
+
128
+ removed = ProjectManager().remove_project(resolved["path"])
129
+ return (
130
+ f"Unregistered: {resolved['name']}"
131
+ if removed
132
+ else f"Not in registry: {resolved['name']}"
133
+ )
134
+
135
+
136
+ # ── Proxied op dispatch ────────────────────────────────────────────────────
137
+
138
+
139
+ def _proxy(action, fsvc, *, query, file_path, symbols, lines, mode, view, top_k,
140
+ max_tokens, search_action, mem_action, fact, category, fact_id,
141
+ edits_action, file, tag, limit, target, old_string, new_string,
142
+ summary, edits, replace_all, tags, cmd, timeout, project_path):
143
+ if action == "search":
144
+ from cli.tools.search import handle_search
145
+
146
+ return handle_search(query, search_action, top_k, max_tokens,
147
+ fsvc, _foreign_finalize, _foreign_facts)
148
+ if action == "read":
149
+ from cli.tools.read import handle_read
150
+
151
+ return handle_read(file_path, symbols=symbols, lines=lines,
152
+ svc=fsvc, finalize=_foreign_finalize)
153
+ if action == "compress":
154
+ from cli.tools.compress import handle_compress
155
+
156
+ return handle_compress(file_path, mode, fsvc, _foreign_finalize, _foreign_facts)
157
+ if action == "status":
158
+ from cli.tools.status import handle_status
159
+
160
+ return handle_status(view, False, fsvc, _foreign_finalize)
161
+ if action == "memory":
162
+ from cli.tools.memory import handle_memory
163
+
164
+ return handle_memory(mem_action, query, fact, category, top_k,
165
+ fsvc, _foreign_finalize, fact_id=fact_id)
166
+ if action == "impact":
167
+ from cli.tools.impact import handle_impact
168
+
169
+ imode = mode if mode in ("symbol", "unstaged") else "symbol"
170
+ return handle_impact(target, file_path, imode, fsvc, _foreign_finalize)
171
+ if action == "edits":
172
+ from cli.tools.edits import handle_edits
173
+
174
+ return handle_edits(edits_action, file, "", "", "", tags, limit, "", "",
175
+ tag, fsvc, _foreign_finalize)
176
+ if action == "validate":
177
+ from cli.tools.validate import handle_validate
178
+
179
+ return asyncio.run(handle_validate(file_path, fsvc, _foreign_finalize))
180
+ if action == "filter":
181
+ from cli.tools.filter import handle_filter
182
+
183
+ return handle_filter(file_path, "", query, 100, "smart", False,
184
+ fsvc, _foreign_finalize)
185
+ if action == "edit":
186
+ from cli.tools.edit import handle_edit
187
+
188
+ return handle_edit(file_path, old_string, new_string, summary, tags,
189
+ replace_all, fsvc, _foreign_finalize, edits)
190
+ if action == "shell":
191
+ from cli.tools.shell import handle_shell
192
+
193
+ return asyncio.run(handle_shell(cmd, project_path, timeout, True, True,
194
+ fsvc, _foreign_finalize))
195
+ return f"[c3_project:error] Unhandled op '{action}'."
196
+
197
+
198
+ # ── Entry point ────────────────────────────────────────────────────────────
199
+
200
+
201
+ def handle_project(action, svc, finalize, *, project="", query="", file_path="",
202
+ symbols=None, lines=None, mode="map", view="health", top_k=5,
203
+ max_tokens=1200, search_action="code", mem_action="recall",
204
+ fact="", category="", fact_id="", edits_action="history",
205
+ file="", tag="", limit=50, target="", old_string="",
206
+ new_string="", summary="", edits="", replace_all=False,
207
+ tags="", cmd="", timeout=60, scan_roots="", allow_write=False):
208
+ action = (action or "").strip().lower()
209
+
210
+ def done(resp, summ="ok"):
211
+ return finalize("c3_project", {"action": action, "project": project},
212
+ resp, summ)
213
+
214
+ if not action:
215
+ return done(
216
+ "[c3_project:error] action required. "
217
+ f"Discovery: {', '.join(sorted(_DISCOVERY_OPS))}. "
218
+ f"Read: {', '.join(sorted(_READ_OPS))}. "
219
+ f"Write (allow_write=true): {', '.join(sorted(_WRITE_OPS))}.",
220
+ "error")
221
+
222
+ # ── Discovery (no foreign runtime needed) ──────────────────────────
223
+ if action in ("list", "scan"):
224
+ return done(_render_discovery(scan_roots, action == "scan"), f"{action} projects")
225
+ if action == "info":
226
+ return done(_render_info(project), "project info")
227
+ if action == "register":
228
+ return done(_do_register(project), "register project")
229
+ if action == "unregister":
230
+ return done(_do_unregister(project), "unregister project")
231
+
232
+ if action not in _READ_OPS and action not in _WRITE_OPS:
233
+ return done(
234
+ f"[c3_project:error] Unknown action '{action}'. "
235
+ f"Discovery: {', '.join(sorted(_DISCOVERY_OPS))}. "
236
+ f"Read: {', '.join(sorted(_READ_OPS))}. "
237
+ f"Write (allow_write=true): {', '.join(sorted(_WRITE_OPS))}.",
238
+ "error")
239
+
240
+ # ── Write guard ────────────────────────────────────────────────────
241
+ is_write = action in _WRITE_OPS or (
242
+ action == "memory" and (mem_action or "").lower() in _MEMORY_WRITE
243
+ )
244
+ if is_write and not allow_write:
245
+ label = action + (f"/{mem_action}" if action == "memory" else "")
246
+ return done(
247
+ f"[c3_project:blocked] '{label}' would modify project '{project}'. "
248
+ "Re-run with allow_write=true to proceed.",
249
+ "blocked")
250
+
251
+ # ── Resolve + borrow the foreign runtime ───────────────────────────
252
+ try:
253
+ resolved = resolve_project(project)
254
+ except ValueError as e:
255
+ return done(f"[c3_project:error] {e}", "error")
256
+ try:
257
+ fsvc = _runtime_for(resolved["path"])
258
+ except Exception as e:
259
+ return done(
260
+ f"[c3_project:error] Could not load '{resolved['name']}': {e}", "error")
261
+
262
+ banner = f"[c3_project:{resolved['name']}] {action}\n"
263
+ try:
264
+ body = _proxy(
265
+ action, fsvc, query=query, file_path=file_path, symbols=symbols,
266
+ lines=lines, mode=mode, view=view, top_k=top_k, max_tokens=max_tokens,
267
+ search_action=search_action, mem_action=mem_action, fact=fact,
268
+ category=category, fact_id=fact_id, edits_action=edits_action,
269
+ file=file, tag=tag, limit=limit, target=target, old_string=old_string,
270
+ new_string=new_string, summary=summary, edits=edits,
271
+ replace_all=replace_all, tags=tags, cmd=cmd, timeout=timeout,
272
+ project_path=resolved["path"],
273
+ )
274
+ except Exception as e:
275
+ return done(f"{banner}[error] {type(e).__name__}: {e}", "error")
276
+
277
+ # Audit foreign mutations on the target project itself.
278
+ if is_write and getattr(fsvc, "activity_log", None):
279
+ try:
280
+ fsvc.activity_log.log("cross_project_write", {
281
+ "action": action,
282
+ "from_project": getattr(svc, "project_path", ""),
283
+ })
284
+ except Exception:
285
+ pass
286
+
287
+ return done(banner + (body or ""), f"{action} on {resolved['name']}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-context-control
3
- Version: 2.30.0
3
+ Version: 2.32.1
4
4
  Summary: Local code-intelligence layer for AI coding tools (Claude Code, Codex, Gemini, Copilot). Retrieve less, read less, edit safer.
5
5
  Author-email: Dimitri Tselenchuk <dtselenc@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -228,7 +228,7 @@ Per-project knobs for everything: budget thresholds, feature flag mode, edit led
228
228
 
229
229
  ## The MCP tool suite
230
230
 
231
- C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
231
+ C3 exposes 16 tools as a native MCP server. Your IDE calls them directly:
232
232
 
233
233
  | Tool | What it does |
234
234
  |---|---|
@@ -247,8 +247,9 @@ C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
247
247
  | `c3_agent` | Multi-step agentic workflows (review, investigate, refactor) |
248
248
  | `c3_edits` | Edit-ledger queries + version diffs + restore points |
249
249
  | `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
250
+ | `c3_project` | Cross-project — discover & operate on other c3-installed projects; guarded writes (v2.31.0) |
250
251
 
251
- Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket`).
252
+ Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket` / `c3_project`).
252
253
 
253
254
  ### Bitbucket Data Center / Server (v2.30.0)
254
255
 
@@ -39,6 +39,7 @@ cli/tools/edits.py
39
39
  cli/tools/filter.py
40
40
  cli/tools/impact.py
41
41
  cli/tools/memory.py
42
+ cli/tools/project.py
42
43
  cli/tools/read.py
43
44
  cli/tools/search.py
44
45
  cli/tools/session.py
@@ -70,9 +71,11 @@ core/config.py
70
71
  core/ide.py
71
72
  oracle/__init__.py
72
73
  oracle/config.py
74
+ oracle/mcp_oracle.py
73
75
  oracle/oracle.html
74
76
  oracle/oracle_server.py
75
77
  oracle/services/__init__.py
78
+ oracle/services/api_auth.py
76
79
  oracle/services/c3_bridge.py
77
80
  oracle/services/chat_engine.py
78
81
  oracle/services/chat_store.py
@@ -85,6 +88,8 @@ oracle/services/memory_writer.py
85
88
  oracle/services/ollama_bridge.py
86
89
  oracle/services/project_scanner.py
87
90
  oracle/services/review_agent.py
91
+ oracle/services/tool_executor.py
92
+ oracle/services/tool_registry.py
88
93
  services/__init__.py
89
94
  services/activity_log.py
90
95
  services/agent_base.py
@@ -118,6 +123,7 @@ services/ollama_client.py
118
123
  services/output_filter.py
119
124
  services/parser.py
120
125
  services/project_manager.py
126
+ services/project_runtime.py
121
127
  services/protocol.py
122
128
  services/proxy_state.py
123
129
  services/retrieval_broker.py
@@ -154,13 +160,18 @@ tests/test_mcp_server_smoke.py
154
160
  tests/test_memory_graph_api.py
155
161
  tests/test_memory_system.py
156
162
  tests/test_notification_discipline.py
163
+ tests/test_oracle_api_auth.py
164
+ tests/test_oracle_apikey_api.py
165
+ tests/test_oracle_discovery_api.py
157
166
  tests/test_output_filter.py
158
167
  tests/test_permissions.py
159
168
  tests/test_project_manager.py
160
169
  tests/test_project_manager_merge.py
170
+ tests/test_project_tool.py
161
171
  tests/test_session_benchmark.py
162
172
  tests/test_session_budget.py
163
173
  tests/test_swe_bench.py
174
+ tests/test_tool_registry.py
164
175
  tests/test_validate.py
165
176
  tests/test_windows_reliability.py
166
177
  tui/__init__.py
@@ -9,6 +9,13 @@ CONFIG_FILE = ORACLE_DIR / "config.json"
9
9
 
10
10
  DEFAULTS = {
11
11
  "port": 3331,
12
+ # ── Discovery API (external LLM tool surface, v2.32.0) ──
13
+ "bind_host": "127.0.0.1", # loopback only by default (was 0.0.0.0)
14
+ "api_enabled": True, # expose /api/discovery/* REST surface
15
+ "api_require_auth": True, # require Bearer token on /api/discovery/*
16
+ "api_max_tier": "action", # cap exposed tools: "read" | "action"
17
+ "mcp_enabled": True, # start FastMCP HTTP/SSE discovery server
18
+ "mcp_port": 3332, # discovery MCP transport port (loopback)
12
19
  "ollama_base_url": "https://ollama.com",
13
20
  "ollama_api_key": "",
14
21
  "model": "gemma4:31b-cloud",