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.
- {code_context_control-2.30.0/code_context_control.egg-info → code_context_control-2.32.1}/PKG-INFO +4 -3
- {code_context_control-2.30.0 → code_context_control-2.32.1}/README.md +3 -2
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/c3.py +58 -1
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/commands/parser.py +21 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/docs.html +1 -1
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/mcp_server.py +59 -0
- code_context_control-2.32.1/cli/tools/project.py +287 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1/code_context_control.egg-info}/PKG-INFO +4 -3
- {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/SOURCES.txt +11 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/config.py +7 -0
- code_context_control-2.32.1/oracle/mcp_oracle.py +146 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/oracle.html +130 -2
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/oracle_server.py +210 -3
- code_context_control-2.32.1/oracle/services/api_auth.py +120 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/chat_engine.py +9 -0
- code_context_control-2.32.1/oracle/services/tool_executor.py +30 -0
- code_context_control-2.32.1/oracle/services/tool_registry.py +412 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/pyproject.toml +1 -1
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/claude_md.py +1 -0
- code_context_control-2.32.1/services/project_runtime.py +291 -0
- code_context_control-2.32.1/tests/test_oracle_api_auth.py +94 -0
- code_context_control-2.32.1/tests/test_oracle_apikey_api.py +101 -0
- code_context_control-2.32.1/tests/test_oracle_discovery_api.py +100 -0
- code_context_control-2.32.1/tests/test_project_tool.py +287 -0
- code_context_control-2.32.1/tests/test_tool_registry.py +91 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/LICENSE +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/_hook_utils.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/commands/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/commands/common.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/edits.html +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_c3read.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_filter.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_ghost_files.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_read.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hub.html +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/hub_server.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/server.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/_helpers.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/agent.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/bitbucket.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/compress.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/delegate.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/edit.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/edits.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/filter.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/impact.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/memory.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/read.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/search.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/session.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/shell.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/status.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/tools/validate.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/api.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/app.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/bitbucket.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/icons.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/shared.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui/theme.js +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui.html +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui_legacy.html +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/cli/ui_nano.html +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/requires.txt +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/core/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/core/config.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/core/ide.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/ollama_bridge.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/activity_log.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/agent_base.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/agents.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/auto_memory.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bitbucket_client.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/bitbucket_credentials.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/compressor.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/context_snapshot.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/conversation_store.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/doc_index.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/e2e_tasks.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/edit_ledger.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/embedding_index.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/error_reporting.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/file_memory.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/hub_service.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/indexer.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_consolidator.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_graph.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_grounder.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/memory_scorer.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/metrics.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/notifications.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/ollama_client.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/output_filter.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/parser.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/project_manager.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/protocol.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/proxy_state.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/retrieval_broker.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/router.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/runtime.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/session_benchmark.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/session_manager.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/session_preloader.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/text_index.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/tool_classifier.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/transcript_index.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/validation_cache.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/vector_store.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/version_tracker.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/services/watcher.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/setup.cfg +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_cli_smoke.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_client.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_credentials.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_bitbucket_tool.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_ghost_files.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_memory_system.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_output_filter.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_permissions.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_project_manager.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_project_manager_merge.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_session_budget.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_validate.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/backend.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/main.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/__init__.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/index_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/init_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/search_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/session_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/stats.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.30.0 → code_context_control-2.32.1}/tui/theme.tcss +0 -0
{code_context_control-2.30.0/code_context_control.egg-info → code_context_control-2.32.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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 & 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']}")
|
{code_context_control-2.30.0 → code_context_control-2.32.1/code_context_control.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
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
|
|
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",
|