cg-code-graph 0.21.2__tar.gz → 0.22.0__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 (392) hide show
  1. {cg_code_graph-0.21.2/cg_code_graph.egg-info → cg_code_graph-0.22.0}/PKG-INFO +2 -2
  2. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/README.md +1 -1
  3. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/__init__.py +1 -1
  4. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/cli.py +23 -8
  5. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/indexer.py +17 -1
  6. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/link.py +14 -1
  7. cg_code_graph-0.22.0/cg_code_graph/mcp_graphs.py +438 -0
  8. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/mcp_install.py +233 -13
  9. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/mcp_server.py +200 -6
  10. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/platforms.py +32 -3
  11. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/plugin.py +55 -14
  12. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/query.py +41 -6
  13. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0/cg_code_graph.egg-info}/PKG-INFO +2 -2
  14. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/SOURCES.txt +8 -0
  15. cg_code_graph-0.22.0/tests/test_issue_202.py +79 -0
  16. cg_code_graph-0.22.0/tests/test_issue_205.py +36 -0
  17. cg_code_graph-0.22.0/tests/test_issue_206.py +32 -0
  18. cg_code_graph-0.22.0/tests/test_issue_208.py +45 -0
  19. cg_code_graph-0.22.0/tests/test_issue_210.py +51 -0
  20. cg_code_graph-0.22.0/tests/test_issue_211_used_at.py +71 -0
  21. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mcp_install.py +1 -1
  22. cg_code_graph-0.22.0/tests/test_mcp_multi_graph.py +282 -0
  23. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/LICENSE +0 -0
  24. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/MANIFEST.in +0 -0
  25. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/__main__.py +0 -0
  26. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/affected.py +0 -0
  27. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/agent_rules.py +0 -0
  28. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/agents.py +0 -0
  29. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/aitools.py +0 -0
  30. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/android_ipc.py +0 -0
  31. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/apple_ipc.py +0 -0
  32. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/apps.py +0 -0
  33. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/blindspots.py +0 -0
  34. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/bridges.py +0 -0
  35. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/brokers.py +0 -0
  36. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/concepts.py +0 -0
  37. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/config.py +0 -0
  38. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/__init__.py +0 -0
  39. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/cache.py +0 -0
  40. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/detect.py +0 -0
  41. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/env.py +0 -0
  42. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/extractors.py +0 -0
  43. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/fsutil.py +0 -0
  44. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/generated.py +0 -0
  45. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/model.py +0 -0
  46. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/paths.py +0 -0
  47. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/plugin.py +0 -0
  48. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/redact.py +0 -0
  49. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/store.py +0 -0
  50. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/syntax_errors.py +0 -0
  51. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/coverage.py +0 -0
  52. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/dart_isolates.py +0 -0
  53. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/doctor.py +0 -0
  54. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/explore.py +0 -0
  55. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/external.py +0 -0
  56. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/graphql.py +0 -0
  57. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/guard_facts.py +0 -0
  58. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/hooks.py +0 -0
  59. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/insecure_transport.py +0 -0
  60. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/jobs.py +0 -0
  61. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/lint_async.py +0 -0
  62. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/local_ipc.py +0 -0
  63. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/local_sockets.py +0 -0
  64. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/parity.py +0 -0
  65. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/parity_structure.py +0 -0
  66. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/payload.py +0 -0
  67. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plans.py +0 -0
  68. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/platform_scan.py +0 -0
  69. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/__init__.py +0 -0
  70. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/astro/__init__.py +0 -0
  71. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/astro/content.py +0 -0
  72. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/astro/plugin.py +0 -0
  73. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
  74. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
  75. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
  76. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/__init__.py +0 -0
  77. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/bridges.py +0 -0
  78. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
  79. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
  80. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
  81. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/http.py +0 -0
  82. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/models.py +0 -0
  83. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/plugin.py +0 -0
  84. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/program.py +0 -0
  85. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/__init__.py +0 -0
  86. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/extras.py +0 -0
  87. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/models.py +0 -0
  88. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/plugin.py +0 -0
  89. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/schemas.py +0 -0
  90. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/shapes.py +0 -0
  91. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/urls.py +0 -0
  92. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/express/__init__.py +0 -0
  93. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/express/plugin.py +0 -0
  94. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/flutter/__init__.py +0 -0
  95. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/flutter/plugin.py +0 -0
  96. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/java/__init__.py +0 -0
  97. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/java/exact.py +0 -0
  98. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/java/plugin.py +0 -0
  99. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/jvm/__init__.py +0 -0
  100. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/jvm/interop.py +0 -0
  101. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/jvm/spring.py +0 -0
  102. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
  103. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/exact.py +0 -0
  104. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/plugin.py +0 -0
  105. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
  106. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/__init__.py +0 -0
  107. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
  108. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/massassign.py +0 -0
  109. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/plugin.py +0 -0
  110. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/tests.py +0 -0
  111. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/values.py +0 -0
  112. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/__init__.py +0 -0
  113. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/gates.py +0 -0
  114. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/runner.py +0 -0
  115. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/scipread.py +0 -0
  116. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/ts.py +0 -0
  117. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nest/__init__.py +0 -0
  118. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nest/plugin.py +0 -0
  119. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
  120. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
  121. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
  122. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nuxt/plugin.py +0 -0
  123. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/__init__.py +0 -0
  124. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/external.py +0 -0
  125. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
  126. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
  127. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
  128. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/gating.py +0 -0
  129. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/http_client.py +0 -0
  130. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/inline_guards.py +0 -0
  131. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/plugin.py +0 -0
  132. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/strings.py +0 -0
  133. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/__init__.py +0 -0
  134. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/aitools.py +0 -0
  135. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/external.py +0 -0
  136. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/fields.py +0 -0
  137. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/plugin.py +0 -0
  138. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/refs.py +0 -0
  139. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/roots.py +0 -0
  140. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/socketio.py +0 -0
  141. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/subproc.py +0 -0
  142. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/tests.py +0 -0
  143. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/values.py +0 -0
  144. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
  145. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
  146. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/pyweb/values.py +0 -0
  147. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/__init__.py +0 -0
  148. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/cargo.py +0 -0
  149. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/plugin.py +0 -0
  150. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/syntax.py +0 -0
  151. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/__init__.py +0 -0
  152. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/importer.py +0 -0
  153. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/scip.proto +0 -0
  154. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
  155. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/stubs/__init__.py +0 -0
  156. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/stubs/plugins.py +0 -0
  157. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/__init__.py +0 -0
  158. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/baseurl.py +0 -0
  159. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/exact.py +0 -0
  160. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/indexstore.py +0 -0
  161. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/packages.py +0 -0
  162. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/__init__.py +0 -0
  163. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/baseurl.py +0 -0
  164. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
  165. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
  166. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
  167. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
  168. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
  169. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/nav.py +0 -0
  170. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/plugin.py +0 -0
  171. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/react_router.py +0 -0
  172. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
  173. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/tsweb/common.py +0 -0
  174. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/tsweb/data.py +0 -0
  175. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/__init__.py +0 -0
  176. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/c_cpp.yaml +0 -0
  177. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/common.yaml +0 -0
  178. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/dart.yaml +0 -0
  179. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/django-ninja.yaml +0 -0
  180. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/django.yaml +0 -0
  181. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/djangorestframework.yaml +0 -0
  182. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/express.yaml +0 -0
  183. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/java.yaml +0 -0
  184. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/kotlin.yaml +0 -0
  185. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/laravel.yaml +0 -0
  186. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/nest.yaml +0 -0
  187. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/nextjs.yaml +0 -0
  188. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/nuxt.yaml +0 -0
  189. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/php.yaml +0 -0
  190. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/python.yaml +0 -0
  191. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/react-router.yaml +0 -0
  192. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/rust.yaml +0 -0
  193. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/spring.yaml +0 -0
  194. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/swift.yaml +0 -0
  195. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/typescript.yaml +0 -0
  196. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/process_runs.py +0 -0
  197. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/__init__.py +0 -0
  198. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/builtin.py +0 -0
  199. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/matchers.py +0 -0
  200. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/view.py +0 -0
  201. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime.py +0 -0
  202. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime_events.py +0 -0
  203. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime_native.py +0 -0
  204. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime_ws.py +0 -0
  205. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/roundtrip.py +0 -0
  206. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/routes.py +0 -0
  207. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/rpc.py +0 -0
  208. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/sdk_systems.py +0 -0
  209. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/sockets.py +0 -0
  210. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/ssrf_input.py +0 -0
  211. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/starters.py +0 -0
  212. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/surface.py +0 -0
  213. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/tests_index.py +0 -0
  214. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/udp_apps.py +0 -0
  215. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/__init__.py +0 -0
  216. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/graph.py +0 -0
  217. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/server.py +0 -0
  218. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/app.css +0 -0
  219. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/app.js +0 -0
  220. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/index.html +0 -0
  221. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/layered.js +0 -0
  222. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
  223. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
  224. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
  225. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
  226. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
  227. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/tools/package-lock.json +0 -0
  228. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/tools/package.json +0 -0
  229. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/tools/shoot.mjs +0 -0
  230. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/watch.py +0 -0
  231. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/webhook_subs.py +0 -0
  232. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/webhooks.py +0 -0
  233. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/xcode.py +0 -0
  234. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/dependency_links.txt +0 -0
  235. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/entry_points.txt +0 -0
  236. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/requires.txt +0 -0
  237. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/top_level.txt +0 -0
  238. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/pyproject.toml +0 -0
  239. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/setup.cfg +0 -0
  240. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_affected.py +0 -0
  241. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_agents_install.py +0 -0
  242. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_agents_md.py +0 -0
  243. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ai_tools.py +0 -0
  244. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_android_ipc.py +0 -0
  245. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_apple_ipc.py +0 -0
  246. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_astro.py +0 -0
  247. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_astro_content.py +0 -0
  248. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_astro_server.py +0 -0
  249. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_bridges.py +0 -0
  250. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_bridges_pigeon_monorepo.py +0 -0
  251. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_brokers.py +0 -0
  252. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cache_clean.py +0 -0
  253. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cache_invalidation.py +0 -0
  254. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cache_migration.py +0 -0
  255. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_channels_tests.py +0 -0
  256. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cli_output.py +0 -0
  257. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_completeness.py +0 -0
  258. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_config_extras.py +0 -0
  259. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_coverage.py +0 -0
  260. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_coverage_ts_hint.py +0 -0
  261. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_dart_isolates.py +0 -0
  262. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_db_connections.py +0 -0
  263. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_dispatch_interfaces.py +0 -0
  264. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_django_flutter.py +0 -0
  265. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_docs_languages.py +0 -0
  266. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_docs_links.py +0 -0
  267. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_echo_ref.py +0 -0
  268. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_echo_wrapper.py +0 -0
  269. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_elysia.py +0 -0
  270. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_enum_constants.py +0 -0
  271. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_env.py +0 -0
  272. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_explore.py +0 -0
  273. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_external.py +0 -0
  274. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_fp_batch.py +0 -0
  275. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_gating.py +0 -0
  276. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_generated.py +0 -0
  277. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_graphql.py +0 -0
  278. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_hooks.py +0 -0
  279. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_impact_overrides.py +0 -0
  280. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_index_isolation.py +0 -0
  281. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_inherited_overrides.py +0 -0
  282. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_inline_guards.py +0 -0
  283. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_192.py +0 -0
  284. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_203.py +0 -0
  285. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_207.py +0 -0
  286. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_209.py +0 -0
  287. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_211.py +0 -0
  288. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_java.py +0 -0
  289. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_java_exact.py +0 -0
  290. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_jobs.py +0 -0
  291. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_js_refs.py +0 -0
  292. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_js_runtime.py +0 -0
  293. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin.py +0 -0
  294. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_binding.py +0 -0
  295. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_exact.py +0 -0
  296. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_fields.py +0 -0
  297. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_mixed.py +0 -0
  298. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_nav_consts.py +0 -0
  299. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_props.py +0 -0
  300. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_laravel_determinism.py +0 -0
  301. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_laravel_resources.py +0 -0
  302. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_lint_async.py +0 -0
  303. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_listing_files.py +0 -0
  304. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_local_ipc.py +0 -0
  305. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_local_sockets.py +0 -0
  306. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mass_assignment.py +0 -0
  307. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mcp.py +0 -0
  308. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mcp_index.py +0 -0
  309. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_native_cfamily.py +0 -0
  310. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_native_concurrency.py +0 -0
  311. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_native_rust.py +0 -0
  312. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_nuxt_import_dirs.py +0 -0
  313. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_nuxt_rootsrc.py +0 -0
  314. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_packaging.py +0 -0
  315. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_parity.py +0 -0
  316. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_parity_structure.py +0 -0
  317. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_php_http.py +0 -0
  318. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_php_props.py +0 -0
  319. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_plain_js.py +0 -0
  320. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_plans.py +0 -0
  321. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platform_gaps.py +0 -0
  322. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platform_type_variants.py +0 -0
  323. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platforms.py +0 -0
  324. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platforms_apple.py +0 -0
  325. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_presets_config.py +0 -0
  326. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_process_ipc.py +0 -0
  327. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_process_runs.py +0 -0
  328. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_protocols.py +0 -0
  329. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_app_tests_module.py +0 -0
  330. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_collection_chains.py +0 -0
  331. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_compat.py +0 -0
  332. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_entry_refs.py +0 -0
  333. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_fields.py +0 -0
  334. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_infer_cycles.py +0 -0
  335. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_roots.py +0 -0
  336. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_subprocess_tests.py +0 -0
  337. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_tests.py +0 -0
  338. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_web_hosts.py +0 -0
  339. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_web_routes.py +0 -0
  340. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_web_routes_more.py +0 -0
  341. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_react_router.py +0 -0
  342. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_readers_writers_specs.py +0 -0
  343. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_realtime.py +0 -0
  344. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_realtime_native.py +0 -0
  345. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_redact_salt.py +0 -0
  346. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_request_keys.py +0 -0
  347. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_roundtrip.py +0 -0
  348. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_route_tables.py +0 -0
  349. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_routes_search_explain.py +0 -0
  350. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_rpc.py +0 -0
  351. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_scip_health.py +0 -0
  352. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sdk_external.py +0 -0
  353. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sdk_external_infra.py +0 -0
  354. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sdk_external_mail.py +0 -0
  355. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_snippet.py +0 -0
  356. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sockets.py +0 -0
  357. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_spring.py +0 -0
  358. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ssrf.py +0 -0
  359. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_starters_budget.py +0 -0
  360. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_surface.py +0 -0
  361. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_surface_transport.py +0 -0
  362. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift.py +0 -0
  363. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_binding.py +0 -0
  364. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_exact.py +0 -0
  365. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_facts.py +0 -0
  366. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_fields.py +0 -0
  367. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_modules.py +0 -0
  368. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_more.py +0 -0
  369. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_nav_values.py +0 -0
  370. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_parse_errors.py +0 -0
  371. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_props.py +0 -0
  372. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_sdk.py +0 -0
  373. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_testing.py +0 -0
  374. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_values.py +0 -0
  375. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_tests_scope.py +0 -0
  376. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_fields.py +0 -0
  377. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_fields_js_vue.py +0 -0
  378. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_file_specs.py +0 -0
  379. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_frameworks.py +0 -0
  380. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_node_http.py +0 -0
  381. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_nuxt.py +0 -0
  382. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_src_tsconfig.py +0 -0
  383. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_unguarded.py +0 -0
  384. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_values.py +0 -0
  385. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_viz.py +0 -0
  386. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_vue_nav.py +0 -0
  387. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_watch.py +0 -0
  388. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_webhooks.py +0 -0
  389. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_webhooks_152.py +0 -0
  390. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_webhooks_152b.py +0 -0
  391. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_websockets.py +0 -0
  392. {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_workspace_link.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cg-code-graph
3
- Version: 0.21.2
3
+ Version: 0.22.0
4
4
  Summary: cg: a code graph of routes, calls, data access and platform boundaries for agents and humans (CLI + MCP server)
5
5
  Author: cyberchronos00
6
6
  License-Expression: MIT
@@ -93,7 +93,7 @@ Go and others: import a SCIP index with `cg index --scip FILE`. Run `cg doctor`
93
93
  - Across repos: `cg link` matches client HTTP calls (frontends and Laravel / Guzzle backends) to server routes, and checks request keys (Laravel FormRequest, Elysia schemas, Nuxt / TypeScript bodies).
94
94
  - Route guards: `cg routes --writes --unguarded` lists routes that write with no auth guard. Laravel checks inside the action count as inline guards unless `--strict`.
95
95
  - Security views: `cg surface` lists the inbound / outbound attack surface and findings (hardcoded credentials, plaintext protocols, unverified webhooks, unguarded handlers, listeners on all interfaces, disabled TLS / SSH verification, plaintext gRPC, exposed IPC, outbound URLs built from request input) as text, JSON or SARIF, with `--fail-on` for CI.
96
- - MCP server (`cg-mcp`) so agents query the graph instead of grepping.
96
+ - MCP server (`cg-mcp`) so agents query the graph instead of grepping. One server can serve many graphs (`graphs` plus an optional `graph` argument); a single `--db` stays one graph. See [MCP](https://code-graph.cyberchronos00.workers.dev/docs/mcp).
97
97
  - Visual view (`cg serve`) and plan checks (`cg plan check`) for planned changes.
98
98
 
99
99
  ## Docs
@@ -66,7 +66,7 @@ Go and others: import a SCIP index with `cg index --scip FILE`. Run `cg doctor`
66
66
  - Across repos: `cg link` matches client HTTP calls (frontends and Laravel / Guzzle backends) to server routes, and checks request keys (Laravel FormRequest, Elysia schemas, Nuxt / TypeScript bodies).
67
67
  - Route guards: `cg routes --writes --unguarded` lists routes that write with no auth guard. Laravel checks inside the action count as inline guards unless `--strict`.
68
68
  - Security views: `cg surface` lists the inbound / outbound attack surface and findings (hardcoded credentials, plaintext protocols, unverified webhooks, unguarded handlers, listeners on all interfaces, disabled TLS / SSH verification, plaintext gRPC, exposed IPC, outbound URLs built from request input) as text, JSON or SARIF, with `--fail-on` for CI.
69
- - MCP server (`cg-mcp`) so agents query the graph instead of grepping.
69
+ - MCP server (`cg-mcp`) so agents query the graph instead of grepping. One server can serve many graphs (`graphs` plus an optional `graph` argument); a single `--db` stays one graph. See [MCP](https://code-graph.cyberchronos00.workers.dev/docs/mcp).
70
70
  - Visual view (`cg serve`) and plan checks (`cg plan check`) for planned changes.
71
71
 
72
72
  ## Docs
@@ -1,2 +1,2 @@
1
1
  """code-graph: deterministic code knowledge graph (beta)."""
2
- __version__ = "0.21.2"
2
+ __version__ = "0.22.0"
@@ -73,6 +73,13 @@ def _add_install_parser(sub, uninstall: bool):
73
73
  p.add_argument("--uninstall", action="store_true", help="remove the entry instead of writing it")
74
74
  p.add_argument("--dry-run", action="store_true", help="print the exact changes and write nothing")
75
75
  p.add_argument("--yes", action="store_true", help="skip the confirmation prompt")
76
+ if not uninstall:
77
+ p.add_argument("--registry", action="store_true",
78
+ help="global single entry: cg-mcp with no --db; graphs come from the registry")
79
+ p.add_argument("--migrate", action="store_true",
80
+ help="fold per-repo cg-* host entries into the graph registry (dry run unless --apply)")
81
+ p.add_argument("--apply", action="store_true", help="with --migrate, write the registry and the host config")
82
+ p.add_argument("--graphs", help="registry file for --migrate (default: ~/.config/cg/graphs.toml)")
76
83
 
77
84
 
78
85
  def _impact_labels(rows: list[dict], name_of, group_of) -> list[str]:
@@ -506,9 +513,14 @@ def main(argv=None):
506
513
  mcp_file=a.mcp_file, dry_run=a.dry_run, assume_yes=a.yes)
507
514
  if a.cmd in ("install", "uninstall"):
508
515
  from .mcp_install import run as run_install
516
+ registry = bool(getattr(a, "registry", False))
517
+ migrate = bool(getattr(a, "migrate", False))
518
+ if (registry or migrate) and not a.project:
519
+ a.glob = True
509
520
  return run_install(a.host, scope="global" if a.glob else "project", root=a.dir, db=a.db,
510
521
  tools=a.tools, portable=a.portable, remove=a.cmd == "uninstall" or a.uninstall,
511
- dry_run=a.dry_run, assume_yes=a.yes)
522
+ dry_run=a.dry_run, assume_yes=a.yes, registry=registry, migrate=migrate,
523
+ apply=bool(getattr(a, "apply", False)), graphs=getattr(a, "graphs", None))
512
524
  if a.cmd == "hooks":
513
525
  from . import hooks as HK
514
526
  return HK.run(a.action, root=a.dir, db=a.db, dry_run=a.dry_run, assume_yes=a.yes)
@@ -675,16 +687,19 @@ def main(argv=None):
675
687
  if res.get("platform"):
676
688
  from .platforms import render_filter
677
689
  print(render_filter(res["platform"]))
678
- if res["platform"].get("targets_not_built"):
679
- print(f"not built for {a.platform}: {', '.join(res['platform']['targets_not_built'][:6])}")
690
+ dropped = res["platform"].get("targets_not_built") or []
691
+ if dropped and res["targets"]:
692
+ print(f"not built for {a.platform}: {', '.join(dropped[:6])}")
693
+ if dropped and not res["targets"]:
694
+ msg = f"{a.spec} is not built for {a.platform}: nothing calls it there"
695
+ if Q.divergence_lists(st, a.platform, dropped):
696
+ msg += (f" (`cg platforms divergence --target {a.platform}` lists references to it that would not build)")
697
+ print(msg); return
680
698
  print(f"targets: {res['targets'][:5]}")
681
699
  if not res["targets"]:
682
700
  print(f"no method matches {a.spec!r}; try `search` with part of the name"); return
683
- if a.platform and res["targets"] and set(res["platform"]["targets_not_built"]) == set(res["targets"]):
684
- msg = f"{a.spec} is not built for {a.platform}: nothing calls it there"
685
- if Q.divergence_lists(st, a.platform, res["targets"]):
686
- msg += (f" (`cg platforms divergence --target {a.platform}` lists references to it that would not build)")
687
- print(msg); return
701
+ for d in res.get("default_arguments") or []:
702
+ print(f"via default argument: {d['src']} @ {d['file']}:{d['line']}")
688
703
  for line in Q.override_lines(res):
689
704
  print(line)
690
705
  if res.get("connections"):
@@ -28,6 +28,19 @@ from .plugins.flutter.plugin import FlutterPlugin
28
28
  from .plugins.nest.plugin import NestPlugin
29
29
  from .plugins.nextjs.plugin import NextPlugin
30
30
  from .plugins.express.plugin import ExpressPlugin
31
+ import subprocess
32
+
33
+
34
+ def _git_head(root) -> str | None:
35
+ """Commit indexed for this root, when it is a git work tree."""
36
+ try:
37
+ proc = subprocess.run(["git", "-C", str(root), "rev-parse", "HEAD"],
38
+ capture_output=True, text=True, timeout=8)
39
+ except (OSError, subprocess.TimeoutExpired):
40
+ return None
41
+ if proc.returncode != 0:
42
+ return None
43
+ return (proc.stdout or "").strip() or None
31
44
  from .plugins.astro.plugin import AstroPlugin
32
45
  from .plugins.kotlin.plugin import KotlinPlugin
33
46
  from .plugins.java.plugin import JavaPlugin
@@ -464,6 +477,9 @@ def index_project(root: str | Path, db_path: str | Path, name: str | None = None
464
477
  stats["nodes"] = len(builder.nodes)
465
478
  stats["edges"] = len(builder.edges)
466
479
  stats["index_seconds"] = round(time.time() - t0, 2)
467
- store.set_meta(project=project.name, root=str(project.root), stats=stats, indexed_at=time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()))
480
+ head = _git_head(project.root)
481
+ extra = {"commit": head} if head else {}
482
+ store.set_meta(project=project.name, root=str(project.root), stats=stats,
483
+ indexed_at=time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()), **extra)
468
484
  store.db.close()
469
485
  return stats
@@ -497,10 +497,23 @@ def link_many(repos: list[tuple[str, str, str]], out_db: str, *, allow: dict | N
497
497
  for name, path, _role in repos:
498
498
  got = for_graph(GraphStore(path))
499
499
  cov.update({name: next(iter(got.values()))} if len(got) == 1 else got)
500
+ commits = {}
501
+ for name, path, _role in repos:
502
+ try:
503
+ member_st = GraphStore(path)
504
+ try:
505
+ member = member_st.meta()
506
+ finally:
507
+ member_st.db.close()
508
+ except Exception:
509
+ member = {}
510
+ if member.get("commit"):
511
+ commits[name] = member["commit"]
500
512
  store.set_meta(project="+".join(names), stats=stats, repos=names, coverage=cov,
501
513
  sources={name: str(Path(path).resolve()) for name, path, _role in repos},
502
514
  repo_roles={name: role for name, _path, role in repos}, link_clients=clients, link_allow=allow,
503
- indexed_at=time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()))
515
+ indexed_at=time.strftime("%Y-%m-%d %H:%M:%S UTC", time.gmtime()),
516
+ **({"commit": commits} if commits else {}))
504
517
  db.close()
505
518
  return {"stats": stats, "results": results, "payload_issues": issues, "uncalled_routes": uncalled,
506
519
  "webhook_subscriptions": subscriptions, "external_callbacks": callbacks}
@@ -0,0 +1,438 @@
1
+ """Graph registry for one cg-mcp process serving many graphs.
2
+
3
+ Entries come from a config file (``~/.config/cg/graphs.toml``, or ``CG_GRAPHS``),
4
+ repeatable ``--db`` / ``--db NAME=PATH``, and ``--db-dir``. A combined graph is one
5
+ entry with several repo roots. Each call opens its own connection.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import subprocess
11
+ import tomllib
12
+ from dataclasses import dataclass, field
13
+ from pathlib import Path
14
+
15
+ from .core.store import GraphStore
16
+
17
+
18
+ class GraphError(Exception):
19
+ """A graph name is unknown, or more than one graph matches and none was chosen."""
20
+
21
+
22
+ @dataclass
23
+ class GraphEntry:
24
+ name: str
25
+ db: Path
26
+ roots: list[Path] = field(default_factory=list)
27
+ default: bool = False
28
+ tools: str | None = None
29
+
30
+ def label(self) -> str:
31
+ roots = ", ".join(str(r) for r in self.roots) or "(no roots)"
32
+ return f"{self.name} [{roots}]"
33
+
34
+
35
+ @dataclass
36
+ class Registry:
37
+ entries: list[GraphEntry]
38
+ default: str | None = None
39
+ source: str = ""
40
+
41
+ def by_name(self) -> dict[str, GraphEntry]:
42
+ return {e.name: e for e in self.entries}
43
+
44
+ def names(self) -> list[str]:
45
+ return [e.name for e in self.entries]
46
+
47
+
48
+ def default_graphs_path() -> Path:
49
+ """``$XDG_CONFIG_HOME/cg/graphs.toml``, else ``~/.config/cg/graphs.toml``."""
50
+ base = os.environ.get("XDG_CONFIG_HOME")
51
+ root = Path(base) if base else Path.home() / ".config"
52
+ return root / "cg" / "graphs.toml"
53
+
54
+
55
+ def git_head(root: Path) -> str | None:
56
+ """HEAD of ``root``, or None when git is missing or ``root`` is not a work tree."""
57
+ try:
58
+ proc = subprocess.run(
59
+ ["git", "-C", str(root), "rev-parse", "HEAD"],
60
+ capture_output=True, text=True, timeout=8,
61
+ )
62
+ except (OSError, subprocess.TimeoutExpired):
63
+ return None
64
+ if proc.returncode != 0:
65
+ return None
66
+ sha = (proc.stdout or "").strip()
67
+ return sha or None
68
+
69
+
70
+ def _valid_name(name: str) -> bool:
71
+ return bool(name) and all(c.isalnum() or c in "_.-" for c in name)
72
+
73
+
74
+ def parse_db_arg(text: str) -> tuple[str, Path]:
75
+ """``NAME=PATH`` or a bare path (the name is the file stem)."""
76
+ raw = text.strip()
77
+ if "=" in raw:
78
+ name, path = raw.split("=", 1)
79
+ name, path = name.strip(), path.strip()
80
+ if _valid_name(name) and "/" not in name and "\\" not in name and path:
81
+ return name, Path(path).expanduser()
82
+ path = Path(raw).expanduser()
83
+ return path.stem or "graph", path
84
+
85
+
86
+ def roots_from_db(db: Path) -> list[Path]:
87
+ """Repo roots recorded in this graph, including member roots of a combined graph."""
88
+ found: list[Path] = []
89
+ seen: set[str] = set()
90
+
91
+ def add(p) -> None:
92
+ if not p:
93
+ return
94
+ try:
95
+ path = Path(p).expanduser()
96
+ except (TypeError, ValueError):
97
+ return
98
+ key = str(path)
99
+ if key in seen:
100
+ return
101
+ seen.add(key)
102
+ found.append(path)
103
+
104
+ try:
105
+ st = GraphStore(db)
106
+ try:
107
+ meta = st.meta()
108
+ finally:
109
+ st.db.close()
110
+ except Exception:
111
+ return []
112
+ add(meta.get("root"))
113
+ sources = meta.get("sources") or {}
114
+ if isinstance(sources, dict):
115
+ for member in sources.values():
116
+ mp = Path(str(member)).expanduser()
117
+ if mp.suffix == ".db":
118
+ try:
119
+ inner = GraphStore(mp)
120
+ try:
121
+ add(inner.meta().get("root"))
122
+ finally:
123
+ inner.db.close()
124
+ except Exception:
125
+ pass
126
+ elif mp.is_dir():
127
+ add(mp)
128
+ return found
129
+
130
+
131
+ def _entry_from_mapping(name: str, body: dict, default_name: str | None) -> GraphEntry:
132
+ if "db" not in body:
133
+ raise GraphError(f"graph {name}: missing db")
134
+ db = Path(str(body["db"])).expanduser()
135
+ raw_roots = body.get("roots") or body.get("root") or []
136
+ if isinstance(raw_roots, str):
137
+ raw_roots = [raw_roots]
138
+ roots = [Path(str(r)).expanduser() for r in raw_roots]
139
+ if not roots:
140
+ roots = roots_from_db(db)
141
+ is_default = bool(body.get("default")) or name == default_name
142
+ tools = body.get("tools")
143
+ return GraphEntry(name=name, db=db, roots=roots, default=is_default,
144
+ tools=str(tools) if isinstance(tools, str) and tools else None)
145
+
146
+
147
+ def load_toml(path: Path) -> tuple[list[GraphEntry], str | None]:
148
+ """Read a registry file. Supports ``[[graphs]]`` and ``[graphs.NAME]``."""
149
+ try:
150
+ data = tomllib.loads(path.read_text(encoding="utf-8"))
151
+ except (OSError, tomllib.TOMLDecodeError) as ex:
152
+ raise GraphError(f"cannot read graph registry {path}: {ex}") from ex
153
+ if not isinstance(data, dict):
154
+ raise GraphError(f"cannot read graph registry {path}: expected a table")
155
+ default = data.get("default")
156
+ default_name = str(default) if isinstance(default, str) and default else None
157
+ entries: list[GraphEntry] = []
158
+ graphs = data.get("graphs")
159
+ if isinstance(graphs, list):
160
+ for i, body in enumerate(graphs):
161
+ if not isinstance(body, dict) or not body.get("name"):
162
+ raise GraphError(f"{path}: [[graphs]] item {i} needs a name")
163
+ entries.append(_entry_from_mapping(str(body["name"]), body, default_name))
164
+ elif isinstance(graphs, dict):
165
+ for name, body in graphs.items():
166
+ if isinstance(body, dict) and "db" in body:
167
+ entries.append(_entry_from_mapping(str(name), body, default_name))
168
+ elif isinstance(body, list):
169
+ for item in body:
170
+ if isinstance(item, dict):
171
+ entries.append(_entry_from_mapping(str(item.get("name") or name), item, default_name))
172
+ if default_name and not any(e.name == default_name for e in entries):
173
+ raise GraphError(f"{path}: default {default_name!r} is not a registered graph")
174
+ return entries, default_name
175
+
176
+
177
+ def entries_from_db_args(args: list[str]) -> list[GraphEntry]:
178
+ out: list[GraphEntry] = []
179
+ for text in args:
180
+ name, db = parse_db_arg(text)
181
+ out.append(GraphEntry(name=name, db=db, roots=roots_from_db(db)))
182
+ return out
183
+
184
+
185
+ def entries_from_dir(directory: Path) -> list[GraphEntry]:
186
+ directory = directory.expanduser()
187
+ if not directory.is_dir():
188
+ raise GraphError(f"--db-dir is not a directory: {directory}")
189
+ out = []
190
+ for db in sorted(directory.glob("*.db")):
191
+ if db.name.endswith(("-wal", "-shm")):
192
+ continue
193
+ out.append(GraphEntry(name=db.stem, db=db, roots=roots_from_db(db)))
194
+ return out
195
+
196
+
197
+ def merge_entries(groups: list[list[GraphEntry]]) -> list[GraphEntry]:
198
+ """Later groups replace earlier entries with the same name."""
199
+ order: list[str] = []
200
+ by: dict[str, GraphEntry] = {}
201
+ for group in groups:
202
+ for entry in group:
203
+ if entry.name not in by:
204
+ order.append(entry.name)
205
+ by[entry.name] = entry
206
+ return [by[n] for n in order]
207
+
208
+
209
+ def build_registry(*, dbs: list[str] | None = None, db_dir: str | None = None,
210
+ config: Path | None = None, default: str | None = None,
211
+ read_config: bool = True) -> Registry:
212
+ groups: list[list[GraphEntry]] = []
213
+ source = []
214
+ file_default = None
215
+ if read_config and config is not None:
216
+ if not config.is_file():
217
+ raise GraphError(f"graph registry not found: {config}")
218
+ loaded, file_default = load_toml(config)
219
+ groups.append(loaded)
220
+ source.append(str(config))
221
+ if db_dir:
222
+ groups.append(entries_from_dir(Path(db_dir)))
223
+ source.append(f"dir:{db_dir}")
224
+ if dbs:
225
+ groups.append(entries_from_db_args(dbs))
226
+ source.append("cli")
227
+ entries = merge_entries(groups)
228
+ chosen = default or file_default
229
+ if chosen is None:
230
+ marked = [e.name for e in entries if e.default]
231
+ chosen = marked[-1] if marked else None
232
+ if chosen and chosen not in {e.name for e in entries}:
233
+ raise GraphError(f"default graph {chosen!r} is not registered")
234
+ if not entries:
235
+ raise GraphError("no graphs registered")
236
+ return Registry(entries=entries, default=chosen, source=", ".join(source))
237
+
238
+
239
+ def save_toml(path: Path, entries: list[GraphEntry], default: str | None = None) -> None:
240
+ """Write a registry. Caller backs up an existing file."""
241
+ lines: list[str] = []
242
+ if default:
243
+ lines.append(f"default = {_toml_str(default)}")
244
+ lines.append("")
245
+ for entry in entries:
246
+ lines.append("[[graphs]]")
247
+ lines.append(f"name = {_toml_str(entry.name)}")
248
+ lines.append(f"db = {_toml_str(str(entry.db))}")
249
+ roots = ", ".join(_toml_str(str(r)) for r in entry.roots)
250
+ lines.append(f"roots = [{roots}]")
251
+ if entry.tools:
252
+ lines.append(f"tools = {_toml_str(entry.tools)}")
253
+ lines.append("")
254
+ path.parent.mkdir(parents=True, exist_ok=True)
255
+ path.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
256
+
257
+
258
+ def _toml_str(text: str) -> str:
259
+ return '"' + text.replace("\\", "\\\\").replace('"', '\\"') + '"'
260
+
261
+
262
+ def _under(root: Path, text: str) -> bool:
263
+ """True when ``text`` is a path inside ``root`` (absolute, cwd-relative, or root-relative)."""
264
+ raw = text.replace("\\", "/").split("#", 1)[0].strip()
265
+ if not raw or raw.startswith(("page:", "repo:", "table:", "column:", "connection:", "env:", "config:")):
266
+ return False
267
+ if "/" not in raw and not raw.startswith("."):
268
+ return False
269
+ try:
270
+ base = root.expanduser().resolve()
271
+ except OSError:
272
+ return False
273
+ candidates = []
274
+ path = Path(raw)
275
+ if path.is_absolute():
276
+ candidates.append(path)
277
+ else:
278
+ candidates.append(Path.cwd() / path)
279
+ candidates.append(base / path)
280
+ for cand in candidates:
281
+ try:
282
+ cand.resolve().relative_to(base)
283
+ return True
284
+ except (ValueError, OSError):
285
+ continue
286
+ return False
287
+
288
+
289
+ def _matches(entry: GraphEntry, texts: list[str]) -> bool:
290
+ return any(_under(root, text) for root in entry.roots for text in texts)
291
+
292
+
293
+ def _choice_error(entries: list[GraphEntry]) -> GraphError:
294
+ listed = ", ".join(e.label() for e in entries)
295
+ return GraphError("ambiguous graph: pass graph= one of: " + listed)
296
+
297
+
298
+ def _root_set(entry: GraphEntry) -> set[Path]:
299
+ out = set()
300
+ for root in entry.roots:
301
+ try:
302
+ out.add(root.expanduser().resolve())
303
+ except OSError:
304
+ out.add(root)
305
+ return out
306
+
307
+
308
+ def _superset(hits: list[GraphEntry]) -> GraphEntry | None:
309
+ """When one match's roots contain every other match's roots, that graph is the combined one."""
310
+ if len(hits) < 2:
311
+ return None
312
+ sets = [(e, _root_set(e)) for e in hits]
313
+ strict = []
314
+ for entry, roots in sets:
315
+ if roots and all(other <= roots for other_entry, other in sets) and any(
316
+ other < roots for other_entry, other in sets if other_entry is not entry):
317
+ strict.append(entry)
318
+ return strict[0] if len(strict) == 1 else None
319
+
320
+
321
+ def resolve(registry: Registry, *, graph: str | None, paths: list[str],
322
+ cwd: Path | None = None, mcp_roots: list[str] | None = None) -> GraphEntry:
323
+ """Pick a graph. Several matches stay an error unless one graph's roots contain the others."""
324
+ by = registry.by_name()
325
+ if graph:
326
+ if graph not in by:
327
+ raise GraphError(f"unknown graph {graph!r}; choices: {', '.join(registry.names())}")
328
+ return by[graph]
329
+ path_hits = [e for e in registry.entries if paths and _matches(e, paths)]
330
+ if len(path_hits) == 1:
331
+ return path_hits[0]
332
+ if len(path_hits) > 1:
333
+ chosen = _superset(path_hits)
334
+ if chosen is not None:
335
+ return chosen
336
+ raise _choice_error(path_hits)
337
+ places: list[str] = []
338
+ if mcp_roots:
339
+ places.extend(mcp_roots)
340
+ places.append(str(cwd or Path.cwd()))
341
+ loc_hits = [e for e in registry.entries if _matches(e, places)]
342
+ if len(loc_hits) == 1:
343
+ return loc_hits[0]
344
+ if len(loc_hits) > 1:
345
+ chosen = _superset(loc_hits)
346
+ if chosen is not None:
347
+ return chosen
348
+ raise _choice_error(loc_hits)
349
+ if registry.default and registry.default in by:
350
+ return by[registry.default]
351
+ if len(registry.entries) == 1:
352
+ return registry.entries[0]
353
+ raise _choice_error(registry.entries)
354
+
355
+
356
+ def _languages(meta: dict) -> list[str]:
357
+ if isinstance(meta.get("languages"), list):
358
+ return [str(x) for x in meta["languages"]]
359
+ stats = meta.get("stats") or {}
360
+ found: list[str] = []
361
+ cov = stats.get("coverage") if isinstance(stats, dict) else None
362
+ if cov is None:
363
+ cov = meta.get("coverage")
364
+ blocks = []
365
+ if isinstance(cov, dict):
366
+ if isinstance(cov.get("languages"), list):
367
+ blocks.append(cov["languages"])
368
+ else:
369
+ for value in cov.values():
370
+ if isinstance(value, dict) and isinstance(value.get("languages"), list):
371
+ blocks.append(value["languages"])
372
+ for block in blocks:
373
+ for item in block:
374
+ if isinstance(item, dict) and item.get("language"):
375
+ found.append(str(item["language"]))
376
+ if not found and isinstance(stats, dict):
377
+ det = (stats.get("detected") or {}).get("languages") or {}
378
+ if isinstance(det, dict):
379
+ found.extend(str(k) for k in det)
380
+ return sorted(set(found))
381
+
382
+
383
+ def _commit_text(meta: dict) -> str:
384
+ commit = meta.get("commit")
385
+ if isinstance(commit, dict):
386
+ parts = [f"{k}={str(v)[:12]}" for k, v in commit.items() if v]
387
+ return ", ".join(parts)
388
+ if isinstance(commit, str) and commit:
389
+ return commit[:12]
390
+ return ""
391
+
392
+
393
+ def _freshness(meta: dict, roots: list[Path]) -> str:
394
+ commit = meta.get("commit")
395
+ heads = [git_head(r) for r in roots]
396
+ heads = [h for h in heads if h]
397
+ if not commit or not heads:
398
+ return "unknown"
399
+ if isinstance(commit, dict):
400
+ vals = [str(v) for v in commit.values() if v]
401
+ if not vals:
402
+ return "unknown"
403
+ return "fresh" if all(v in heads for v in vals) else "stale"
404
+ return "fresh" if str(commit) in heads else "stale"
405
+
406
+
407
+ def describe(entry: GraphEntry) -> dict:
408
+ """Name, roots, languages, indexed commit and freshness. Opens the DB briefly."""
409
+ meta: dict = {}
410
+ try:
411
+ st = GraphStore(entry.db)
412
+ try:
413
+ meta = st.meta()
414
+ finally:
415
+ st.db.close()
416
+ except Exception:
417
+ meta = {}
418
+ roots = entry.roots or ([Path(meta["root"])] if meta.get("root") else [])
419
+ return {
420
+ "name": entry.name,
421
+ "roots": [str(r) for r in roots],
422
+ "languages": _languages(meta),
423
+ "commit": _commit_text(meta),
424
+ "freshness": _freshness(meta, roots),
425
+ }
426
+
427
+
428
+ def render_graphs(registry: Registry) -> str:
429
+ lines = [f"{len(registry.entries)} graph(s)" + (f" default={registry.default}" if registry.default else "")]
430
+ for entry in registry.entries:
431
+ info = describe(entry)
432
+ mark = " default" if registry.default == entry.name else ""
433
+ langs = ", ".join(info["languages"]) or "none"
434
+ roots = ", ".join(info["roots"]) or "(no roots)"
435
+ commit = info["commit"] or "unknown"
436
+ lines.append(f"{info['name']}{mark} roots: {roots} languages: {langs} "
437
+ f"commit: {commit} freshness: {info['freshness']} db: {entry.db}")
438
+ return "\n".join(lines)