code-context-control 2.28.3__tar.gz → 2.30.0__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.28.3 → code_context_control-2.30.0}/PKG-INFO +37 -9
- {code_context_control-2.28.3 → code_context_control-2.30.0}/README.md +35 -8
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/c3.py +177 -3
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/commands/parser.py +39 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/docs.html +37 -1
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_ghost_files.py +17 -1
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hub.html +128 -3
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hub_server.py +23 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/mcp_server.py +50 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/server.py +365 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/_helpers.py +17 -3
- code_context_control-2.30.0/cli/tools/bitbucket.py +654 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/app.js +4 -0
- code_context_control-2.30.0/cli/ui/components/bitbucket.js +297 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/code_context_control.egg-info/PKG-INFO +37 -9
- {code_context_control-2.28.3 → code_context_control-2.30.0}/code_context_control.egg-info/SOURCES.txt +9 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/code_context_control.egg-info/requires.txt +1 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/core/config.py +29 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/pyproject.toml +2 -1
- code_context_control-2.30.0/services/bitbucket_client.py +485 -0
- code_context_control-2.30.0/services/bitbucket_credentials.py +215 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/claude_md.py +1 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/project_manager.py +244 -0
- code_context_control-2.30.0/tests/test_bitbucket_cli_smoke.py +59 -0
- code_context_control-2.30.0/tests/test_bitbucket_client.py +203 -0
- code_context_control-2.30.0/tests/test_bitbucket_credentials.py +124 -0
- code_context_control-2.30.0/tests/test_bitbucket_tool.py +179 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_ghost_files.py +22 -1
- code_context_control-2.30.0/tests/test_project_manager_merge.py +223 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/LICENSE +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/_hook_utils.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/commands/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/commands/common.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/edits.html +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_auto_snapshot.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_c3_signal.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_c3read.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_edit_ledger.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_edit_unlock.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_filter.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_pretool_enforce.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_read.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_session_stats.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/hook_terse_advisor.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/mcp_proxy.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/agent.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/compress.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/delegate.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/edit.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/edits.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/filter.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/impact.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/memory.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/read.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/search.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/session.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/shell.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/status.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/tools/validate.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/api.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/chat.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/dashboard.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/edits.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/instructions.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/memory.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/sessions.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/settings.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/components/sidebar.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/icons.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/shared.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui/theme.js +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui.html +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui_legacy.html +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/cli/ui_nano.html +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/code_context_control.egg-info/dependency_links.txt +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/code_context_control.egg-info/entry_points.txt +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/code_context_control.egg-info/top_level.txt +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/core/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/core/ide.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/config.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/oracle.html +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/oracle_server.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/c3_bridge.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/chat_engine.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/chat_store.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/cross_memory.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/federated_graph.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/health_checker.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/insight_engine.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/memory_reader.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/memory_writer.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/ollama_bridge.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/project_scanner.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/oracle/services/review_agent.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/activity_log.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/agent_base.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/agents.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/auto_memory.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/bench/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/bench/external/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/bench/external/aider_polyglot.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/bench/external/swe_bench.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/benchmark_dashboard.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/compressor.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/context_snapshot.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/conversation_store.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/doc_index.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/e2e_benchmark.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/e2e_evaluator.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/e2e_tasks.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/edit_ledger.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/embedding_index.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/error_reporting.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/file_memory.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/hub_service.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/indexer.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/memory.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/memory_consolidator.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/memory_graph.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/memory_grounder.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/memory_scorer.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/metrics.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/notifications.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/ollama_client.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/output_filter.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/parser.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/protocol.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/proxy_state.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/retrieval_broker.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/router.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/runtime.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/session_benchmark.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/session_manager.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/session_preloader.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/text_index.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/tool_classifier.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/transcript_index.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/validation_cache.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/vector_store.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/version_tracker.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/services/watcher.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/setup.cfg +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_aider_polyglot.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_c3_shell.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_cli_smoke.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_e2e_benchmark.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_edit_normalization.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_enforcement_flip.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_federated_graph.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_hub_server_smoke.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_mcp_server_smoke.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_memory_graph_api.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_memory_system.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_notification_discipline.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_output_filter.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_permissions.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_project_manager.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_session_benchmark.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_session_budget.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_swe_bench.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_validate.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tests/test_windows_reliability.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/backend.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/main.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/__init__.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/benchmark_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/claudemd_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/compress_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/index_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/init_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/mcp_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/optimize_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/pipe_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/projects_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/search_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/session_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/stats.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/screens/ui_view.py +0 -0
- {code_context_control-2.28.3 → code_context_control-2.30.0}/tui/theme.tcss +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-context-control
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.30.0
|
|
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
|
|
@@ -41,6 +41,7 @@ Requires-Dist: flask>=3.0.0
|
|
|
41
41
|
Requires-Dist: rich>=13.0.0
|
|
42
42
|
Requires-Dist: click>=8.0.0
|
|
43
43
|
Requires-Dist: pyyaml>=6.0.0
|
|
44
|
+
Requires-Dist: keyring>=24.0
|
|
44
45
|
Provides-Extra: vector
|
|
45
46
|
Requires-Dist: scikit-learn>=1.3.0; extra == "vector"
|
|
46
47
|
Requires-Dist: numpy>=1.24.0; extra == "vector"
|
|
@@ -147,13 +148,9 @@ C3 ships with two web UIs (no electron, no install — pure Flask + vanilla JS):
|
|
|
147
148
|
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/hub_projects.png" alt="C3 Project Hub - all projects" width="900">
|
|
148
149
|
</p>
|
|
149
150
|
|
|
150
|
-
Every C3-initialized project on your machine appears here. Group them by tag, filter by active/idle, see which IDE each project uses, jump straight into your IDE with one click, and monitor session activity at a glance. Each project card shows live status, version, MCP wiring mode, port, and last activity.
|
|
151
|
+
Every C3-initialized project on your machine appears here automatically — `c3 init` registers the project with the hub on first run, no extra step. Group them by tag, filter by active/idle, see which IDE each project uses, jump straight into your IDE with one click, and monitor session activity at a glance. Each project card shows live status, version, MCP wiring mode, port, and last activity.
|
|
151
152
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
<p align="center">
|
|
155
|
-
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/hub_projects_grid.png" alt="C3 Project Hub - grid view" width="900">
|
|
156
|
-
</p>
|
|
153
|
+
Per-card actions cover the full lifecycle: launch the IDE, open the per-project UI, edit name / tags / notes, transfer the registration to a new path, **merge** another project's memory + conversation history + edit ledger into this one (with optional source cleanup), or remove it from the registry.
|
|
157
154
|
|
|
158
155
|
**Open in your IDE of choice** — C3 auto-detects which CLIs you have installed and gives you one-click launchers:
|
|
159
156
|
|
|
@@ -231,7 +228,7 @@ Per-project knobs for everything: budget thresholds, feature flag mode, edit led
|
|
|
231
228
|
|
|
232
229
|
## The MCP tool suite
|
|
233
230
|
|
|
234
|
-
C3 exposes
|
|
231
|
+
C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
|
|
235
232
|
|
|
236
233
|
| Tool | What it does |
|
|
237
234
|
|---|---|
|
|
@@ -249,8 +246,39 @@ C3 exposes 14 tools as a native MCP server. Your IDE calls them directly:
|
|
|
249
246
|
| `c3_delegate` | Offload heavy work to local Ollama / Codex / Gemini / etc. |
|
|
250
247
|
| `c3_agent` | Multi-step agentic workflows (review, investigate, refactor) |
|
|
251
248
|
| `c3_edits` | Edit-ledger queries + version diffs + restore points |
|
|
249
|
+
| `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
|
|
250
|
+
|
|
251
|
+
Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket`).
|
|
252
|
+
|
|
253
|
+
### Bitbucket Data Center / Server (v2.30.0)
|
|
254
|
+
|
|
255
|
+
`c3_bitbucket` connects to self-hosted enterprise Bitbucket via REST + Personal
|
|
256
|
+
Access Token. Tokens live in the **OS keyring** (Windows Credential Manager,
|
|
257
|
+
macOS Keychain, Linux Secret Service) — never in `.c3/config.json`.
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# One-time login per server
|
|
261
|
+
c3 bitbucket login --url https://bitbucket.example.com
|
|
262
|
+
# → prompts for username + PAT (masked)
|
|
263
|
+
|
|
264
|
+
# Pin defaults so subsequent calls don't need project/repo
|
|
265
|
+
c3 bitbucket set-default --project PROJ --repo my-service
|
|
266
|
+
|
|
267
|
+
# Inspect status
|
|
268
|
+
c3 bitbucket status
|
|
269
|
+
```
|
|
252
270
|
|
|
253
|
-
|
|
271
|
+
The MCP tool dispatches by `action`. Read-only actions: `status`, `whoami`,
|
|
272
|
+
`list_projects`, `list_repos`, `get_repo`, `list_prs`, `get_pr`, `get_pr_diff`,
|
|
273
|
+
`get_pr_activities`, `list_branches`, `list_commits`, `list_activity`,
|
|
274
|
+
`build_status`, `repo_settings`, `list_webhooks`, `list_permissions`. Write
|
|
275
|
+
actions: `create_pr`, `comment_pr`, `approve_pr`, `unapprove_pr`, `decline_pr`,
|
|
276
|
+
`merge_pr`, `create_branch`, `delete_branch`, `update_repo_settings`,
|
|
277
|
+
`create_webhook`, `delete_webhook`. PR merges and branch deletes are recorded
|
|
278
|
+
to the C3 edit ledger so the audit trail covers platform-side changes too.
|
|
279
|
+
|
|
280
|
+
The **Hub UI** (per-project) gains a "Bitbucket" tab with sub-views for
|
|
281
|
+
Overview / Pull Requests / Branches / Activity / Admin.
|
|
254
282
|
|
|
255
283
|
---
|
|
256
284
|
|
|
@@ -86,13 +86,9 @@ C3 ships with two web UIs (no electron, no install — pure Flask + vanilla JS):
|
|
|
86
86
|
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/hub_projects.png" alt="C3 Project Hub - all projects" width="900">
|
|
87
87
|
</p>
|
|
88
88
|
|
|
89
|
-
Every C3-initialized project on your machine appears here. Group them by tag, filter by active/idle, see which IDE each project uses, jump straight into your IDE with one click, and monitor session activity at a glance. Each project card shows live status, version, MCP wiring mode, port, and last activity.
|
|
89
|
+
Every C3-initialized project on your machine appears here automatically — `c3 init` registers the project with the hub on first run, no extra step. Group them by tag, filter by active/idle, see which IDE each project uses, jump straight into your IDE with one click, and monitor session activity at a glance. Each project card shows live status, version, MCP wiring mode, port, and last activity.
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<p align="center">
|
|
94
|
-
<img src="https://raw.githubusercontent.com/drknowhow/code-context-control/main/docs/screenshots/hub_projects_grid.png" alt="C3 Project Hub - grid view" width="900">
|
|
95
|
-
</p>
|
|
91
|
+
Per-card actions cover the full lifecycle: launch the IDE, open the per-project UI, edit name / tags / notes, transfer the registration to a new path, **merge** another project's memory + conversation history + edit ledger into this one (with optional source cleanup), or remove it from the registry.
|
|
96
92
|
|
|
97
93
|
**Open in your IDE of choice** — C3 auto-detects which CLIs you have installed and gives you one-click launchers:
|
|
98
94
|
|
|
@@ -170,7 +166,7 @@ Per-project knobs for everything: budget thresholds, feature flag mode, edit led
|
|
|
170
166
|
|
|
171
167
|
## The MCP tool suite
|
|
172
168
|
|
|
173
|
-
C3 exposes
|
|
169
|
+
C3 exposes 15 tools as a native MCP server. Your IDE calls them directly:
|
|
174
170
|
|
|
175
171
|
| Tool | What it does |
|
|
176
172
|
|---|---|
|
|
@@ -188,8 +184,39 @@ C3 exposes 14 tools as a native MCP server. Your IDE calls them directly:
|
|
|
188
184
|
| `c3_delegate` | Offload heavy work to local Ollama / Codex / Gemini / etc. |
|
|
189
185
|
| `c3_agent` | Multi-step agentic workflows (review, investigate, refactor) |
|
|
190
186
|
| `c3_edits` | Edit-ledger queries + version diffs + restore points |
|
|
187
|
+
| `c3_bitbucket` | Bitbucket Data Center integration — PRs, branches, builds, repo admin (v2.30.0) |
|
|
188
|
+
|
|
189
|
+
Every tool is **read-only safe in plan mode** (except `c3_edit`, `c3_shell`, and write actions on `c3_bitbucket`).
|
|
190
|
+
|
|
191
|
+
### Bitbucket Data Center / Server (v2.30.0)
|
|
192
|
+
|
|
193
|
+
`c3_bitbucket` connects to self-hosted enterprise Bitbucket via REST + Personal
|
|
194
|
+
Access Token. Tokens live in the **OS keyring** (Windows Credential Manager,
|
|
195
|
+
macOS Keychain, Linux Secret Service) — never in `.c3/config.json`.
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# One-time login per server
|
|
199
|
+
c3 bitbucket login --url https://bitbucket.example.com
|
|
200
|
+
# → prompts for username + PAT (masked)
|
|
201
|
+
|
|
202
|
+
# Pin defaults so subsequent calls don't need project/repo
|
|
203
|
+
c3 bitbucket set-default --project PROJ --repo my-service
|
|
204
|
+
|
|
205
|
+
# Inspect status
|
|
206
|
+
c3 bitbucket status
|
|
207
|
+
```
|
|
191
208
|
|
|
192
|
-
|
|
209
|
+
The MCP tool dispatches by `action`. Read-only actions: `status`, `whoami`,
|
|
210
|
+
`list_projects`, `list_repos`, `get_repo`, `list_prs`, `get_pr`, `get_pr_diff`,
|
|
211
|
+
`get_pr_activities`, `list_branches`, `list_commits`, `list_activity`,
|
|
212
|
+
`build_status`, `repo_settings`, `list_webhooks`, `list_permissions`. Write
|
|
213
|
+
actions: `create_pr`, `comment_pr`, `approve_pr`, `unapprove_pr`, `decline_pr`,
|
|
214
|
+
`merge_pr`, `create_branch`, `delete_branch`, `update_repo_settings`,
|
|
215
|
+
`create_webhook`, `delete_webhook`. PR merges and branch deletes are recorded
|
|
216
|
+
to the C3 edit ledger so the audit trail covers platform-side changes too.
|
|
217
|
+
|
|
218
|
+
The **Hub UI** (per-project) gains a "Bitbucket" tab with sub-views for
|
|
219
|
+
Overview / Pull Requests / Branches / Activity / Admin.
|
|
193
220
|
|
|
194
221
|
---
|
|
195
222
|
|
|
@@ -60,7 +60,7 @@ from cli.commands.common import cmd_stats as common_cmd_stats
|
|
|
60
60
|
from cli.commands.common import cmd_ui as common_cmd_ui
|
|
61
61
|
from cli.commands.parser import build_parser
|
|
62
62
|
from core import count_tokens, format_token_count
|
|
63
|
-
from core.config import AGENT_DEFAULTS, DELEGATE_DEFAULTS, PROXY_DEFAULTS, load_delegate_config
|
|
63
|
+
from core.config import AGENT_DEFAULTS, BITBUCKET_DEFAULTS, DELEGATE_DEFAULTS, PROXY_DEFAULTS, load_delegate_config
|
|
64
64
|
from core.config import DEFAULTS as HYBRID_DEFAULTS
|
|
65
65
|
from core.ide import PROFILES, detect_ide, get_profile, load_ide_config, normalize_ide_name
|
|
66
66
|
from services.compressor import CodeCompressor
|
|
@@ -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.30.0"
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def _command_deps() -> CommandDeps:
|
|
@@ -164,6 +164,7 @@ def _build_init_config(project_path: str) -> dict:
|
|
|
164
164
|
"proxy": deepcopy(PROXY_DEFAULTS),
|
|
165
165
|
"delegate": deepcopy(DELEGATE_DEFAULTS),
|
|
166
166
|
"agents": deepcopy(AGENT_DEFAULTS),
|
|
167
|
+
"bitbucket": deepcopy(BITBUCKET_DEFAULTS),
|
|
167
168
|
}
|
|
168
169
|
merged = _deep_merge_dict(defaults, existing if isinstance(existing, dict) else {})
|
|
169
170
|
# Always persist current path/version on init/update.
|
|
@@ -237,7 +238,7 @@ _C3_MCP_ALLOW = [
|
|
|
237
238
|
"mcp__c3__c3_session", "mcp__c3__c3_status", "mcp__c3__c3_filter",
|
|
238
239
|
"mcp__c3__c3_memory", "mcp__c3__c3_validate", "mcp__c3__c3_edit",
|
|
239
240
|
"mcp__c3__c3_agent", "mcp__c3__c3_delegate", "mcp__c3__c3_edits",
|
|
240
|
-
"mcp__c3__c3_impact", "mcp__c3__c3_shell",
|
|
241
|
+
"mcp__c3__c3_impact", "mcp__c3__c3_shell", "mcp__c3__c3_bitbucket",
|
|
241
242
|
]
|
|
242
243
|
|
|
243
244
|
# Obsolete MCP tool names from earlier C3 versions. `c3 permissions clean`
|
|
@@ -563,6 +564,25 @@ def _check_c3_health(project_path: str) -> dict:
|
|
|
563
564
|
facts_dir = c3_dir / "facts"
|
|
564
565
|
info["facts"] = len(list(facts_dir.glob("*.json"))) if facts_dir.exists() else 0
|
|
565
566
|
|
|
567
|
+
# Bitbucket integration (v2.30.0+) — informational
|
|
568
|
+
bb_section = config.get("bitbucket") if isinstance(config, dict) else None
|
|
569
|
+
if isinstance(bb_section, dict):
|
|
570
|
+
active = bb_section.get("active") or {}
|
|
571
|
+
accounts = bb_section.get("accounts") or []
|
|
572
|
+
info["bitbucket_accounts"] = len(accounts) if isinstance(accounts, list) else 0
|
|
573
|
+
info["bitbucket_active_account"] = (
|
|
574
|
+
f"{active.get('username', '')}@{active.get('base_url', '')}"
|
|
575
|
+
if active.get("base_url") and active.get("username") else ""
|
|
576
|
+
)
|
|
577
|
+
info["bitbucket_default_repo"] = (
|
|
578
|
+
f"{bb_section.get('default_project', '')}/{bb_section.get('default_repo', '')}"
|
|
579
|
+
if bb_section.get("default_project") and bb_section.get("default_repo") else ""
|
|
580
|
+
)
|
|
581
|
+
else:
|
|
582
|
+
info["bitbucket_accounts"] = 0
|
|
583
|
+
info["bitbucket_active_account"] = ""
|
|
584
|
+
info["bitbucket_default_repo"] = ""
|
|
585
|
+
|
|
566
586
|
info["issues"] = issues
|
|
567
587
|
info["healthy"] = len(issues) == 0
|
|
568
588
|
return info
|
|
@@ -827,6 +847,11 @@ def cmd_init(args):
|
|
|
827
847
|
if not c3_dir.exists() or not (c3_dir / "config.json").exists():
|
|
828
848
|
print_header(f"Initializing C3 for: {project_path}")
|
|
829
849
|
_do_init(project_path, ide_name=requested_ide)
|
|
850
|
+
try:
|
|
851
|
+
from services.project_manager import ProjectManager
|
|
852
|
+
ProjectManager().add_project(project_path)
|
|
853
|
+
except Exception as _e:
|
|
854
|
+
print(f" [warn] Could not register project with hub: {_e}")
|
|
830
855
|
if getattr(args, "force", False):
|
|
831
856
|
if git_requested:
|
|
832
857
|
_init_local_git_repo(project_path)
|
|
@@ -941,6 +966,15 @@ def cmd_init(args):
|
|
|
941
966
|
except Exception:
|
|
942
967
|
print(" Gemini: unknown")
|
|
943
968
|
|
|
969
|
+
# Bitbucket integration (v2.30.0+)
|
|
970
|
+
bb_n = int(health.get("bitbucket_accounts") or 0)
|
|
971
|
+
if bb_n:
|
|
972
|
+
active = health.get("bitbucket_active_account") or "(no active)"
|
|
973
|
+
repo = health.get("bitbucket_default_repo") or "(no default repo)"
|
|
974
|
+
print(f" Bitbkt: {bb_n} account(s), active={active}, repo={repo}")
|
|
975
|
+
else:
|
|
976
|
+
print(" Bitbkt: not configured (run 'c3 bitbucket login --url <URL>')")
|
|
977
|
+
|
|
944
978
|
if health["healthy"]:
|
|
945
979
|
print("\n Status: healthy — no issues detected.")
|
|
946
980
|
else:
|
|
@@ -4457,6 +4491,7 @@ back to native tools as the task progresses.
|
|
|
4457
4491
|
- **Shell**: `c3_shell(cmd, timeout=60)` — structured shell exec (tests/git/build). Auto-filters output, logs git mutations to the ledger. Native Bash for interactive/TTY only
|
|
4458
4492
|
- **Memory**: `c3_memory(action='recall')` — full recall. `index` + `fetch` for token-efficient two-step retrieval
|
|
4459
4493
|
- **Delegate**: `c3_delegate(task, backend='ollama|codex|gemini|claude|auto')` — offload to other models
|
|
4494
|
+
- **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.
|
|
4460
4495
|
|
|
4461
4496
|
## Self-Check
|
|
4462
4497
|
If you haven't called a c3_* tool in several turns during active development, re-engage
|
|
@@ -5383,6 +5418,144 @@ def cmd_hub(args):
|
|
|
5383
5418
|
run_hub(port=port, open_browser=open_browser, silent=silent, quiet=quiet)
|
|
5384
5419
|
|
|
5385
5420
|
|
|
5421
|
+
def cmd_bitbucket(args):
|
|
5422
|
+
"""Bitbucket Data Center / Server credential + workspace management."""
|
|
5423
|
+
sub = getattr(args, "bitbucket_cmd", None)
|
|
5424
|
+
if not sub:
|
|
5425
|
+
print("Usage: c3 bitbucket {login,logout,status,use,set-default} [args]")
|
|
5426
|
+
return
|
|
5427
|
+
|
|
5428
|
+
project_path = getattr(args, "project_path", ".") or "."
|
|
5429
|
+
|
|
5430
|
+
if sub == "login":
|
|
5431
|
+
_bb_cmd_login(args, project_path)
|
|
5432
|
+
elif sub == "logout":
|
|
5433
|
+
_bb_cmd_logout(args, project_path)
|
|
5434
|
+
elif sub == "status":
|
|
5435
|
+
_bb_cmd_status(args, project_path)
|
|
5436
|
+
elif sub == "use":
|
|
5437
|
+
_bb_cmd_use(args, project_path)
|
|
5438
|
+
elif sub == "set-default":
|
|
5439
|
+
_bb_cmd_set_default(args, project_path)
|
|
5440
|
+
else:
|
|
5441
|
+
print(f"Unknown bitbucket subcommand: {sub}")
|
|
5442
|
+
|
|
5443
|
+
|
|
5444
|
+
def _bb_cmd_login(args, project_path: str) -> None:
|
|
5445
|
+
import getpass
|
|
5446
|
+
|
|
5447
|
+
from services import bitbucket_credentials as bb_creds
|
|
5448
|
+
from services.bitbucket_client import BitbucketDataCenterClient, BitbucketError
|
|
5449
|
+
|
|
5450
|
+
base_url = (args.url or "").rstrip("/")
|
|
5451
|
+
username = args.username or input(f"Username for {base_url}: ").strip()
|
|
5452
|
+
if not username:
|
|
5453
|
+
print("Login cancelled — username required.")
|
|
5454
|
+
return
|
|
5455
|
+
token = args.token or getpass.getpass(f"Personal Access Token for {username}: ").strip()
|
|
5456
|
+
if not token:
|
|
5457
|
+
print("Login cancelled — token required.")
|
|
5458
|
+
return
|
|
5459
|
+
|
|
5460
|
+
try:
|
|
5461
|
+
bb_creds.save_credentials(
|
|
5462
|
+
base_url, username, token,
|
|
5463
|
+
project_path=project_path,
|
|
5464
|
+
set_active=not getattr(args, "no_set_active", False),
|
|
5465
|
+
)
|
|
5466
|
+
except bb_creds.BitbucketCredentialError as exc:
|
|
5467
|
+
print(f"[error] {exc}")
|
|
5468
|
+
return
|
|
5469
|
+
|
|
5470
|
+
if getattr(args, "insecure", False):
|
|
5471
|
+
bb_creds.set_verify_tls(False, project_path=project_path)
|
|
5472
|
+
|
|
5473
|
+
print(f"[OK] Stored credentials for {username}@{base_url}")
|
|
5474
|
+
|
|
5475
|
+
# Connection probe — non-fatal if it fails (token might be valid but
|
|
5476
|
+
# network blocked at this moment).
|
|
5477
|
+
try:
|
|
5478
|
+
client = BitbucketDataCenterClient(
|
|
5479
|
+
base_url=base_url, token=token,
|
|
5480
|
+
verify_tls=not getattr(args, "insecure", False),
|
|
5481
|
+
)
|
|
5482
|
+
props = client.application_properties()
|
|
5483
|
+
version = props.get("version", "?")
|
|
5484
|
+
user = client.whoami()
|
|
5485
|
+
print(f" Server: {version} ({base_url})")
|
|
5486
|
+
print(f" Auth as: {user.get('displayName', username)} <{user.get('emailAddress', '?')}>")
|
|
5487
|
+
except BitbucketError as exc:
|
|
5488
|
+
print(f"[warn] Connection probe failed: {exc}")
|
|
5489
|
+
print(" Token saved anyway — re-test with `c3 bitbucket status`.")
|
|
5490
|
+
|
|
5491
|
+
|
|
5492
|
+
def _bb_cmd_logout(args, project_path: str) -> None:
|
|
5493
|
+
from services import bitbucket_credentials as bb_creds
|
|
5494
|
+
|
|
5495
|
+
base_url = (getattr(args, "url", "") or "").rstrip("/")
|
|
5496
|
+
username = getattr(args, "username", "") or ""
|
|
5497
|
+
if not base_url or not username:
|
|
5498
|
+
active = bb_creds.get_active_account(project_path)
|
|
5499
|
+
base_url = base_url or active.get("base_url", "")
|
|
5500
|
+
username = username or active.get("username", "")
|
|
5501
|
+
if not base_url or not username:
|
|
5502
|
+
print("[error] No account specified and no active account configured.")
|
|
5503
|
+
return
|
|
5504
|
+
removed = bb_creds.delete_credentials(base_url, username, project_path=project_path)
|
|
5505
|
+
if removed:
|
|
5506
|
+
print(f"[OK] Removed {username}@{base_url}")
|
|
5507
|
+
else:
|
|
5508
|
+
print(f"[warn] Nothing to remove for {username}@{base_url}")
|
|
5509
|
+
|
|
5510
|
+
|
|
5511
|
+
def _bb_cmd_status(args, project_path: str) -> None:
|
|
5512
|
+
from core.config import load_bitbucket_config
|
|
5513
|
+
from services import bitbucket_credentials as bb_creds
|
|
5514
|
+
from services.bitbucket_client import BitbucketDataCenterClient, BitbucketError
|
|
5515
|
+
|
|
5516
|
+
cfg = load_bitbucket_config(project_path)
|
|
5517
|
+
active = cfg.get("active") or {}
|
|
5518
|
+
accounts = cfg.get("accounts") or []
|
|
5519
|
+
|
|
5520
|
+
print("[bitbucket:status]")
|
|
5521
|
+
print(f" Active : {active.get('username') or '-'}@{active.get('base_url') or '-'}")
|
|
5522
|
+
print(f" Defaults: project={cfg.get('default_project') or '-'} repo={cfg.get('default_repo') or '-'}")
|
|
5523
|
+
print(f" Verify TLS: {cfg.get('verify_tls', True)}")
|
|
5524
|
+
print(f" Accounts ({len(accounts)}):")
|
|
5525
|
+
for a in accounts:
|
|
5526
|
+
marker = "*" if a == active else " "
|
|
5527
|
+
print(f" {marker} {a.get('username','?')}@{a.get('base_url','?')}")
|
|
5528
|
+
|
|
5529
|
+
if not active.get("base_url") or not active.get("username"):
|
|
5530
|
+
print(" Connection: (no active account)")
|
|
5531
|
+
return
|
|
5532
|
+
token = bb_creds.load_token(active["base_url"], active["username"])
|
|
5533
|
+
if not token:
|
|
5534
|
+
print(" Connection: FAIL — no token in keyring")
|
|
5535
|
+
return
|
|
5536
|
+
try:
|
|
5537
|
+
client = BitbucketDataCenterClient(
|
|
5538
|
+
base_url=active["base_url"], token=token,
|
|
5539
|
+
verify_tls=bool(cfg.get("verify_tls", True)),
|
|
5540
|
+
)
|
|
5541
|
+
props = client.application_properties()
|
|
5542
|
+
print(f" Connection: OK (version {props.get('version','?')})")
|
|
5543
|
+
except BitbucketError as exc:
|
|
5544
|
+
print(f" Connection: FAIL — {exc}")
|
|
5545
|
+
|
|
5546
|
+
|
|
5547
|
+
def _bb_cmd_use(args, project_path: str) -> None:
|
|
5548
|
+
from services import bitbucket_credentials as bb_creds
|
|
5549
|
+
bb_creds.set_active_account(args.url, args.username, project_path=project_path)
|
|
5550
|
+
print(f"[OK] Active account: {args.username}@{args.url.rstrip('/')}")
|
|
5551
|
+
|
|
5552
|
+
|
|
5553
|
+
def _bb_cmd_set_default(args, project_path: str) -> None:
|
|
5554
|
+
from services import bitbucket_credentials as bb_creds
|
|
5555
|
+
bb_creds.set_default_repo(args.project, args.repo, project_path=project_path)
|
|
5556
|
+
print(f"[OK] Default repo: {args.project}/{args.repo}")
|
|
5557
|
+
|
|
5558
|
+
|
|
5386
5559
|
def cmd_projects(args):
|
|
5387
5560
|
"""Manage the global C3 project registry."""
|
|
5388
5561
|
from services.project_manager import ProjectManager
|
|
@@ -6134,6 +6307,7 @@ def main():
|
|
|
6134
6307
|
"ui": cmd_ui,
|
|
6135
6308
|
"projects": cmd_projects,
|
|
6136
6309
|
"hub": cmd_hub,
|
|
6310
|
+
"bitbucket": cmd_bitbucket,
|
|
6137
6311
|
}
|
|
6138
6312
|
|
|
6139
6313
|
cmd_func = commands.get(args.command)
|
|
@@ -283,4 +283,43 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
283
283
|
p_bext.add_argument("--dry-run", action="store_true",
|
|
284
284
|
help="Validate setup (CLIs, datasets) without running the agent")
|
|
285
285
|
|
|
286
|
+
# ── Bitbucket Data Center / Server (v2.30.0) ─────────────────────────
|
|
287
|
+
p_bitbucket = subparsers.add_parser(
|
|
288
|
+
"bitbucket",
|
|
289
|
+
help="Bitbucket Data Center / Server credential + workspace management",
|
|
290
|
+
)
|
|
291
|
+
bb_subs = p_bitbucket.add_subparsers(dest="bitbucket_cmd")
|
|
292
|
+
|
|
293
|
+
bb_login = bb_subs.add_parser(
|
|
294
|
+
"login",
|
|
295
|
+
help="Authenticate with a Bitbucket Data Center server (interactive PAT prompt)",
|
|
296
|
+
)
|
|
297
|
+
bb_login.add_argument("--url", required=True, help="Bitbucket server base URL (e.g. https://bitbucket.example.com)")
|
|
298
|
+
bb_login.add_argument("--username", help="Bitbucket username (prompted if omitted)")
|
|
299
|
+
bb_login.add_argument("--token", help="Personal Access Token (prompted via getpass if omitted — preferred)")
|
|
300
|
+
bb_login.add_argument("--no-set-active", action="store_true", help="Do not switch the active account to this one")
|
|
301
|
+
bb_login.add_argument("--insecure", action="store_true", help="Disable TLS verification (self-signed certs)")
|
|
302
|
+
bb_login.add_argument("project_path", nargs="?", default=".")
|
|
303
|
+
|
|
304
|
+
bb_logout = bb_subs.add_parser("logout", help="Remove a Bitbucket account from keyring + config")
|
|
305
|
+
bb_logout.add_argument("--url", help="Bitbucket server base URL (defaults to active account)")
|
|
306
|
+
bb_logout.add_argument("--username", help="Username to log out (defaults to active account)")
|
|
307
|
+
bb_logout.add_argument("project_path", nargs="?", default=".")
|
|
308
|
+
|
|
309
|
+
bb_status = bb_subs.add_parser("status", help="Show configured Bitbucket accounts and connectivity")
|
|
310
|
+
bb_status.add_argument("project_path", nargs="?", default=".")
|
|
311
|
+
|
|
312
|
+
bb_use = bb_subs.add_parser("use", help="Switch the active Bitbucket account")
|
|
313
|
+
bb_use.add_argument("--url", required=True)
|
|
314
|
+
bb_use.add_argument("--username", required=True)
|
|
315
|
+
bb_use.add_argument("project_path", nargs="?", default=".")
|
|
316
|
+
|
|
317
|
+
bb_default = bb_subs.add_parser(
|
|
318
|
+
"set-default",
|
|
319
|
+
help="Set the default project key + repo slug for this C3 project",
|
|
320
|
+
)
|
|
321
|
+
bb_default.add_argument("--project", required=True, help="Bitbucket project key (e.g. PROJ)")
|
|
322
|
+
bb_default.add_argument("--repo", required=True, help="Repository slug")
|
|
323
|
+
bb_default.add_argument("project_path", nargs="?", default=".")
|
|
324
|
+
|
|
286
325
|
return parser
|
|
@@ -751,6 +751,7 @@
|
|
|
751
751
|
|
|
752
752
|
<div class="sidebar-section">MCP Server</div>
|
|
753
753
|
<a href="#mcp-tools">MCP Tools</a>
|
|
754
|
+
<a href="#bitbucket-tool">Bitbucket Integration</a>
|
|
754
755
|
<a href="#context-tools">Context Manager</a>
|
|
755
756
|
<a href="#claudemd-tools">Instructions Tools</a>
|
|
756
757
|
<a href="#agent-tools">Background Agents</a>
|
|
@@ -1147,7 +1148,7 @@ python cli/c3.py install-mcp . gemini</code></pre>
|
|
|
1147
1148
|
|
|
1148
1149
|
<!-- ─── MCP Tools ───────────────────── -->
|
|
1149
1150
|
<h2 id="mcp-tools">MCP Tools Reference</h2>
|
|
1150
|
-
<p>C3 exposes
|
|
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
1152
|
|
|
1152
1153
|
<h3>Discovery & Compression</h3>
|
|
1153
1154
|
<table>
|
|
@@ -1298,6 +1299,41 @@ python cli/c3.py install-mcp . gemini</code></pre>
|
|
|
1298
1299
|
View the full timeline at <code>/edits</code>.
|
|
1299
1300
|
</div>
|
|
1300
1301
|
|
|
1302
|
+
<!-- Bitbucket Integration (v2.30.0) -->
|
|
1303
|
+
<h2 id="bitbucket-tool">Bitbucket Data Center / Server</h2>
|
|
1304
|
+
<p>C3 v2.30.0 ships a dedicated <code>c3_bitbucket</code> tool for self-hosted enterprise Bitbucket. It supports read browsing (PRs, branches, builds, activity), PR write actions (create / comment / approve / decline / merge), branch writes, and repository administration (settings, webhooks, permissions). PATs are stored in the OS keyring — never in <code>.c3/config.json</code>.</p>
|
|
1305
|
+
|
|
1306
|
+
<table>
|
|
1307
|
+
<tr><th>Surface</th><th>What it provides</th></tr>
|
|
1308
|
+
<tr><td><code>c3_bitbucket</code> MCP tool</td><td>Action-dispatched Bitbucket calls from Claude Code (27 actions across read / PR-write / branch / admin)</td></tr>
|
|
1309
|
+
<tr><td><code>c3 bitbucket {login,logout,status,use,set-default}</code></td><td>CLI for credential and default-repo management. Login uses <code>getpass</code> for masked PAT entry.</td></tr>
|
|
1310
|
+
<tr><td>Hub UI Bitbucket tab</td><td>Per-project visual browser: Overview, Pull Requests, Branches, Activity, Admin</td></tr>
|
|
1311
|
+
<tr><td><code>/api/bitbucket/*</code> REST endpoints</td><td>Project session-server endpoints proxying to <code>BitbucketDataCenterClient</code></td></tr>
|
|
1312
|
+
</table>
|
|
1313
|
+
|
|
1314
|
+
<div class="tip">
|
|
1315
|
+
<div class="tip-title">Where the token lives</div>
|
|
1316
|
+
Tokens are stored exclusively in the <strong>OS keyring</strong> (Windows Credential Manager / macOS Keychain / Linux Secret Service) under service <code>c3-bitbucket</code>. Only a non-secret index of <code>(base_url, username)</code> pairs and the active-account pointer is written to <code>.c3/config.json</code>. <code>.c3/</code> is gitignored.
|
|
1317
|
+
</div>
|
|
1318
|
+
|
|
1319
|
+
<p><strong>Quick start</strong></p>
|
|
1320
|
+
<pre><code>c3 bitbucket login --url https://bitbucket.example.com
|
|
1321
|
+
c3 bitbucket set-default --project PROJ --repo my-service
|
|
1322
|
+
c3 bitbucket status</code></pre>
|
|
1323
|
+
|
|
1324
|
+
<p>From Claude Code:</p>
|
|
1325
|
+
<pre><code>c3_bitbucket(action='list_prs', state='OPEN')
|
|
1326
|
+
c3_bitbucket(action='get_pr', pr_id=42)
|
|
1327
|
+
c3_bitbucket(action='approve_pr', pr_id=42)
|
|
1328
|
+
c3_bitbucket(action='merge_pr', pr_id=42) # version auto-fetched</code></pre>
|
|
1329
|
+
|
|
1330
|
+
<div class="tip">
|
|
1331
|
+
<div class="tip-title">Audit trail</div>
|
|
1332
|
+
PR merges, branch deletes, webhook writes, and other mutating actions are appended to the C3 edit ledger under the virtual path <code>bitbucket://<project>/<repo></code> so the local audit trail covers platform-side state changes too. Token text is stripped from logged kwargs before persisting.
|
|
1333
|
+
</div>
|
|
1334
|
+
|
|
1335
|
+
<p>Full reference (action tables, security model, configuration shape, examples, troubleshooting): <a href="/guide/bitbucket.html">Bitbucket integration guide</a>. Currently <strong>Bitbucket Cloud</strong> (<code>bitbucket.org</code>) is not supported — only Data Center / Server.</p>
|
|
1336
|
+
|
|
1301
1337
|
<h3 id="agent-tools">Background Agents</h3>
|
|
1302
1338
|
<p>C3 runs 9 autonomous daemon threads that perform periodic analysis and surface findings via a notification
|
|
1303
1339
|
queue. Notifications are automatically prepended to the next MCP tool response so Claude sees them naturally.
|
|
@@ -35,6 +35,16 @@ _PYTHON_TYPE_NAMES = {
|
|
|
35
35
|
"Awaitable", "Coroutine", "AsyncIterator", "AsyncGenerator",
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
# Common heredoc / here-string end-markers that leak as filenames when
|
|
39
|
+
# Bash or PowerShell misparses a `<<EOF` / `@'...'@` block. Match is
|
|
40
|
+
# size-agnostic: a non-empty `EOF` file is still a ghost.
|
|
41
|
+
_HEREDOC_MARKERS = {
|
|
42
|
+
"EOF", "EOM", "EOL", "END", "STOP", "DONE",
|
|
43
|
+
"MARK", "MARKER", "DELIM", "DELIMITER",
|
|
44
|
+
"INPUT", "OUTPUT", "DATA", "BLOCK", "HEREDOC",
|
|
45
|
+
"'@", "@'", # PowerShell here-string fragments
|
|
46
|
+
}
|
|
47
|
+
|
|
38
48
|
# Max file size to consider a ghost (bytes). Genuine files are usually larger.
|
|
39
49
|
_MAX_GHOST_SIZE = 4096
|
|
40
50
|
|
|
@@ -108,6 +118,10 @@ def _is_ghost_file(path: Path) -> bool:
|
|
|
108
118
|
if name in _PYTHON_TYPE_NAMES:
|
|
109
119
|
return True
|
|
110
120
|
|
|
121
|
+
# HEREDOC end-marker leaked as filename (e.g., "EOF", "'@", "END")
|
|
122
|
+
if name in _HEREDOC_MARKERS and not real_suffix:
|
|
123
|
+
return True
|
|
124
|
+
|
|
111
125
|
# Partial type annotation (e.g., "tuple[float", "dict[str")
|
|
112
126
|
if "[" in name and not real_suffix:
|
|
113
127
|
return True
|
|
@@ -154,7 +168,9 @@ def scan_ghost_files(project_root: Path) -> list[dict]:
|
|
|
154
168
|
name = entry.name
|
|
155
169
|
|
|
156
170
|
# Determine reason
|
|
157
|
-
if name in
|
|
171
|
+
if name in _HEREDOC_MARKERS:
|
|
172
|
+
reason = "heredoc end-marker leak"
|
|
173
|
+
elif name in _PYTHON_TYPE_NAMES:
|
|
158
174
|
reason = "Python type name"
|
|
159
175
|
elif "[" in name:
|
|
160
176
|
reason = "partial type annotation"
|