codegraphcontext 0.6.0__tar.gz → 0.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. {codegraphcontext-0.6.0/src/codegraphcontext.egg-info → codegraphcontext-0.6.2}/PKG-INFO +1 -1
  2. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/pyproject.toml +1 -1
  3. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/config_manager.py +1 -0
  4. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database_embedded_kuzu.py +26 -12
  5. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/jobs.py +27 -4
  6. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/simulator.py +4 -2
  7. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/watcher.py +7 -0
  8. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/graph_builder.py +10 -19
  9. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/handlers/indexing_handlers.py +28 -19
  10. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/constants.py +3 -0
  11. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/persistence/writer.py +17 -2
  12. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/pipeline.py +26 -4
  13. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/cpp.py +9 -5
  14. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/javascript.py +36 -25
  15. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/typescript.py +38 -20
  16. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/cypher_readonly.py +26 -1
  17. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2/src/codegraphcontext.egg-info}/PKG-INFO +1 -1
  18. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/LICENSE +0 -0
  19. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/MANIFEST.in +0 -0
  20. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/README.md +0 -0
  21. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/setup.cfg +0 -0
  22. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/__init__.py +0 -0
  23. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/__main__.py +0 -0
  24. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/api/__init__.py +0 -0
  25. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/api/app.py +0 -0
  26. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/api/auth.py +0 -0
  27. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/api/mcp_sse.py +0 -0
  28. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/api/router.py +0 -0
  29. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/api/schemas.py +0 -0
  30. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/__init__.py +0 -0
  31. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/cli_helpers.py +0 -0
  32. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/hook_manager.py +0 -0
  33. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/main.py +0 -0
  34. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/project_config.py +0 -0
  35. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/registry_commands.py +0 -0
  36. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/setup_macos.py +0 -0
  37. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/setup_wizard.py +0 -0
  38. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/simulator.py +0 -0
  39. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/cli/visualizer.py +0 -0
  40. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/__init__.py +0 -0
  41. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/bundle_registry.py +0 -0
  42. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/cgc_bundle.py +0 -0
  43. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/cgcignore.py +0 -0
  44. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database.py +0 -0
  45. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database_falkordb.py +0 -0
  46. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
  47. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database_kuzu.py +0 -0
  48. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database_ladybug.py +0 -0
  49. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/database_nornic.py +0 -0
  50. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/falkor_worker.py +0 -0
  51. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/core/graph_query.py +0 -0
  52. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/prompts.py +0 -0
  53. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/server.py +0 -0
  54. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/stdlibs.py +0 -0
  55. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tool_definitions.py +0 -0
  56. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/__init__.py +0 -0
  57. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
  58. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/code_finder.py +0 -0
  59. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/datasources/__init__.py +0 -0
  60. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/datasources/cassandra_ingester.py +0 -0
  61. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/datasources/mysql_ingester.py +0 -0
  62. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/datasources/redis_ingester.py +0 -0
  63. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/handlers/analysis_handlers.py +0 -0
  64. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/handlers/management_handlers.py +0 -0
  65. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -0
  66. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/handlers/watcher_handlers.py +0 -0
  67. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/__init__.py +0 -0
  68. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/discovery.py +0 -0
  69. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/embeddings.py +0 -0
  70. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/persistence/__init__.py +0 -0
  71. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/persistence/utils.py +0 -0
  72. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/pre_scan.py +0 -0
  73. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/resolution/__init__.py +0 -0
  74. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/resolution/calls.py +0 -0
  75. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/resolution/inheritance.py +0 -0
  76. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/resolution/post_resolution.py +0 -0
  77. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/sanitize.py +0 -0
  78. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/schema.py +0 -0
  79. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/schema_contract.py +0 -0
  80. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/scip_pipeline.py +0 -0
  81. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/indexing/vector_resolver.py +0 -0
  82. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/c.py +0 -0
  83. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/csharp.py +0 -0
  84. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/css.py +0 -0
  85. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/dart.py +0 -0
  86. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/elisp.py +0 -0
  87. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/elixir.py +0 -0
  88. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/go.py +0 -0
  89. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/gradle.py +0 -0
  90. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/haskell.py +0 -0
  91. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/html.py +0 -0
  92. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/java.py +0 -0
  93. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
  94. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/lua.py +0 -0
  95. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/maven.py +0 -0
  96. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/mybatis.py +0 -0
  97. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/perl.py +0 -0
  98. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/php.py +0 -0
  99. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/python.py +0 -0
  100. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/ruby.py +0 -0
  101. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/rust.py +0 -0
  102. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/scala.py +0 -0
  103. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/sfc_common.py +0 -0
  104. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/solidity.py +0 -0
  105. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/solidity_remappings.py +0 -0
  106. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/svelte.py +0 -0
  107. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/swift.py +0 -0
  108. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
  109. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/languages/vue.py +0 -0
  110. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/package_resolver.py +0 -0
  111. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
  112. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
  113. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
  114. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
  115. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/elisp_toolkit.py +0 -0
  116. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
  117. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
  118. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
  119. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
  120. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
  121. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
  122. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
  123. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
  124. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
  125. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/solidity_toolkit.py +0 -0
  126. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
  127. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
  128. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/report_generator.py +0 -0
  129. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/scip_indexer.py +0 -0
  130. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/scip_pb2.py +0 -0
  131. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/system.py +0 -0
  132. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/tree_sitter_parser.py +0 -0
  133. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/tools/type_utils.py +0 -0
  134. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/cypher_ddl.py +0 -0
  135. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/debug_log.py +0 -0
  136. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/gcf_encoder.py +0 -0
  137. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/git_utils.py +0 -0
  138. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/path_ignore.py +0 -0
  139. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/path_sandbox.py +0 -0
  140. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/repo_path.py +0 -0
  141. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/secret_scanner.py +0 -0
  142. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/tool_limits.py +0 -0
  143. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/tree_sitter_manager.py +0 -0
  144. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/utils/visualize_graph.py +0 -0
  145. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/__vite-browser-external-9wXp6ZBx.js +0 -0
  146. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
  147. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
  148. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
  149. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
  150. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/index-C-187lf0.js +0 -0
  151. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/index-fNAa6jgv.css +0 -0
  152. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/parser-pyodide.worker-BgsDfaad.js +0 -0
  153. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/parser.worker-_nvrecvj.js +0 -0
  154. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/assets/tree-sitter-qKYAACSa.wasm +0 -0
  155. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/cgcIcon.png +0 -0
  156. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/favicon.ico +0 -0
  157. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/index.html +0 -0
  158. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/logo-icon.svg +0 -0
  159. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/logo.svg +0 -0
  160. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/placeholder.svg +0 -0
  161. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/preview-image.png +0 -0
  162. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/robots.txt +0 -0
  163. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c.wasm +0 -0
  164. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
  165. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-core.js +0 -0
  166. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-cpp.wasm +0 -0
  167. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-dart.wasm +0 -0
  168. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-go.wasm +0 -0
  169. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-java.wasm +0 -0
  170. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-javascript.wasm +0 -0
  171. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-kotlin.wasm +0 -0
  172. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-perl.wasm +0 -0
  173. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-php.wasm +0 -0
  174. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-python.wasm +0 -0
  175. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-ruby.wasm +0 -0
  176. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-rust.wasm +0 -0
  177. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-swift.wasm +0 -0
  178. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-tsx.wasm +0 -0
  179. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm +0 -0
  180. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/tree-sitter.wasm +0 -0
  181. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.js +0 -0
  182. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm +0 -0
  183. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext/viz/server.py +0 -0
  184. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext.egg-info/SOURCES.txt +0 -0
  185. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
  186. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
  187. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext.egg-info/requires.txt +0 -0
  188. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/src/codegraphcontext.egg-info/top_level.txt +0 -0
  189. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/tests/test_issue_806_fix.py +0 -0
  190. {codegraphcontext-0.6.0 → codegraphcontext-0.6.2}/tests/test_mcp_sse.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codegraphcontext
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: An MCP server that indexes local code into a graph database to provide context to AI assistants.
5
5
  Author-email: Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codegraphcontext"
3
- version = "0.6.0"
3
+ version = "0.6.2"
4
4
  description = "An MCP server that indexes local code into a graph database to provide context to AI assistants."
5
5
  authors = [{ name = "Shashank Shekhar Singh", email = "shashankshekharsingh1205@gmail.com" }]
6
6
  readme = "README.md"
@@ -274,6 +274,7 @@ dist/
274
274
  build/
275
275
  target/
276
276
  out/
277
+ obj/
277
278
  .git/
278
279
  .idea/
279
280
  .vscode/
@@ -798,21 +798,32 @@ class EmbeddedSessionWrapper:
798
798
  translated_query, translated_params = self._translate_query(query, parameters)
799
799
  debug_log(f"Translated Query: {translated_query[:200]}")
800
800
  try:
801
- # Force loop fallback for relationship writes inside UNWIND to avoid Kuzu query planner bugs
802
- # which can incorrectly bind/corrupt relationship endpoints across rows in the batch.
803
- # Only force it for `UNWIND $param AS row`, the single shape the
804
- # recovery path below can rewrite into a per-row loop. Read queries
805
- # that unwind a bound list (`WITH relationships(p) AS rels UNWIND
806
- # rels AS r`, used by find_all_callers/find_all_callees and the
807
- # visualizer) matched this guard too, but no `$`-UNWIND for the
808
- # fallback to latch onto so the fabricated exception fell through
809
- # every handler and surfaced to the caller as a hard failure.
801
+ # Force the per-row loop fallback ONLY for UNWIND batches containing a
802
+ # node-MERGE. Kùzu's MERGE pipeline mis-binds when a merged node's key
803
+ # value repeats NON-adjacently across the batch: in
804
+ # [(A,P), (B,X), (C,P)] the C row binds to X's node instead of
805
+ # re-matching P (reproduced on Kùzu 0.11.3; see #1605). Relationship-only
806
+ # MERGEs (MATCH … MATCH … MERGE (a)-[r]->(b)) do not exhibit the bug —
807
+ # verified with interleaved duplicate endpoint keys and duplicate pairs
808
+ # so they now run batched, which removes the bulk of the per-row planner
809
+ # overhead (~2.4x on a full index of the Python sample project).
810
+ # Only `UNWIND $param AS row` shapes are guarded — that is the single
811
+ # shape the recovery path below can rewrite into a per-row loop. Read
812
+ # queries that unwind a bound list (`WITH relationships(p) AS rels
813
+ # UNWIND rels AS r`) must not match, or the fabricated exception would
814
+ # surface to the caller as a hard failure.
815
+ # Node-only UNWIND writes (`MERGE (n:Label {…}) SET n += row`, no
816
+ # relationship pattern) have always batched through the SET-expansion
817
+ # path and the per-row rewriter cannot handle their bare `SET n += row`,
818
+ # so the guard additionally requires a relationship pattern.
819
+ _has_node_merge = re.search(r"MERGE\s*\(\s*\w+\s*:", query)
810
820
  if (
811
821
  re.search(r"UNWIND\s+\$\w+\s+AS\s+\w+", query)
812
822
  and ("-[" in query or "]->" in query)
823
+ and _has_node_merge
813
824
  and not getattr(self, "_skip_unwind_fallback", False)
814
825
  ):
815
- raise Exception("unordered_map::at (forced fallback to avoid relationship UNWIND planner bugs)")
826
+ raise Exception("unordered_map::at (forced fallback: node-MERGE inside UNWIND mis-binds repeated keys)")
816
827
 
817
828
  # 2. Execute under the lock. _write_lock (name kept for backward
818
829
  # compat) now serializes ALL access, reads included: kuzu.Connection
@@ -1200,8 +1211,11 @@ class EmbeddedSessionWrapper:
1200
1211
  return f"{prefix}NOT label({var_name}) = '{label_name}'"
1201
1212
  query = re.sub(r'(WHERE\s+|AND\s+|OR\s+)NOT\s+(\w+):([a-zA-Z0-9_`]+)', not_label_replacer, query, flags=re.IGNORECASE)
1202
1213
 
1203
- # 4. Polymorphic matches and label access
1204
- query = query.replace("labels(n)[0]", "label(n)")
1214
+ # 4. Polymorphic matches and label access. Kùzu has no labels();
1215
+ # rewrite labels(<var>)[0] for ANY variable name — the literal
1216
+ # "labels(n)[0]" form missed n1/n2 and the simulator's relationship
1217
+ # query reached the engine unsupported (#1512).
1218
+ query = re.sub(r'labels\((\w+)\)\s*\[\s*0\s*\]', r'label(\1)', query)
1205
1219
 
1206
1220
  query = query.replace("coalesce(", "COALESCE(")
1207
1221
  query = re.sub(r'\btype\(', 'label(', query)
@@ -40,6 +40,7 @@ class JobInfo:
40
40
  result: Optional[Dict[str, Any]] = None
41
41
  path: Optional[str] = None
42
42
  is_dependency: bool = False
43
+ last_update_time: Optional[datetime] = None
43
44
 
44
45
  def __post_init__(self):
45
46
  """Ensures the errors list is initialized after the object is created."""
@@ -93,6 +94,7 @@ class JobManager:
93
94
  for key, value in kwargs.items():
94
95
  if hasattr(job, key):
95
96
  setattr(job, key, value)
97
+ job.last_update_time = datetime.now()
96
98
 
97
99
  def get_job(self, job_id: str) -> Optional[JobInfo]:
98
100
  """Retrieves the information for a single job."""
@@ -132,15 +134,36 @@ class JobManager:
132
134
  def cleanup_old_jobs(self, max_age_hours: int = 24):
133
135
  """Removes old jobs from memory to prevent memory leaks.
134
136
 
135
- Finished jobs are aged by end_time; jobs that never finished (e.g.
136
- crashed while PENDING/RUNNING) are aged by start_time so they don't
137
- leak forever.
137
+ Terminal jobs (COMPLETED/FAILED/CANCELLED) are aged by end_time,
138
+ falling back to start_time.
139
+
140
+ Jobs still PENDING/RUNNING are never deleted outright (#1537): a
141
+ healthy long-running index updates its progress constantly, and
142
+ deleting its record makes update_job silently no-op and
143
+ check_job_status report not_found while the worker keeps writing.
144
+ Instead, an active job with *no progress update* for the whole window
145
+ is presumed crashed and flipped to FAILED — the record stays visible,
146
+ and the next sweep ages it out through the terminal path.
138
147
  """
139
148
  cutoff_time = datetime.now() - timedelta(hours=max_age_hours)
140
149
  with self.lock:
150
+ active = (JobStatus.PENDING, JobStatus.RUNNING)
141
151
  jobs_to_remove = [
142
152
  job_id for job_id, job in self.jobs.items()
143
- if (job.end_time or job.start_time) < cutoff_time
153
+ if job.status not in active
154
+ and (job.end_time or job.start_time) < cutoff_time
144
155
  ]
145
156
  for job_id in jobs_to_remove:
146
157
  del self.jobs[job_id]
158
+
159
+ for job in self.jobs.values():
160
+ if job.status in active:
161
+ last_progress = job.last_update_time or job.start_time
162
+ if last_progress < cutoff_time:
163
+ job.status = JobStatus.FAILED
164
+ job.end_time = datetime.now()
165
+ if job.errors is None:
166
+ job.errors = []
167
+ job.errors.append(
168
+ f"Presumed crashed: no progress update for {max_age_hours}h"
169
+ )
@@ -48,9 +48,11 @@ class CodeGraphTwin:
48
48
  """
49
49
 
50
50
  # 2. Fetch all relationships originating from nodes in the repository
51
+ # `*0..` includes the repository node itself (zero-length path), which
52
+ # replaces the old `WHERE n1 = r OR (r)-[:CONTAINS*]->(n1)` form — a
53
+ # bare pattern predicate the embedded backends cannot plan (#1512).
51
54
  rel_query = """
52
- MATCH (r:Repository {path: $path})
53
- MATCH (n1) WHERE n1 = r OR (r)-[:CONTAINS*]->(n1)
55
+ MATCH (r:Repository {path: $path})-[:CONTAINS*0..]->(n1)
54
56
  MATCH (n1)-[rel]->(n2)
55
57
  RETURN
56
58
  labels(n1)[0] as source_label,
@@ -458,6 +458,13 @@ class CodeWatcher:
458
458
  h.cancel_timers()
459
459
  self.handlers.clear()
460
460
 
461
+ # A stopped watchdog Observer cannot be restarted, so the watch state
462
+ # must not survive it: a stale entry makes watch_directory answer
463
+ # "Already watching" for a dead observer and the graph silently goes
464
+ # stale (#1519).
465
+ self.watched_paths.clear()
466
+ self.watches.clear()
467
+
461
468
  if self.observer.is_alive():
462
469
  self.observer.stop()
463
470
  self.observer.join()
@@ -39,7 +39,7 @@ class GraphBuilder:
39
39
  linking for Neo4j, FalkorDB, and Kùzu backends.
40
40
  """
41
41
 
42
- def __init__(self, db_manager: DatabaseManager, job_manager: JobManager, loop: asyncio.AbstractEventLoop):
42
+ def __init__(self, db_manager: DatabaseManager, job_manager: JobManager, loop: asyncio.AbstractEventLoop, graph_name: str = None):
43
43
  """Initialize GraphBuilder.
44
44
 
45
45
  Parameters
@@ -50,11 +50,16 @@ class GraphBuilder:
50
50
  Job manager for tracking indexing progress.
51
51
  loop : asyncio.AbstractEventLoop
52
52
  Event loop for async operations.
53
+ graph_name : str, optional
54
+ Named graph to write into, on backends that support multiple
55
+ graphs per instance (FalkorDB). None selects the default graph
56
+ (#1558).
53
57
  """
54
58
  self.db_manager = db_manager
55
59
  self.job_manager = job_manager
56
60
  self.loop = loop
57
- self._writer = GraphWriter(self.db_manager.get_driver(), db_manager=self.db_manager)
61
+ self.graph_name = graph_name
62
+ self._writer = GraphWriter(self.db_manager.get_driver(graph_name), db_manager=self.db_manager)
58
63
  self.last_call_resolution_diagnostics: list[Dict[str, Any]] = []
59
64
  self.last_index_summary: Dict[str, Any] = {}
60
65
  self.parsers = {
@@ -118,8 +123,9 @@ class GraphBuilder:
118
123
 
119
124
  @property
120
125
  def driver(self):
121
- """Default graph driver (backward compatible)."""
122
- return self.db_manager.get_driver()
126
+ """Driver for this builder's graph (default graph unless a
127
+ graph_name was given at construction)."""
128
+ return self.db_manager.get_driver(self.graph_name)
123
129
 
124
130
  def _driver_for(self, graph_name: str = None):
125
131
  """Get driver for a specific graph, or default."""
@@ -184,21 +190,6 @@ class GraphBuilder:
184
190
 
185
191
 
186
192
  # Language-agnostic method
187
- def add_repository_to_graph(self, repo_path: Path, is_dependency: bool = False):
188
- """Adds a repository node using its absolute path as the unique key."""
189
- repo_name = repo_path.name
190
- repo_path_str = repo_path.resolve().as_posix()
191
- with self.driver.session() as session:
192
- session.run(
193
- """
194
- MERGE (r:Repository {path: $path})
195
- SET r.name = $name, r.is_dependency = $is_dependency
196
- """,
197
- path=repo_path_str,
198
- name=repo_name,
199
- is_dependency=is_dependency,
200
- )
201
-
202
193
  def add_repository_to_graph(self, repo_path: Path, is_dependency: bool = False) -> None:
203
194
  """Add a repository node to the graph.
204
195
 
@@ -20,24 +20,29 @@ def add_code_to_graph(graph_builder, job_manager, loop, list_repos_func, **args)
20
20
  if not path:
21
21
  return {"error": "Path is a required argument (repo_path)."}
22
22
 
23
- # `graph_name` is advertised in this tool's schema but indexing cannot yet
24
- # honour it: GraphBuilder binds its GraphWriter to the default driver at
25
- # construction, so a named graph would need a per-job writer threaded
26
- # through the whole pipeline. Refuse explicitly rather than write to the
27
- # default graph and report successan agent that believed the repository
28
- # landed in a named graph would find nothing there later, with no error to
29
- # explain it.
23
+ # Indexing into a named graph is supported on multi-graph backends
24
+ # (FalkorDB): a scoped GraphBuilder is constructed whose writer binds to
25
+ # get_driver(graph_name). Single-graph backends (KùzuDB/LadybugDB/Neo4j)
26
+ # would silently ignore the name and land the repo in the default graph —
27
+ # the exact lie #1558 is about so those still refuse explicitly.
30
28
  graph_name = args.get("graph_name")
31
29
  if graph_name:
32
- return {
33
- "error": (
34
- f"Indexing into a named graph is not supported yet, so "
35
- f"graph_name={graph_name!r} cannot be honoured. Omit it to index "
36
- "into the default graph, or select the graph via the CLI context "
37
- "(`cgc context create` / `cgc index --context`)."
38
- ),
39
- "unsupported_argument": "graph_name",
40
- }
30
+ backend = graph_builder.db_manager.get_backend_type()
31
+ if backend in ("falkordb", "falkordb-remote"):
32
+ from ..graph_builder import GraphBuilder
33
+ graph_builder = GraphBuilder(
34
+ graph_builder.db_manager, job_manager, loop, graph_name=graph_name
35
+ )
36
+ else:
37
+ return {
38
+ "error": (
39
+ f"The active backend ({backend}) is single-graph, so "
40
+ f"graph_name={graph_name!r} cannot be honoured. Omit it to "
41
+ "index into the default graph, or select a graph via the CLI "
42
+ "context (`cgc context create` / `cgc index --context`)."
43
+ ),
44
+ "unsupported_argument": "graph_name",
45
+ }
41
46
 
42
47
  try:
43
48
  path_obj = Path(path).resolve()
@@ -61,8 +66,10 @@ def add_code_to_graph(graph_builder, job_manager, loop, list_repos_func, **args)
61
66
  "message": f"Path '{path}' does not exist.",
62
67
  }
63
68
 
64
- # Prevent re-indexing the same repository.
65
- indexed_repos = list_repos_func().get("repositories", [])
69
+ # Prevent re-indexing the same repository. list_repos_func reads the
70
+ # default graph, so the check only applies there — a named graph is a
71
+ # separate namespace and legitimately re-indexes the same path.
72
+ indexed_repos = [] if graph_name else list_repos_func().get("repositories", [])
66
73
  for repo in indexed_repos:
67
74
  if repo_record_matches_path(repo, path_obj):
68
75
  return {
@@ -85,7 +92,9 @@ def add_code_to_graph(graph_builder, job_manager, loop, list_repos_func, **args)
85
92
 
86
93
  return {
87
94
  "success": True, "job_id": job_id,
88
- "message": f"Background processing started for {str(path_obj)}",
95
+ **({"graph_name": graph_name} if graph_name else {}),
96
+ "message": f"Background processing started for {str(path_obj)}"
97
+ + (f" into graph '{graph_name}'" if graph_name else ""),
89
98
  "estimated_files": total_files,
90
99
  "estimated_duration_seconds": round(estimated_time, 2),
91
100
  "estimated_duration_human": f"{int(estimated_time // 60)}m {int(estimated_time % 60)}s" if estimated_time >= 60 else f"{int(estimated_time)}s",
@@ -15,6 +15,9 @@ DEFAULT_IGNORE_PATTERNS = [
15
15
  "build/",
16
16
  "target/",
17
17
  "out/",
18
+ # .NET intermediate output: contains *generated* source (AssemblyInfo.cs,
19
+ # GlobalUsings.g.cs) that pollutes the graph with phantom modules (#1585).
20
+ "obj/",
18
21
  ".git/",
19
22
  "__pycache__/",
20
23
  "*.png",
@@ -1138,8 +1138,23 @@ class GraphWriter:
1138
1138
  batch_size = 500
1139
1139
  backend = get_backend_type(self.driver, self._db_manager)
1140
1140
  def _work(session):
1141
- internal_batch = [r for r in inheritance_batch if r.get("resolved_parent_file_path") != "__external__"]
1142
- external_batch = [r for r in inheritance_batch if r.get("resolved_parent_file_path") == "__external__"]
1141
+ # Dedupe identical rows first: parsers can emit the same
1142
+ # (child, parent) record more than once, and while Neo4j's MERGE
1143
+ # absorbs the repeat, the embedded backends' rewritten
1144
+ # node-MERGE+rel-MERGE shape has been observed writing a duplicate
1145
+ # INHERITS edge for it. Deduping is correct on every backend.
1146
+ seen_rows: set = set()
1147
+ deduped_batch: List[Dict[str, Any]] = []
1148
+ for r in inheritance_batch:
1149
+ key = (r.get("child_name"), r.get("path"), r.get("parent_name"),
1150
+ r.get("resolved_parent_file_path"))
1151
+ if key in seen_rows:
1152
+ continue
1153
+ seen_rows.add(key)
1154
+ deduped_batch.append(r)
1155
+
1156
+ internal_batch = [r for r in deduped_batch if r.get("resolved_parent_file_path") != "__external__"]
1157
+ external_batch = [r for r in deduped_batch if r.get("resolved_parent_file_path") == "__external__"]
1143
1158
 
1144
1159
  labels = ("Class", "Trait", "Interface", "Struct", "Enum", "Union", "Record", "Mixin", "Extension", "Module", "Object", "Variable")
1145
1160
 
@@ -201,10 +201,32 @@ async def run_tree_sitter_index_async(
201
201
  # it to this file's path string turned a single recoverable write
202
202
  # failure into an AttributeError that aborted the whole job.
203
203
  failed_path = file_data.get("path")
204
- write_failures.append({"path": failed_path, "error": str(exc)})
205
- error_logger(f"Failed to write {failed_path} to the graph: {exc}")
206
- file_data["error"] = str(exc)
207
- file_data["parse_failed"] = True
204
+ # Retry once before giving up: writes are MERGE-idempotent, and a
205
+ # transient failure under runner load silently costs the graph the
206
+ # whole file's edges (observed as LadybugDB intermittently writing
207
+ # ~51 fewer CONTAINS edges in the parity run, #1612).
208
+ retried_ok = False
209
+ if "error" not in file_data:
210
+ try:
211
+ await asyncio.sleep(0.2)
212
+ await asyncio.to_thread(
213
+ writer.add_file_to_graph,
214
+ file_data,
215
+ repo_name,
216
+ imports_map,
217
+ repo_path_str=resolved_repo_path_str,
218
+ )
219
+ retried_ok = True
220
+ warning_logger(
221
+ f"Write for {failed_path} succeeded on retry after: {exc}"
222
+ )
223
+ except Exception as retry_exc: # noqa: BLE001
224
+ exc = retry_exc
225
+ if not retried_ok:
226
+ write_failures.append({"path": failed_path, "error": str(exc)})
227
+ error_logger(f"Failed to write {failed_path} to the graph: {exc}")
228
+ file_data["error"] = str(exc)
229
+ file_data["parse_failed"] = True
208
230
 
209
231
  if write_failures:
210
232
  warning_logger(
@@ -519,11 +519,7 @@ class CppTreeSitterParser:
519
519
  if lambda_node is None or lambda_node.type != 'lambda_expression':
520
520
  continue
521
521
 
522
- params_node = lambda_node.child_by_field_name('declarator')
523
- if params_node:
524
- params_node = params_node.child_by_field_name('parameters')
525
522
  name = self._get_node_text(node)
526
- params_node = lambda_node.child_by_field_name('parameters')
527
523
 
528
524
  context, context_type, _ = self._get_parent_context(assignment_node)
529
525
  class_context, _, _ = self._get_parent_context(assignment_node, types=('class_specifier',))
@@ -532,7 +528,15 @@ class CppTreeSitterParser:
532
528
  "name": name,
533
529
  "line_number": node.start_point[0] + 1,
534
530
  "end_line": assignment_node.end_point[0] + 1,
535
- "args": [p for p in [self._get_node_text(p) for p in params_node.children if p.type == 'identifier'] if p] if params_node else [],
531
+ # lambda_expression carries the same declarator→parameters
532
+ # field chain as a function_definition, so the shared
533
+ # extractor handles parameter_declaration unwrapping
534
+ # (pointers/refs included). The old inline version first
535
+ # clobbered its correctly-walked parameter_list with a
536
+ # nonexistent field and then filtered for bare identifiers
537
+ # over parameter_declaration nodes — every lambda got
538
+ # args: [] (#1527, case 5).
539
+ "args": self._extract_function_params(lambda_node),
536
540
 
537
541
  "docstring": None,
538
542
  "cyclomatic_complexity": 1,
@@ -505,38 +505,49 @@ class JavascriptTreeSitterParser:
505
505
  if node.type == 'import_statement':
506
506
  source = self._get_node_text(node.child_by_field_name('source')).strip('\'"')
507
507
 
508
- # Look for different import structures
509
- import_clause = node.child_by_field_name('import')
508
+ # `import_clause` is an unnamed child of import_statement, not a
509
+ # field, so child_by_field_name('import') always returned None and
510
+ # every ES import collapsed into the bare-module fallback (#1526).
511
+ import_clause = next(
512
+ (c for c in node.children if c.type == 'import_clause'), None
513
+ )
510
514
  if not import_clause:
515
+ # Side-effect import: import 'polyfill';
511
516
  imports.append({'name': source, 'source': source, 'alias': None, 'line_number': line_number,
512
517
  'lang': self.language_name})
513
518
  continue
514
519
 
515
- # Default import: import defaultExport from '...'
516
- if import_clause.type == 'identifier':
517
- alias = self._get_node_text(import_clause)
518
- imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
519
- 'lang': self.language_name})
520
-
521
- # Namespace import: import * as name from '...'
522
- elif import_clause.type == 'namespace_import':
523
- alias_node = import_clause.child_by_field_name('alias')
524
- if alias_node:
525
- alias = self._get_node_text(alias_node)
526
- imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
520
+ # One clause can carry several bindings at once
521
+ # (import Def, { a as b } from 'mod'), so walk its children.
522
+ for binding in import_clause.children:
523
+ # Default import: import defaultExport from '...'
524
+ if binding.type == 'identifier':
525
+ alias = self._get_node_text(binding)
526
+ imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
527
527
  'lang': self.language_name})
528
528
 
529
- # Named imports: import { name, name as alias } from '...'
530
- elif import_clause.type == 'named_imports':
531
- for specifier in import_clause.children:
532
- if specifier.type == 'import_specifier':
533
- name_node = specifier.child_by_field_name('name')
534
- alias_node = specifier.child_by_field_name('alias')
535
- original_name = self._get_node_text(name_node)
536
- alias = self._get_node_text(alias_node) if alias_node else None
537
- imports.append(
538
- {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
539
- 'lang': self.language_name})
529
+ # Namespace import: import * as name from '...' — the alias
530
+ # is the identifier child (there is no 'alias' field).
531
+ elif binding.type == 'namespace_import':
532
+ alias = next(
533
+ (self._get_node_text(c) for c in binding.children if c.type == 'identifier'),
534
+ None,
535
+ )
536
+ if alias:
537
+ imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
538
+ 'lang': self.language_name})
539
+
540
+ # Named imports: import { name, name as alias } from '...'
541
+ elif binding.type == 'named_imports':
542
+ for specifier in binding.children:
543
+ if specifier.type == 'import_specifier':
544
+ name_node = specifier.child_by_field_name('name')
545
+ alias_node = specifier.child_by_field_name('alias')
546
+ original_name = self._get_node_text(name_node)
547
+ alias = self._get_node_text(alias_node) if alias_node else None
548
+ imports.append(
549
+ {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
550
+ 'lang': self.language_name})
540
551
 
541
552
  elif node.type == 'call_expression': # require('...')
542
553
  args = node.child_by_field_name('arguments')
@@ -419,31 +419,49 @@ class TypescriptTreeSitterParser:
419
419
  line_number = node.start_point[0] + 1
420
420
  if node.type == 'import_statement':
421
421
  source = self._get_node_text(node.child_by_field_name('source')).strip('\'"')
422
- import_clause = node.child_by_field_name('import')
422
+ # `import_clause` is an unnamed child of import_statement, not a
423
+ # field, so child_by_field_name('import') always returned None and
424
+ # every ES import collapsed into the bare-module fallback (#1526).
425
+ import_clause = next(
426
+ (c for c in node.children if c.type == 'import_clause'), None
427
+ )
423
428
  if not import_clause:
429
+ # Side-effect import: import 'polyfill';
424
430
  imports.append({'name': source, 'source': source, 'alias': None, 'line_number': line_number,
425
431
  'lang': self.language_name})
426
432
  continue
427
- if import_clause.type == 'identifier':
428
- alias = self._get_node_text(import_clause)
429
- imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
430
- 'lang': self.language_name})
431
- elif import_clause.type == 'namespace_import':
432
- alias_node = import_clause.child_by_field_name('alias')
433
- if alias_node:
434
- alias = self._get_node_text(alias_node)
435
- imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
433
+
434
+ # One clause can carry several bindings at once
435
+ # (import Def, { a as b } from 'mod'), so walk its children.
436
+ for binding in import_clause.children:
437
+ # Default import: import defaultExport from '...'
438
+ if binding.type == 'identifier':
439
+ alias = self._get_node_text(binding)
440
+ imports.append({'name': 'default', 'source': source, 'alias': alias, 'line_number': line_number,
436
441
  'lang': self.language_name})
437
- elif import_clause.type == 'named_imports':
438
- for specifier in import_clause.children:
439
- if specifier.type == 'import_specifier':
440
- name_node = specifier.child_by_field_name('name')
441
- alias_node = specifier.child_by_field_name('alias')
442
- original_name = self._get_node_text(name_node)
443
- alias = self._get_node_text(alias_node) if alias_node else None
444
- imports.append(
445
- {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
446
- 'lang': self.language_name})
442
+
443
+ # Namespace import: import * as name from '...' — the alias
444
+ # is the identifier child (there is no 'alias' field).
445
+ elif binding.type == 'namespace_import':
446
+ alias = next(
447
+ (self._get_node_text(c) for c in binding.children if c.type == 'identifier'),
448
+ None,
449
+ )
450
+ if alias:
451
+ imports.append({'name': '*', 'source': source, 'alias': alias, 'line_number': line_number,
452
+ 'lang': self.language_name})
453
+
454
+ # Named imports: import { name, name as alias } from '...'
455
+ elif binding.type == 'named_imports':
456
+ for specifier in binding.children:
457
+ if specifier.type == 'import_specifier':
458
+ name_node = specifier.child_by_field_name('name')
459
+ alias_node = specifier.child_by_field_name('alias')
460
+ original_name = self._get_node_text(name_node)
461
+ alias = self._get_node_text(alias_node) if alias_node else None
462
+ imports.append(
463
+ {'name': original_name, 'source': source, 'alias': alias, 'line_number': line_number,
464
+ 'lang': self.language_name})
447
465
  elif node.type == 'call_expression':
448
466
  args = node.child_by_field_name('arguments')
449
467
  if not args or args.named_child_count == 0: continue
@@ -68,6 +68,31 @@ def _strip_literals_and_comments(query: str) -> str:
68
68
  return _LITERAL_OR_COMMENT_RE.sub(" ", query)
69
69
 
70
70
 
71
+ # A forbidden keyword only functions as a write *clause* in clause position.
72
+ # The same word is inert — and common in real codebases' graphs — when it is:
73
+ # n.load a property access (preceded by '.')
74
+ # (n:Insert) a label / rel-type (preceded by ':')
75
+ # $update a parameter name (preceded by '$')
76
+ # AS set a result-column alias (preceded by the token AS)
77
+ # Only those provably-safe positions are carved out (#1511); anything
78
+ # ambiguous stays rejected, because a false negative here is a write slipping
79
+ # through a read-only gate while a false positive is merely an inconvenience.
80
+ _TOKEN_RE = re.compile(r"\w+|[^\w\s]")
81
+
82
+
83
+ def _keyword_in_clause_position(stripped: str, keyword: str) -> bool:
84
+ tokens = _TOKEN_RE.findall(stripped)
85
+ kw = keyword.upper()
86
+ for i, tok in enumerate(tokens):
87
+ if tok.upper() != kw:
88
+ continue
89
+ prev = tokens[i - 1] if i > 0 else ""
90
+ if prev in (".", ":", "$") or prev.upper() == "AS":
91
+ continue
92
+ return True
93
+ return False
94
+
95
+
71
96
  def is_read_only_cypher(query: str) -> bool:
72
97
  """Return True when *query* has no write keywords outside string literals."""
73
98
  if not query or not query.strip():
@@ -76,7 +101,7 @@ def is_read_only_cypher(query: str) -> bool:
76
101
  if ";" in stripped:
77
102
  return False
78
103
  for keyword in _FORBIDDEN_KEYWORDS:
79
- if re.search(r"\b" + keyword + r"\b", stripped, re.IGNORECASE):
104
+ if _keyword_in_clause_position(stripped, keyword):
80
105
  return False
81
106
  for pattern in _FORBIDDEN_PATTERNS:
82
107
  if pattern.search(stripped):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codegraphcontext
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: An MCP server that indexes local code into a graph database to provide context to AI assistants.
5
5
  Author-email: Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
6
6
  License: MIT License