code-context-control 2.29.0__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.
Files changed (185) hide show
  1. {code_context_control-2.29.0 → code_context_control-2.30.0}/PKG-INFO +37 -9
  2. {code_context_control-2.29.0 → code_context_control-2.30.0}/README.md +35 -8
  3. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/c3.py +172 -3
  4. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/commands/parser.py +39 -0
  5. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/docs.html +37 -1
  6. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_ghost_files.py +17 -1
  7. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/mcp_server.py +50 -0
  8. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/server.py +365 -0
  9. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/_helpers.py +17 -3
  10. code_context_control-2.30.0/cli/tools/bitbucket.py +654 -0
  11. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/app.js +4 -0
  12. code_context_control-2.30.0/cli/ui/components/bitbucket.js +297 -0
  13. {code_context_control-2.29.0 → code_context_control-2.30.0}/code_context_control.egg-info/PKG-INFO +37 -9
  14. {code_context_control-2.29.0 → code_context_control-2.30.0}/code_context_control.egg-info/SOURCES.txt +8 -0
  15. {code_context_control-2.29.0 → code_context_control-2.30.0}/code_context_control.egg-info/requires.txt +1 -0
  16. {code_context_control-2.29.0 → code_context_control-2.30.0}/core/config.py +29 -0
  17. {code_context_control-2.29.0 → code_context_control-2.30.0}/pyproject.toml +2 -1
  18. code_context_control-2.30.0/services/bitbucket_client.py +485 -0
  19. code_context_control-2.30.0/services/bitbucket_credentials.py +215 -0
  20. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/claude_md.py +1 -0
  21. code_context_control-2.30.0/tests/test_bitbucket_cli_smoke.py +59 -0
  22. code_context_control-2.30.0/tests/test_bitbucket_client.py +203 -0
  23. code_context_control-2.30.0/tests/test_bitbucket_credentials.py +124 -0
  24. code_context_control-2.30.0/tests/test_bitbucket_tool.py +179 -0
  25. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_ghost_files.py +22 -1
  26. {code_context_control-2.29.0 → code_context_control-2.30.0}/LICENSE +0 -0
  27. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/__init__.py +0 -0
  28. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/_hook_utils.py +0 -0
  29. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/commands/__init__.py +0 -0
  30. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/commands/common.py +0 -0
  31. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/edits.html +0 -0
  32. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_auto_snapshot.py +0 -0
  33. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_c3_signal.py +0 -0
  34. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_c3read.py +0 -0
  35. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_edit_ledger.py +0 -0
  36. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_edit_unlock.py +0 -0
  37. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_filter.py +0 -0
  38. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_pretool_enforce.py +0 -0
  39. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_read.py +0 -0
  40. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_session_stats.py +0 -0
  41. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hook_terse_advisor.py +0 -0
  42. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hub.html +0 -0
  43. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/hub_server.py +0 -0
  44. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/mcp_proxy.py +0 -0
  45. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/__init__.py +0 -0
  46. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/agent.py +0 -0
  47. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/compress.py +0 -0
  48. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/delegate.py +0 -0
  49. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/edit.py +0 -0
  50. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/edits.py +0 -0
  51. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/filter.py +0 -0
  52. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/impact.py +0 -0
  53. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/memory.py +0 -0
  54. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/read.py +0 -0
  55. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/search.py +0 -0
  56. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/session.py +0 -0
  57. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/shell.py +0 -0
  58. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/status.py +0 -0
  59. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/tools/validate.py +0 -0
  60. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/api.js +0 -0
  61. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/chat.js +0 -0
  62. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/dashboard.js +0 -0
  63. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/edits.js +0 -0
  64. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/instructions.js +0 -0
  65. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/memory.js +0 -0
  66. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/sessions.js +0 -0
  67. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/settings.js +0 -0
  68. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/components/sidebar.js +0 -0
  69. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/icons.js +0 -0
  70. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/shared.js +0 -0
  71. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui/theme.js +0 -0
  72. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui.html +0 -0
  73. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui_legacy.html +0 -0
  74. {code_context_control-2.29.0 → code_context_control-2.30.0}/cli/ui_nano.html +0 -0
  75. {code_context_control-2.29.0 → code_context_control-2.30.0}/code_context_control.egg-info/dependency_links.txt +0 -0
  76. {code_context_control-2.29.0 → code_context_control-2.30.0}/code_context_control.egg-info/entry_points.txt +0 -0
  77. {code_context_control-2.29.0 → code_context_control-2.30.0}/code_context_control.egg-info/top_level.txt +0 -0
  78. {code_context_control-2.29.0 → code_context_control-2.30.0}/core/__init__.py +0 -0
  79. {code_context_control-2.29.0 → code_context_control-2.30.0}/core/ide.py +0 -0
  80. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/__init__.py +0 -0
  81. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/config.py +0 -0
  82. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/oracle.html +0 -0
  83. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/oracle_server.py +0 -0
  84. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/__init__.py +0 -0
  85. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/c3_bridge.py +0 -0
  86. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/chat_engine.py +0 -0
  87. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/chat_store.py +0 -0
  88. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/cross_memory.py +0 -0
  89. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/federated_graph.py +0 -0
  90. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/health_checker.py +0 -0
  91. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/insight_engine.py +0 -0
  92. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/memory_reader.py +0 -0
  93. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/memory_writer.py +0 -0
  94. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/ollama_bridge.py +0 -0
  95. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/project_scanner.py +0 -0
  96. {code_context_control-2.29.0 → code_context_control-2.30.0}/oracle/services/review_agent.py +0 -0
  97. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/__init__.py +0 -0
  98. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/activity_log.py +0 -0
  99. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/agent_base.py +0 -0
  100. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/agents.py +0 -0
  101. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/auto_memory.py +0 -0
  102. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/bench/__init__.py +0 -0
  103. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/bench/external/__init__.py +0 -0
  104. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/bench/external/aider_polyglot.py +0 -0
  105. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/bench/external/swe_bench.py +0 -0
  106. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/benchmark_dashboard.py +0 -0
  107. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/compressor.py +0 -0
  108. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/context_snapshot.py +0 -0
  109. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/conversation_store.py +0 -0
  110. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/doc_index.py +0 -0
  111. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/e2e_benchmark.py +0 -0
  112. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/e2e_evaluator.py +0 -0
  113. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/e2e_tasks.py +0 -0
  114. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/edit_ledger.py +0 -0
  115. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/embedding_index.py +0 -0
  116. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/error_reporting.py +0 -0
  117. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/file_memory.py +0 -0
  118. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/hub_service.py +0 -0
  119. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/indexer.py +0 -0
  120. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/memory.py +0 -0
  121. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/memory_consolidator.py +0 -0
  122. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/memory_graph.py +0 -0
  123. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/memory_grounder.py +0 -0
  124. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/memory_scorer.py +0 -0
  125. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/metrics.py +0 -0
  126. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/notifications.py +0 -0
  127. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/ollama_client.py +0 -0
  128. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/output_filter.py +0 -0
  129. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/parser.py +0 -0
  130. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/project_manager.py +0 -0
  131. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/protocol.py +0 -0
  132. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/proxy_state.py +0 -0
  133. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/retrieval_broker.py +0 -0
  134. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/router.py +0 -0
  135. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/runtime.py +0 -0
  136. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/session_benchmark.py +0 -0
  137. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/session_manager.py +0 -0
  138. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/session_preloader.py +0 -0
  139. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/text_index.py +0 -0
  140. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/tool_classifier.py +0 -0
  141. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/transcript_index.py +0 -0
  142. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/validation_cache.py +0 -0
  143. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/vector_store.py +0 -0
  144. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/version_tracker.py +0 -0
  145. {code_context_control-2.29.0 → code_context_control-2.30.0}/services/watcher.py +0 -0
  146. {code_context_control-2.29.0 → code_context_control-2.30.0}/setup.cfg +0 -0
  147. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_aider_polyglot.py +0 -0
  148. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_c3_shell.py +0 -0
  149. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_cli_smoke.py +0 -0
  150. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_e2e_benchmark.py +0 -0
  151. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_edit_normalization.py +0 -0
  152. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_enforcement_flip.py +0 -0
  153. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_federated_graph.py +0 -0
  154. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_hub_server_smoke.py +0 -0
  155. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_mcp_server_smoke.py +0 -0
  156. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_memory_graph_api.py +0 -0
  157. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_memory_system.py +0 -0
  158. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_notification_discipline.py +0 -0
  159. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_output_filter.py +0 -0
  160. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_permissions.py +0 -0
  161. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_project_manager.py +0 -0
  162. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_project_manager_merge.py +0 -0
  163. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_session_benchmark.py +0 -0
  164. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_session_budget.py +0 -0
  165. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_swe_bench.py +0 -0
  166. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_validate.py +0 -0
  167. {code_context_control-2.29.0 → code_context_control-2.30.0}/tests/test_windows_reliability.py +0 -0
  168. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/__init__.py +0 -0
  169. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/backend.py +0 -0
  170. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/main.py +0 -0
  171. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/__init__.py +0 -0
  172. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/benchmark_view.py +0 -0
  173. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/claudemd_view.py +0 -0
  174. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/compress_view.py +0 -0
  175. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/index_view.py +0 -0
  176. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/init_view.py +0 -0
  177. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/mcp_view.py +0 -0
  178. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/optimize_view.py +0 -0
  179. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/pipe_view.py +0 -0
  180. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/projects_view.py +0 -0
  181. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/search_view.py +0 -0
  182. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/session_view.py +0 -0
  183. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/stats.py +0 -0
  184. {code_context_control-2.29.0 → code_context_control-2.30.0}/tui/screens/ui_view.py +0 -0
  185. {code_context_control-2.29.0 → 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.29.0
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
- Same data, grid layout:
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 14 tools as a native MCP server. Your IDE calls them directly:
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
- Every tool is **read-only safe in plan mode** (except `c3_edit` and `c3_shell`).
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
- Same data, grid layout:
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 14 tools as a native MCP server. Your IDE calls them directly:
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
- Every tool is **read-only safe in plan mode** (except `c3_edit` and `c3_shell`).
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.28.3"
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
@@ -946,6 +966,15 @@ def cmd_init(args):
946
966
  except Exception:
947
967
  print(" Gemini: unknown")
948
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
+
949
978
  if health["healthy"]:
950
979
  print("\n Status: healthy — no issues detected.")
951
980
  else:
@@ -4462,6 +4491,7 @@ back to native tools as the task progresses.
4462
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
4463
4492
  - **Memory**: `c3_memory(action='recall')` — full recall. `index` + `fetch` for token-efficient two-step retrieval
4464
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.
4465
4495
 
4466
4496
  ## Self-Check
4467
4497
  If you haven't called a c3_* tool in several turns during active development, re-engage
@@ -5388,6 +5418,144 @@ def cmd_hub(args):
5388
5418
  run_hub(port=port, open_browser=open_browser, silent=silent, quiet=quiet)
5389
5419
 
5390
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
+
5391
5559
  def cmd_projects(args):
5392
5560
  """Manage the global C3 project registry."""
5393
5561
  from services.project_manager import ProjectManager
@@ -6139,6 +6307,7 @@ def main():
6139
6307
  "ui": cmd_ui,
6140
6308
  "projects": cmd_projects,
6141
6309
  "hub": cmd_hub,
6310
+ "bitbucket": cmd_bitbucket,
6142
6311
  }
6143
6312
 
6144
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 9 MCP tools. All core tools work without Ollama; delegate requires it.</p>
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 &amp; 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://&lt;project&gt;/&lt;repo&gt;</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 _PYTHON_TYPE_NAMES:
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"
@@ -649,6 +649,56 @@ async def c3_shell(cmd: str, cwd: str = "", timeout: int = 60,
649
649
  return await handle_shell(cmd, cwd, timeout, filter_output, log, svc, finalize)
650
650
 
651
651
 
652
+ @mcp.tool()
653
+ async def c3_bitbucket(
654
+ action: str,
655
+ project: str = "",
656
+ repo: str = "",
657
+ pr_id: int = 0,
658
+ branch: str = "",
659
+ state: str = "OPEN",
660
+ title: str = "",
661
+ body: str = "",
662
+ from_branch: str = "",
663
+ to_branch: str = "",
664
+ description: str = "",
665
+ reviewers: str = "",
666
+ name: str = "",
667
+ url: str = "",
668
+ events: str = "",
669
+ start_point: str = "",
670
+ commit: str = "",
671
+ settings: str = "",
672
+ webhook_id: int = 0,
673
+ limit: int = 50,
674
+ ctx: Context = None,
675
+ ) -> str:
676
+ """BITBUCKET (Data Center / Server) — see and act on PRs, branches, builds, repo admin.
677
+ actions: status, whoami, list_projects, list_repos, get_repo,
678
+ list_prs, get_pr, get_pr_diff, get_pr_activities,
679
+ create_pr, comment_pr, approve_pr, unapprove_pr, decline_pr, merge_pr,
680
+ list_branches, create_branch, delete_branch,
681
+ list_commits, list_activity, build_status,
682
+ repo_settings, update_repo_settings, list_webhooks, create_webhook, delete_webhook,
683
+ list_permissions.
684
+ project/repo fall back to bitbucket.default_project/default_repo from .c3/config.json.
685
+ Tokens live in the OS keyring — `c3 bitbucket login` to set them up first."""
686
+ svc = _svc(ctx)
687
+
688
+ def finalize(fname, fargs, fresp, fsumm, **kw):
689
+ return _finalize_response(ctx, fname, fargs, fresp, fsumm, **kw)
690
+
691
+ from cli.tools.bitbucket import handle_bitbucket
692
+ return await asyncio.to_thread(
693
+ handle_bitbucket, action, svc, finalize,
694
+ project=project, repo=repo, pr_id=pr_id, branch=branch, state=state,
695
+ title=title, body=body, from_branch=from_branch, to_branch=to_branch,
696
+ description=description, reviewers=reviewers, name=name, url=url,
697
+ events=events, start_point=start_point, commit=commit,
698
+ settings=settings, webhook_id=webhook_id, limit=limit,
699
+ )
700
+
701
+
652
702
  def main() -> None:
653
703
  """Entry-point for the ``c3-mcp`` console script."""
654
704
  from services import error_reporting