codegraphcontext 0.6.2__tar.gz → 0.6.4__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 (190) hide show
  1. {codegraphcontext-0.6.2/src/codegraphcontext.egg-info → codegraphcontext-0.6.4}/PKG-INFO +1 -1
  2. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/pyproject.toml +1 -1
  3. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/cli_helpers.py +4 -0
  4. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/config_manager.py +15 -0
  5. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/main.py +227 -16
  6. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/watcher.py +20 -8
  7. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/code_finder.py +162 -9
  8. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/embeddings.py +32 -0
  9. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/persistence/writer.py +95 -38
  10. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/pipeline.py +24 -10
  11. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/inheritance.py +83 -6
  12. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/csharp.py +20 -1
  13. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/dart.py +12 -5
  14. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/python.py +9 -1
  15. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/ruby.py +11 -3
  16. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/rust.py +58 -24
  17. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/scala.py +1 -1
  18. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4/src/codegraphcontext.egg-info}/PKG-INFO +1 -1
  19. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/LICENSE +0 -0
  20. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/MANIFEST.in +0 -0
  21. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/README.md +0 -0
  22. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/setup.cfg +0 -0
  23. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/__init__.py +0 -0
  24. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/__main__.py +0 -0
  25. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/__init__.py +0 -0
  26. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/app.py +0 -0
  27. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/auth.py +0 -0
  28. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/mcp_sse.py +0 -0
  29. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/router.py +0 -0
  30. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/schemas.py +0 -0
  31. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/__init__.py +0 -0
  32. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/hook_manager.py +0 -0
  33. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/project_config.py +0 -0
  34. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/registry_commands.py +0 -0
  35. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/setup_macos.py +0 -0
  36. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/setup_wizard.py +0 -0
  37. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/simulator.py +0 -0
  38. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/visualizer.py +0 -0
  39. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/__init__.py +0 -0
  40. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/bundle_registry.py +0 -0
  41. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/cgc_bundle.py +0 -0
  42. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/cgcignore.py +0 -0
  43. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database.py +0 -0
  44. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_embedded_kuzu.py +0 -0
  45. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_falkordb.py +0 -0
  46. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
  47. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_kuzu.py +0 -0
  48. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_ladybug.py +0 -0
  49. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_nornic.py +0 -0
  50. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/falkor_worker.py +0 -0
  51. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/graph_query.py +0 -0
  52. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/jobs.py +0 -0
  53. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/simulator.py +0 -0
  54. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/prompts.py +0 -0
  55. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/server.py +0 -0
  56. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/stdlibs.py +0 -0
  57. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tool_definitions.py +0 -0
  58. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/__init__.py +0 -0
  59. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
  60. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/__init__.py +0 -0
  61. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/cassandra_ingester.py +0 -0
  62. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/mysql_ingester.py +0 -0
  63. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/redis_ingester.py +0 -0
  64. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/graph_builder.py +0 -0
  65. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/analysis_handlers.py +0 -0
  66. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/indexing_handlers.py +0 -0
  67. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/management_handlers.py +0 -0
  68. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -0
  69. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/watcher_handlers.py +0 -0
  70. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/__init__.py +0 -0
  71. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/constants.py +0 -0
  72. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/discovery.py +0 -0
  73. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/persistence/__init__.py +0 -0
  74. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/persistence/utils.py +0 -0
  75. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/pre_scan.py +0 -0
  76. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/__init__.py +0 -0
  77. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/calls.py +0 -0
  78. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/post_resolution.py +0 -0
  79. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/sanitize.py +0 -0
  80. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/schema.py +0 -0
  81. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/schema_contract.py +0 -0
  82. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/scip_pipeline.py +0 -0
  83. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/vector_resolver.py +0 -0
  84. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/c.py +0 -0
  85. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/cpp.py +0 -0
  86. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/css.py +0 -0
  87. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/elisp.py +0 -0
  88. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/elixir.py +0 -0
  89. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/go.py +0 -0
  90. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/gradle.py +0 -0
  91. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/haskell.py +0 -0
  92. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/html.py +0 -0
  93. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/java.py +0 -0
  94. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/javascript.py +0 -0
  95. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
  96. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/lua.py +0 -0
  97. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/maven.py +0 -0
  98. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/mybatis.py +0 -0
  99. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/perl.py +0 -0
  100. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/php.py +0 -0
  101. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/sfc_common.py +0 -0
  102. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/solidity.py +0 -0
  103. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/solidity_remappings.py +0 -0
  104. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/svelte.py +0 -0
  105. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/swift.py +0 -0
  106. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/typescript.py +0 -0
  107. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
  108. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/vue.py +0 -0
  109. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/package_resolver.py +0 -0
  110. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
  111. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
  112. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
  113. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
  114. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/elisp_toolkit.py +0 -0
  115. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
  116. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
  117. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
  118. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
  119. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
  120. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
  121. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
  122. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
  123. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
  124. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/solidity_toolkit.py +0 -0
  125. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
  126. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
  127. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/report_generator.py +0 -0
  128. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/scip_indexer.py +0 -0
  129. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/scip_pb2.py +0 -0
  130. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/system.py +0 -0
  131. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/tree_sitter_parser.py +0 -0
  132. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/type_utils.py +0 -0
  133. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/cypher_ddl.py +0 -0
  134. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/cypher_readonly.py +0 -0
  135. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/debug_log.py +0 -0
  136. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/gcf_encoder.py +0 -0
  137. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/git_utils.py +0 -0
  138. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/path_ignore.py +0 -0
  139. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/path_sandbox.py +0 -0
  140. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/repo_path.py +0 -0
  141. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/secret_scanner.py +0 -0
  142. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/tool_limits.py +0 -0
  143. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/tree_sitter_manager.py +0 -0
  144. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/visualize_graph.py +0 -0
  145. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/__vite-browser-external-9wXp6ZBx.js +0 -0
  146. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
  147. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
  148. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
  149. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
  150. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/index-C-187lf0.js +0 -0
  151. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/index-fNAa6jgv.css +0 -0
  152. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/parser-pyodide.worker-BgsDfaad.js +0 -0
  153. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/parser.worker-_nvrecvj.js +0 -0
  154. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/tree-sitter-qKYAACSa.wasm +0 -0
  155. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/cgcIcon.png +0 -0
  156. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/favicon.ico +0 -0
  157. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/index.html +0 -0
  158. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/logo-icon.svg +0 -0
  159. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/logo.svg +0 -0
  160. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/placeholder.svg +0 -0
  161. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/preview-image.png +0 -0
  162. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/robots.txt +0 -0
  163. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c.wasm +0 -0
  164. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
  165. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-core.js +0 -0
  166. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-cpp.wasm +0 -0
  167. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-dart.wasm +0 -0
  168. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-go.wasm +0 -0
  169. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-java.wasm +0 -0
  170. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-javascript.wasm +0 -0
  171. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-kotlin.wasm +0 -0
  172. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-perl.wasm +0 -0
  173. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-php.wasm +0 -0
  174. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-python.wasm +0 -0
  175. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-ruby.wasm +0 -0
  176. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-rust.wasm +0 -0
  177. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-swift.wasm +0 -0
  178. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-tsx.wasm +0 -0
  179. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm +0 -0
  180. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter.wasm +0 -0
  181. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.js +0 -0
  182. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm +0 -0
  183. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/server.py +0 -0
  184. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/SOURCES.txt +0 -0
  185. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
  186. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
  187. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/requires.txt +0 -0
  188. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/top_level.txt +0 -0
  189. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/tests/test_issue_806_fix.py +0 -0
  190. {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/tests/test_mcp_sse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codegraphcontext
3
- Version: 0.6.2
3
+ Version: 0.6.4
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codegraphcontext"
3
- version = "0.6.2"
3
+ version = "0.6.4"
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"
@@ -123,6 +123,10 @@ def _print_index_execution_summary(graph_builder: GraphBuilder) -> None:
123
123
  f"{summary.get('serialization_seconds', 0.0):.2f}",
124
124
  )
