codegraphcontext 0.6.0__tar.gz → 0.6.1__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.1}/PKG-INFO +1 -1
  2. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/pyproject.toml +1 -1
  3. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/config_manager.py +1 -0
  4. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database_embedded_kuzu.py +5 -2
  5. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/jobs.py +27 -4
  6. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/simulator.py +4 -2
  7. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/watcher.py +7 -0
  8. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/graph_builder.py +10 -19
  9. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/handlers/indexing_handlers.py +28 -19
  10. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/constants.py +3 -0
  11. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/javascript.py +36 -25
  12. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/typescript.py +38 -20
  13. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/cypher_readonly.py +26 -1
  14. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1/src/codegraphcontext.egg-info}/PKG-INFO +1 -1
  15. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/LICENSE +0 -0
  16. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/MANIFEST.in +0 -0
  17. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/README.md +0 -0
  18. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/setup.cfg +0 -0
  19. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/__init__.py +0 -0
  20. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/__main__.py +0 -0
  21. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/api/__init__.py +0 -0
  22. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/api/app.py +0 -0
  23. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/api/auth.py +0 -0
  24. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/api/mcp_sse.py +0 -0
  25. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/api/router.py +0 -0
  26. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/api/schemas.py +0 -0
  27. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/__init__.py +0 -0
  28. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/cli_helpers.py +0 -0
  29. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/hook_manager.py +0 -0
  30. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/main.py +0 -0
  31. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/project_config.py +0 -0
  32. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/registry_commands.py +0 -0
  33. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/setup_macos.py +0 -0
  34. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/setup_wizard.py +0 -0
  35. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/simulator.py +0 -0
  36. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/cli/visualizer.py +0 -0
  37. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/__init__.py +0 -0
  38. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/bundle_registry.py +0 -0
  39. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/cgc_bundle.py +0 -0
  40. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/cgcignore.py +0 -0
  41. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database.py +0 -0
  42. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database_falkordb.py +0 -0
  43. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
  44. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database_kuzu.py +0 -0
  45. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database_ladybug.py +0 -0
  46. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/database_nornic.py +0 -0
  47. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/falkor_worker.py +0 -0
  48. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/core/graph_query.py +0 -0
  49. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/prompts.py +0 -0
  50. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/server.py +0 -0
  51. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/stdlibs.py +0 -0
  52. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tool_definitions.py +0 -0
  53. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/__init__.py +0 -0
  54. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
  55. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/code_finder.py +0 -0
  56. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/datasources/__init__.py +0 -0
  57. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/datasources/cassandra_ingester.py +0 -0
  58. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/datasources/mysql_ingester.py +0 -0
  59. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/datasources/redis_ingester.py +0 -0
  60. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/handlers/analysis_handlers.py +0 -0
  61. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/handlers/management_handlers.py +0 -0
  62. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -0
  63. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/handlers/watcher_handlers.py +0 -0
  64. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/__init__.py +0 -0
  65. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/discovery.py +0 -0
  66. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/embeddings.py +0 -0
  67. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/persistence/__init__.py +0 -0
  68. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/persistence/utils.py +0 -0
  69. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/persistence/writer.py +0 -0
  70. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/pipeline.py +0 -0
  71. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/pre_scan.py +0 -0
  72. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/resolution/__init__.py +0 -0
  73. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/resolution/calls.py +0 -0
  74. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/resolution/inheritance.py +0 -0
  75. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/resolution/post_resolution.py +0 -0
  76. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/sanitize.py +0 -0
  77. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/schema.py +0 -0
  78. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/schema_contract.py +0 -0
  79. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/scip_pipeline.py +0 -0
  80. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/indexing/vector_resolver.py +0 -0
  81. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/c.py +0 -0
  82. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/cpp.py +0 -0
  83. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/csharp.py +0 -0
  84. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/css.py +0 -0
  85. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/dart.py +0 -0
  86. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/elisp.py +0 -0
  87. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/elixir.py +0 -0
  88. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/go.py +0 -0
  89. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/gradle.py +0 -0
  90. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/haskell.py +0 -0
  91. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/html.py +0 -0
  92. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/java.py +0 -0
  93. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
  94. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/lua.py +0 -0
  95. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/maven.py +0 -0
  96. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/mybatis.py +0 -0
  97. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/perl.py +0 -0
  98. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/php.py +0 -0
  99. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/python.py +0 -0
  100. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/ruby.py +0 -0
  101. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/rust.py +0 -0
  102. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/scala.py +0 -0
  103. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/sfc_common.py +0 -0
  104. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/solidity.py +0 -0
  105. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/solidity_remappings.py +0 -0
  106. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/svelte.py +0 -0
  107. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/swift.py +0 -0
  108. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
  109. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/languages/vue.py +0 -0
  110. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/package_resolver.py +0 -0
  111. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
  112. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
  113. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
  114. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
  115. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/elisp_toolkit.py +0 -0
  116. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
  117. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
  118. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
  119. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
  120. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
  121. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
  122. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
  123. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
  124. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
  125. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/solidity_toolkit.py +0 -0
  126. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
  127. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
  128. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/report_generator.py +0 -0
  129. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/scip_indexer.py +0 -0
  130. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/scip_pb2.py +0 -0
  131. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/system.py +0 -0
  132. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/tree_sitter_parser.py +0 -0
  133. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/tools/type_utils.py +0 -0
  134. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/cypher_ddl.py +0 -0
  135. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/debug_log.py +0 -0
  136. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/gcf_encoder.py +0 -0
  137. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/git_utils.py +0 -0
  138. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/path_ignore.py +0 -0
  139. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/path_sandbox.py +0 -0
  140. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/repo_path.py +0 -0
  141. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/secret_scanner.py +0 -0
  142. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/tool_limits.py +0 -0
  143. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/tree_sitter_manager.py +0 -0
  144. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/utils/visualize_graph.py +0 -0
  145. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/__vite-browser-external-9wXp6ZBx.js +0 -0
  146. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
  147. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
  148. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
  149. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
  150. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/index-C-187lf0.js +0 -0
  151. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/index-fNAa6jgv.css +0 -0
  152. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/parser-pyodide.worker-BgsDfaad.js +0 -0
  153. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/parser.worker-_nvrecvj.js +0 -0
  154. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/assets/tree-sitter-qKYAACSa.wasm +0 -0
  155. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/cgcIcon.png +0 -0
  156. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/favicon.ico +0 -0
  157. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/index.html +0 -0
  158. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/logo-icon.svg +0 -0
  159. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/logo.svg +0 -0
  160. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/placeholder.svg +0 -0
  161. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/preview-image.png +0 -0
  162. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/robots.txt +0 -0
  163. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c.wasm +0 -0
  164. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
  165. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-core.js +0 -0
  166. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-cpp.wasm +0 -0
  167. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-dart.wasm +0 -0
  168. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-go.wasm +0 -0
  169. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-java.wasm +0 -0
  170. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-javascript.wasm +0 -0
  171. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-kotlin.wasm +0 -0
  172. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-perl.wasm +0 -0
  173. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-php.wasm +0 -0
  174. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-python.wasm +0 -0
  175. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-ruby.wasm +0 -0
  176. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-rust.wasm +0 -0
  177. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-swift.wasm +0 -0
  178. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-tsx.wasm +0 -0
  179. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm +0 -0
  180. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/tree-sitter.wasm +0 -0
  181. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.js +0 -0
  182. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm +0 -0
  183. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext/viz/server.py +0 -0
  184. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext.egg-info/SOURCES.txt +0 -0
  185. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
  186. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
  187. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext.egg-info/requires.txt +0 -0
  188. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/src/codegraphcontext.egg-info/top_level.txt +0 -0
  189. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/tests/test_issue_806_fix.py +0 -0
  190. {codegraphcontext-0.6.0 → codegraphcontext-0.6.1}/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.1
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.1"
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/
@@ -1200,8 +1200,11 @@ class EmbeddedSessionWrapper:
1200
1200
  return f"{prefix}NOT label({var_name}) = '{label_name}'"
1201
1201
  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
1202
 
1203
- # 4. Polymorphic matches and label access
1204
- query = query.replace("labels(n)[0]", "label(n)")
1203
+ # 4. Polymorphic matches and label access. Kùzu has no labels();
1204
+ # rewrite labels(<var>)[0] for ANY variable name — the literal
1205
+ # "labels(n)[0]" form missed n1/n2 and the simulator's relationship
1206
+ # query reached the engine unsupported (#1512).
1207
+ query = re.sub(r'labels\((\w+)\)\s*\[\s*0\s*\]', r'label(\1)', query)
1205
1208
 
1206
1209
  query = query.replace("coalesce(", "COALESCE(")
1207
1210
  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",
@@ -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.1
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