codegraphcontext 0.4.0__tar.gz → 0.4.2__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 (140) hide show
  1. {codegraphcontext-0.4.0/src/codegraphcontext.egg-info → codegraphcontext-0.4.2}/PKG-INFO +8 -6
  2. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/README.md +6 -5
  3. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/pyproject.toml +2 -1
  4. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/cli_helpers.py +33 -14
  5. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/config_manager.py +173 -0
  6. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/main.py +30 -35
  7. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/registry_commands.py +4 -84
  8. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/setup_wizard.py +23 -2
  9. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/__init__.py +19 -30
  10. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/bundle_registry.py +12 -2
  11. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/cgc_bundle.py +3 -3
  12. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/watcher.py +6 -6
  13. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/server.py +139 -8
  14. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tool_definitions.py +23 -0
  15. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/code_finder.py +126 -38
  16. codegraphcontext-0.4.2/src/codegraphcontext/tools/graph_builder.py +320 -0
  17. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/handlers/analysis_handlers.py +3 -2
  18. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/handlers/indexing_handlers.py +2 -1
  19. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/handlers/management_handlers.py +8 -3
  20. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -4
  21. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/handlers/watcher_handlers.py +4 -5
  22. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/__init__.py +1 -0
  23. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/constants.py +25 -0
  24. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/discovery.py +64 -0
  25. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/persistence/__init__.py +3 -0
  26. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/persistence/writer.py +758 -0
  27. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/pipeline.py +89 -0
  28. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/pre_scan.py +105 -0
  29. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/resolution/__init__.py +8 -0
  30. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/resolution/calls.py +204 -0
  31. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/resolution/inheritance.py +91 -0
  32. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/sanitize.py +41 -0
  33. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/schema.py +79 -0
  34. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/schema_contract.py +44 -0
  35. codegraphcontext-0.4.2/src/codegraphcontext/tools/indexing/scip_pipeline.py +140 -0
  36. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/dart.py +14 -4
  37. codegraphcontext-0.4.2/src/codegraphcontext/tools/languages/haskell.py +426 -0
  38. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/java.py +0 -24
  39. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/javascript.py +1 -1
  40. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/perl.py +7 -2
  41. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/php.py +27 -0
  42. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/rust.py +18 -21
  43. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/scala.py +1 -1
  44. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/typescript.py +0 -2
  45. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/scip_indexer.py +2 -2
  46. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/system.py +6 -2
  47. codegraphcontext-0.4.2/src/codegraphcontext/tools/tree_sitter_parser.py +103 -0
  48. codegraphcontext-0.4.2/src/codegraphcontext/utils/repo_path.py +27 -0
  49. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/utils/tree_sitter_manager.py +1 -0
  50. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/__vite-browser-external-9wXp6ZBx.js +1 -0
  51. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
  52. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
  53. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
  54. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
  55. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/index-BJT3EMmQ.js +5571 -0
  56. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/index-DjDPHWki.css +1 -0
  57. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/parser.worker-CZgm11E5.js +208 -0
  58. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/assets/tree-sitter-qKYAACSa.wasm +0 -0
  59. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/favicon.ico +0 -0
  60. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/index.html +31 -0
  61. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/placeholder.svg +1 -0
  62. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/preview-image.png +0 -0
  63. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/robots.txt +14 -0
  64. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-c.wasm +0 -0
  65. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
  66. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-core.js +1 -0
  67. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-cpp.wasm +0 -0
  68. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-dart.wasm +0 -0
  69. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-go.wasm +0 -0
  70. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-java.wasm +0 -0
  71. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-javascript.wasm +0 -0
  72. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-kotlin.wasm +0 -0
  73. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-perl.wasm +1 -0
  74. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-php.wasm +0 -0
  75. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-python.wasm +0 -0
  76. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-ruby.wasm +0 -0
  77. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-rust.wasm +0 -0
  78. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-swift.wasm +0 -0
  79. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-tsx.wasm +0 -0
  80. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm +0 -0
  81. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/tree-sitter.wasm +0 -0
  82. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.js +4007 -0
  83. codegraphcontext-0.4.2/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm +0 -0
  84. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2/src/codegraphcontext.egg-info}/PKG-INFO +8 -6
  85. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext.egg-info/SOURCES.txt +51 -1
  86. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext.egg-info/requires.txt +3 -0
  87. codegraphcontext-0.4.0/src/codegraphcontext/tools/graph_builder.py +0 -1710
  88. codegraphcontext-0.4.0/src/codegraphcontext/tools/languages/haskell.py +0 -542
  89. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/LICENSE +0 -0
  90. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/MANIFEST.in +0 -0
  91. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/setup.cfg +0 -0
  92. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/__init__.py +0 -0
  93. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/__main__.py +0 -0
  94. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/__init__.py +0 -0
  95. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/setup_macos.py +0 -0
  96. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/cli/visualizer.py +0 -0
  97. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/cgcignore.py +0 -0
  98. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/database.py +0 -0
  99. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/database_falkordb.py +0 -0
  100. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
  101. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/database_kuzu.py +0 -0
  102. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/falkor_worker.py +0 -0
  103. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/core/jobs.py +0 -0
  104. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/prompts.py +0 -0
  105. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/__init__.py +0 -0
  106. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
  107. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/c.py +0 -0
  108. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/cpp.py +0 -0
  109. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/csharp.py +0 -0
  110. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/elixir.py +0 -0
  111. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/go.py +0 -0
  112. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
  113. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/python.py +0 -0
  114. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/ruby.py +0 -0
  115. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/swift.py +0 -0
  116. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
  117. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/package_resolver.py +0 -0
  118. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
  119. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
  120. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
  121. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
  122. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
  123. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
  124. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
  125. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
  126. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
  127. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
  128. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
  129. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
  130. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
  131. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
  132. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
  133. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/tools/scip_pb2.py +0 -0
  134. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/utils/debug_log.py +0 -0
  135. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/utils/path_ignore.py +0 -0
  136. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/utils/visualize_graph.py +0 -0
  137. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext/viz/server.py +0 -0
  138. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
  139. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
  140. {codegraphcontext-0.4.0 → codegraphcontext-0.4.2}/src/codegraphcontext.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codegraphcontext
3
- Version: 0.4.0
3
+ Version: 0.4.2
4
4
  Summary: An MCP server that indexes local code into a graph database to provide context to AI assistants.
5
5
  Author-email: Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
6
6
  License: MIT License
@@ -53,6 +53,7 @@ Requires-Dist: pathspec>=0.12.1
53
53
  Requires-Dist: falkordb>=0.1.0
54
54
  Requires-Dist: requests>=2.28.0
55
55
  Requires-Dist: falkordblite>=0.1.0; sys_platform != "win32" and python_version >= "3.12"
56
+ Requires-Dist: kuzu>=0.4.0; sys_platform == "win32" or (sys_platform != "win32" and python_version >= "3.10" and python_version < "3.12")
56
57
  Requires-Dist: fastapi>=0.100.0
57
58
  Requires-Dist: uvicorn>=0.22.0
58
59
  Provides-Extra: parsing
@@ -164,7 +165,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
164
165
  ---
165
166
 
166
167
  ## Project Details
167
- - **Version:** 0.4.0
168
+ - **Version:** 0.4.2
168
169
  - **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
169
170
  - **License:** MIT License (See [LICENSE](LICENSE) for details)
170
171
  - **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
@@ -197,7 +198,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
197
198
  - **Interactive Setup:** A user-friendly command-line wizard for easy setup.
198
199
  - **Dual Mode:** Works as a standalone **CLI toolkit** for developers and as an **MCP server** for AI agents.
199
200
  - **Multi-Language Support:** Full support for 14 programming languages.
200
- - **Flexible Database Backend:** KùzuDB (default, zero-config for all platforms), FalkorDB Lite (Unix-only), FalkorDB Remote, or Neo4j (all platforms via Docker/native).
201
+ - **Flexible Database Backend:** KùzuDB (default on Windows), FalkorDB Lite (typical embedded default on Unix when installed), FalkorDB Remote, or Neo4j (all platforms via Docker/native).
201
202
 
202
203
  ---
203
204
 
@@ -221,8 +222,9 @@ Each language parser extracts functions, classes, methods, parameters, inheritan
221
222
 
222
223
  CodeGraphContext supports multiple graph database backends to suit your environment:
223
224
 
224
- | Feature | KùzuDB (Default) | FalkorDB Lite | Neo4j |
225
+ | Feature | KùzuDB | FalkorDB Lite | Neo4j |
225
226
  | :--- | :--- | :--- | :--- |
227
+ | **Typical default** | **Windows** (embedded, when `kuzu` is installed) | **Unix** (Python 3.12+, when `falkordblite` works) | When explicitly configured |
226
228
  | **Setup** | Zero-config / Embedded | Zero-config / In-process | Docker / External |
227
229
  | **Platform** | **All (Windows Native, macOS, Linux)** | Unix-only (Linux/macOS/WSL) | All Platforms |
228
230
  | **Use Case** | Desktop, IDE, Local development | Specialized Unix development | Enterprise, Massive graphs |
@@ -337,8 +339,8 @@ Use CodeGraphContext as an **MCP server** for AI assistants:
337
339
 
338
340
  2. **Database Setup (Automatic)**
339
341
 
340
- - **KùzuDB (Default):** Runs natively on Windows, macOS, and Linux without any setup. Just `pip install kuzu` and you're ready!
341
- - **FalkorDB Lite (Alternative):** Supported on Unix/macOS/WSL for Python 3.12+.
342
+ - **KùzuDB (default on Windows):** Runs natively on Windows, macOS, and Linux. On Windows it is the usual embedded choice; `pip install kuzu` if needed.
343
+ - **FalkorDB Lite (typical default on Unix):** When Python 3.12+ and `falkordblite` are available on Unix/macOS/WSL, the embedded backend prefers FalkorDB Lite; otherwise KùzuDB is used.
342
344
  - **Neo4j (Alternative):** To use Neo4j instead, or if you prefer a server-based approach, run: `cgc neo4j setup`
343
345
 
344
346
  ---
@@ -97,7 +97,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
97
97
  ---
98
98
 
99
99
  ## Project Details
100
- - **Version:** 0.4.0
100
+ - **Version:** 0.4.2
101
101
  - **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
102
102
  - **License:** MIT License (See [LICENSE](LICENSE) for details)
103
103
  - **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
@@ -130,7 +130,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
130
130
  - **Interactive Setup:** A user-friendly command-line wizard for easy setup.
131
131
  - **Dual Mode:** Works as a standalone **CLI toolkit** for developers and as an **MCP server** for AI agents.
132
132
  - **Multi-Language Support:** Full support for 14 programming languages.
133
- - **Flexible Database Backend:** KùzuDB (default, zero-config for all platforms), FalkorDB Lite (Unix-only), FalkorDB Remote, or Neo4j (all platforms via Docker/native).
133
+ - **Flexible Database Backend:** KùzuDB (default on Windows), FalkorDB Lite (typical embedded default on Unix when installed), FalkorDB Remote, or Neo4j (all platforms via Docker/native).
134
134
 
135
135
  ---
136
136
 
@@ -154,8 +154,9 @@ Each language parser extracts functions, classes, methods, parameters, inheritan
154
154
 
155
155
  CodeGraphContext supports multiple graph database backends to suit your environment:
156
156
 
157
- | Feature | KùzuDB (Default) | FalkorDB Lite | Neo4j |
157
+ | Feature | KùzuDB | FalkorDB Lite | Neo4j |
158
158
  | :--- | :--- | :--- | :--- |
159
+ | **Typical default** | **Windows** (embedded, when `kuzu` is installed) | **Unix** (Python 3.12+, when `falkordblite` works) | When explicitly configured |
159
160
  | **Setup** | Zero-config / Embedded | Zero-config / In-process | Docker / External |
160
161
  | **Platform** | **All (Windows Native, macOS, Linux)** | Unix-only (Linux/macOS/WSL) | All Platforms |
161
162
  | **Use Case** | Desktop, IDE, Local development | Specialized Unix development | Enterprise, Massive graphs |
@@ -270,8 +271,8 @@ Use CodeGraphContext as an **MCP server** for AI assistants:
270
271
 
271
272
  2. **Database Setup (Automatic)**
272
273
 
273
- - **KùzuDB (Default):** Runs natively on Windows, macOS, and Linux without any setup. Just `pip install kuzu` and you're ready!
274
- - **FalkorDB Lite (Alternative):** Supported on Unix/macOS/WSL for Python 3.12+.
274
+ - **KùzuDB (default on Windows):** Runs natively on Windows, macOS, and Linux. On Windows it is the usual embedded choice; `pip install kuzu` if needed.
275
+ - **FalkorDB Lite (typical default on Unix):** When Python 3.12+ and `falkordblite` are available on Unix/macOS/WSL, the embedded backend prefers FalkorDB Lite; otherwise KùzuDB is used.
275
276
  - **Neo4j (Alternative):** To use Neo4j instead, or if you prefer a server-based approach, run: `cgc neo4j setup`
276
277
 
277
278
  ---
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codegraphcontext"
3
- version = "0.4.0"
3
+ version = "0.4.2"
4
4
  description = "An MCP server that indexes local code into a graph database to provide context to AI assistants."
5
5
  authors = [{ name = "Shashank Shekhar Singh", email = "shashankshekharsingh1205@gmail.com" }]
6
6
  readme = "README.md"
@@ -32,6 +32,7 @@ dependencies = [
32
32
  "falkordb>=0.1.0",
33
33
  "requests>=2.28.0",
34
34
  "falkordblite>=0.1.0; sys_platform != 'win32' and python_version >= '3.12'",
35
+ "kuzu>=0.4.0; sys_platform == 'win32' or (sys_platform != 'win32' and python_version >= '3.10' and python_version < '3.12')",
35
36
  "fastapi>=0.100.0",
36
37
  "uvicorn>=0.22.0"
37
38
  ]
@@ -24,6 +24,7 @@ from ..tools.code_finder import CodeFinder
24
24
  from ..tools.graph_builder import GraphBuilder
25
25
  from ..tools.package_resolver import get_local_package_path
26
26
  from ..utils.debug_log import info_logger, warning_logger
27
+ from ..utils.repo_path import any_repo_matches_path
27
28
  from .config_manager import resolve_context, ResolvedContext, register_repo_in_context, ensure_first_run_bootstrap
28
29
 
29
30
  console = Console()
@@ -175,8 +176,8 @@ def index_helper(path: str, context: Optional[str] = None):
175
176
  return
176
177
 
177
178
  indexed_repos = code_finder.list_indexed_repositories()
178
- repo_exists = any(Path(repo["path"]).resolve() == path_obj for repo in indexed_repos)
179
-
179
+ repo_exists = any_repo_matches_path(indexed_repos, path_obj)
180
+
180
181
  if repo_exists:
181
182
  # Check if the repository actually has files (not just an empty node from interrupted indexing)
182
183
  # Use variable-length path to handle both flat (Repository->File) and
@@ -184,7 +185,7 @@ def index_helper(path: str, context: Optional[str] = None):
184
185
  try:
185
186
  with db_manager.get_driver().session() as session:
186
187
  result = session.run(
187
- "MATCH (r:Repository {path: $path})-[:CONTAINS*]->(f:File) RETURN count(f) as file_count",
188
+ "MATCH (r:Repository {path: $path})-[:CONTAINS*]->(f:File) RETURN count(DISTINCT f) as file_count",
188
189
  path=str(path_obj)
189
190
  )
190
191
  record = result.single()
@@ -284,7 +285,7 @@ def list_repos_helper(context: Optional[str] = None):
284
285
 
285
286
  for repo in repos:
286
287
  repo_type = "Dependency" if repo.get("is_dependency") else "Project"
287
- table.add_row(repo["name"], repo["path"], repo_type)
288
+ table.add_row(repo.get("name") or "", str(repo.get("path") or ""), repo_type)
288
289
 
289
290
  console.print(table)
290
291
  except Exception as e:
@@ -377,7 +378,7 @@ import urllib.parse
377
378
  from ..viz.server import run_server, set_db_manager
378
379
 
379
380
  def visualize_helper(repo_path: Optional[str] = None, port: int = 8000, context: Optional[str] = None):
380
- """"Generates an interactive visualization using the Playground UI."""
381
+ """Generates an interactive visualization using the Playground UI."""
381
382
  services = _initialize_services(context)
382
383
  if not all(services[:3]):
383
384
  return
@@ -415,15 +416,33 @@ def visualize_helper(repo_path: Optional[str] = None, port: int = 8000, context:
415
416
  if cwd_static_dir.exists():
416
417
  static_dir = cwd_static_dir
417
418
  else:
418
- console.print(f"[yellow]Warning: Visualization assets not found.[/yellow]")
419
- console.print(f"[dim]Checked paths:[/dim]")
420
- console.print(f" [dim]- {static_dir}[/dim]")
419
+ console.print("[bold red]Visualization assets not found.[/bold red]")
420
+ console.print("[dim]Checked paths:[/dim]")
421
+ console.print(f" [dim]- {package_root / 'viz' / 'dist'}[/dim]")
421
422
  console.print(f" [dim]- {dev_static_dir}[/dim]")
422
423
  console.print(f" [dim]- {alt_dev_dir}[/dim]")
423
424
  console.print(f" [dim]- {cwd_static_dir}[/dim]")
424
- console.print("[dim]Please run 'cd website && npm run build' first.[/dim]")
425
- # We continue anyway to let the server start (helpful for dev)
426
-
425
+ console.print(
426
+ "[dim]If you installed from PyPI, upgrade after the next release "
427
+ "(wheels must bundle viz/dist). If you are developing from source, run:[/dim]"
428
+ )
429
+ console.print(" [cyan]./scripts/sync_viz_dist.sh[/cyan]")
430
+ console.print(
431
+ "[dim]or[/dim] [cyan]cd website && npm ci && npm run build[/cyan] "
432
+ "[dim]then sync[/dim] [cyan]website/dist[/cyan] [dim]→[/dim] "
433
+ "[cyan]src/codegraphcontext/viz/dist[/cyan][dim].[/dim]"
434
+ )
435
+ db_manager.close_driver()
436
+ raise SystemExit(1)
437
+
438
+ index_html = static_dir / "index.html"
439
+ if not index_html.is_file():
440
+ console.print(
441
+ f"[bold red]Invalid visualization bundle:[/bold red] missing {index_html}"
442
+ )
443
+ db_manager.close_driver()
444
+ raise SystemExit(1)
445
+
427
446
  # Construct the URL
428
447
  backend_url = f"http://localhost:{port}"
429
448
  params = {"backend": backend_url}
@@ -471,8 +490,8 @@ def reindex_helper(path: str, context: Optional[str] = None):
471
490
 
472
491
  # Check if already indexed
473
492
  indexed_repos = code_finder.list_indexed_repositories()
474
- repo_exists = any(Path(repo["path"]).resolve() == path_obj for repo in indexed_repos)
475
-
493
+ repo_exists = any_repo_matches_path(indexed_repos, path_obj)
494
+
476
495
  if repo_exists:
477
496
  console.print(f"[yellow]Deleting existing index for: {path_obj}[/yellow]")
478
497
  try:
@@ -671,7 +690,7 @@ def watch_helper(path: str, context: Optional[str] = None):
671
690
  # transient empty result from list_indexed_repositories never triggers a
672
691
  # destructive full rescan of an already-populated graph.
673
692
  indexed_repos = code_finder.list_indexed_repositories()
674
- is_indexed = any(Path(repo["path"]).resolve() == path_obj for repo in indexed_repos)
693
+ is_indexed = any_repo_matches_path(indexed_repos, path_obj)
675
694
  if not is_indexed:
676
695
  # Fallback: count File nodes whose path starts with this repo's path.
677
696
  # If > 100 exist, the repo is clearly already indexed — skip the scan.
@@ -219,6 +219,18 @@ def find_local_env() -> Optional[Path]:
219
219
  return None
220
220
 
221
221
 
222
+ def codegraphcontext_dotenv_at_cwd(cwd: Optional[Path] = None) -> Optional[Path]:
223
+ """
224
+ Return ``<cwd>/.codegraphcontext/.env`` if that file exists, else None.
225
+
226
+ *cwd* defaults to ``Path.cwd()``. Parent directories are **not** searched—same rule as
227
+ local context resolution (``find_local_cgc_dir``).
228
+ """
229
+ root = (cwd or Path.cwd()).resolve()
230
+ candidate = root / ".codegraphcontext" / ".env"
231
+ return candidate if candidate.exists() else None
232
+
233
+
222
234
  def save_config(config: Dict[str, str], preserve_db_credentials: bool = True):
223
235
  """
224
236
  Save configuration to file.
@@ -739,6 +751,21 @@ def resolve_context(
739
751
  is_local=True,
740
752
  )
741
753
 
754
+ # --- 2b. Saved workspace mapping (CWD -> child .codegraphcontext/) ---
755
+ mapping = get_workspace_mapping(cwd)
756
+ if mapping:
757
+ mapped_ctx_path = Path(mapping["context_path"])
758
+ if mapped_ctx_path.exists() and mapped_ctx_path.is_dir():
759
+ mapped_db = mapping.get("database", "falkordb")
760
+ return ResolvedContext(
761
+ mode="per-repo",
762
+ context_name="",
763
+ database=mapped_db,
764
+ db_path=str(mapped_ctx_path / "db" / mapped_db),
765
+ cgcignore_path=str(mapped_ctx_path / ".cgcignore"),
766
+ is_local=True,
767
+ )
768
+
742
769
  # --- 3. Global config.yaml ---
743
770
  if cfg.mode == "named":
744
771
  ctx_name = cfg.default_context
@@ -876,3 +903,149 @@ def list_contexts() -> List[ContextInfo]:
876
903
  """Return all named contexts."""
877
904
  cfg = load_context_config()
878
905
  return list(cfg.contexts.values())
906
+
907
+
908
+ # =============================================================================
909
+ # CHILD CONTEXT DISCOVERY
910
+ # =============================================================================
911
+
912
+ @dataclass
913
+ class DiscoveredContext:
914
+ """A .codegraphcontext folder found in a child directory."""
915
+ path: str # absolute path to the parent repo directory
916
+ cgc_path: str # absolute path to the .codegraphcontext directory
917
+ repo_name: str # name of the parent directory
918
+ database: str # backend from local config.yaml, or default
919
+ db_path: str # resolved db path
920
+ cgcignore_path: str # path to .cgcignore if present
921
+
922
+
923
+ def discover_child_contexts(
924
+ start: Optional[Path] = None,
925
+ max_depth: int = 1,
926
+ ) -> List[DiscoveredContext]:
927
+ """Walk child directories of *start* up to *max_depth* levels looking for
928
+ ``.codegraphcontext/`` folders that represent per-repo databases.
929
+
930
+ Returns a list of :class:`DiscoveredContext` for each match found.
931
+ The global ``~/.codegraphcontext`` is always excluded.
932
+ """
933
+ start = (start or Path.cwd()).resolve()
934
+ global_dir = CONFIG_DIR.resolve()
935
+ results: List[DiscoveredContext] = []
936
+
937
+ def _scan(directory: Path, depth: int) -> None:
938
+ if depth > max_depth:
939
+ return
940
+ try:
941
+ entries = sorted(directory.iterdir())
942
+ except PermissionError:
943
+ return
944
+ for entry in entries:
945
+ if not entry.is_dir() or entry.name.startswith("."):
946
+ continue
947
+ candidate = entry / ".codegraphcontext"
948
+ if candidate.exists() and candidate.is_dir() and candidate.resolve() != global_dir:
949
+ local_db = "falkordb"
950
+ local_yaml = candidate / "config.yaml"
951
+ if local_yaml.exists():
952
+ try:
953
+ with open(local_yaml) as f:
954
+ raw = yaml.safe_load(f) or {}
955
+ local_db = raw.get("database", "falkordb")
956
+ except Exception:
957
+ pass
958
+ results.append(DiscoveredContext(
959
+ path=str(entry),
960
+ cgc_path=str(candidate),
961
+ repo_name=entry.name,
962
+ database=local_db,
963
+ db_path=str(candidate / "db" / local_db),
964
+ cgcignore_path=str(candidate / ".cgcignore"),
965
+ ))
966
+ if depth < max_depth:
967
+ _scan(entry, depth + 1)
968
+
969
+ _scan(start, 1)
970
+ return results
971
+
972
+
973
+ # =============================================================================
974
+ # WORKSPACE MAPPINGS (global persistence of CWD -> context path)
975
+ # =============================================================================
976
+
977
+ def _load_workspace_mappings() -> Dict[str, Dict[str, str]]:
978
+ """Load the ``workspace_mappings`` section from config.yaml."""
979
+ if not CONTEXT_CONFIG_FILE.exists():
980
+ return {}
981
+ try:
982
+ with open(CONTEXT_CONFIG_FILE, "r") as f:
983
+ raw = yaml.safe_load(f) or {}
984
+ return raw.get("workspace_mappings", {}) or {}
985
+ except Exception:
986
+ return {}
987
+
988
+
989
+ def _save_workspace_mappings(mappings: Dict[str, Dict[str, str]]) -> None:
990
+ """Write *mappings* back into the ``workspace_mappings`` key of config.yaml,
991
+ preserving all other keys."""
992
+ ensure_config_dir()
993
+ raw: Dict[str, Any] = {}
994
+ if CONTEXT_CONFIG_FILE.exists():
995
+ try:
996
+ with open(CONTEXT_CONFIG_FILE, "r") as f:
997
+ raw = yaml.safe_load(f) or {}
998
+ except Exception:
999
+ raw = {}
1000
+ raw["workspace_mappings"] = mappings
1001
+ try:
1002
+ with open(CONTEXT_CONFIG_FILE, "w") as f:
1003
+ yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
1004
+ except Exception as e:
1005
+ console.print(f"[red]Error saving workspace mappings: {e}[/red]")
1006
+
1007
+
1008
+ def get_workspace_mapping(cwd: Path) -> Optional[Dict[str, str]]:
1009
+ """Look up a saved workspace mapping for *cwd*.
1010
+
1011
+ Returns a dict with ``context_path`` and ``database`` keys, or None.
1012
+ """
1013
+ mappings = _load_workspace_mappings()
1014
+ return mappings.get(str(cwd.resolve()))
1015
+
1016
+
1017
+ def save_workspace_mapping(cwd: Path, context_path: Path) -> None:
1018
+ """Persist an association from *cwd* to a ``.codegraphcontext`` directory."""
1019
+ context_path = context_path.resolve()
1020
+ local_db = "falkordb"
1021
+ local_yaml = context_path / "config.yaml"
1022
+ if local_yaml.exists():
1023
+ try:
1024
+ with open(local_yaml) as f:
1025
+ raw = yaml.safe_load(f) or {}
1026
+ local_db = raw.get("database", "falkordb")
1027
+ except Exception:
1028
+ pass
1029
+
1030
+ mappings = _load_workspace_mappings()
1031
+ mappings[str(cwd.resolve())] = {
1032
+ "context_path": str(context_path),
1033
+ "database": local_db,
1034
+ }
1035
+ _save_workspace_mappings(mappings)
1036
+
1037
+
1038
+ def remove_workspace_mapping(cwd: Path) -> bool:
1039
+ """Delete a saved workspace mapping. Returns True if one was removed."""
1040
+ mappings = _load_workspace_mappings()
1041
+ key = str(cwd.resolve())
1042
+ if key in mappings:
1043
+ del mappings[key]
1044
+ _save_workspace_mappings(mappings)
1045
+ return True
1046
+ return False
1047
+
1048
+
1049
+ def list_workspace_mappings() -> Dict[str, Dict[str, str]]:
1050
+ """Return all saved workspace mappings."""
1051
+ return _load_workspace_mappings()
@@ -19,7 +19,6 @@ import logging
19
19
  import json
20
20
  import os
21
21
  from pathlib import Path
22
- from dotenv import load_dotenv, find_dotenv, set_key
23
22
  from importlib.metadata import version as pkg_version, PackageNotFoundError
24
23
 
25
24
  from codegraphcontext.server import MCPServer
@@ -111,6 +110,7 @@ def mcp_setup():
111
110
  - VS Code, Cursor, Windsurf
112
111
  - Claude Desktop, Gemini CLI
113
112
  - Cline, RooCode, Amazon Q Developer
113
+ - OpenCode (prints stdio config + link to vendor docs)
114
114
 
115
115
  Works with FalkorDB by default (no database setup needed).
116
116
  """
@@ -290,19 +290,18 @@ def _load_credentials():
290
290
  Uses per-variable precedence - each variable is loaded from the highest priority source.
291
291
  Priority order (highest to lowest):
292
292
  1. Local `mcp.json` env vars (highest - explicit MCP server config)
293
- 2. Local `.env` in project directory (high - project-specific overrides)
293
+ 2. ``<cwd>/.codegraphcontext/.env`` only (no parent-directory walk)
294
294
  3. Global `~/.codegraphcontext/.env` (lowest - user defaults)
295
+
296
+ Step 2 skips duplicate loading when that file is the same path as the global file.
297
+ Arbitrary repo-root `.env` files are not loaded—only CodeGraphContext config paths.
295
298
  """
296
299
  from dotenv import dotenv_values
297
- from codegraphcontext.cli.config_manager import ensure_config_dir
300
+ from codegraphcontext.cli.config_manager import (
301
+ ensure_config_dir,
302
+ codegraphcontext_dotenv_at_cwd,
303
+ )
298
304
 
299
- # Capture DATABASE_TYPE from actual shell env BEFORE we load .env files.
300
- # If the user ran `DATABASE_TYPE=falkordb cgc …` we must not let
301
- # DEFAULT_DATABASE=neo4j in .env steal priority later.
302
- shell_db_type = os.environ.get('DATABASE_TYPE')
303
- if shell_db_type and not os.environ.get('CGC_RUNTIME_DB_TYPE'):
304
- os.environ['CGC_RUNTIME_DB_TYPE'] = shell_db_type
305
-
306
305
  # Ensure config directory exists (lazy initialization)
307
306
  ensure_config_dir()
308
307
 
@@ -319,14 +318,16 @@ def _load_credentials():
319
318
  except Exception as e:
320
319
  console.print(f"[yellow]Warning: Could not load global .env: {e}[/yellow]")
321
320
 
322
- # 2. Local project .env (higher priority - project-specific overrides)
321
+ # 2. <cwd>/.codegraphcontext/.env only (overrides global when distinct)
323
322
  try:
324
- dotenv_path = find_dotenv(usecwd=True, raise_error_if_not_found=False)
325
- if dotenv_path:
326
- config_sources.append(dotenv_values(dotenv_path))
327
- config_source_names.append(str(dotenv_path))
323
+ local_cgc_env = codegraphcontext_dotenv_at_cwd(Path.cwd())
324
+ if local_cgc_env and local_cgc_env.resolve() != global_env_path.resolve():
325
+ config_sources.append(dotenv_values(str(local_cgc_env)))
326
+ config_source_names.append(str(local_cgc_env))
328
327
  except Exception as e:
329
- console.print(f"[yellow]Warning: Could not load .env from current directory: {e}[/yellow]")
328
+ console.print(
329
+ f"[yellow]Warning: Could not load .codegraphcontext/.env at cwd: {e}[/yellow]"
330
+ )
330
331
 
331
332
  # 1. Local mcp.json (highest priority - explicit MCP server config)
332
333
  mcp_file_path = Path.cwd() / "mcp.json"
@@ -348,9 +349,9 @@ def _load_credentials():
348
349
 
349
350
  # Apply merged config to environment.
350
351
  # IMPORTANT: DB-selection keys set in the shell must win over .env defaults.
351
- # E.g. `DATABASE_TYPE=falkordb cgc index …` must not be overridden by
352
+ # E.g. `DEFAULT_DATABASE=falkordb cgc index …` must not be overridden by
352
353
  # DEFAULT_DATABASE=neo4j sitting in ~/.codegraphcontext/.env
353
- DB_OVERRIDE_KEYS = {"DATABASE_TYPE", "CGC_RUNTIME_DB_TYPE", "DEFAULT_DATABASE"}
354
+ DB_OVERRIDE_KEYS = {"CGC_RUNTIME_DB_TYPE", "DEFAULT_DATABASE"}
354
355
  for key, value in merged_config.items():
355
356
  if value is not None: # Only set non-None values
356
357
  # Never let .env clobber a DB-type key that the user already set in the shell
@@ -369,16 +370,10 @@ def _load_credentials():
369
370
 
370
371
 
371
372
  # Show which database is actually being used.
372
- # When DATABASE_TYPE is explicitly set, trust it. When it's left to auto-
373
- # detect, call get_database_manager() so the banner can never lie: e.g. if
374
- # falkordblite is installed but its native .so is missing (frozen bundle),
375
- # the factory falls back to KùzuDB and we display that correctly.
373
+ # When CGC_RUNTIME_DB_TYPE or DEFAULT_DATABASE is set, trust it. Otherwise
374
+ # call get_database_manager() so the banner matches factory fallbacks.
376
375
  runtime_db = os.environ.get("CGC_RUNTIME_DB_TYPE")
377
- explicit_db = (
378
- runtime_db
379
- or os.environ.get("DEFAULT_DATABASE")
380
- or os.environ.get("DATABASE_TYPE")
381
- )
376
+ explicit_db = runtime_db or os.environ.get("DEFAULT_DATABASE")
382
377
 
383
378
  if explicit_db:
384
379
  default_db = explicit_db.lower()
@@ -416,12 +411,9 @@ def _load_credentials():
416
411
  if host:
417
412
  console.print(f"[cyan]Using database: FalkorDB Remote ({host})[/cyan]")
418
413
  else:
419
- console.print("[yellow]⚠ DATABASE_TYPE=falkordb-remote but FALKORDB_HOST not set.[/yellow]")
420
- elif default_db == "falkordb":
421
- if os.environ.get("FALKORDB_HOST"):
422
- console.print(f"[cyan]Using database: FalkorDB Remote ({os.environ.get('FALKORDB_HOST')})[/cyan]")
423
- else:
424
- console.print("[cyan]Using database: FalkorDB[/cyan]")
414
+ console.print(
415
+ "[yellow]⚠ DEFAULT_DATABASE=falkordb-remote but FALKORDB_HOST not set.[/yellow]"
416
+ )
425
417
  else:
426
418
  console.print(f"[cyan]Using database: {default_db}[/cyan]")
427
419
 
@@ -677,10 +669,12 @@ def bundle_load(
677
669
  @app.command("export", rich_help_panel="Bundle Shortcuts")
678
670
  def export_shortcut(
679
671
  output: str = typer.Argument(..., help="Output path for the .cgc bundle file"),
680
- repo: Optional[str] = typer.Option(None, "--repo", "-r", help="Specific repository path to export")
672
+ repo: Optional[str] = typer.Option(None, "--repo", "-r", help="Specific repository path to export"),
673
+ no_stats: bool = typer.Option(False, "--no-stats", help="Skip generating statistics in the bundle"),
674
+ context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
681
675
  ):
682
676
  """Shortcut for 'cgc bundle export'"""
683
- bundle_export(output, repo, False)
677
+ bundle_export(output, repo, no_stats, context)
684
678
 
685
679
  @app.command("load", rich_help_panel="Bundle Shortcuts")
686
680
  def load_shortcut(
@@ -801,6 +795,7 @@ def doctor():
801
795
 
802
796
  # 1. Check configuration
803
797
  console.print("[bold]1. Checking Configuration...[/bold]")
798
+ config = {}
804
799
  try:
805
800
  config = config_manager.load_config()
806
801
 
@@ -17,93 +17,12 @@ console = Console()
17
17
 
18
18
  GITHUB_ORG = "CodeGraphContext"
19
19
  GITHUB_REPO = "CodeGraphContext"
20
- REGISTRY_API_URL = f"https://api.github.com/repos/{GITHUB_ORG}/{GITHUB_REPO}/releases"
21
- MANIFEST_URL = f"https://github.com/{GITHUB_ORG}/{GITHUB_REPO}/releases/download/on-demand-bundles/manifest.json"
22
20
 
23
21
 
24
22
  def fetch_available_bundles() -> List[Dict[str, Any]]:
25
- """
26
- Fetch all available bundles from GitHub Releases.
27
- Returns a list of bundle dictionaries with metadata.
28
- Preserves all versions - no deduplication.
29
- """
30
- all_bundles = []
31
-
32
- try:
33
- # 1. Fetch on-demand bundles from manifest
34
- try:
35
- response = requests.get(MANIFEST_URL, timeout=10)
36
- if response.status_code == 200:
37
- manifest = response.json()
38
- if manifest.get('bundles'):
39
- for bundle in manifest['bundles']:
40
- bundle['source'] = 'on-demand'
41
- # Ensure bundle has a full_name field (with version info)
42
- if 'bundle_name' in bundle:
43
- # Extract full name without .cgc extension
44
- bundle['full_name'] = bundle['bundle_name'].replace('.cgc', '')
45
- all_bundles.append(bundle)
46
- except Exception as e:
47
- console.print(f"[dim]Note: Could not fetch on-demand bundles: {e}[/dim]")
48
-
49
- # 2. Fetch weekly pre-indexed bundles
50
- try:
51
- response = requests.get(REGISTRY_API_URL, timeout=10)
52
- if response.status_code == 200:
53
- releases = response.json()
54
-
55
- # Find weekly releases (bundles-YYYYMMDD pattern)
56
- weekly_releases = [r for r in releases if r['tag_name'].startswith('bundles-') and r['tag_name'] != 'bundles-latest']
57
-
58
- if weekly_releases:
59
- # Get the most recent weekly release
60
- latest_weekly = weekly_releases[0]
61
-
62
- for asset in latest_weekly.get('assets', []):
63
- if asset['name'].endswith('.cgc'):
64
- # Full bundle name without extension
65
- full_name = asset['name'].replace('.cgc', '')
66
-
67
- # Parse bundle name
68
- name_parts = full_name.split('-')
69
- bundle = {
70
- 'name': name_parts[0], # Base package name
71
- 'full_name': full_name, # Complete name with version
72
- 'repo': f"{name_parts[0]}/{name_parts[0]}", # Simplified
73
- 'bundle_name': asset['name'],
74
- 'version': name_parts[1] if len(name_parts) > 1 else 'latest',
75
- 'commit': name_parts[2] if len(name_parts) > 2 else 'unknown',
76
- 'size': f"{asset['size'] / 1024 / 1024:.1f}MB",
77
- 'download_url': asset['browser_download_url'],
78
- 'generated_at': asset['updated_at'],
79
- 'source': 'weekly'
80
- }
81
- all_bundles.append(bundle)
82
- except Exception as e:
83
- console.print(f"[dim]Note: Could not fetch weekly bundles: {e}[/dim]")
84
-
85
- # Normalize all bundles to have required fields
86
- for bundle in all_bundles:
87
- # Ensure 'name' field exists (base package name)
88
- if 'name' not in bundle:
89
- repo = bundle.get('repo', '')
90
- if '/' in repo:
91
- bundle['name'] = repo.split('/')[-1]
92
- else:
93
- # Extract from full_name or bundle_name
94
- full_name = bundle.get('full_name', bundle.get('bundle_name', 'unknown'))
95
- bundle['name'] = full_name.split('-')[0]
96
-
97
- # Ensure 'full_name' exists
98
- if 'full_name' not in bundle:
99
- bundle['full_name'] = bundle.get('bundle_name', bundle.get('name', 'unknown')).replace('.cgc', '')
100
-
101
- # NO DEDUPLICATION - Keep all versions
102
- return all_bundles
103
-
104
- except Exception as e:
105
- console.print(f"[bold red]Error fetching bundles: {e}[/bold red]")
106
- return []
23
+ """Fetch all available bundles from GitHub Releases (delegates to core BundleRegistry)."""
24
+ from ..core.bundle_registry import BundleRegistry
25
+ return BundleRegistry.fetch_available_bundles()
107
26
 
108
27
 
109
28
  def _get_base_package_name(bundle_name: str) -> str:
@@ -213,6 +132,7 @@ def search_bundles(query: str):
213
132
  matching_bundles = [
214
133
  b for b in bundles
215
134
  if query_lower in b.get('name', '').lower() or
135
+ query_lower in b.get('full_name', '').lower() or
216
136
  query_lower in b.get('repo', '').lower() or
217
137
  query_lower in b.get('description', '').lower()
218
138
  ]