125
125
  console.print(table)
126
+ # Always-visible warnings (#1597): these describe an explicitly enabled
127
+ # feature that did NOT run — they must not depend on the log level.
128
+ for warning in summary.get("warnings", []):
129
+ console.print(f"[bold yellow]⚠ {warning}[/bold yellow]")
126
130
 
127
131
 
128
132
  def _initialize_services(
@@ -685,6 +685,21 @@ def set_config_value(key: str, value: str) -> bool:
685
685
  save_config(config)
686
686
 
687
687
  console.print(f"[green]✅ Set {key} = {value}[/green]")
688
+
689
+ # Surface a missing embedding backend at the moment of intent, not after
690
+ # an index run that silently generated nothing (#1597).
691
+ if key == "ENABLE_VECTOR_RESOLVE" and value.lower() == "true":
692
+ try:
693
+ from codegraphcontext.tools.indexing.embeddings import probe_embedding_backend
694
+ ok, detail = probe_embedding_backend()
695
+ if not ok:
696
+ console.print(
697
+ f"[bold yellow]⚠ Vector resolve is enabled but cannot run yet: "
698
+ f"{detail}. Indexing will proceed without embeddings until "
699
+ f"this is installed.[/bold yellow]"
700
+ )
701
+ except Exception:
702
+ pass
688
703
  return True
689
704
 
690
705
 
@@ -1149,6 +1149,104 @@ def export_shortcut(
1149
1149
  context=context,
1150
1150
  )
1151
1151
 
1152
+ @app.command("diagram")
1153
+ def diagram(
1154
+ path: Optional[str] = typer.Argument(None, help="Repository path to scope the diagram to"),
1155
+ output_format: str = typer.Option("mermaid", "--format", help="Diagram format: mermaid or dot (#1287)"),
1156
+ level: str = typer.Option("file", "--level", help="Granularity: 'file' (file→module imports) or 'call' (function call graph)"),
1157
+ output: Optional[str] = typer.Option(None, "--output", "-o", help="Write to a file instead of stdout"),
1158
+ limit: int = typer.Option(300, "--limit", "-l", help="Maximum edges to include (truncation is reported in the diagram)"),
1159
+ context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
1160
+ ):
1161
+ """
1162
+ Export the context graph as a Mermaid or Graphviz DOT diagram.
1163
+
1164
+ Mermaid output pastes straight into GitHub Markdown / Notion; DOT renders
1165
+ locally with graphviz. The diagram is a generated artifact of the current
1166
+ index — regenerate it after refactors rather than committing it as
1167
+ documentation.
1168
+
1169
+ Example:
1170
+ cgc diagram . > architecture.mmd
1171
+ cgc diagram . --format dot -o graph.dot && dot -Tsvg graph.dot -o graph.svg
1172
+ cgc diagram . --level call --limit 100
1173
+ """
1174
+ output_format = output_format.lower()
1175
+ if output_format not in ("mermaid", "dot"):
1176
+ console.print(f"[red]Unknown --format '{output_format}' (expected mermaid or dot)[/red]")
1177
+ raise typer.Exit(code=2)
1178
+ if level not in ("file", "call"):
1179
+ console.print(f"[red]Unknown --level '{level}' (expected file or call)[/red]")
1180
+ raise typer.Exit(code=2)
1181
+ # stdout carries only the diagram; init chatter goes to stderr for the
1182
+ # init window only (restored after — a permanent rebind leaks a closed
1183
+ # stream into later in-process invocations).
1184
+ import sys as _sys
1185
+ from . import cli_helpers as _cli_helpers
1186
+ # NB: the .file property GETTER materializes the current (possibly
1187
+ # transient, CliRunner-captured) stream; the dynamic state lives in
1188
+ # ._file, which is None while the console follows sys.stdout live.
1189
+ _prev_console_file = _cli_helpers.console._file
1190
+ if output is None:
1191
+ _cli_helpers.console.file = _sys.stderr
1192
+ try:
1193
+ _load_credentials()
1194
+ services = _initialize_services(context)
1195
+ finally:
1196
+ _cli_helpers.console._file = _prev_console_file
1197
+ if not all(services[:3]):
1198
+ raise typer.Exit(code=1)
1199
+ db_manager, graph_builder, code_finder = services[:3]
1200
+
1201
+ try:
1202
+ repo_path = Path(path).resolve().as_posix() if path else None
1203
+ result = code_finder.export_diagram_edges(level=level, repo_path=repo_path, limit=limit)
1204
+ finally:
1205
+ db_manager.close_driver()
1206
+
1207
+ edges = result["edges"]
1208
+ ids: dict = {}
1209
+
1210
+ def _node_id(name: str) -> str:
1211
+ if name not in ids:
1212
+ ids[name] = f"n{len(ids)}"
1213
+ return ids[name]
1214
+
1215
+ lines = []
1216
+ if output_format == "mermaid":
1217
+ lines.append("graph LR")
1218
+ if result["truncated"]:
1219
+ lines.append(f" %% truncated: showing {len(edges)} of {result['total_count']} edges (raise --limit)")
1220
+ for src, dst in edges:
1221
+ sid, did = _node_id(src), _node_id(dst)
1222
+ s_label = src.replace('"', "'")
1223
+ d_label = dst.replace('"', "'")
1224
+ lines.append(f' {sid}["{s_label}"] --> {did}["{d_label}"]')
1225
+ if not edges:
1226
+ lines.append(" %% no edges found for this scope")
1227
+ else:
1228
+ lines.append("digraph cgc {")
1229
+ lines.append(" rankdir=LR;")
1230
+ if result["truncated"]:
1231
+ lines.append(f" // truncated: showing {len(edges)} of {result['total_count']} edges (raise --limit)")
1232
+ for src, dst in edges:
1233
+ sid, did = _node_id(src), _node_id(dst)
1234
+ lines.append(f' {sid} -> {did};')
1235
+ for name, nid in ids.items():
1236
+ label = name.replace('"', "'")
1237
+ lines.append(f' {nid} [label="{label}"];')
1238
+ lines.append("}")
1239
+
1240
+ text = "\n".join(lines) + "\n"
1241
+ if output:
1242
+ Path(output).write_text(text, encoding="utf-8")
1243
+ console.print(f"[green]✅ Wrote {output_format} diagram ({len(edges)} edges) to {output}[/green]")
1244
+ if result["truncated"]:
1245
+ console.print(f"[yellow]⚠ Truncated: {result['total_count']} total edges; raise --limit to include all[/yellow]")
1246
+ else:
1247
+ print(text, end="")
1248
+
1249
+
1152
1250
  @app.command("load", rich_help_panel="Bundle Shortcuts")
1153
1251
  def load_shortcut(
1154
1252
  bundle_name: str = typer.Argument(..., help="Bundle name or path to load"),
@@ -2905,9 +3003,11 @@ def analyze_inheritance_tree(
2905
3003
  def analyze_complexity(
2906
3004
  path: Optional[str] = typer.Argument(None, help="Function name or file path to analyze"),
2907
3005
  threshold: Optional[int] = typer.Option(None, "--threshold", "-t", help="Complexity threshold for warnings (default: from config or 10)"),
2908
- limit: int = typer.Option(20, "--limit", "-l", help="Maximum results to show"),
3006
+ limit: Optional[int] = typer.Option(None, "--limit", "-l", help="Maximum results to show (default 20 for text; unlimited for json/csv)"),
2909
3007
  file: Optional[str] = typer.Option(None, "--file", "-f", help="Specific file path to scope analysis"),
2910
3008
  context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
3009
+ output_format: str = typer.Option("text", "--format", help="Output format: text, json or csv (#1333)"),
3010
+ fail_on_violations: bool = typer.Option(False, "--fail-on-violations", help="Exit with code 1 when any function exceeds the threshold (CI gate)"),
2911
3011
  ):
2912
3012
  """
2913
3013
  Show cyclomatic complexity for functions.
@@ -2920,9 +3020,30 @@ def analyze_complexity(
2920
3020
  cgc analyze complexity src/main.py # Most complex functions in file
2921
3021
  cgc analyze complexity main.py # Most complex functions in file
2922
3022
  cgc analyze complexity --file src/main.py # Alternative file syntax
2923
- """
2924
- _load_credentials()
2925
- services = _initialize_services(context)
3023
+ cgc analyze complexity -t 10 --format json --fail-on-violations # CI gate
3024
+ """
3025
+ output_format = output_format.lower()
3026
+ if output_format not in ("text", "json", "csv"):
3027
+ console.print(f"[red]Unknown --format '{output_format}' (expected text, json or csv)[/red]")
3028
+ raise typer.Exit(code=2)
3029
+ # stdout must carry ONLY the parseable document in machine formats: the
3030
+ # service-init chatter from cli_helpers prints to stdout, so reroute that
3031
+ # console to stderr FOR THE INIT WINDOW ONLY (`--format json | jq .`).
3032
+ # The rebind must be restored — a permanent one leaks a closed stream into
3033
+ # later in-process invocations (CliRunner-based tests).
3034
+ import sys as _sys
3035
+ from . import cli_helpers as _cli_helpers
3036
+ # NB: the .file property GETTER materializes the current (possibly
3037
+ # transient, CliRunner-captured) stream; the dynamic state lives in
3038
+ # ._file, which is None while the console follows sys.stdout live.
3039
+ _prev_console_file = _cli_helpers.console._file
3040
+ if output_format in ("json", "csv"):
3041
+ _cli_helpers.console.file = _sys.stderr
3042
+ try:
3043
+ _load_credentials()
3044
+ services = _initialize_services(context)
3045
+ finally:
3046
+ _cli_helpers.console._file = _prev_console_file
2926
3047
  if not all(services[:3]):
2927
3048
  raise typer.Exit(code=1)
2928
3049
  db_manager, graph_builder, code_finder = services[:3]
@@ -2938,6 +3059,47 @@ def analyze_complexity(
2938
3059
  else:
2939
3060
  threshold = 10
2940
3061
 
3062
+ machine_output = output_format in ("json", "csv")
3063
+ # Enforcement and export need the full set: a display page must never
3064
+ # truncate the violation count a CI gate acts on (#1333).
3065
+ effective_limit = limit if limit is not None else (None if (machine_output or fail_on_violations) else 20)
3066
+
3067
+ def _violations_from(results):
3068
+ rows = []
3069
+ for func in results or []:
3070
+ # The synthetic `<module>` frame is the attribution target for
3071
+ # module-level calls, not a function anyone can refactor.
3072
+ if func.get("function_name") == "<module>":
3073
+ continue
3074
+ complexity = func.get("complexity", 0) or 0
3075
+ if complexity > threshold:
3076
+ rows.append({
3077
+ "function": func.get("function_name", ""),
3078
+ "file": func.get("path", ""),
3079
+ "line": func.get("line_number"),
3080
+ "complexity": complexity,
3081
+ "exceeds_by": complexity - threshold,
3082
+ })
3083
+ return rows
3084
+
3085
+ def _emit_machine(violations):
3086
+ import csv as _csv
3087
+ import io as _io
3088
+ import json as _json
3089
+ if output_format == "json":
3090
+ print(_json.dumps({
3091
+ "threshold": threshold,
3092
+ "violations_count": len(violations),
3093
+ "violations": violations,
3094
+ }, indent=2))
3095
+ else:
3096
+ buf = _io.StringIO()
3097
+ w = _csv.writer(buf)
3098
+ w.writerow(["function", "file", "line", "complexity", "exceeds_by"])
3099
+ for v in violations:
3100
+ w.writerow([v["function"], v["file"], v["line"], v["complexity"], v["exceeds_by"]])
3101
+ print(buf.getvalue(), end="")
3102
+
2941
3103
  _FILE_EXTENSIONS = ('.py', '.js', '.ts', '.jsx', '.tsx', '.go', '.rs', '.rb',
2942
3104
  '.java', '.cpp', '.c', '.cs', '.swift', '.kt', '.scala',
2943
3105
  '.php', '.lua', '.zig', '.ex', '.exs', '.r', '.m', '.sh')
@@ -2970,15 +3132,31 @@ def analyze_complexity(
2970
3132
  console.print(table)
2971
3133
  console.print(f"\n[dim]{len([f for f in results if f.get('complexity', 0) > threshold])} function(s) exceed threshold[/dim]")
2972
3134
 
3135
+ violations = None
2973
3136
  try:
2974
3137
  if path and _is_file_path(path):
2975
3138
  # File path provided as positional argument
2976
- results = code_finder.find_most_complex_functions_in_file(path, limit)
2977
- _render_complexity_table(results, f"Most Complex Functions in '{path}' (threshold: {threshold}):")
3139
+ results = code_finder.find_most_complex_functions_in_file(path, effective_limit)
3140
+ violations = _violations_from(results)
3141
+ if machine_output:
3142
+ _emit_machine(violations)
3143
+ else:
3144
+ _render_complexity_table(results, f"Most Complex Functions in '{path}' (threshold: {threshold}):")
2978
3145
  elif path:
2979
3146
  # Specific function name
2980
3147
  result = code_finder.get_cyclomatic_complexity(path, file)
3148
+ single = []
2981
3149
  if result:
3150
+ single = [{
3151
+ "function_name": path,
3152
+ "path": result.get("path", ""),
3153
+ "line_number": result.get("line_number"),
3154
+ "complexity": result.get("complexity", 0) or 0,
3155
+ }]
3156
+ violations = _violations_from(single)
3157
+ if machine_output:
3158
+ _emit_machine(violations)
3159
+ elif result:
2982
3160
  console.print(f"\n[bold cyan]Complexity for '{path}':[/bold cyan]")
2983
3161
  console.print(f" Cyclomatic Complexity: [yellow]{result.get('complexity', 'N/A')}[/yellow]")
2984
3162
  console.print(f" File: [dim]{result.get('path', '')}[/dim]")
@@ -2987,20 +3165,36 @@ def analyze_complexity(
2987
3165
  console.print(f"[yellow]Function '{path}' not found or has no complexity data[/yellow]")
2988
3166
  elif file:
2989
3167
  # --file option without positional arg
2990
- results = code_finder.find_most_complex_functions_in_file(file, limit)
2991
- _render_complexity_table(results, f"Most Complex Functions in '{file}' (threshold: {threshold}):")
3168
+ results = code_finder.find_most_complex_functions_in_file(file, effective_limit)
3169
+ violations = _violations_from(results)
3170
+ if machine_output:
3171
+ _emit_machine(violations)
3172
+ else:
3173
+ _render_complexity_table(results, f"Most Complex Functions in '{file}' (threshold: {threshold}):")
2992
3174
  else:
2993
3175
  # Global - most complex functions
2994
- results = code_finder.find_most_complex_functions(limit)
2995
- _render_complexity_table(results, f"Most Complex Functions (threshold: {threshold}):")
3176
+ results = code_finder.find_most_complex_functions(effective_limit)
3177
+ violations = _violations_from(results)
3178
+ if machine_output:
3179
+ _emit_machine(violations)
3180
+ else:
3181
+ _render_complexity_table(results, f"Most Complex Functions (threshold: {threshold}):")
2996
3182
  finally:
2997
3183
  db_manager.close_driver()
2998
3184
 
3185
+ # CI gate (#1333): explicit opt-in keeps exploratory usage exit-0 —
3186
+ # the config default threshold means most codebases have *some*
3187
+ # function above it, and failing every casual invocation would break
3188
+ # innocent `cgc analyze complexity && …` chains.
3189
+ if fail_on_violations and violations:
3190
+ raise typer.Exit(code=1)
3191
+
2999
3192
  @analyze_app.command("dead-code")
3000
3193
  def analyze_dead_code(
3001
3194
  path: Optional[str] = typer.Argument(None, help="Repository path to scope the analysis to"),
3002
3195
  exclude_decorators: Optional[str] = typer.Option(None, "--exclude", "-e", help="Comma-separated decorators to exclude"),
3003
3196
  context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
3197
+ show_all: bool = typer.Option(False, "--show-all", help="Include low-confidence rows (dunders, test hooks, entry-point names) normally hidden (#1332)"),
3004
3198
  ):
3005
3199
  """
3006
3200
  Find potentially unused functions.
@@ -3030,7 +3224,8 @@ def analyze_dead_code(
3030
3224
  # of table rows. The true count comes from total_count below (#1606).
3031
3225
  display_limit = get_tool_result_limit("find_dead_code")
3032
3226
  results = code_finder.find_dead_code(
3033
- exclude_list, repo_path=repo_path, limit=display_limit
3227
+ exclude_list, repo_path=repo_path, limit=display_limit,
3228
+ include_low_confidence=show_all,
3034
3229
  )
3035
3230
 
3036
3231
  unused_funcs = results.get('potentially_unused_functions', [])
@@ -3042,16 +3237,22 @@ def analyze_dead_code(
3042
3237
 
3043
3238
  table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
3044
3239
  table.add_column("Function", style="cyan")
3240
+ table.add_column("Confidence", justify="center")
3045
3241
  table.add_column("Location", style="dim", overflow="fold")
3046
-
3242
+
3243
+ _conf_render = {
3244
+ "high": "[red]● high[/red]",
3245
+ "medium": "[yellow]● medium[/yellow]",
3246
+ "low": "[dim]● low[/dim]",
3247
+ }
3047
3248
  for func in unused_funcs:
3048
- path = func.get('path', '')
3249
+ fpath = func.get('path', '')
3049
3250
  line_str = str(func.get('line_number', ''))
3050
- location_str = f"{path}:{line_str}" if line_str else path
3051
-
3251
+ location_str = f"{fpath}:{line_str}" if line_str else fpath
3052
3252
  table.add_row(
3053
3253
  func.get('function_name', ''),
3054
- location_str
3254
+ _conf_render.get(func.get('confidence', 'high'), func.get('confidence', '')),
3255
+ location_str,
3055
3256
  )
3056
3257
 
3057
3258
  console.print("\n[bold yellow]⚠️ Potentially Unused Functions:[/bold yellow]")
@@ -3063,6 +3264,16 @@ def analyze_dead_code(
3063
3264
  )
3064
3265
  else:
3065
3266
  console.print(f"\n[dim]Total: {total_count} function(s)[/dim]")
3267
+ counts = results.get('confidence_counts') or {}
3268
+ if counts:
3269
+ summary = (
3270
+ f"[red]{counts.get('high', 0)} high[/red], "
3271
+ f"[yellow]{counts.get('medium', 0)} medium[/yellow], "
3272
+ f"[dim]{counts.get('low', 0)} low[/dim] confidence"
3273
+ )
3274
+ if not show_all:
3275
+ summary += " [dim](low-confidence categories are hidden — use --show-all)[/dim]"
3276
+ console.print(summary)
3066
3277
  console.print(f"[dim]Note: {results.get('note', '')}[/dim]")
3067
3278
  finally:
3068
3279
  db_manager.close_driver()
@@ -324,14 +324,26 @@ class RepositoryEventHandler(FileSystemEventHandler):
324
324
  _inherit_enabled = False
325
325
 
326
326
  if _vector_enabled:
327
- try:
328
- from codegraphcontext.tools.indexing.embeddings import EmbeddingPipeline
329
- embed_pipeline = EmbeddingPipeline(self.graph_builder.driver)
330
- embed_pipeline.invalidate_for_file(changed_path_str)
331
- embed_pipeline.run(str(self.repo_path))
332
- info_logger(f"[EMBED] Incremental embedding complete for {changed_path_str}")
333
- except Exception as _e:
334
- warning_logger(f"[EMBED] Incremental embedding failed: {_e}")
327
+ # Probe once per handler: with no backend installed, the old code
328
+ # re-attempted (and re-failed) the import on every file event and
329
+ # only said so at a suppressed log level (#1597).
330
+ if not hasattr(self, "_embed_backend_ok"):
331
+ from codegraphcontext.tools.indexing.embeddings import probe_embedding_backend
332
+ self._embed_backend_ok, _detail = probe_embedding_backend()
333
+ if not self._embed_backend_ok:
334
+ error_logger(
335
+ f"[EMBED] ENABLE_VECTOR_RESOLVE=true but incremental embeddings "
336
+ f"cannot run: {_detail} (reported once; further file events skip this)"
337
+ )
338
+ if self._embed_backend_ok:
339
+ try:
340
+ from codegraphcontext.tools.indexing.embeddings import EmbeddingPipeline
341
+ embed_pipeline = EmbeddingPipeline(self.graph_builder.driver)
342
+ embed_pipeline.invalidate_for_file(changed_path_str)
343
+ embed_pipeline.run(str(self.repo_path))
344
+ info_logger(f"[EMBED] Incremental embedding complete for {changed_path_str}")
345
+ except Exception as _e:
346
+ warning_logger(f"[EMBED] Incremental embedding failed: {_e}")
335
347
 
336
348
  if _inherit_enabled:
337
349
  try:
@@ -44,6 +44,41 @@ _ANDROID_ENTRY_POINT_NAMES = (
44
44
  "onconfigurationchanged", "onlowmemory", "ontrimmemory",
45
45
  "onbindviewholder", "oncreateviewholder", "getitemcount",
46
46
  )
47
+ _TEST_HOOK_NAMES = {
48
+ "setup", "teardown", "setupclass", "teardownclass",
49
+ "setupmodule", "teardownmodule", "setup_method", "teardown_method",
50
+ }
51
+
52
+
53
+ def _classify_dead_code_confidence(row: dict) -> tuple:
54
+ """(confidence, reason) for a zero-caller symbol (#1332).
55
+
56
+ low — matches a category that is almost always a false positive
57
+ (dunder, test hook/prefix, entry-point name, override, test file)
58
+ medium — decorated: decorators frequently register implicit callers
59
+ (@property, @app.route, @pytest.fixture, …)
60
+ high — none of the above; very likely genuinely dead
61
+ """
62
+ name = (row.get("function_name") or "")
63
+ lname = name.lower()
64
+ path = (row.get("path") or "")
65
+ if name.startswith("__") and name.endswith("__"):
66
+ return "low", "dunder — called implicitly by the runtime"
67
+ if lname in _TEST_HOOK_NAMES or name.startswith(("test_", "_test")):
68
+ return "low", "test hook/prefix — invoked by the test runner"
69
+ if lname in {n.lower() for n in _ENTRY_POINT_NAMES}:
70
+ return "low", "entry-point name — typically called externally"
71
+ if lname in {n.lower() for n in _ANDROID_ENTRY_POINT_NAMES}:
72
+ return "low", "framework entry point"
73
+ if "override" in (row.get("modifiers") or []):
74
+ return "low", "override — dispatched via its base declaration"
75
+ if "/tests/" in path or "/test/" in path or path.endswith("conftest.py"):
76
+ return "low", "test-tree file — commonly runner-invoked"
77
+ if row.get("decorators"):
78
+ return "medium", "decorated — decorators often add implicit callers"
79
+ return "high", "no callers, no excluding signal"
80
+
81
+
47
82
  _ANDROID_ENTRY_POINT_NAMES_CYPHER = "[" + ", ".join(
48
83
  f"'{n}'" for n in _ANDROID_ENTRY_POINT_NAMES
49
84
  ) + "]"
@@ -938,7 +973,7 @@ class CodeFinder:
938
973
 
939
974
  return result.data()
940
975
 
941
- def find_dead_code(self, exclude_decorated_with: Optional[List[str]] = None, repo_path: Optional[str] = None, graph_name: str = None, limit: Optional[int] = None) -> Dict[str, Any]:
976
+ def find_dead_code(self, exclude_decorated_with: Optional[List[str]] = None, repo_path: Optional[str] = None, graph_name: str = None, limit: Optional[int] = None, include_low_confidence: bool = False) -> Dict[str, Any]:
942
977
  self._active_graph = graph_name
943
978
  """Find potentially unused functions (not called by other functions in the project), optionally excluding those with specific decorators.
944
979
 
@@ -996,6 +1031,8 @@ class CodeFinder:
996
1031
  func.line_number as line_number,
997
1032
  func.docstring as docstring,
998
1033
  func.context as context,
1034
+ func.decorators as decorators,
1035
+ func.modifiers as modifiers,
999
1036
  file.name as file_name
1000
1037
  ORDER BY func.path, func.line_number
1001
1038
  """
@@ -1014,15 +1051,119 @@ class CodeFinder:
1014
1051
  # exclude_decorated_with look inert: excluded rows were backfilled
1015
1052
  # by the next ones in path order and the count came back 50 either
1016
1053
  # way (#1606).
1054
+ for row in rows:
1055
+ confidence, reason = _classify_dead_code_confidence(row)
1056
+ row["confidence"] = confidence
1057
+ row["confidence_reason"] = reason
1058
+
1059
+ if include_low_confidence:
1060
+ # The main query hard-excludes categories that are almost
1061
+ # always false positives (dunders, test hooks, entry-point
1062
+ # names, overrides). --show-all reintroduces them as
1063
+ # low-confidence rows instead of leaving them invisible
1064
+ # (#1332).
1065
+ low_query = f"""
1066
+ MATCH (func:Function)
1067
+ WHERE func.is_dependency = false {repo_filter} {func_ignore}
1068
+ AND func.name <> '<module>'
1069
+ AND (
1070
+ toLower(func.name) IN {_ENTRY_POINT_NAMES_CYPHER}
1071
+ OR (func.lang IN {_JVM_LANGS_CYPHER}
1072
+ AND toLower(func.name) IN {_ANDROID_ENTRY_POINT_NAMES_CYPHER})
1073
+ OR (func.modifiers IS NOT NULL AND 'override' IN func.modifiers)
1074
+ OR (func.name STARTS WITH '__' AND func.name ENDS WITH '__')
1075
+ OR func.name STARTS WITH '_test'
1076
+ OR func.name STARTS WITH 'test_'
1077
+ )
1078
+ {decorator_filter}
1079
+ WITH func
1080
+ OPTIONAL MATCH (caller)-[:CALLS|HEURISTIC_CALLS]->(func)
1081
+ WHERE (caller.is_dependency IS NULL OR caller.is_dependency = false)
1082
+ {caller_ignore}
1083
+ WITH func, count(caller) as caller_count
1084
+ WHERE caller_count = 0
1085
+ OPTIONAL MATCH (file:File)-[:CONTAINS]->(func)
1086
+ RETURN
1087
+ func.name as function_name,
1088
+ func.path as path,
1089
+ func.line_number as line_number,
1090
+ func.docstring as docstring,
1091
+ func.context as context,
1092
+ func.decorators as decorators,
1093
+ func.modifiers as modifiers,
1094
+ file.name as file_name
1095
+ ORDER BY func.path, func.line_number
1096
+ """
1097
+ low_rows = session.run(low_query, **params).data()
1098
+ for row in low_rows:
1099
+ confidence, reason = _classify_dead_code_confidence(row)
1100
+ # Everything the main query excluded is low by construction,
1101
+ # but reuse the classifier so the reason strings match.
1102
+ row["confidence"] = "low" if confidence == "high" else confidence
1103
+ row["confidence_reason"] = reason
1104
+ rows = rows + low_rows
1105
+ rows.sort(key=lambda r: (str(r.get("path") or ""), r.get("line_number") or 0))
1106
+
1017
1107
  total_count = len(rows)
1108
+ confidence_counts = {"high": 0, "medium": 0, "low": 0}
1109
+ for row in rows:
1110
+ confidence_counts[row.get("confidence", "high")] += 1
1018
1111
  page = rows[:limit] if limit else rows
1019
1112
 
1020
1113
  return {
1021
1114
  "potentially_unused_functions": page,
1022
1115
  "total_count": total_count,
1116
+ "confidence_counts": confidence_counts,
1023
1117
  "note": "These functions might be unused, but could be entry points, callbacks, or called dynamically"
1024
1118
  }
1025
1119
 
1120
+ def export_diagram_edges(self, level: str = "file", repo_path: Optional[str] = None, limit: Optional[int] = 300) -> Dict[str, Any]:
1121
+ """Edges for a Mermaid/DOT export (#1287).
1122
+
1123
+ level="file": File -[IMPORTS]-> Module dependencies.
1124
+ level="call": Function -[CALLS]-> Function within the repo.
1125
+
1126
+ Returns {"edges": [(src, dst), ...], "total_count": n, "truncated": bool}
1127
+ — the cap is reported, never silent.
1128
+ """
1129
+ repo_path = self._normalize_repo_path_filter(repo_path)
1130
+ with self.driver.session() as session:
1131
+ if level == "call":
1132
+ repo_filter = "AND caller.path STARTS WITH $repo_path" if repo_path else ""
1133
+ query = f"""
1134
+ MATCH (caller:Function)-[:CALLS]->(callee:Function)
1135
+ WHERE caller.is_dependency = false AND callee.is_dependency = false
1136
+ AND caller.name <> '<module>' AND callee.name <> '<module>'
1137
+ {repo_filter}
1138
+ RETURN DISTINCT caller.name AS src, callee.name AS dst
1139
+ ORDER BY src, dst
1140
+ """
1141
+ else:
1142
+ repo_filter = "AND file.path STARTS WITH $repo_path" if repo_path else ""
1143
+ query = f"""
1144
+ MATCH (file:File)-[:IMPORTS]->(module:Module)
1145
+ WHERE file.is_dependency = false {repo_filter}
1146
+ RETURN DISTINCT file.relative_path AS src_rel, file.name AS src_name,
1147
+ module.name AS dst
1148
+ ORDER BY src_rel, dst
1149
+ """
1150
+ params = {"repo_path": repo_path} if repo_path else {}
1151
+ rows = session.run(query, **params).data()
1152
+
1153
+ if level == "call":
1154
+ edges = [(r["src"], r["dst"]) for r in rows if r.get("src") and r.get("dst")]
1155
+ else:
1156
+ edges = [
1157
+ ((r.get("src_rel") or r.get("src_name") or ""), r["dst"])
1158
+ for r in rows
1159
+ if (r.get("src_rel") or r.get("src_name")) and r.get("dst")
1160
+ ]
1161
+ total = len(edges)
1162
+ truncated = limit is not None and total > limit
1163
+ if truncated:
1164
+ edges = edges[:limit]
1165
+ return {"edges": edges, "total_count": total, "truncated": truncated}
1166
+
1026
1167
  def find_all_callers(self, function_name: str, path: Optional[str] = None, repo_path: Optional[str] = None, depth: int = 3) -> List[Dict]:
1027
1168
  """Find all direct and indirect callers of a specific function, returning edges."""
1028
1169
  repo_path = self._normalize_repo_path_filter(repo_path)
@@ -1634,28 +1775,40 @@ class CodeFinder:
1634
1775
  return result_data[0]
1635
1776
  return None
1636
1777
 
1637
- def find_most_complex_functions(self, limit: int = 10, repo_path: Optional[str] = None, graph_name: str = None) -> List[Dict]:
1778
+ def find_most_complex_functions(self, limit: Optional[int] = 10, repo_path: Optional[str] = None, graph_name: str = None) -> List[Dict]:
1638
1779
  self._active_graph = graph_name
1639
- """Find the most complex functions based on cyclomatic complexity."""
1780
+ """Find the most complex functions based on cyclomatic complexity.
1781
+
1782
+ ``limit=None`` returns the full set — CI enforcement must not have its
1783
+ violation count truncated by a display page (#1333).
1784
+ """
1640
1785
  repo_path = self._normalize_repo_path_filter(repo_path)
1641
1786
  with self.driver.session() as session:
1642
1787
  repo_filter = "AND f.path STARTS WITH $repo_path" if repo_path else ""
1643
1788
  path_ignore = cypher_path_not_under_ignore_dirs("f.path")
1789
+ limit_clause = "LIMIT $limit" if limit is not None else ""
1790
+ params = {"repo_path": repo_path}
1791
+ if limit is not None:
1792
+ params["limit"] = limit
1644
1793
  query = f"""
1645
1794
  MATCH (f:Function)
1646
1795
  WHERE f.cyclomatic_complexity IS NOT NULL AND f.is_dependency = false {repo_filter} {path_ignore}
1647
1796
  RETURN f.name as function_name, f.path as path, f.cyclomatic_complexity as complexity, f.line_number as line_number
1648
1797
  ORDER BY f.cyclomatic_complexity DESC
1649
- LIMIT $limit
1798
+ {limit_clause}
1650
1799
  """
1651
- result = session.run(query, limit=limit, repo_path=repo_path)
1800
+ result = session.run(query, **params)
1652
1801
  return result.data()
1653
1802
 
1654
- def find_most_complex_functions_in_file(self, file_path: str, limit: int = 20, repo_path: Optional[str] = None) -> List[Dict]:
1655
- """Find the most complex functions in a specific file."""
1803
+ def find_most_complex_functions_in_file(self, file_path: str, limit: Optional[int] = 20, repo_path: Optional[str] = None) -> List[Dict]:
1804
+ """Find the most complex functions in a specific file (limit=None = all)."""
1656
1805
  repo_path = self._normalize_repo_path_filter(repo_path)
1657
1806
  with self.driver.session() as session:
1658
1807
  repo_filter = "AND f.path STARTS WITH $repo_path" if repo_path else ""
1808
+ limit_clause = "LIMIT $limit" if limit is not None else ""
1809
+ params = {"file_path": file_path, "repo_path": repo_path}
1810
+ if limit is not None:
1811
+ params["limit"] = limit
1659
1812
  query = f"""
1660
1813
  MATCH (f:Function)
1661
1814
  WHERE f.cyclomatic_complexity IS NOT NULL
@@ -1664,9 +1817,9 @@ class CodeFinder:
1664
1817
  RETURN f.name as function_name, f.path as path,
1665
1818
  f.cyclomatic_complexity as complexity, f.line_number as line_number
1666
1819
  ORDER BY f.cyclomatic_complexity DESC
1667
- LIMIT $limit
1820
+ {limit_clause}
1668
1821
  """
1669
- result = session.run(query, file_path=file_path, limit=limit, repo_path=repo_path)
1822
+ result = session.run(query, **params)
1670
1823
  return result.data()
1671
1824
 
1672
1825
  def list_indexed_repositories(self, graph_name: str = None) -> List[Dict]: