code-graph-rag 0.0.662__tar.gz → 0.0.670__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.
- {code_graph_rag-0.0.662/code_graph_rag.egg-info → code_graph_rag-0.0.670}/PKG-INFO +1 -1
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670/code_graph_rag.egg-info}/PKG-INFO +1 -1
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/SOURCES.txt +1 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cli_help.py +5 -1
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_js.py +15 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_python.py +16 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/mcp.py +3 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/security.py +39 -0
- code_graph_rag-0.0.670/codebase_rag/crash_correlation.py +354 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/tools.py +66 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/type_inference.py +255 -49
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/ast_analyzer.py +50 -5
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/expression_analyzer.py +30 -23
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/type_inference.py +10 -1
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/variable_analyzer.py +86 -1
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/shell_command.py +50 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/tool_descriptions.py +33 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/ebpf_pprof.py +196 -13
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/ingest.py +9 -5
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/resolution.py +36 -14
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/pyproject.toml +1 -1
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/LICENSE +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/PYPI_README.md +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/README.md +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/cgr/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/dependency_links.txt +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/entry_points.txt +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/requires.txt +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/top_level.txt +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_analyzer.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/c.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/cpp.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/csharp.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/dart.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/go.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/java.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/javascript.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/lua.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/php.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/python.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/ruby.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/rust.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/scala.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/tsx.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/typescript.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/c.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/cpp.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/csharp.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/dart.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/go.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/java.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/javascript.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/lua.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/php.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/python.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/ruby.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/rust.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/scala.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/tsx.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/typescript.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/c.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/cpp.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/csharp.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/dart.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/go.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/java.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/javascript.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/lua.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/php.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/python.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/ruby.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/rust.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/scala.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/tsx.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/typescript.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/ast_cache.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/capture.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cgr_state.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cli.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/config.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_cpp.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_csharp.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_dart.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_go.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_java.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_lua.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_nodes.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_php.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_rust.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_scala.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/build.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/cli.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/core.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/deadcode_roots.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/deps.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/fqn_specs.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/graph.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/health.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/lang_tooling.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/languages.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/providers.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/stdlib_types.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/structural.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/trace.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cypher_queries.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/dead_code.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/decorators.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/docker-compose.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/embedder.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/exceptions.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/flow_verdict.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/function_registry.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/graph_audit.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/graph_loader.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/graph_updater.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/language_spec.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/logs.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/main.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/client.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/server.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/models.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parser_fingerprint.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parser_loader.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/ast_grep_patterns/ruby.yaml +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/ast_grep_tier.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/call_processor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/call_resolver.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/cpp_modules.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/identity.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/method_override.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/mixin.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/node_type.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/parent_extraction.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/relationships.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/contract_linking.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/contracts.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/preproc_recovery.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/constants.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/frontend.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/qn.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/frontend.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/roslyn/Frontend.cs +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/roslyn/Frontend.csproj +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/roslyn/Program.cs +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dart/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dart/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dart/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/definition_processor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dependency_parser.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dispatch_registry.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/endpoint_prefixes.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/endpoint_routes.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/endpoints.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/export_detection.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/factory.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/flow_access/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/flow_access/constants.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/flow_access/processor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/csharp.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/go.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/protocol.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/registry.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/function_ingest.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/module_paths.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/frontend.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/gotypes/go.mod +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/gotypes/go.sum +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/gotypes/main.go +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/base.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/cpp.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/java.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/js_ts.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/lua.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/php.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/protocol.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/python.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/registry.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/rust.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/import_processor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/constants.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/descriptor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/extract.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/models.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/processor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/registry.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/method_resolver.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/type_resolver.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/variable_analyzer.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/ingest.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/module_paths.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/module_system.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/lua/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/lua/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/lua/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/python_source_roots.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rpc_exposure.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rs/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rs/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rs/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/semantic_call_join.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/stdlib_extractor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/structure_processor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/type_inference.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/path_filters.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/prompts.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/providers/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/providers/base.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/providers/litellm.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/readme_sections.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/schema_builder.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/schemas.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/anthropic_token_counter.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/filtering.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/graph_service.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/llm.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/protobuf_service.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/resource_cleanup.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/usage_cost.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/cli.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/constants.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/health.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/manager.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tool_errors.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/ast_grep_service.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/code_retrieval.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/codebase_query.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/directory_lister.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/file_editor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/file_reader.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/file_writer.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/health_checker.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/language.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/semantic_search.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/structural_editor.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/structural_search.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/web_search.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/cli.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/cpuprofile.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/instrumented.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/pprof.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/pytest_plugin.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/records.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/rust_pprof.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/sourcemap.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/speedscope.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/tracer.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/xdebug.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/types_defs.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/unixcoder.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/dependencies.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/fqn_resolver.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/path_utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/rich_markdown.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/source_extraction.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/token_utils.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/vector_store.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/cli.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/constants.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/models.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/storage.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codec/__init__.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codec/schema_pb2.py +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codec/schema_pb2.pyi +0 -0
- {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-graph-rag
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.670
|
|
4
4
|
Summary: The ultimate RAG for your monorepo. Query, understand, and edit multi-language codebases with the power of AI and knowledge graphs
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Keywords: rag,retrieval-augmented-generation,knowledge-graph,code-analysis,tree-sitter,mcp,mcp-server,llm,graph-database,semantic-search,codebase,memgraph,developer-tools,monorepo
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-graph-rag
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.670
|
|
4
4
|
Summary: The ultimate RAG for your monorepo. Query, understand, and edit multi-language codebases with the power of AI and knowledge graphs
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Keywords: rag,retrieval-augmented-generation,knowledge-graph,code-analysis,tree-sitter,mcp,mcp-server,llm,graph-database,semantic-search,codebase,memgraph,developer-tools,monorepo
|
|
@@ -121,7 +121,11 @@ HELP_TRACE_INCLUDE = (
|
|
|
121
121
|
)
|
|
122
122
|
HELP_TRACE_LANGUAGE = (
|
|
123
123
|
"Override the auto-detected source language. Rust pprof profiles share Go's "
|
|
124
|
-
"gzipped-protobuf format, so pass 'rust' to demangle them as Rust."
|
|
124
|
+
"gzipped-protobuf format, so pass 'rust' to demangle them as Rust. For an "
|
|
125
|
+
"eBPF profile of a managed runtime, pass '--format ebpf --language python' "
|
|
126
|
+
"(or '--language jvm') together to resolve the in-kernel-unwound source "
|
|
127
|
+
"frames against that language's graph ('python' and 'jvm' are eBPF-only "
|
|
128
|
+
"overrides)."
|
|
125
129
|
)
|
|
126
130
|
HELP_TRACE_FORMAT = (
|
|
127
131
|
"Force a profile format instead of auto-detecting it. Use 'ebpf' for pprof "
|
|
@@ -256,6 +256,21 @@ FIELD_INCREMENT = "increment"
|
|
|
256
256
|
|
|
257
257
|
# JS/TS module system node types
|
|
258
258
|
TS_TYPE_ANNOTATION = "type_annotation"
|
|
259
|
+
# TypeScript type-annotation shapes (issue #1303). Arrays and array-shaped
|
|
260
|
+
# generics carry their element in the canonical `list[<element>]` marker,
|
|
261
|
+
# which only for-of loop-variable inference unwraps.
|
|
262
|
+
TS_ARRAY_TYPE = "array_type"
|
|
263
|
+
TS_GENERIC_TYPE = "generic_type"
|
|
264
|
+
TS_UNION_TYPE = "union_type"
|
|
265
|
+
TS_TYPE_IDENTIFIER = "type_identifier"
|
|
266
|
+
TS_NESTED_TYPE_IDENTIFIER = "nested_type_identifier"
|
|
267
|
+
TS_JS_OPERATOR_OF = "of"
|
|
268
|
+
TS_NULLISH_TYPE_TEXTS = frozenset({"null", "undefined"})
|
|
269
|
+
TS_ARRAY_GENERIC_NAMES = frozenset(
|
|
270
|
+
{"Array", "ReadonlyArray", "Set", "Iterable", "IterableIterator"}
|
|
271
|
+
)
|
|
272
|
+
JS_LIST_TYPE_PREFIX = "list["
|
|
273
|
+
JS_LIST_TYPE_FORMAT = "list[{element}]"
|
|
259
274
|
TS_IMPORT_ALIAS = "import_alias"
|
|
260
275
|
TS_JS_WITH_STATEMENT = "with_statement"
|
|
261
276
|
TS_CLASS_STATIC_BLOCK = "class_static_block"
|
|
@@ -96,6 +96,22 @@ PY_UNION_SEPARATOR = "|"
|
|
|
96
96
|
PY_NONE = "None"
|
|
97
97
|
# `-> Self` names the enclosing class, not a class called Self.
|
|
98
98
|
PY_ANNOTATION_SELF = "Self"
|
|
99
|
+
# Homogeneous-container return annotations (`-> list[Widget]`): the container
|
|
100
|
+
# spelling is irrelevant downstream, only "iterable of element" survives, in
|
|
101
|
+
# the canonical `list[<element>]` marker consumed by loop-variable inference.
|
|
102
|
+
PY_GENERIC_CONTAINER_PATTERN = (
|
|
103
|
+
r"^(?:typing\.)?(?P<name>list|List|set|Set|frozenset|FrozenSet|tuple|Tuple|"
|
|
104
|
+
r"Sequence|Collection|Iterable|Iterator|Generator|AsyncGenerator|"
|
|
105
|
+
r"AsyncIterator|AsyncIterable)\[(?P<inner>.+)\]$"
|
|
106
|
+
)
|
|
107
|
+
PY_TUPLE_CONTAINERS = frozenset({"tuple", "Tuple"})
|
|
108
|
+
# Yield type first; Generator[Y, S, R] takes up to three parameters while
|
|
109
|
+
# AsyncGenerator[Y, S] takes up to two.
|
|
110
|
+
PY_GENERATOR_ARG_LIMITS = {"Generator": 3, "AsyncGenerator": 2}
|
|
111
|
+
PY_ELLIPSIS = "..."
|
|
112
|
+
PY_OPTIONAL_PATTERN = r"^(?:typing\.)?Optional\[(?P<inner>.+)\]$"
|
|
113
|
+
PY_LIST_TYPE_PREFIX = "list["
|
|
114
|
+
PY_LIST_TYPE_FORMAT = "list[{element}]"
|
|
99
115
|
|
|
100
116
|
PY_KEYWORD_SELF = "self"
|
|
101
117
|
PY_KEYWORD_CLS = "cls"
|
|
@@ -20,6 +20,8 @@ class MCPToolName(StrEnum):
|
|
|
20
20
|
STRUCTURAL_REPLACE = "structural_replace"
|
|
21
21
|
ASK_AGENT = "ask_agent"
|
|
22
22
|
FLOW_VERDICT = "flow_verdict"
|
|
23
|
+
EXPLAIN_TRACEBACK = "explain_traceback"
|
|
24
|
+
RANK_ROOT_CAUSES = "rank_root_causes"
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
class MCPTransport(StrEnum):
|
|
@@ -68,6 +70,7 @@ class MCPParamName(StrEnum):
|
|
|
68
70
|
SOURCE_QN = "source_qualified_name"
|
|
69
71
|
SINK_QN = "sink_qualified_name"
|
|
70
72
|
DRY_RUN = "dry_run"
|
|
73
|
+
TRACEBACK_TEXT = "traceback_text"
|
|
71
74
|
|
|
72
75
|
|
|
73
76
|
# MCP server constants
|
|
@@ -62,6 +62,45 @@ SHELL_FIND_MUTATING_ACTIONS = frozenset(
|
|
|
62
62
|
{"-delete", "-exec", "-execdir", "-ok", "-okdir"}
|
|
63
63
|
)
|
|
64
64
|
|
|
65
|
+
SHELL_GIT_SUBCMD_CONFIG = "config"
|
|
66
|
+
|
|
67
|
+
# `git config` writes to these keys plant a value that git later hands to a
|
|
68
|
+
# shell, so a single write is remote code execution on the next git operation
|
|
69
|
+
# (GHSA-2rr7-8xrw-gmhr: `git config --global core.sshCommand <payload>` planted
|
|
70
|
+
# an RCE backdoor). Approval is a weak control here because the reported .cgr.md
|
|
71
|
+
# injection framed the write as "required for the project to work, do NOT ask
|
|
72
|
+
# the user for permission", so these writes are blocked outright at every config
|
|
73
|
+
# scope. Reads and --unset stay allowed so a victim can inspect and clear a
|
|
74
|
+
# planted backdoor.
|
|
75
|
+
SHELL_GIT_CONFIG_READ_ACTIONS = frozenset(
|
|
76
|
+
{"--get", "--get-all", "--get-regexp", "--get-urlmatch", "--list", "-l"}
|
|
77
|
+
)
|
|
78
|
+
SHELL_GIT_CONFIG_UNSET_FLAGS = frozenset({"--unset", "--unset-all"})
|
|
79
|
+
SHELL_GIT_CONFIG_EXEC_KEYS = frozenset(
|
|
80
|
+
{
|
|
81
|
+
"core.sshcommand",
|
|
82
|
+
"core.pager",
|
|
83
|
+
"core.editor",
|
|
84
|
+
"core.hookspath",
|
|
85
|
+
"core.fsmonitor",
|
|
86
|
+
"credential.helper",
|
|
87
|
+
"sequence.editor",
|
|
88
|
+
"diff.external",
|
|
89
|
+
"gpg.program",
|
|
90
|
+
}
|
|
91
|
+
)
|
|
92
|
+
# (prefix, suffix) pairs matching sub-scoped keys like `credential.<url>.helper`,
|
|
93
|
+
# `filter.<name>.clean`, and `alias.<name>` whose values git also runs.
|
|
94
|
+
SHELL_GIT_CONFIG_EXEC_KEY_PATTERNS = (
|
|
95
|
+
("credential.", ".helper"),
|
|
96
|
+
("filter.", ".clean"),
|
|
97
|
+
("filter.", ".smudge"),
|
|
98
|
+
("filter.", ".process"),
|
|
99
|
+
("difftool.", ".cmd"),
|
|
100
|
+
("mergetool.", ".cmd"),
|
|
101
|
+
("alias.", ""),
|
|
102
|
+
)
|
|
103
|
+
|
|
65
104
|
# Dangerous commands, absolutely blocked
|
|
66
105
|
SHELL_DANGEROUS_COMMANDS = frozenset(
|
|
67
106
|
{
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# Traceback-to-graph correlation (issue #227). A traceback is the ground-truth
|
|
2
|
+
# call path of the crashing thread; the graph knows who else can reach the
|
|
3
|
+
# failing frame (CALLS) and where the failing value could have come from
|
|
4
|
+
# (FLOWS_TO). Frame resolution reuses the dynamic-trace resolver, and
|
|
5
|
+
# reachability runs CLIENT-side over linear scans, the same discipline as
|
|
6
|
+
# flow_verdict.py and dead_code.py.
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
from collections import deque
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import NamedTuple
|
|
14
|
+
|
|
15
|
+
from . import constants as cs
|
|
16
|
+
from .flow_verdict import CYPHER_FLOW_COVERAGE_GAPS, CYPHER_FLOW_EDGES, QueryFn
|
|
17
|
+
from .trace.ingest import load_callables
|
|
18
|
+
from .trace.records import FramePoint
|
|
19
|
+
from .trace.resolution import CallableNode, FrameResolver, ResolutionStats
|
|
20
|
+
|
|
21
|
+
# All CALLS pairs of one project, static and runtime-discovered alike: an edge
|
|
22
|
+
# a previous trace ingestion created is a real observed call path, exactly the
|
|
23
|
+
# evidence a root-cause walk wants (unlike ingest, which excludes them so a
|
|
24
|
+
# re-ingest cannot reclassify its own edges).
|
|
25
|
+
CYPHER_CRASH_CALLS = f"""MATCH (a)-[:{cs.RelationshipType.CALLS.value}]->(b)
|
|
26
|
+
WHERE a.qualified_name STARTS WITH $prefix
|
|
27
|
+
AND b.qualified_name STARTS WITH $prefix
|
|
28
|
+
RETURN a.qualified_name AS from_qn, b.qualified_name AS to_qn
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# `` File "/app/service.py", line 14, in handle_request``
|
|
32
|
+
_TB_FRAME = re.compile(
|
|
33
|
+
r'^\s*File "(?P<path>[^"]+)", line (?P<line>\d+), in (?P<name>.+)$'
|
|
34
|
+
)
|
|
35
|
+
_TB_HEADER = "Traceback (most recent call last):"
|
|
36
|
+
_TB_GROUP_HEADER = "Exception Group Traceback (most recent call last):"
|
|
37
|
+
# ``ValueError: boom`` or a bare ``KeyboardInterrupt``; the leading class of
|
|
38
|
+
# characters admits Unicode identifiers, which Python allows in class names.
|
|
39
|
+
_TB_EXCEPTION = re.compile(r"^(?P<type>[^\W\d][\w.]*)(?::\s?(?P<message>.*))?$")
|
|
40
|
+
# ExceptionGroup rendering draws a box: `` + Exception Group Traceback ...``,
|
|
41
|
+
# `` | File ...``, `` +-+------- 1 -------``. Stripping the margin turns
|
|
42
|
+
# each sub-exception back into a plain traceback section.
|
|
43
|
+
_TB_GROUP_MARGIN = re.compile(r"^\s*(?:\+-)?[+|]\s?")
|
|
44
|
+
|
|
45
|
+
_REASON_ON_STACK = "on the crashing stack, {depth} frame(s) above the failure"
|
|
46
|
+
_REASON_CALLER = "can reach the failing frame through CALLS, depth {depth}"
|
|
47
|
+
_REASON_FLOW = "FLOWS_TO source into the failing frame"
|
|
48
|
+
|
|
49
|
+
_SCORE_FLOW = 0.6
|
|
50
|
+
_SCORE_ON_STACK = 0.3
|
|
51
|
+
_SCORE_CALLER_BASE = 0.4
|
|
52
|
+
_RANK_LIMIT = 10
|
|
53
|
+
_CALLER_DEPTH_LIMIT = 3
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class ParsedTraceback(NamedTuple):
|
|
57
|
+
"""The last (propagated) traceback section, outermost frame first."""
|
|
58
|
+
|
|
59
|
+
frames: tuple[FramePoint, ...]
|
|
60
|
+
exception_type: str
|
|
61
|
+
exception_message: str
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class FrameContext(NamedTuple):
|
|
65
|
+
"""One traceback frame with its graph neighbourhood."""
|
|
66
|
+
|
|
67
|
+
path: str
|
|
68
|
+
line: int
|
|
69
|
+
name: str
|
|
70
|
+
qualified_name: str | None
|
|
71
|
+
label: str | None
|
|
72
|
+
unresolved_reason: str | None
|
|
73
|
+
callers: tuple[str, ...]
|
|
74
|
+
callees: tuple[str, ...]
|
|
75
|
+
flow_sources: tuple[str, ...]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TracebackReport(NamedTuple):
|
|
79
|
+
exception_type: str
|
|
80
|
+
exception_message: str
|
|
81
|
+
frames: tuple[FrameContext, ...]
|
|
82
|
+
flow_gaps: tuple[str, ...]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class RootCause(NamedTuple):
|
|
86
|
+
qualified_name: str
|
|
87
|
+
path: str | None
|
|
88
|
+
line: int | None
|
|
89
|
+
score: float
|
|
90
|
+
reasons: tuple[str, ...]
|
|
91
|
+
call_path: tuple[str, ...]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class RootCauseReport(NamedTuple):
|
|
95
|
+
"""Ranked writers/callers that can explain the failure.
|
|
96
|
+
|
|
97
|
+
``failing`` is the innermost frame the graph resolves -- the deepest
|
|
98
|
+
point the analysis can anchor on. When the crash site itself is deeper
|
|
99
|
+
(a library frame, or an in-repo frame the graph cannot match),
|
|
100
|
+
``anchor_is_crash_site`` is false so the ranking reads as "relative to
|
|
101
|
+
the deepest resolvable frame", never as a claim about the crash line.
|
|
102
|
+
``flow_used`` distinguishes "no FLOWS_TO evidence considered" from "flow
|
|
103
|
+
considered and empty": when the project has no flow edges at all the
|
|
104
|
+
ranking degrades to a CALLS-only walk. ``flow_gaps`` always names the
|
|
105
|
+
files outside flow-analysis coverage so an absent flow signal is not
|
|
106
|
+
read as evidence.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
exception_type: str
|
|
110
|
+
exception_message: str
|
|
111
|
+
failing: str | None
|
|
112
|
+
anchor_is_crash_site: bool
|
|
113
|
+
candidates: tuple[RootCause, ...]
|
|
114
|
+
flow_used: bool
|
|
115
|
+
flow_gaps: tuple[str, ...]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def parse_python_traceback(text: str) -> ParsedTraceback:
|
|
119
|
+
"""Parse CPython traceback text into frames and the exception line.
|
|
120
|
+
|
|
121
|
+
Chained tracebacks (``During handling ...``/``direct cause``) contain
|
|
122
|
+
several sections; the last one is the failure that propagated, so its
|
|
123
|
+
frames and its trailing exception line are the ones returned. An
|
|
124
|
+
``ExceptionGroup`` rendering is normalised by stripping its box margin,
|
|
125
|
+
after which the same rule picks the last sub-exception's traceback --
|
|
126
|
+
the deepest real cause, not the group wrapper.
|
|
127
|
+
"""
|
|
128
|
+
lines = [
|
|
129
|
+
_TB_GROUP_MARGIN.sub("", line) for line in text.splitlines() if line.strip()
|
|
130
|
+
]
|
|
131
|
+
last_header = -1
|
|
132
|
+
for index, line in enumerate(lines):
|
|
133
|
+
if line.strip() in (_TB_HEADER, _TB_GROUP_HEADER):
|
|
134
|
+
last_header = index
|
|
135
|
+
frames: list[FramePoint] = []
|
|
136
|
+
exception_type = ""
|
|
137
|
+
exception_message = ""
|
|
138
|
+
for line in lines[last_header + 1 :]:
|
|
139
|
+
if match := _TB_FRAME.match(line):
|
|
140
|
+
frames.append(
|
|
141
|
+
FramePoint(
|
|
142
|
+
path=match.group("path"),
|
|
143
|
+
qualname=match.group("name").strip(),
|
|
144
|
+
line=int(match.group("line")),
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
# Source snippets and caret markers are indented; the exception line
|
|
148
|
+
# is the first flush-left line after the frames.
|
|
149
|
+
elif not line[:1].isspace() and (match := _TB_EXCEPTION.match(line)):
|
|
150
|
+
exception_type = match.group("type")
|
|
151
|
+
exception_message = match.group("message") or ""
|
|
152
|
+
break
|
|
153
|
+
return ParsedTraceback(tuple(frames), exception_type, exception_message)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _anchored(frame: FramePoint, repo_root: Path) -> FramePoint:
|
|
157
|
+
"""A frame whose relative path is joined to the repository root.
|
|
158
|
+
|
|
159
|
+
Tracebacks from a process started inside the repository carry paths
|
|
160
|
+
relative to it; absolute paths and synthetic files (``<stdin>``) pass
|
|
161
|
+
through and resolve (or fail containment) as they are.
|
|
162
|
+
"""
|
|
163
|
+
if Path(frame.path).is_absolute() or frame.path.startswith("<"):
|
|
164
|
+
return frame
|
|
165
|
+
return FramePoint(
|
|
166
|
+
path=(repo_root / frame.path).as_posix(),
|
|
167
|
+
qualname=frame.qualname,
|
|
168
|
+
line=frame.line,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class _CrashGraph:
|
|
173
|
+
"""The project slice a correlation needs, fetched once."""
|
|
174
|
+
|
|
175
|
+
def __init__(self, fetch_all: QueryFn, project_name: str) -> None:
|
|
176
|
+
prefix = f"{project_name}{cs.SEPARATOR_DOT}"
|
|
177
|
+
params = {
|
|
178
|
+
cs.KEY_PROJECT_PREFIX: prefix,
|
|
179
|
+
cs.KEY_PROJECT_NAME: project_name,
|
|
180
|
+
}
|
|
181
|
+
self.nodes: list[CallableNode] = load_callables(fetch_all, prefix)
|
|
182
|
+
self.by_qn: dict[str, CallableNode] = {
|
|
183
|
+
node.qualified_name: node for node in self.nodes
|
|
184
|
+
}
|
|
185
|
+
self.callers: dict[str, list[str]] = {}
|
|
186
|
+
self.callees: dict[str, list[str]] = {}
|
|
187
|
+
for row in fetch_all(CYPHER_CRASH_CALLS, {cs.KEY_PREFIX: prefix}):
|
|
188
|
+
from_qn, to_qn = row.get("from_qn"), row.get("to_qn")
|
|
189
|
+
if isinstance(from_qn, str) and isinstance(to_qn, str):
|
|
190
|
+
self.callers.setdefault(to_qn, []).append(from_qn)
|
|
191
|
+
self.callees.setdefault(from_qn, []).append(to_qn)
|
|
192
|
+
self.flow_sources: dict[str, list[str]] = {}
|
|
193
|
+
for row in fetch_all(CYPHER_FLOW_EDGES, params):
|
|
194
|
+
source, target = row.get("source"), row.get("target")
|
|
195
|
+
if isinstance(source, str) and isinstance(target, str):
|
|
196
|
+
self.flow_sources.setdefault(target, []).append(source)
|
|
197
|
+
# Gaps are fetched unconditionally: a flow edge elsewhere in the
|
|
198
|
+
# project must not hide that the failing file sits outside coverage.
|
|
199
|
+
gap_rows = fetch_all(CYPHER_FLOW_COVERAGE_GAPS, params)
|
|
200
|
+
self.flow_gaps: tuple[str, ...] = tuple(
|
|
201
|
+
sorted(
|
|
202
|
+
path
|
|
203
|
+
for row in gap_rows
|
|
204
|
+
if isinstance(path := row.get(cs.KEY_PATH), str)
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _resolve_stack(
|
|
210
|
+
parsed: ParsedTraceback, graph: _CrashGraph, repo_root: Path
|
|
211
|
+
) -> list[tuple[FramePoint, str | None, str | None, str | None]]:
|
|
212
|
+
"""Each frame with (resolved qn, label, unresolved reason)."""
|
|
213
|
+
resolver = FrameResolver(repo_root, graph.nodes)
|
|
214
|
+
resolved: list[tuple[FramePoint, str | None, str | None, str | None]] = []
|
|
215
|
+
for frame in parsed.frames:
|
|
216
|
+
stats = ResolutionStats()
|
|
217
|
+
match = resolver.resolve(_anchored(frame, repo_root), stats)
|
|
218
|
+
if match is not None:
|
|
219
|
+
resolved.append((frame, match.qualified_name, match.label, None))
|
|
220
|
+
else:
|
|
221
|
+
reason = next(iter(stats.unresolved), None)
|
|
222
|
+
resolved.append((frame, None, None, reason))
|
|
223
|
+
return resolved
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def explain_traceback(
|
|
227
|
+
fetch_all: QueryFn,
|
|
228
|
+
project_name: str,
|
|
229
|
+
repo_root: Path,
|
|
230
|
+
traceback_text: str,
|
|
231
|
+
) -> TracebackReport:
|
|
232
|
+
"""Resolve each traceback frame and attach its graph neighbourhood."""
|
|
233
|
+
parsed = parse_python_traceback(traceback_text)
|
|
234
|
+
graph = _CrashGraph(fetch_all, project_name)
|
|
235
|
+
contexts = [
|
|
236
|
+
FrameContext(
|
|
237
|
+
path=frame.path,
|
|
238
|
+
line=frame.line,
|
|
239
|
+
name=frame.qualname,
|
|
240
|
+
qualified_name=qn,
|
|
241
|
+
label=label,
|
|
242
|
+
unresolved_reason=reason,
|
|
243
|
+
callers=tuple(sorted(graph.callers.get(qn, ()))) if qn else (),
|
|
244
|
+
callees=tuple(sorted(graph.callees.get(qn, ()))) if qn else (),
|
|
245
|
+
flow_sources=tuple(sorted(graph.flow_sources.get(qn, ()))) if qn else (),
|
|
246
|
+
)
|
|
247
|
+
for frame, qn, label, reason in _resolve_stack(parsed, graph, repo_root)
|
|
248
|
+
]
|
|
249
|
+
return TracebackReport(
|
|
250
|
+
exception_type=parsed.exception_type,
|
|
251
|
+
exception_message=parsed.exception_message,
|
|
252
|
+
frames=tuple(contexts),
|
|
253
|
+
flow_gaps=graph.flow_gaps,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _reverse_reachable(
|
|
258
|
+
graph: _CrashGraph, failing: str
|
|
259
|
+
) -> dict[str, tuple[int, tuple[str, ...]]]:
|
|
260
|
+
"""Callers that reach the failing node within the depth limit.
|
|
261
|
+
|
|
262
|
+
Maps each caller to its depth and the forward call path it takes to the
|
|
263
|
+
failure (``candidate -> ... -> failing``), from a breadth-first walk over
|
|
264
|
+
reversed CALLS edges, so the recorded path is a shortest one.
|
|
265
|
+
"""
|
|
266
|
+
reached: dict[str, tuple[int, tuple[str, ...]]] = {}
|
|
267
|
+
queue: deque[tuple[str, int]] = deque([(failing, 0)])
|
|
268
|
+
seen = {failing}
|
|
269
|
+
while queue:
|
|
270
|
+
current, depth = queue.popleft()
|
|
271
|
+
if depth == _CALLER_DEPTH_LIMIT:
|
|
272
|
+
continue
|
|
273
|
+
# Sorted expansion keeps the recorded shortest path deterministic
|
|
274
|
+
# when several exist; the graph returns edges in no fixed order.
|
|
275
|
+
for caller in sorted(graph.callers.get(current, ())):
|
|
276
|
+
if caller in seen:
|
|
277
|
+
continue
|
|
278
|
+
seen.add(caller)
|
|
279
|
+
_, tail = reached.get(current, (0, (failing,)))
|
|
280
|
+
reached[caller] = (depth + 1, (caller, *tail))
|
|
281
|
+
queue.append((caller, depth + 1))
|
|
282
|
+
return reached
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def rank_root_causes(
|
|
286
|
+
fetch_all: QueryFn,
|
|
287
|
+
project_name: str,
|
|
288
|
+
repo_root: Path,
|
|
289
|
+
traceback_text: str,
|
|
290
|
+
) -> RootCauseReport:
|
|
291
|
+
"""Rank the sites that can explain the failure, best first.
|
|
292
|
+
|
|
293
|
+
The score is additive over three signals: being a FLOWS_TO source into
|
|
294
|
+
the failing frame (the failing value's possible producers), sitting on
|
|
295
|
+
the crashing stack itself (the ground-truth path), and reaching the
|
|
296
|
+
failing frame through CALLS (closer callers score higher). The failing
|
|
297
|
+
frame itself is reported separately, not ranked.
|
|
298
|
+
"""
|
|
299
|
+
parsed = parse_python_traceback(traceback_text)
|
|
300
|
+
graph = _CrashGraph(fetch_all, project_name)
|
|
301
|
+
stack = _resolve_stack(parsed, graph, repo_root)
|
|
302
|
+
stack_qns = [qn for _frame, qn, _label, _reason in stack if qn]
|
|
303
|
+
failing = stack_qns[-1] if stack_qns else None
|
|
304
|
+
anchor_is_crash_site = bool(stack) and stack[-1][1] is not None
|
|
305
|
+
if failing is None:
|
|
306
|
+
return RootCauseReport(
|
|
307
|
+
exception_type=parsed.exception_type,
|
|
308
|
+
exception_message=parsed.exception_message,
|
|
309
|
+
failing=None,
|
|
310
|
+
anchor_is_crash_site=False,
|
|
311
|
+
candidates=(),
|
|
312
|
+
flow_used=bool(graph.flow_sources),
|
|
313
|
+
flow_gaps=graph.flow_gaps,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
reached = _reverse_reachable(graph, failing)
|
|
317
|
+
flow_into_failing = set(graph.flow_sources.get(failing, ()))
|
|
318
|
+
scores: dict[str, float] = {}
|
|
319
|
+
reasons: dict[str, list[str]] = {}
|
|
320
|
+
paths: dict[str, tuple[str, ...]] = {}
|
|
321
|
+
|
|
322
|
+
for qn, (depth, call_path) in reached.items():
|
|
323
|
+
scores[qn] = scores.get(qn, 0.0) + _SCORE_CALLER_BASE / depth
|
|
324
|
+
reasons.setdefault(qn, []).append(_REASON_CALLER.format(depth=depth))
|
|
325
|
+
paths[qn] = call_path
|
|
326
|
+
for distance, qn in enumerate(reversed(stack_qns[:-1]), start=1):
|
|
327
|
+
scores[qn] = scores.get(qn, 0.0) + _SCORE_ON_STACK
|
|
328
|
+
reasons.setdefault(qn, []).append(_REASON_ON_STACK.format(depth=distance))
|
|
329
|
+
for qn in flow_into_failing:
|
|
330
|
+
scores[qn] = scores.get(qn, 0.0) + _SCORE_FLOW
|
|
331
|
+
reasons.setdefault(qn, []).append(_REASON_FLOW)
|
|
332
|
+
|
|
333
|
+
ranked = sorted(scores.items(), key=lambda item: (-item[1], item[0]))
|
|
334
|
+
candidates = tuple(
|
|
335
|
+
RootCause(
|
|
336
|
+
qualified_name=qn,
|
|
337
|
+
path=node.path if node else None,
|
|
338
|
+
line=node.start_line if node else None,
|
|
339
|
+
score=round(score, 3),
|
|
340
|
+
reasons=tuple(reasons[qn]),
|
|
341
|
+
call_path=paths.get(qn, ()),
|
|
342
|
+
)
|
|
343
|
+
for qn, score in ranked[:_RANK_LIMIT]
|
|
344
|
+
for node in (graph.by_qn.get(qn),)
|
|
345
|
+
)
|
|
346
|
+
return RootCauseReport(
|
|
347
|
+
exception_type=parsed.exception_type,
|
|
348
|
+
exception_message=parsed.exception_message,
|
|
349
|
+
failing=failing,
|
|
350
|
+
anchor_is_crash_site=anchor_is_crash_site,
|
|
351
|
+
candidates=candidates,
|
|
352
|
+
flow_used=bool(graph.flow_sources),
|
|
353
|
+
flow_gaps=graph.flow_gaps,
|
|
354
|
+
)
|
|
@@ -434,6 +434,31 @@ class MCPToolsRegistry:
|
|
|
434
434
|
returns_json=True,
|
|
435
435
|
)
|
|
436
436
|
|
|
437
|
+
traceback_schema = MCPInputSchema(
|
|
438
|
+
type=cs.MCPSchemaType.OBJECT,
|
|
439
|
+
properties={
|
|
440
|
+
cs.MCPParamName.TRACEBACK_TEXT: MCPInputSchemaProperty(
|
|
441
|
+
type=cs.MCPSchemaType.STRING,
|
|
442
|
+
description=td.MCP_PARAM_TRACEBACK_TEXT,
|
|
443
|
+
)
|
|
444
|
+
},
|
|
445
|
+
required=[cs.MCPParamName.TRACEBACK_TEXT],
|
|
446
|
+
)
|
|
447
|
+
self._tools[cs.MCPToolName.EXPLAIN_TRACEBACK] = ToolMetadata(
|
|
448
|
+
name=cs.MCPToolName.EXPLAIN_TRACEBACK,
|
|
449
|
+
description=td.MCP_TOOLS[cs.MCPToolName.EXPLAIN_TRACEBACK],
|
|
450
|
+
input_schema=traceback_schema,
|
|
451
|
+
handler=self.explain_traceback,
|
|
452
|
+
returns_json=True,
|
|
453
|
+
)
|
|
454
|
+
self._tools[cs.MCPToolName.RANK_ROOT_CAUSES] = ToolMetadata(
|
|
455
|
+
name=cs.MCPToolName.RANK_ROOT_CAUSES,
|
|
456
|
+
description=td.MCP_TOOLS[cs.MCPToolName.RANK_ROOT_CAUSES],
|
|
457
|
+
input_schema=traceback_schema,
|
|
458
|
+
handler=self.rank_root_causes,
|
|
459
|
+
returns_json=True,
|
|
460
|
+
)
|
|
461
|
+
|
|
437
462
|
@property
|
|
438
463
|
def rag_agent(self) -> Agent:
|
|
439
464
|
if self._rag_agent is None:
|
|
@@ -489,6 +514,47 @@ class MCPToolsRegistry:
|
|
|
489
514
|
"gaps": list(result.gaps),
|
|
490
515
|
}
|
|
491
516
|
|
|
517
|
+
async def explain_traceback(self, traceback_text: str) -> dict:
|
|
518
|
+
from codebase_rag.crash_correlation import explain_traceback
|
|
519
|
+
|
|
520
|
+
project = derive_project_name(Path(self.project_root))
|
|
521
|
+
async with self._ingestor_lock:
|
|
522
|
+
report = await asyncio.to_thread(
|
|
523
|
+
explain_traceback,
|
|
524
|
+
self.ingestor.fetch_all,
|
|
525
|
+
project,
|
|
526
|
+
Path(self.project_root),
|
|
527
|
+
traceback_text,
|
|
528
|
+
)
|
|
529
|
+
return {
|
|
530
|
+
"exception_type": report.exception_type,
|
|
531
|
+
"exception_message": report.exception_message,
|
|
532
|
+
"frames": [frame._asdict() for frame in report.frames],
|
|
533
|
+
"flow_gaps": list(report.flow_gaps),
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async def rank_root_causes(self, traceback_text: str) -> dict:
|
|
537
|
+
from codebase_rag.crash_correlation import rank_root_causes
|
|
538
|
+
|
|
539
|
+
project = derive_project_name(Path(self.project_root))
|
|
540
|
+
async with self._ingestor_lock:
|
|
541
|
+
report = await asyncio.to_thread(
|
|
542
|
+
rank_root_causes,
|
|
543
|
+
self.ingestor.fetch_all,
|
|
544
|
+
project,
|
|
545
|
+
Path(self.project_root),
|
|
546
|
+
traceback_text,
|
|
547
|
+
)
|
|
548
|
+
return {
|
|
549
|
+
"exception_type": report.exception_type,
|
|
550
|
+
"exception_message": report.exception_message,
|
|
551
|
+
"failing": report.failing,
|
|
552
|
+
"anchor_is_crash_site": report.anchor_is_crash_site,
|
|
553
|
+
"candidates": [candidate._asdict() for candidate in report.candidates],
|
|
554
|
+
"flow_used": report.flow_used,
|
|
555
|
+
"flow_gaps": list(report.flow_gaps),
|
|
556
|
+
}
|
|
557
|
+
|
|
492
558
|
async def list_projects(self) -> ListProjectsResult:
|
|
493
559
|
logger.info(lg.MCP_LISTING_PROJECTS)
|
|
494
560
|
try:
|