codegraphcontext 0.6.2__tar.gz → 0.6.3__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.3}/PKG-INFO +1 -1
  2. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/pyproject.toml +1 -1
  3. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/cli_helpers.py +4 -0
  4. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/config_manager.py +15 -0
  5. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/main.py +208 -14
  6. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/watcher.py +20 -8
  7. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/code_finder.py +162 -9
  8. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/embeddings.py +32 -0
  9. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/pipeline.py +24 -10
  10. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3/src/codegraphcontext.egg-info}/PKG-INFO +1 -1
  11. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/LICENSE +0 -0
  12. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/MANIFEST.in +0 -0
  13. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/README.md +0 -0
  14. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/setup.cfg +0 -0
  15. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/__init__.py +0 -0
  16. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/__main__.py +0 -0
  17. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/api/__init__.py +0 -0
  18. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/api/app.py +0 -0
  19. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/api/auth.py +0 -0
  20. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/api/mcp_sse.py +0 -0
  21. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/api/router.py +0 -0
  22. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/api/schemas.py +0 -0
  23. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/__init__.py +0 -0
  24. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/hook_manager.py +0 -0
  25. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/project_config.py +0 -0
  26. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/registry_commands.py +0 -0
  27. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/setup_macos.py +0 -0
  28. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/setup_wizard.py +0 -0
  29. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/simulator.py +0 -0
  30. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/cli/visualizer.py +0 -0
  31. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/__init__.py +0 -0
  32. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/bundle_registry.py +0 -0
  33. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/cgc_bundle.py +0 -0
  34. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/cgcignore.py +0 -0
  35. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database.py +0 -0
  36. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database_embedded_kuzu.py +0 -0
  37. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database_falkordb.py +0 -0
  38. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
  39. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database_kuzu.py +0 -0
  40. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database_ladybug.py +0 -0
  41. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/database_nornic.py +0 -0
  42. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/falkor_worker.py +0 -0
  43. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/graph_query.py +0 -0
  44. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/jobs.py +0 -0
  45. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/core/simulator.py +0 -0
  46. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/prompts.py +0 -0
  47. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/server.py +0 -0
  48. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/stdlibs.py +0 -0
  49. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tool_definitions.py +0 -0
  50. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/__init__.py +0 -0
  51. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
  52. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/datasources/__init__.py +0 -0
  53. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/datasources/cassandra_ingester.py +0 -0
  54. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/datasources/mysql_ingester.py +0 -0
  55. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/datasources/redis_ingester.py +0 -0
  56. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/graph_builder.py +0 -0
  57. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/handlers/analysis_handlers.py +0 -0
  58. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/handlers/indexing_handlers.py +0 -0
  59. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/handlers/management_handlers.py +0 -0
  60. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -0
  61. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/handlers/watcher_handlers.py +0 -0
  62. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/__init__.py +0 -0
  63. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/constants.py +0 -0
  64. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/discovery.py +0 -0
  65. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/persistence/__init__.py +0 -0
  66. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/persistence/utils.py +0 -0
  67. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/persistence/writer.py +0 -0
  68. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/pre_scan.py +0 -0
  69. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/resolution/__init__.py +0 -0
  70. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/resolution/calls.py +0 -0
  71. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/resolution/inheritance.py +0 -0
  72. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/resolution/post_resolution.py +0 -0
  73. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/sanitize.py +0 -0
  74. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/schema.py +0 -0
  75. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/schema_contract.py +0 -0
  76. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/scip_pipeline.py +0 -0
  77. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/indexing/vector_resolver.py +0 -0
  78. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/c.py +0 -0
  79. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/cpp.py +0 -0
  80. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/csharp.py +0 -0
  81. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/css.py +0 -0
  82. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/dart.py +0 -0
  83. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/elisp.py +0 -0
  84. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/elixir.py +0 -0
  85. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/go.py +0 -0
  86. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/gradle.py +0 -0
  87. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/haskell.py +0 -0
  88. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/html.py +0 -0
  89. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/java.py +0 -0
  90. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/javascript.py +0 -0
  91. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
  92. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/lua.py +0 -0
  93. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/maven.py +0 -0
  94. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/mybatis.py +0 -0
  95. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/perl.py +0 -0
  96. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/php.py +0 -0
  97. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/python.py +0 -0
  98. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/ruby.py +0 -0
  99. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/rust.py +0 -0
  100. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/scala.py +0 -0
  101. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/sfc_common.py +0 -0
  102. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/solidity.py +0 -0
  103. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/solidity_remappings.py +0 -0
  104. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/svelte.py +0 -0
  105. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/swift.py +0 -0
  106. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/typescript.py +0 -0
  107. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
  108. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/languages/vue.py +0 -0
  109. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/package_resolver.py +0 -0
  110. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
  111. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
  112. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
  113. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
  114. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/elisp_toolkit.py +0 -0
  115. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
  116. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
  117. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
  118. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
  119. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
  120. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
  121. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
  122. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
  123. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
  124. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/solidity_toolkit.py +0 -0
  125. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
  126. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
  127. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/report_generator.py +0 -0
  128. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/scip_indexer.py +0 -0
  129. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/scip_pb2.py +0 -0
  130. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/system.py +0 -0
  131. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/tree_sitter_parser.py +0 -0
  132. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/tools/type_utils.py +0 -0
  133. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/cypher_ddl.py +0 -0
  134. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/cypher_readonly.py +0 -0
  135. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/debug_log.py +0 -0
  136. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/gcf_encoder.py +0 -0
  137. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/git_utils.py +0 -0
  138. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/path_ignore.py +0 -0
  139. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/path_sandbox.py +0 -0
  140. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/repo_path.py +0 -0
  141. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/secret_scanner.py +0 -0
  142. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/tool_limits.py +0 -0
  143. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/tree_sitter_manager.py +0 -0
  144. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/utils/visualize_graph.py +0 -0
  145. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/__vite-browser-external-9wXp6ZBx.js +0 -0
  146. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
  147. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
  148. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
  149. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
  150. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/index-C-187lf0.js +0 -0
  151. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/index-fNAa6jgv.css +0 -0
  152. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/parser-pyodide.worker-BgsDfaad.js +0 -0
  153. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/parser.worker-_nvrecvj.js +0 -0
  154. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/assets/tree-sitter-qKYAACSa.wasm +0 -0
  155. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/cgcIcon.png +0 -0
  156. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/favicon.ico +0 -0
  157. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/index.html +0 -0
  158. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/logo-icon.svg +0 -0
  159. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/logo.svg +0 -0
  160. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/placeholder.svg +0 -0
  161. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/preview-image.png +0 -0
  162. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/robots.txt +0 -0
  163. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c.wasm +0 -0
  164. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
  165. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-core.js +0 -0
  166. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-cpp.wasm +0 -0
  167. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-dart.wasm +0 -0
  168. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-go.wasm +0 -0
  169. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-java.wasm +0 -0
  170. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-javascript.wasm +0 -0
  171. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-kotlin.wasm +0 -0
  172. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-perl.wasm +0 -0
  173. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-php.wasm +0 -0
  174. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-python.wasm +0 -0
  175. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-ruby.wasm +0 -0
  176. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-rust.wasm +0 -0
  177. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-swift.wasm +0 -0
  178. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-tsx.wasm +0 -0
  179. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm +0 -0
  180. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/tree-sitter.wasm +0 -0
  181. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.js +0 -0
  182. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm +0 -0
  183. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext/viz/server.py +0 -0
  184. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext.egg-info/SOURCES.txt +0 -0
  185. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
  186. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
  187. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext.egg-info/requires.txt +0 -0
  188. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/src/codegraphcontext.egg-info/top_level.txt +0 -0
  189. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/tests/test_issue_806_fix.py +0 -0
  190. {codegraphcontext-0.6.2 → codegraphcontext-0.6.3}/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.3
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.3"
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,96 @@ 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
+ if output is None:
1182
+ # stdout carries only the diagram; init chatter goes to stderr.
1183
+ import sys as _sys
1184
+ from . import cli_helpers as _cli_helpers
1185
+ _cli_helpers.console.file = _sys.stderr
1186
+
1187
+ _load_credentials()
1188
+ services = _initialize_services(context)
1189
+ if not all(services[:3]):
1190
+ raise typer.Exit(code=1)
1191
+ db_manager, graph_builder, code_finder = services[:3]
1192
+
1193
+ try:
1194
+ repo_path = Path(path).resolve().as_posix() if path else None
1195
+ result = code_finder.export_diagram_edges(level=level, repo_path=repo_path, limit=limit)
1196
+ finally:
1197
+ db_manager.close_driver()
1198
+
1199
+ edges = result["edges"]
1200
+ ids: dict = {}
1201
+
1202
+ def _node_id(name: str) -> str:
1203
+ if name not in ids:
1204
+ ids[name] = f"n{len(ids)}"
1205
+ return ids[name]
1206
+
1207
+ lines = []
1208
+ if output_format == "mermaid":
1209
+ lines.append("graph LR")
1210
+ if result["truncated"]:
1211
+ lines.append(f" %% truncated: showing {len(edges)} of {result['total_count']} edges (raise --limit)")
1212
+ for src, dst in edges:
1213
+ sid, did = _node_id(src), _node_id(dst)
1214
+ s_label = src.replace('"', "'")
1215
+ d_label = dst.replace('"', "'")
1216
+ lines.append(f' {sid}["{s_label}"] --> {did}["{d_label}"]')
1217
+ if not edges:
1218
+ lines.append(" %% no edges found for this scope")
1219
+ else:
1220
+ lines.append("digraph cgc {")
1221
+ lines.append(" rankdir=LR;")
1222
+ if result["truncated"]:
1223
+ lines.append(f" // truncated: showing {len(edges)} of {result['total_count']} edges (raise --limit)")
1224
+ for src, dst in edges:
1225
+ sid, did = _node_id(src), _node_id(dst)
1226
+ lines.append(f' {sid} -> {did};')
1227
+ for name, nid in ids.items():
1228
+ label = name.replace('"', "'")
1229
+ lines.append(f' {nid} [label="{label}"];')
1230
+ lines.append("}")
1231
+
1232
+ text = "\n".join(lines) + "\n"
1233
+ if output:
1234
+ Path(output).write_text(text, encoding="utf-8")
1235
+ console.print(f"[green]✅ Wrote {output_format} diagram ({len(edges)} edges) to {output}[/green]")
1236
+ if result["truncated"]:
1237
+ console.print(f"[yellow]⚠ Truncated: {result['total_count']} total edges; raise --limit to include all[/yellow]")
1238
+ else:
1239
+ print(text, end="")
1240
+
1241
+
1152
1242
  @app.command("load", rich_help_panel="Bundle Shortcuts")
1153
1243
  def load_shortcut(
1154
1244
  bundle_name: str = typer.Argument(..., help="Bundle name or path to load"),
@@ -2905,9 +2995,11 @@ def analyze_inheritance_tree(
2905
2995
  def analyze_complexity(
2906
2996
  path: Optional[str] = typer.Argument(None, help="Function name or file path to analyze"),
2907
2997
  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"),
2998
+ limit: Optional[int] = typer.Option(None, "--limit", "-l", help="Maximum results to show (default 20 for text; unlimited for json/csv)"),
2909
2999
  file: Optional[str] = typer.Option(None, "--file", "-f", help="Specific file path to scope analysis"),
2910
3000
  context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
3001
+ output_format: str = typer.Option("text", "--format", help="Output format: text, json or csv (#1333)"),
3002
+ fail_on_violations: bool = typer.Option(False, "--fail-on-violations", help="Exit with code 1 when any function exceeds the threshold (CI gate)"),
2911
3003
  ):
2912
3004
  """
2913
3005
  Show cyclomatic complexity for functions.
@@ -2920,7 +3012,19 @@ def analyze_complexity(
2920
3012
  cgc analyze complexity src/main.py # Most complex functions in file
2921
3013
  cgc analyze complexity main.py # Most complex functions in file
2922
3014
  cgc analyze complexity --file src/main.py # Alternative file syntax
2923
- """
3015
+ cgc analyze complexity -t 10 --format json --fail-on-violations # CI gate
3016
+ """
3017
+ output_format = output_format.lower()
3018
+ if output_format not in ("text", "json", "csv"):
3019
+ console.print(f"[red]Unknown --format '{output_format}' (expected text, json or csv)[/red]")
3020
+ raise typer.Exit(code=2)
3021
+ if output_format in ("json", "csv"):
3022
+ # stdout must carry ONLY the parseable document: the service-init
3023
+ # chatter from cli_helpers prints to stdout, so reroute that console
3024
+ # to stderr before initializing anything (`--format json | jq .`).
3025
+ import sys as _sys
3026
+ from . import cli_helpers as _cli_helpers
3027
+ _cli_helpers.console.file = _sys.stderr
2924
3028
  _load_credentials()
2925
3029
  services = _initialize_services(context)
2926
3030
  if not all(services[:3]):
@@ -2938,6 +3042,47 @@ def analyze_complexity(
2938
3042
  else:
2939
3043
  threshold = 10
2940
3044
 
3045
+ machine_output = output_format in ("json", "csv")
3046
+ # Enforcement and export need the full set: a display page must never
3047
+ # truncate the violation count a CI gate acts on (#1333).
3048
+ effective_limit = limit if limit is not None else (None if (machine_output or fail_on_violations) else 20)
3049
+
3050
+ def _violations_from(results):
3051
+ rows = []
3052
+ for func in results or []:
3053
+ # The synthetic `<module>` frame is the attribution target for
3054
+ # module-level calls, not a function anyone can refactor.
3055
+ if func.get("function_name") == "<module>":
3056
+ continue
3057
+ complexity = func.get("complexity", 0) or 0
3058
+ if complexity > threshold:
3059
+ rows.append({
3060
+ "function": func.get("function_name", ""),
3061
+ "file": func.get("path", ""),
3062
+ "line": func.get("line_number"),
3063
+ "complexity": complexity,
3064
+ "exceeds_by": complexity - threshold,
3065
+ })
3066
+ return rows
3067
+
3068
+ def _emit_machine(violations):
3069
+ import csv as _csv
3070
+ import io as _io
3071
+ import json as _json
3072
+ if output_format == "json":
3073
+ print(_json.dumps({
3074
+ "threshold": threshold,
3075
+ "violations_count": len(violations),
3076
+ "violations": violations,
3077
+ }, indent=2))
3078
+ else:
3079
+ buf = _io.StringIO()
3080
+ w = _csv.writer(buf)
3081
+ w.writerow(["function", "file", "line", "complexity", "exceeds_by"])
3082
+ for v in violations:
3083
+ w.writerow([v["function"], v["file"], v["line"], v["complexity"], v["exceeds_by"]])
3084
+ print(buf.getvalue(), end="")
3085
+
2941
3086
  _FILE_EXTENSIONS = ('.py', '.js', '.ts', '.jsx', '.tsx', '.go', '.rs', '.rb',
2942
3087
  '.java', '.cpp', '.c', '.cs', '.swift', '.kt', '.scala',
2943
3088
  '.php', '.lua', '.zig', '.ex', '.exs', '.r', '.m', '.sh')
@@ -2970,15 +3115,31 @@ def analyze_complexity(
2970
3115
  console.print(table)
2971
3116
  console.print(f"\n[dim]{len([f for f in results if f.get('complexity', 0) > threshold])} function(s) exceed threshold[/dim]")
2972
3117
 
3118
+ violations = None
2973
3119
  try:
2974
3120
  if path and _is_file_path(path):
2975
3121
  # 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}):")
3122
+ results = code_finder.find_most_complex_functions_in_file(path, effective_limit)
3123
+ violations = _violations_from(results)
3124
+ if machine_output:
3125
+ _emit_machine(violations)
3126
+ else:
3127
+ _render_complexity_table(results, f"Most Complex Functions in '{path}' (threshold: {threshold}):")
2978
3128
  elif path:
2979
3129
  # Specific function name
2980
3130
  result = code_finder.get_cyclomatic_complexity(path, file)
3131
+ single = []
2981
3132
  if result:
3133
+ single = [{
3134
+ "function_name": path,
3135
+ "path": result.get("path", ""),
3136
+ "line_number": result.get("line_number"),
3137
+ "complexity": result.get("complexity", 0) or 0,
3138
+ }]
3139
+ violations = _violations_from(single)
3140
+ if machine_output:
3141
+ _emit_machine(violations)
3142
+ elif result:
2982
3143
  console.print(f"\n[bold cyan]Complexity for '{path}':[/bold cyan]")
2983
3144
  console.print(f" Cyclomatic Complexity: [yellow]{result.get('complexity', 'N/A')}[/yellow]")
2984
3145
  console.print(f" File: [dim]{result.get('path', '')}[/dim]")
@@ -2987,20 +3148,36 @@ def analyze_complexity(
2987
3148
  console.print(f"[yellow]Function '{path}' not found or has no complexity data[/yellow]")
2988
3149
  elif file:
2989
3150
  # --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}):")
3151
+ results = code_finder.find_most_complex_functions_in_file(file, effective_limit)
3152
+ violations = _violations_from(results)
3153
+ if machine_output:
3154
+ _emit_machine(violations)
3155
+ else:
3156
+ _render_complexity_table(results, f"Most Complex Functions in '{file}' (threshold: {threshold}):")
2992
3157
  else:
2993
3158
  # Global - most complex functions
2994
- results = code_finder.find_most_complex_functions(limit)
2995
- _render_complexity_table(results, f"Most Complex Functions (threshold: {threshold}):")
3159
+ results = code_finder.find_most_complex_functions(effective_limit)
3160
+ violations = _violations_from(results)
3161
+ if machine_output:
3162
+ _emit_machine(violations)
3163
+ else:
3164
+ _render_complexity_table(results, f"Most Complex Functions (threshold: {threshold}):")
2996
3165
  finally:
2997
3166
  db_manager.close_driver()
2998
3167
 
3168
+ # CI gate (#1333): explicit opt-in keeps exploratory usage exit-0 —
3169
+ # the config default threshold means most codebases have *some*
3170
+ # function above it, and failing every casual invocation would break
3171
+ # innocent `cgc analyze complexity && …` chains.
3172
+ if fail_on_violations and violations:
3173
+ raise typer.Exit(code=1)
3174
+
2999
3175
  @analyze_app.command("dead-code")
3000
3176
  def analyze_dead_code(
3001
3177
  path: Optional[str] = typer.Argument(None, help="Repository path to scope the analysis to"),
3002
3178
  exclude_decorators: Optional[str] = typer.Option(None, "--exclude", "-e", help="Comma-separated decorators to exclude"),
3003
3179
  context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
3180
+ show_all: bool = typer.Option(False, "--show-all", help="Include low-confidence rows (dunders, test hooks, entry-point names) normally hidden (#1332)"),
3004
3181
  ):
3005
3182
  """
3006
3183
  Find potentially unused functions.
@@ -3030,7 +3207,8 @@ def analyze_dead_code(
3030
3207
  # of table rows. The true count comes from total_count below (#1606).
3031
3208
  display_limit = get_tool_result_limit("find_dead_code")
3032
3209
  results = code_finder.find_dead_code(
3033
- exclude_list, repo_path=repo_path, limit=display_limit
3210
+ exclude_list, repo_path=repo_path, limit=display_limit,
3211
+ include_low_confidence=show_all,
3034
3212
  )
3035
3213
 
3036
3214
  unused_funcs = results.get('potentially_unused_functions', [])
@@ -3042,16 +3220,22 @@ def analyze_dead_code(
3042
3220
 
3043
3221
  table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
3044
3222
  table.add_column("Function", style="cyan")
3223
+ table.add_column("Confidence", justify="center")
3045
3224
  table.add_column("Location", style="dim", overflow="fold")
3046
-
3225
+
3226
+ _conf_render = {
3227
+ "high": "[red]● high[/red]",
3228
+ "medium": "[yellow]● medium[/yellow]",
3229
+ "low": "[dim]● low[/dim]",
3230
+ }
3047
3231
  for func in unused_funcs:
3048
- path = func.get('path', '')
3232
+ fpath = func.get('path', '')
3049
3233
  line_str = str(func.get('line_number', ''))
3050
- location_str = f"{path}:{line_str}" if line_str else path
3051
-
3234
+ location_str = f"{fpath}:{line_str}" if line_str else fpath
3052
3235
  table.add_row(
3053
3236
  func.get('function_name', ''),
3054
- location_str
3237
+ _conf_render.get(func.get('confidence', 'high'), func.get('confidence', '')),
3238
+ location_str,
3055
3239
  )
3056
3240
 
3057
3241
  console.print("\n[bold yellow]⚠️ Potentially Unused Functions:[/bold yellow]")
@@ -3063,6 +3247,16 @@ def analyze_dead_code(
3063
3247
  )
3064
3248
  else:
3065
3249
  console.print(f"\n[dim]Total: {total_count} function(s)[/dim]")
3250
+ counts = results.get('confidence_counts') or {}
3251
+ if counts:
3252
+ summary = (
3253
+ f"[red]{counts.get('high', 0)} high[/red], "
3254
+ f"[yellow]{counts.get('medium', 0)} medium[/yellow], "
3255
+ f"[dim]{counts.get('low', 0)} low[/dim] confidence"
3256
+ )
3257
+ if not show_all:
3258
+ summary += " [dim](low-confidence categories are hidden — use --show-all)[/dim]"
3259
+ console.print(summary)
3066
3260
  console.print(f"[dim]Note: {results.get('note', '')}[/dim]")
3067
3261
  finally:
3068
3262
  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]: