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.
- {codegraphcontext-0.6.2/src/codegraphcontext.egg-info → codegraphcontext-0.6.4}/PKG-INFO +1 -1
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/pyproject.toml +1 -1
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/cli_helpers.py +4 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/config_manager.py +15 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/main.py +227 -16
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/watcher.py +20 -8
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/code_finder.py +162 -9
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/embeddings.py +32 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/persistence/writer.py +95 -38
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/pipeline.py +24 -10
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/inheritance.py +83 -6
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/csharp.py +20 -1
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/dart.py +12 -5
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/python.py +9 -1
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/ruby.py +11 -3
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/rust.py +58 -24
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/scala.py +1 -1
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4/src/codegraphcontext.egg-info}/PKG-INFO +1 -1
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/LICENSE +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/MANIFEST.in +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/README.md +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/setup.cfg +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/__main__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/app.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/auth.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/mcp_sse.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/router.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/api/schemas.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/hook_manager.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/project_config.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/registry_commands.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/setup_macos.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/setup_wizard.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/simulator.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/visualizer.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/bundle_registry.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/cgc_bundle.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/cgcignore.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_embedded_kuzu.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_falkordb.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_kuzu.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_ladybug.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/database_nornic.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/falkor_worker.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/graph_query.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/jobs.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/core/simulator.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/prompts.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/server.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/stdlibs.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tool_definitions.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/cassandra_ingester.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/mysql_ingester.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/datasources/redis_ingester.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/graph_builder.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/analysis_handlers.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/indexing_handlers.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/management_handlers.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/handlers/watcher_handlers.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/constants.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/discovery.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/persistence/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/persistence/utils.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/pre_scan.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/__init__.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/calls.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/resolution/post_resolution.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/sanitize.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/schema.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/schema_contract.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/scip_pipeline.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/indexing/vector_resolver.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/c.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/cpp.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/css.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/elisp.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/elixir.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/go.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/gradle.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/haskell.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/html.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/java.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/javascript.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/lua.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/maven.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/mybatis.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/perl.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/php.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/sfc_common.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/solidity.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/solidity_remappings.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/svelte.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/swift.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/typescript.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/languages/vue.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/package_resolver.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/elisp_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/solidity_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/report_generator.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/scip_indexer.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/scip_pb2.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/system.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/tree_sitter_parser.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/tools/type_utils.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/cypher_ddl.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/cypher_readonly.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/debug_log.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/gcf_encoder.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/git_utils.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/path_ignore.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/path_sandbox.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/repo_path.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/secret_scanner.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/tool_limits.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/tree_sitter_manager.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/utils/visualize_graph.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/__vite-browser-external-9wXp6ZBx.js +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/index-C-187lf0.js +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/index-fNAa6jgv.css +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/parser-pyodide.worker-BgsDfaad.js +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/parser.worker-_nvrecvj.js +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/assets/tree-sitter-qKYAACSa.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/cgcIcon.png +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/favicon.ico +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/index.html +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/logo-icon.svg +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/logo.svg +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/placeholder.svg +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/preview-image.png +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/robots.txt +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-core.js +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-cpp.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-dart.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-go.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-java.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-javascript.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-kotlin.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-perl.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-php.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-python.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-ruby.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-rust.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-swift.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-tsx.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/tree-sitter.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.js +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/viz/server.py +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/SOURCES.txt +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/requires.txt +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext.egg-info/top_level.txt +0 -0
- {codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/tests/test_issue_806_fix.py +0 -0
- {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.
|
|
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.
|
|
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(
|
{codegraphcontext-0.6.2 → codegraphcontext-0.6.4}/src/codegraphcontext/cli/config_manager.py
RENAMED
|
@@ -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(
|
|
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
|
-
|
|
2925
|
-
|
|
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,
|
|
2977
|
-
|
|
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,
|
|
2991
|
-
|
|
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(
|
|
2995
|
-
|
|
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
|
-
|
|
3249
|
+
fpath = func.get('path', '')
|
|
3049
3250
|
line_str = str(func.get('line_number', ''))
|
|
3050
|
-
location_str = f"{
|
|
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
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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
|
-
|
|
1798
|
+
{limit_clause}
|
|
1650
1799
|
"""
|
|
1651
|
-
result = session.run(query,
|
|
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
|
-
|
|
1820
|
+
{limit_clause}
|
|
1668
1821
|
"""
|
|
1669
|
-
result = session.run(query,
|
|
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]:
|