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.
Files changed (300) hide show
  1. {code_graph_rag-0.0.662/code_graph_rag.egg-info → code_graph_rag-0.0.670}/PKG-INFO +1 -1
  2. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670/code_graph_rag.egg-info}/PKG-INFO +1 -1
  3. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/SOURCES.txt +1 -0
  4. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cli_help.py +5 -1
  5. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_js.py +15 -0
  6. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_python.py +16 -0
  7. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/mcp.py +3 -0
  8. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/security.py +39 -0
  9. code_graph_rag-0.0.670/codebase_rag/crash_correlation.py +354 -0
  10. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/tools.py +66 -0
  11. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/type_inference.py +255 -49
  12. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/ast_analyzer.py +50 -5
  13. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/expression_analyzer.py +30 -23
  14. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/type_inference.py +10 -1
  15. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/variable_analyzer.py +86 -1
  16. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/shell_command.py +50 -0
  17. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/tool_descriptions.py +33 -0
  18. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/ebpf_pprof.py +196 -13
  19. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/ingest.py +9 -5
  20. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/resolution.py +36 -14
  21. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/pyproject.toml +1 -1
  22. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/LICENSE +0 -0
  23. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/PYPI_README.md +0 -0
  24. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/README.md +0 -0
  25. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/cgr/__init__.py +0 -0
  26. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/dependency_links.txt +0 -0
  27. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/entry_points.txt +0 -0
  28. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/requires.txt +0 -0
  29. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/code_graph_rag.egg-info/top_level.txt +0 -0
  30. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/__init__.py +0 -0
  31. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/__init__.py +0 -0
  32. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_analyzer.py +0 -0
  33. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/c.yaml +0 -0
  34. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/cpp.yaml +0 -0
  35. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/csharp.yaml +0 -0
  36. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/dart.yaml +0 -0
  37. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/go.yaml +0 -0
  38. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/java.yaml +0 -0
  39. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/javascript.yaml +0 -0
  40. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/lua.yaml +0 -0
  41. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/php.yaml +0 -0
  42. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/python.yaml +0 -0
  43. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/ruby.yaml +0 -0
  44. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/rust.yaml +0 -0
  45. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/scala.yaml +0 -0
  46. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/tsx.yaml +0 -0
  47. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/patterns/typescript.yaml +0 -0
  48. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/c.yaml +0 -0
  49. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/cpp.yaml +0 -0
  50. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/csharp.yaml +0 -0
  51. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/dart.yaml +0 -0
  52. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/go.yaml +0 -0
  53. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/java.yaml +0 -0
  54. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/javascript.yaml +0 -0
  55. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/lua.yaml +0 -0
  56. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/php.yaml +0 -0
  57. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/python.yaml +0 -0
  58. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/ruby.yaml +0 -0
  59. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/rust.yaml +0 -0
  60. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/scala.yaml +0 -0
  61. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/tsx.yaml +0 -0
  62. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/security/typescript.yaml +0 -0
  63. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/c.yaml +0 -0
  64. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/cpp.yaml +0 -0
  65. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/csharp.yaml +0 -0
  66. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/dart.yaml +0 -0
  67. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/go.yaml +0 -0
  68. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/java.yaml +0 -0
  69. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/javascript.yaml +0 -0
  70. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/lua.yaml +0 -0
  71. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/php.yaml +0 -0
  72. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/python.yaml +0 -0
  73. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/ruby.yaml +0 -0
  74. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/rust.yaml +0 -0
  75. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/scala.yaml +0 -0
  76. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/tsx.yaml +0 -0
  77. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/analyzers/ast_grep_rules/smells/typescript.yaml +0 -0
  78. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/ast_cache.py +0 -0
  79. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/capture.py +0 -0
  80. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cgr_state.py +0 -0
  81. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cli.py +0 -0
  82. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/config.py +0 -0
  83. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/__init__.py +0 -0
  84. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_cpp.py +0 -0
  85. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_csharp.py +0 -0
  86. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_dart.py +0 -0
  87. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_go.py +0 -0
  88. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_java.py +0 -0
  89. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_lua.py +0 -0
  90. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_nodes.py +0 -0
  91. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_php.py +0 -0
  92. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_rust.py +0 -0
  93. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/ast_scala.py +0 -0
  94. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/build.py +0 -0
  95. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/cli.py +0 -0
  96. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/core.py +0 -0
  97. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/deadcode_roots.py +0 -0
  98. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/deps.py +0 -0
  99. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/fqn_specs.py +0 -0
  100. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/graph.py +0 -0
  101. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/health.py +0 -0
  102. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/lang_tooling.py +0 -0
  103. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/languages.py +0 -0
  104. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/providers.py +0 -0
  105. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/stdlib_types.py +0 -0
  106. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/structural.py +0 -0
  107. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/constants/trace.py +0 -0
  108. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/cypher_queries.py +0 -0
  109. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/dead_code.py +0 -0
  110. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/decorators.py +0 -0
  111. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/docker-compose.yaml +0 -0
  112. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/embedder.py +0 -0
  113. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/exceptions.py +0 -0
  114. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/flow_verdict.py +0 -0
  115. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/function_registry.py +0 -0
  116. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/graph_audit.py +0 -0
  117. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/graph_loader.py +0 -0
  118. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/graph_updater.py +0 -0
  119. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/language_spec.py +0 -0
  120. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/logs.py +0 -0
  121. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/main.py +0 -0
  122. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/__init__.py +0 -0
  123. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/client.py +0 -0
  124. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/mcp/server.py +0 -0
  125. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/models.py +0 -0
  126. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parser_fingerprint.py +0 -0
  127. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parser_loader.py +0 -0
  128. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/__init__.py +0 -0
  129. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/ast_grep_patterns/ruby.yaml +0 -0
  130. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/ast_grep_tier.py +0 -0
  131. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/call_processor.py +0 -0
  132. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/call_resolver.py +0 -0
  133. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/__init__.py +0 -0
  134. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/cpp_modules.py +0 -0
  135. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/identity.py +0 -0
  136. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/method_override.py +0 -0
  137. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/mixin.py +0 -0
  138. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/node_type.py +0 -0
  139. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/parent_extraction.py +0 -0
  140. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/relationships.py +0 -0
  141. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/class_ingest/utils.py +0 -0
  142. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/contract_linking.py +0 -0
  143. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/contracts.py +0 -0
  144. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/__init__.py +0 -0
  145. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/preproc_recovery.py +0 -0
  146. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/type_inference.py +0 -0
  147. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp/utils.py +0 -0
  148. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/__init__.py +0 -0
  149. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/constants.py +0 -0
  150. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/frontend.py +0 -0
  151. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/cpp_frontend/qn.py +0 -0
  152. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp/__init__.py +0 -0
  153. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp/type_inference.py +0 -0
  154. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp/utils.py +0 -0
  155. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/__init__.py +0 -0
  156. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/frontend.py +0 -0
  157. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/roslyn/Frontend.cs +0 -0
  158. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/roslyn/Frontend.csproj +0 -0
  159. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/csharp_frontend/roslyn/Program.cs +0 -0
  160. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dart/__init__.py +0 -0
  161. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dart/type_inference.py +0 -0
  162. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dart/utils.py +0 -0
  163. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/definition_processor.py +0 -0
  164. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dependency_parser.py +0 -0
  165. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/dispatch_registry.py +0 -0
  166. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/endpoint_prefixes.py +0 -0
  167. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/endpoint_routes.py +0 -0
  168. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/endpoints.py +0 -0
  169. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/export_detection.py +0 -0
  170. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/factory.py +0 -0
  171. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/flow_access/__init__.py +0 -0
  172. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/flow_access/constants.py +0 -0
  173. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/flow_access/processor.py +0 -0
  174. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/__init__.py +0 -0
  175. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/csharp.py +0 -0
  176. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/go.py +0 -0
  177. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/protocol.py +0 -0
  178. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/frontends/registry.py +0 -0
  179. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/function_ingest.py +0 -0
  180. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/__init__.py +0 -0
  181. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/module_paths.py +0 -0
  182. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/type_inference.py +0 -0
  183. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go/utils.py +0 -0
  184. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/__init__.py +0 -0
  185. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/frontend.py +0 -0
  186. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/gotypes/go.mod +0 -0
  187. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/gotypes/go.sum +0 -0
  188. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/go_frontend/gotypes/main.go +0 -0
  189. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/__init__.py +0 -0
  190. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/base.py +0 -0
  191. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/cpp.py +0 -0
  192. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/java.py +0 -0
  193. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/js_ts.py +0 -0
  194. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/lua.py +0 -0
  195. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/php.py +0 -0
  196. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/protocol.py +0 -0
  197. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/python.py +0 -0
  198. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/registry.py +0 -0
  199. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/handlers/rust.py +0 -0
  200. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/import_processor.py +0 -0
  201. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/__init__.py +0 -0
  202. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/constants.py +0 -0
  203. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/descriptor.py +0 -0
  204. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/extract.py +0 -0
  205. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/models.py +0 -0
  206. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/processor.py +0 -0
  207. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/io_access/registry.py +0 -0
  208. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/__init__.py +0 -0
  209. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/method_resolver.py +0 -0
  210. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/type_inference.py +0 -0
  211. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/type_resolver.py +0 -0
  212. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/utils.py +0 -0
  213. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/java/variable_analyzer.py +0 -0
  214. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/__init__.py +0 -0
  215. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/ingest.py +0 -0
  216. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/module_paths.py +0 -0
  217. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/module_system.py +0 -0
  218. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/js_ts/utils.py +0 -0
  219. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/lua/__init__.py +0 -0
  220. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/lua/type_inference.py +0 -0
  221. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/lua/utils.py +0 -0
  222. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/__init__.py +0 -0
  223. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/py/utils.py +0 -0
  224. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/python_source_roots.py +0 -0
  225. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rpc_exposure.py +0 -0
  226. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rs/__init__.py +0 -0
  227. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rs/type_inference.py +0 -0
  228. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/rs/utils.py +0 -0
  229. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/semantic_call_join.py +0 -0
  230. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/stdlib_extractor.py +0 -0
  231. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/structure_processor.py +0 -0
  232. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/type_inference.py +0 -0
  233. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/parsers/utils.py +0 -0
  234. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/path_filters.py +0 -0
  235. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/prompts.py +0 -0
  236. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/providers/__init__.py +0 -0
  237. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/providers/base.py +0 -0
  238. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/providers/litellm.py +0 -0
  239. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/readme_sections.py +0 -0
  240. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/schema_builder.py +0 -0
  241. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/schemas.py +0 -0
  242. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/__init__.py +0 -0
  243. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/anthropic_token_counter.py +0 -0
  244. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/filtering.py +0 -0
  245. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/graph_service.py +0 -0
  246. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/llm.py +0 -0
  247. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/protobuf_service.py +0 -0
  248. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/resource_cleanup.py +0 -0
  249. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/services/usage_cost.py +0 -0
  250. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/__init__.py +0 -0
  251. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/cli.py +0 -0
  252. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/constants.py +0 -0
  253. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/health.py +0 -0
  254. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/stack/manager.py +0 -0
  255. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tool_errors.py +0 -0
  256. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/__init__.py +0 -0
  257. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/ast_grep_service.py +0 -0
  258. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/code_retrieval.py +0 -0
  259. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/codebase_query.py +0 -0
  260. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/directory_lister.py +0 -0
  261. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/file_editor.py +0 -0
  262. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/file_reader.py +0 -0
  263. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/file_writer.py +0 -0
  264. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/health_checker.py +0 -0
  265. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/language.py +0 -0
  266. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/semantic_search.py +0 -0
  267. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/structural_editor.py +0 -0
  268. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/structural_search.py +0 -0
  269. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/tools/web_search.py +0 -0
  270. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/__init__.py +0 -0
  271. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/cli.py +0 -0
  272. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/cpuprofile.py +0 -0
  273. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/instrumented.py +0 -0
  274. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/pprof.py +0 -0
  275. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/pytest_plugin.py +0 -0
  276. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/records.py +0 -0
  277. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/rust_pprof.py +0 -0
  278. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/sourcemap.py +0 -0
  279. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/speedscope.py +0 -0
  280. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/tracer.py +0 -0
  281. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/trace/xdebug.py +0 -0
  282. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/types_defs.py +0 -0
  283. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/unixcoder.py +0 -0
  284. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/__init__.py +0 -0
  285. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/dependencies.py +0 -0
  286. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/fqn_resolver.py +0 -0
  287. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/path_utils.py +0 -0
  288. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/rich_markdown.py +0 -0
  289. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/source_extraction.py +0 -0
  290. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/utils/token_utils.py +0 -0
  291. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/vector_store.py +0 -0
  292. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/__init__.py +0 -0
  293. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/cli.py +0 -0
  294. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/constants.py +0 -0
  295. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/models.py +0 -0
  296. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codebase_rag/workspaces/storage.py +0 -0
  297. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codec/__init__.py +0 -0
  298. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codec/schema_pb2.py +0 -0
  299. {code_graph_rag-0.0.662 → code_graph_rag-0.0.670}/codec/schema_pb2.pyi +0 -0
  300. {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.662
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.662
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
@@ -16,6 +16,7 @@ codebase_rag/cgr_state.py
16
16
  codebase_rag/cli.py
17
17
  codebase_rag/cli_help.py
18
18
  codebase_rag/config.py
19
+ codebase_rag/crash_correlation.py
19
20
  codebase_rag/cypher_queries.py
20
21
  codebase_rag/dead_code.py
21
22
  codebase_rag/decorators.py
@@ -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: