cg-code-graph 0.21.0__tar.gz → 0.21.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. {cg_code_graph-0.21.0/cg_code_graph.egg-info → cg_code_graph-0.21.2}/PKG-INFO +3 -1
  2. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/README.md +2 -0
  3. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/__init__.py +1 -1
  4. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/cli.py +48 -20
  5. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/redact.py +46 -21
  6. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/coverage.py +47 -10
  7. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/external.py +37 -0
  8. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/mcp_install.py +1 -1
  9. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/mcp_server.py +131 -50
  10. cg_code_graph-0.21.2/cg_code_graph/plugins/laravel/massassign.py +286 -0
  11. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/laravel/plugin.py +143 -21
  12. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/laravel/values.py +2 -0
  13. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/query.py +366 -33
  14. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/routes.py +5 -4
  15. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/surface.py +2 -2
  16. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2/cg_code_graph.egg-info}/PKG-INFO +3 -1
  17. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph.egg-info/SOURCES.txt +10 -0
  18. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph.egg-info/entry_points.txt +1 -0
  19. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/pyproject.toml +1 -0
  20. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_affected.py +3 -0
  21. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_bridges.py +3 -1
  22. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_coverage.py +4 -4
  23. cg_code_graph-0.21.2/tests/test_db_connections.py +280 -0
  24. cg_code_graph-0.21.2/tests/test_issue_192.py +60 -0
  25. cg_code_graph-0.21.2/tests/test_issue_203.py +52 -0
  26. cg_code_graph-0.21.2/tests/test_issue_207.py +58 -0
  27. cg_code_graph-0.21.2/tests/test_issue_209.py +42 -0
  28. cg_code_graph-0.21.2/tests/test_issue_211.py +45 -0
  29. cg_code_graph-0.21.2/tests/test_listing_files.py +45 -0
  30. cg_code_graph-0.21.2/tests/test_mass_assignment.py +164 -0
  31. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_mcp_install.py +10 -7
  32. cg_code_graph-0.21.2/tests/test_readers_writers_specs.py +211 -0
  33. cg_code_graph-0.21.2/tests/test_redact_salt.py +235 -0
  34. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_routes_search_explain.py +3 -2
  35. cg_code_graph-0.21.0/tests/test_redact_salt.py +0 -97
  36. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/LICENSE +0 -0
  37. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/MANIFEST.in +0 -0
  38. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/__main__.py +0 -0
  39. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/affected.py +0 -0
  40. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/agent_rules.py +0 -0
  41. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/agents.py +0 -0
  42. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/aitools.py +0 -0
  43. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/android_ipc.py +0 -0
  44. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/apple_ipc.py +0 -0
  45. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/apps.py +0 -0
  46. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/blindspots.py +0 -0
  47. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/bridges.py +0 -0
  48. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/brokers.py +0 -0
  49. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/concepts.py +0 -0
  50. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/config.py +0 -0
  51. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/__init__.py +0 -0
  52. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/cache.py +0 -0
  53. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/detect.py +0 -0
  54. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/env.py +0 -0
  55. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/extractors.py +0 -0
  56. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/fsutil.py +0 -0
  57. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/generated.py +0 -0
  58. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/model.py +0 -0
  59. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/paths.py +0 -0
  60. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/plugin.py +0 -0
  61. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/store.py +0 -0
  62. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/core/syntax_errors.py +0 -0
  63. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/dart_isolates.py +0 -0
  64. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/doctor.py +0 -0
  65. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/explore.py +0 -0
  66. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/graphql.py +0 -0
  67. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/guard_facts.py +0 -0
  68. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/hooks.py +0 -0
  69. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/indexer.py +0 -0
  70. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/insecure_transport.py +0 -0
  71. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/jobs.py +0 -0
  72. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/link.py +0 -0
  73. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/lint_async.py +0 -0
  74. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/local_ipc.py +0 -0
  75. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/local_sockets.py +0 -0
  76. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/parity.py +0 -0
  77. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/parity_structure.py +0 -0
  78. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/payload.py +0 -0
  79. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plans.py +0 -0
  80. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/platform_scan.py +0 -0
  81. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/platforms.py +0 -0
  82. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/__init__.py +0 -0
  83. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/astro/__init__.py +0 -0
  84. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/astro/content.py +0 -0
  85. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/astro/plugin.py +0 -0
  86. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
  87. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
  88. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
  89. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/__init__.py +0 -0
  90. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/bridges.py +0 -0
  91. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
  92. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
  93. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
  94. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/http.py +0 -0
  95. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/models.py +0 -0
  96. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/plugin.py +0 -0
  97. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/dart/program.py +0 -0
  98. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/__init__.py +0 -0
  99. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/extras.py +0 -0
  100. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/models.py +0 -0
  101. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/plugin.py +0 -0
  102. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/schemas.py +0 -0
  103. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/shapes.py +0 -0
  104. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/django/urls.py +0 -0
  105. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/express/__init__.py +0 -0
  106. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/express/plugin.py +0 -0
  107. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/flutter/__init__.py +0 -0
  108. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/flutter/plugin.py +0 -0
  109. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/java/__init__.py +0 -0
  110. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/java/exact.py +0 -0
  111. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/java/plugin.py +0 -0
  112. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/jvm/__init__.py +0 -0
  113. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/jvm/interop.py +0 -0
  114. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/jvm/spring.py +0 -0
  115. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
  116. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/kotlin/exact.py +0 -0
  117. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/kotlin/plugin.py +0 -0
  118. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
  119. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/laravel/__init__.py +0 -0
  120. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
  121. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/laravel/tests.py +0 -0
  122. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/native/__init__.py +0 -0
  123. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/native/gates.py +0 -0
  124. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/native/runner.py +0 -0
  125. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/native/scipread.py +0 -0
  126. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/native/ts.py +0 -0
  127. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/nest/__init__.py +0 -0
  128. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/nest/plugin.py +0 -0
  129. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
  130. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
  131. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
  132. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/nuxt/plugin.py +0 -0
  133. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/__init__.py +0 -0
  134. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/external.py +0 -0
  135. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
  136. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
  137. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
  138. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/gating.py +0 -0
  139. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/http_client.py +0 -0
  140. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/inline_guards.py +0 -0
  141. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/plugin.py +0 -0
  142. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/php/strings.py +0 -0
  143. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/__init__.py +0 -0
  144. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/aitools.py +0 -0
  145. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/external.py +0 -0
  146. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/fields.py +0 -0
  147. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/plugin.py +0 -0
  148. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/refs.py +0 -0
  149. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/roots.py +0 -0
  150. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/socketio.py +0 -0
  151. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/subproc.py +0 -0
  152. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/tests.py +0 -0
  153. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/python/values.py +0 -0
  154. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
  155. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
  156. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/pyweb/values.py +0 -0
  157. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/rust/__init__.py +0 -0
  158. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/rust/cargo.py +0 -0
  159. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/rust/plugin.py +0 -0
  160. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/rust/syntax.py +0 -0
  161. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/scip/__init__.py +0 -0
  162. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/scip/importer.py +0 -0
  163. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/scip/scip.proto +0 -0
  164. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
  165. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/stubs/__init__.py +0 -0
  166. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/stubs/plugins.py +0 -0
  167. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/swift/__init__.py +0 -0
  168. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/swift/baseurl.py +0 -0
  169. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/swift/exact.py +0 -0
  170. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/swift/indexstore.py +0 -0
  171. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/swift/packages.py +0 -0
  172. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/swift/plugin.py +0 -0
  173. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/__init__.py +0 -0
  174. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/baseurl.py +0 -0
  175. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
  176. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
  177. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
  178. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
  179. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
  180. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/nav.py +0 -0
  181. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/plugin.py +0 -0
  182. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/ts/react_router.py +0 -0
  183. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
  184. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/tsweb/common.py +0 -0
  185. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/plugins/tsweb/data.py +0 -0
  186. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/__init__.py +0 -0
  187. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/c_cpp.yaml +0 -0
  188. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/common.yaml +0 -0
  189. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/dart.yaml +0 -0
  190. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/django-ninja.yaml +0 -0
  191. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/django.yaml +0 -0
  192. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/djangorestframework.yaml +0 -0
  193. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/express.yaml +0 -0
  194. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/java.yaml +0 -0
  195. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/kotlin.yaml +0 -0
  196. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/laravel.yaml +0 -0
  197. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/nest.yaml +0 -0
  198. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/nextjs.yaml +0 -0
  199. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/nuxt.yaml +0 -0
  200. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/php.yaml +0 -0
  201. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/python.yaml +0 -0
  202. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/react-router.yaml +0 -0
  203. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/rust.yaml +0 -0
  204. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/spring.yaml +0 -0
  205. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/swift.yaml +0 -0
  206. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/presets/typescript.yaml +0 -0
  207. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/process_runs.py +0 -0
  208. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/protocols/__init__.py +0 -0
  209. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/protocols/builtin.py +0 -0
  210. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/protocols/matchers.py +0 -0
  211. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/protocols/view.py +0 -0
  212. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/realtime.py +0 -0
  213. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/realtime_events.py +0 -0
  214. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/realtime_native.py +0 -0
  215. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/realtime_ws.py +0 -0
  216. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/roundtrip.py +0 -0
  217. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/rpc.py +0 -0
  218. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/sdk_systems.py +0 -0
  219. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/sockets.py +0 -0
  220. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/ssrf_input.py +0 -0
  221. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/starters.py +0 -0
  222. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/tests_index.py +0 -0
  223. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/udp_apps.py +0 -0
  224. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/__init__.py +0 -0
  225. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/graph.py +0 -0
  226. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/server.py +0 -0
  227. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/app.css +0 -0
  228. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/app.js +0 -0
  229. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/index.html +0 -0
  230. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/layered.js +0 -0
  231. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
  232. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
  233. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
  234. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
  235. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
  236. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/tools/package-lock.json +0 -0
  237. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/tools/package.json +0 -0
  238. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/viz/tools/shoot.mjs +0 -0
  239. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/watch.py +0 -0
  240. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/webhook_subs.py +0 -0
  241. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/webhooks.py +0 -0
  242. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph/xcode.py +0 -0
  243. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph.egg-info/dependency_links.txt +0 -0
  244. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph.egg-info/requires.txt +0 -0
  245. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/cg_code_graph.egg-info/top_level.txt +0 -0
  246. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/setup.cfg +0 -0
  247. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_agents_install.py +0 -0
  248. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_agents_md.py +0 -0
  249. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ai_tools.py +0 -0
  250. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_android_ipc.py +0 -0
  251. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_apple_ipc.py +0 -0
  252. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_astro.py +0 -0
  253. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_astro_content.py +0 -0
  254. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_astro_server.py +0 -0
  255. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_bridges_pigeon_monorepo.py +0 -0
  256. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_brokers.py +0 -0
  257. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_cache_clean.py +0 -0
  258. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_cache_invalidation.py +0 -0
  259. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_cache_migration.py +0 -0
  260. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_channels_tests.py +0 -0
  261. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_cli_output.py +0 -0
  262. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_completeness.py +0 -0
  263. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_config_extras.py +0 -0
  264. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_coverage_ts_hint.py +0 -0
  265. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_dart_isolates.py +0 -0
  266. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_dispatch_interfaces.py +0 -0
  267. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_django_flutter.py +0 -0
  268. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_docs_languages.py +0 -0
  269. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_docs_links.py +0 -0
  270. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_echo_ref.py +0 -0
  271. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_echo_wrapper.py +0 -0
  272. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_elysia.py +0 -0
  273. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_enum_constants.py +0 -0
  274. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_env.py +0 -0
  275. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_explore.py +0 -0
  276. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_external.py +0 -0
  277. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_fp_batch.py +0 -0
  278. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_gating.py +0 -0
  279. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_generated.py +0 -0
  280. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_graphql.py +0 -0
  281. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_hooks.py +0 -0
  282. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_impact_overrides.py +0 -0
  283. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_index_isolation.py +0 -0
  284. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_inherited_overrides.py +0 -0
  285. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_inline_guards.py +0 -0
  286. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_java.py +0 -0
  287. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_java_exact.py +0 -0
  288. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_jobs.py +0 -0
  289. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_js_refs.py +0 -0
  290. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_js_runtime.py +0 -0
  291. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin.py +0 -0
  292. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin_binding.py +0 -0
  293. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin_exact.py +0 -0
  294. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin_fields.py +0 -0
  295. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin_mixed.py +0 -0
  296. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin_nav_consts.py +0 -0
  297. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_kotlin_props.py +0 -0
  298. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_laravel_determinism.py +0 -0
  299. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_laravel_resources.py +0 -0
  300. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_lint_async.py +0 -0
  301. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_local_ipc.py +0 -0
  302. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_local_sockets.py +0 -0
  303. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_mcp.py +0 -0
  304. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_mcp_index.py +0 -0
  305. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_native_cfamily.py +0 -0
  306. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_native_concurrency.py +0 -0
  307. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_native_rust.py +0 -0
  308. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_nuxt_import_dirs.py +0 -0
  309. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_nuxt_rootsrc.py +0 -0
  310. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_packaging.py +0 -0
  311. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_parity.py +0 -0
  312. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_parity_structure.py +0 -0
  313. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_php_http.py +0 -0
  314. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_php_props.py +0 -0
  315. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_plain_js.py +0 -0
  316. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_plans.py +0 -0
  317. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_platform_gaps.py +0 -0
  318. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_platform_type_variants.py +0 -0
  319. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_platforms.py +0 -0
  320. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_platforms_apple.py +0 -0
  321. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_presets_config.py +0 -0
  322. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_process_ipc.py +0 -0
  323. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_process_runs.py +0 -0
  324. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_protocols.py +0 -0
  325. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_app_tests_module.py +0 -0
  326. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_collection_chains.py +0 -0
  327. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_compat.py +0 -0
  328. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_entry_refs.py +0 -0
  329. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_fields.py +0 -0
  330. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_infer_cycles.py +0 -0
  331. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_roots.py +0 -0
  332. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_subprocess_tests.py +0 -0
  333. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_tests.py +0 -0
  334. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_web_hosts.py +0 -0
  335. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_web_routes.py +0 -0
  336. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_python_web_routes_more.py +0 -0
  337. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_react_router.py +0 -0
  338. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_realtime.py +0 -0
  339. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_realtime_native.py +0 -0
  340. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_request_keys.py +0 -0
  341. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_roundtrip.py +0 -0
  342. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_route_tables.py +0 -0
  343. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_rpc.py +0 -0
  344. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_scip_health.py +0 -0
  345. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_sdk_external.py +0 -0
  346. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_sdk_external_infra.py +0 -0
  347. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_sdk_external_mail.py +0 -0
  348. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_snippet.py +0 -0
  349. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_sockets.py +0 -0
  350. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_spring.py +0 -0
  351. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ssrf.py +0 -0
  352. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_starters_budget.py +0 -0
  353. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_surface.py +0 -0
  354. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_surface_transport.py +0 -0
  355. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift.py +0 -0
  356. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_binding.py +0 -0
  357. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_exact.py +0 -0
  358. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_facts.py +0 -0
  359. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_fields.py +0 -0
  360. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_modules.py +0 -0
  361. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_more.py +0 -0
  362. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_nav_values.py +0 -0
  363. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_parse_errors.py +0 -0
  364. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_props.py +0 -0
  365. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_sdk.py +0 -0
  366. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_testing.py +0 -0
  367. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_swift_values.py +0 -0
  368. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_tests_scope.py +0 -0
  369. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_fields.py +0 -0
  370. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_fields_js_vue.py +0 -0
  371. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_file_specs.py +0 -0
  372. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_frameworks.py +0 -0
  373. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_node_http.py +0 -0
  374. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_nuxt.py +0 -0
  375. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_ts_src_tsconfig.py +0 -0
  376. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_unguarded.py +0 -0
  377. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_values.py +0 -0
  378. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_viz.py +0 -0
  379. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_vue_nav.py +0 -0
  380. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_watch.py +0 -0
  381. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_webhooks.py +0 -0
  382. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_webhooks_152.py +0 -0
  383. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_webhooks_152b.py +0 -0
  384. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/tests/test_websockets.py +0 -0
  385. {cg_code_graph-0.21.0 → cg_code_graph-0.21.2}/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.0
3
+ Version: 0.21.2
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
@@ -33,6 +33,8 @@ Dynamic: license-file
33
33
 
34
34
  For you and your AI agent (CLI + MCP). No LLM in the graph.
35
35
 
36
+ <!-- mcp-name: io.github.cyberchronos00/cg-code-graph -->
37
+
36
38
  [![PyPI](https://img.shields.io/pypi/v/cg-code-graph)](https://pypi.org/project/cg-code-graph/) [![Downloads](https://img.shields.io/pepy/dt/cg-code-graph)](https://pepy.tech/project/cg-code-graph) [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB)](https://pypi.org/project/cg-code-graph/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/cyberchronos00/code-graph/blob/main/LICENSE) [![Docs](https://img.shields.io/badge/docs-code--graph-93b600)](https://code-graph.cyberchronos00.workers.dev/)
37
39
 
38
40
  [Docs](https://code-graph.cyberchronos00.workers.dev/) · [Quick start](https://code-graph.cyberchronos00.workers.dev/docs/quickstart) · [CLI](https://code-graph.cyberchronos00.workers.dev/docs/cli) · [MCP](https://code-graph.cyberchronos00.workers.dev/docs/mcp) · [Changelog](https://github.com/cyberchronos00/code-graph/blob/main/CHANGELOG.md)
@@ -6,6 +6,8 @@
6
6
 
7
7
  For you and your AI agent (CLI + MCP). No LLM in the graph.
8
8
 
9
+ <!-- mcp-name: io.github.cyberchronos00/cg-code-graph -->
10
+
9
11
  [![PyPI](https://img.shields.io/pypi/v/cg-code-graph)](https://pypi.org/project/cg-code-graph/) [![Downloads](https://img.shields.io/pepy/dt/cg-code-graph)](https://pepy.tech/project/cg-code-graph) [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-3776AB)](https://pypi.org/project/cg-code-graph/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/cyberchronos00/code-graph/blob/main/LICENSE) [![Docs](https://img.shields.io/badge/docs-code--graph-93b600)](https://code-graph.cyberchronos00.workers.dev/)
10
12
 
11
13
  [Docs](https://code-graph.cyberchronos00.workers.dev/) · [Quick start](https://code-graph.cyberchronos00.workers.dev/docs/quickstart) · [CLI](https://code-graph.cyberchronos00.workers.dev/docs/cli) · [MCP](https://code-graph.cyberchronos00.workers.dev/docs/mcp) · [Changelog](https://github.com/cyberchronos00/code-graph/blob/main/CHANGELOG.md)
@@ -1,2 +1,2 @@
1
1
  """code-graph: deterministic code knowledge graph (beta)."""
2
- __version__ = "0.21.0"
2
+ __version__ = "0.21.2"
@@ -75,6 +75,20 @@ def _add_install_parser(sub, uninstall: bool):
75
75
  p.add_argument("--yes", action="store_true", help="skip the confirmation prompt")
76
76
 
77
77
 
78
+ def _impact_labels(rows: list[dict], name_of, group_of) -> list[str]:
79
+ """Display names for one impact listing. Same-name rows in one group gain a file suffix."""
80
+ from collections import defaultdict
81
+ groups = defaultdict(list)
82
+ for i, row in enumerate(rows):
83
+ groups[group_of(row)].append(i)
84
+ labels = [name_of(row) for row in rows]
85
+ for idxs in groups.values():
86
+ named = Q.disambiguated([labels[i] for i in idxs], [rows[i].get("file") for i in idxs])
87
+ for i, lab in zip(idxs, named):
88
+ labels[i] = lab
89
+ return labels
90
+
91
+
78
92
  def main(argv=None):
79
93
  from . import __version__
80
94
  ap = argparse.ArgumentParser(prog="cg")
@@ -321,8 +335,8 @@ def main(argv=None):
321
335
  p.add_argument("--quiet", action="store_true", help="pass --quiet to each refresh")
322
336
  helps = {"reaches": "everything that depends on the targets, grouped by entry classification",
323
337
  "siblings": "code related to a symbol: class hierarchy, the same method in sibling classes, shared resources, co-callers",
324
- "writers": "code that writes a table (or column), or a stored property `Type.prop`",
325
- "readers": "code that reads a stored property `Type.prop` (READS_PROP)",
338
+ "writers": "code that writes a table, a column (`table.column`) or a stored property `Type.prop`",
339
+ "readers": "code that reads a table, a column (`table.column`) or a stored property `Type.prop`",
326
340
  "impact": "callers of a method up to their entry points (reverse walk), overrides listed apart",
327
341
  "stats": "node / edge counts of a graph DB",
328
342
  "node": "one node's details and its incoming / outgoing edges",
@@ -342,6 +356,9 @@ def main(argv=None):
342
356
  p.add_argument("--no-paths", action="store_true")
343
357
  p.add_argument("--max-depth", type=int, default=30)
344
358
  p.add_argument("--gate", default="auto", help="gate scenario for live/gated split (default: the one indexed; 'none' to disable)")
359
+ if name in ("reaches", "writers", "readers"):
360
+ p.add_argument("--connection", help="only the table / column edges that go to this database connection "
361
+ "(a dynamic name by its pattern, e.g. 'legacy_{store.id}'; docs/cli.md)")
345
362
  if name in ("reaches", "impact", "downstream"):
346
363
  p.add_argument("--platform", help="only code built for this target (windows, linux, macos, ios, android, web; see docs/platforms.md)")
347
364
  if name == "impact":
@@ -646,7 +663,7 @@ def main(argv=None):
646
663
  return
647
664
  if a.cmd == "reaches":
648
665
  res = Q.reaches(st, a.specs, min_conf=a.min_confidence, max_depth=a.max_depth, gate=None if a.gate == "none" else a.gate,
649
- platform=a.platform)
666
+ platform=a.platform, connection=a.connection)
650
667
  res["completeness"] = _completeness(st, [x for t in res["targets"].values() for x in t] + [i["id"] for i in res["items"]])
651
668
  print(json.dumps(res, indent=1, default=str) if a.json else Q.render_reaches(res, show_paths=not a.no_paths))
652
669
  _note(res["completeness"], a.json)
@@ -664,20 +681,26 @@ def main(argv=None):
664
681
  if not res["targets"]:
665
682
  print(f"no method matches {a.spec!r}; try `search` with part of the name"); return
666
683
  if a.platform and res["targets"] and set(res["platform"]["targets_not_built"]) == set(res["targets"]):
667
- print(f"{a.spec} is not built for {a.platform}: nothing calls it there (`cg platforms divergence --target "
668
- f"{a.platform}` lists references to it that would not build)"); return
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
669
688
  for line in Q.override_lines(res):
670
689
  print(line)
690
+ if res.get("connections"):
691
+ print(Q.connections_line(res["connections"]))
671
692
  if not res["callers"] and not res["entry_points"]:
672
693
  print(Q.explain_no_callers(st, a.spec, res["targets"], a.min_confidence)); return
673
694
  print(f"callers (transitive): {len(res['callers'])}")
674
- for c in res["callers"]:
695
+ caller_names = _impact_labels(res["callers"], lambda c: c.get("fqn") or c["id"], lambda c: c.get("module") or c.get("kind"))
696
+ for c, nm in zip(res["callers"], caller_names):
675
697
  loc = f" @ {c['file']}:{c['line']}" if Q.NATIVE_FILE_RE.search(c.get("file") or "") else ""
676
- print(f" d={c['depth']} [{c['module'] or c['kind']}] {c['fqn']}{loc}{Q.caller_label(c)}")
698
+ print(f" d={c['depth']} [{c['module'] or c['kind']}] {nm}{loc}{Q.caller_label(c)}")
677
699
  print(f"entry points: {len(res['entry_points'])}")
678
- for e in res["entry_points"]:
700
+ entry_names = _impact_labels(res["entry_points"], lambda e: e["name"], lambda e: e.get("entry_kind"))
701
+ for e, nm0 in zip(res["entry_points"], entry_names):
679
702
  native = Q.NATIVE_FILE_RE.search(e.get("file") or "")
680
- nm = f"{e.get('fqn') or e['name']} @ {e['file']}:{e['line']}" if native else e["name"]
703
+ nm = f"{e.get('fqn') or e['name']} @ {e['file']}:{e['line']}" if native else nm0
681
704
  print(f" {e['entry_kind']:16} {nm} conf={e['path_confidence']}{Q.CANDIDATE_LABEL if e.get('candidate') else ''}"
682
705
  f"{Q.generated_label(e)}{Q.platform_label(e)}")
683
706
  if not a.no_paths:
@@ -702,17 +725,14 @@ def main(argv=None):
702
725
  res = RT.roundtrip(st, a.spec, include_tests=a.tests)
703
726
  print(RT.to_json(res) if a.json else RT.render(res))
704
727
  elif a.cmd in ("writers", "readers"):
705
- rows = Q.writers(st, a.spec) if a.cmd == "writers" else Q.readers(st, a.spec)
728
+ groups = Q.access(st, a.spec, a.cmd, a.connection)
729
+ rows = [r for g in groups for r in g["rows"]]
706
730
  if a.json:
707
731
  print(json.dumps(rows, indent=1)); return
708
732
  if not rows:
709
- print(Q.explain_no_writers(st, a.spec, a.cmd)); return
710
- for r in rows:
711
- ek = ",".join(sorted(r["entry_kinds"]))
712
- ex = {k: v for k, v in (r.get("attrs") or {}).items() if k in ("receiver", "accessor", "storage")}
713
- extra = (" " + " ".join(f"{k}={v}" for k, v in ex.items())) if ex else ""
714
- kind = f"{r['kind']}({r['attrs']['orig']})" if r.get("test") else r['kind']
715
- print(f"[{r['module']}] {r['fqn']} {kind} {r['dst']} @{r['file']}:{r['line']} ({r['confidence']}){extra} entries: {ek}")
733
+ print(Q.explain_no_connection(st, a.spec, a.connection, a.cmd) if a.connection else Q.explain_no_writers(st, a.spec, a.cmd))
734
+ return
735
+ print("\n".join(Q.render_access(groups)))
716
736
  verb = "write" if a.cmd == "writers" else "read"
717
737
  nt = sum(1 for r in rows if r.get("test"))
718
738
  print(f"{len(rows)} {verb} edges, {len({r['src'] for r in rows})} {a.cmd}" + (f" ({nt} from test code)" if nt else ""))
@@ -773,6 +793,14 @@ def node_doc(st, nid: str) -> dict:
773
793
  return {"node": n, "out": edges("src", "dst"), "in": edges("dst", "src")}
774
794
 
775
795
 
796
+ def _mass_note(e: dict) -> str:
797
+ """` via update(validated()) keys from UpdateBookRequest::rules ∩ Book::$fillable` for a mass-assignment column write (#177)."""
798
+ at = e.get("attrs") or {}
799
+ if e["kind"] != "WRITES_COLUMN" or not at.get("mass_assignment"):
800
+ return ""
801
+ return f" via {at.get('via')}" + (f" keys from {' ∩ '.join(at['keys_from'])}" if at.get("keys_from") else "")
802
+
803
+
776
804
  def render_node(d: dict) -> str:
777
805
  """`cg node` text: the node's location, kind and attrs, then its edges; the same edge from one site (one row per
778
806
  gate scenario or accessor) is listed once with a count."""
@@ -801,10 +829,10 @@ def render_node(d: dict) -> str:
801
829
  out.append(f" {'outgoing' if key == 'out' else 'incoming'} ({len(es)}):" if es else f" {'outgoing' if key == 'out' else 'incoming'}: none")
802
830
  seen: dict = {}
803
831
  for e in es:
804
- k = (e["kind"], e[other], e["file"], e["line"], e["confidence"])
832
+ k = (e["kind"], e[other], e["file"], e["line"], e["confidence"], _mass_note(e))
805
833
  seen[k] = seen.get(k, 0) + 1
806
- for (kind, o, f, line, conf), c in seen.items():
807
- out.append(f" {arrow} {kind} {o} @{f}:{line} {conf}" + (f" ×{c}" if c > 1 else ""))
834
+ for (kind, o, f, line, conf, note), c in seen.items():
835
+ out.append(f" {arrow} {kind} {o} @{f}:{line} {conf}{note}" + (f" ×{c}" if c > 1 else ""))
808
836
  return "\n".join(out)
809
837
 
810
838
 
@@ -1,7 +1,9 @@
1
1
  """Secret values never reach the graph database (#47).
2
2
 
3
- A literal that belongs to a credential-looking key (password, secret, token, key, api_key, auth, private, credential,
4
- passphrase, dsn, ...) is stored as `redacted:hmac:<first 8 hex of HMAC-SHA-256(graph salt, value)>`: enough to see that
3
+ A literal that belongs to a credential-looking key (its last word is password, secret, dsn, ..., or an
4
+ explicit compound such as api_key; a bare `key` / `token` counts unless a known non-secret word precedes it
5
+ (`primary_key`, `cache.key`), whatever the value looks like; `AUTH_GUARD` or `..._TOKEN_TABLE`
6
+ do not count) is stored as `redacted:hmac:<first 8 hex of HMAC-SHA-256(graph salt, value)>`: enough to see that
5
7
  a literal exists and to tell two values apart within one graph, not enough to recover one, and not recognisable by
6
8
  hashing a common password. The salt is `secrets.token_hex(16)`, created on the first index of a graph DB, kept in its
7
9
  `meta` table (`redact_salt`) and carried over by a re-index or refresh of that DB; a new DB gets a new salt, so markers
@@ -20,29 +22,52 @@ import secrets
20
22
 
21
23
  MARK = "redacted:hmac:"
22
24
  LEGACY_MARK = "redacted:sha256:"
23
- SECRET_WORDS = ("PASSWORD", "PASS", "PASSWD", "SECRET", "TOKEN", "SECRET_KEY", "SECRET_ACCESS_KEY", "KEY", "AUTH", "PWD")
24
- _EXTRA_WORDS = {"PASSWORD", "PASSWD", "PWD", "PASSPHRASE", "SECRET", "SECRETS", "TOKEN", "TOKENS", "AUTH", "AUTHORIZATION",
25
- "CREDENTIAL", "CREDENTIALS", "PRIVATE", "APIKEY", "DSN", "BEARER", "SALT", "SIGNATURE"}
26
- _NOT_SECRET_TAIL = ("_KEY_ID", "_PUBLIC_KEY", "_KEY_PATH")
25
+ _SECRET_LAST = {"password", "passwd", "pwd", "pass", "passphrase", "secret", "dsn"}
26
+ _SECRET_COMPOUNDS = {("api", "key"), ("apikey",), ("access", "key"), ("secret", "key"), ("private", "key"),
27
+ ("signing", "key"), ("encryption", "key"), ("client", "secret"), ("webhook", "secret"),
28
+ ("auth", "token"), ("api", "token"), ("access", "token"), ("refresh", "token"), ("bearer", "token")}
29
+ _BARE_LAST = {"key", "token"}
30
+ SECRET_WORDS = tuple(sorted({w.upper() for w in _SECRET_LAST} | {"_".join(c).upper() for c in _SECRET_COMPOUNDS}
31
+ | {w.upper() for w in _BARE_LAST}))
32
+ _NON_SECRET_BEFORE = {"primary", "foreign", "sort", "partition", "route", "cache", "idempotency", "remember", "csrf",
33
+ "xsrf", "public", "i18n", "translation", "lookup", "unique", "index", "storage", "prefix"}
27
34
  _URL_PW = re.compile(r"(?P<head>\b[A-Za-z][\w+.-]*://[^/\s:@'\"]*:)(?P<pw>[^@/\s'\"]+)(?P<tail>@)")
28
35
  _PLACEHOLDER = ("${", "{{", "%(", "<", "$")
29
36
 
30
37
 
31
- def secret_key(key: str) -> bool:
32
- """The `cg surface` rule for a config key / env name that holds a credential."""
33
- k = re.sub(r"[^A-Za-z0-9]+", "_", key).upper().strip("_")
34
- return any(k.endswith("_" + s) or k == s for s in SECRET_WORDS) and not k.endswith(_NOT_SECRET_TAIL)
35
-
36
-
37
- def looks_secret(key: str) -> bool:
38
- """Wider than `secret_key`: any word of the name says credential (private_key_pem, db_dsn, apiKey, auth_header)."""
39
- if secret_key(key):
38
+ def _words(segment: str) -> list[str]:
39
+ spaced = re.sub(r"([a-z])([A-Z])", r"\1_\2", segment)
40
+ return [w for w in re.split(r"[^A-Za-z0-9]+", spaced.lower()) if w]
41
+
42
+
43
+ def secret_key(key: str, value=None) -> bool:
44
+ """Whether a config key / env name holds a credential, from the words of the name (split on `.`, `_`, `-` and
45
+ camelCase). A credential when the last word is password, passwd, pwd, pass, passphrase, secret or dsn, when the
46
+ name ends in an explicit compound (api_key, access_key, signing_key, client_secret, auth_token, refresh_token, ...),
47
+ or for Laravel's `app.key` / `APP_KEY`. A bare `key` or `token` as last word is a credential by default, as it
48
+ was in 0.21.0, and is kept only when the word before it (a dotted segment counts) is a known non-secret one
49
+ (primary, foreign, sort, partition, route, cache, idempotency, remember, csrf, xsrf, public, i18n, translation,
50
+ lookup, unique, index, storage, prefix). The value never decides: a token can be any shape (lowercase words,
51
+ dotted, `key-` prefixed), so `value` is accepted for the callers' signature only. A credential word earlier in the name never counts
52
+ (`AUTH_GUARD`, `AUTH_PASSWORD_BROKER`, `AUTH_PASSWORD_RESET_TOKEN_TABLE`, `try_it_credentials_policy`), and
53
+ `*_PUBLIC_KEY`, `*_KEY_ID`, `*_KEY_PATH`, `*_KEY_FILE` are not credentials."""
54
+ key = str(key)
55
+ words = _words(key.rsplit(".", 1)[-1])
56
+ if not words:
57
+ return False
58
+ all_words = _words(key)
59
+ if all_words == ["app", "key"]:
40
60
  return True
41
- spaced = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", str(key))
42
- words = [w for w in re.split(r"[^A-Za-z0-9]+", spaced.upper()) if w]
43
- if any(w in _EXTRA_WORDS for w in words):
61
+ if words[-1] in _SECRET_LAST or any(tuple(words[-n:]) in _SECRET_COMPOUNDS for n in (1, 2) if len(words) >= n):
44
62
  return True
45
- return "KEY" in words and not set(words) & {"PUBLIC", "ID", "PATH", "FILE", "NAME", "PREFIX", "TYPE", "SIZE", "LENGTH"}
63
+ if words[-1] not in _BARE_LAST:
64
+ return False
65
+ if len(all_words) > 1 and all_words[-2] in _NON_SECRET_BEFORE:
66
+ return False
67
+ return True
68
+
69
+
70
+ looks_secret = secret_key
46
71
 
47
72
 
48
73
  def is_redacted(v) -> bool:
@@ -79,7 +104,7 @@ def redact(value, key: str | None, salt: str):
79
104
  by one, anything else unchanged. Non-strings and placeholders pass through."""
80
105
  if not isinstance(value, str):
81
106
  return value
82
- if key is not None and looks_secret(key) and not placeholder(value):
107
+ if key is not None and looks_secret(key, value) and not placeholder(value):
83
108
  return marker(value, salt)
84
109
  return redact_url(value, salt)
85
110
 
@@ -100,7 +125,7 @@ def _holds_secret(d: dict, k: str) -> bool:
100
125
  if k.lower() in _DIRECT:
101
126
  return not _REFERENCE.match(str(d[k]))
102
127
  if k in _VALUE_KEYS:
103
- return any(isinstance(d.get(nk), str) and looks_secret(d[nk]) for nk in _NAME_KEYS)
128
+ return any(isinstance(d.get(nk), str) and looks_secret(d[nk], d.get(k)) for nk in _NAME_KEYS)
104
129
  return False
105
130
 
106
131
 
@@ -233,9 +233,20 @@ def file_completeness(discovered: list[str], report: dict) -> dict:
233
233
  for b in BUCKETS:
234
234
  res[b] = len(out[b])
235
235
  res["paths"] = {b: v[:MAX_PATHS] for b, v in out.items() if v}
236
+ if out["excluded"]:
237
+ res["exclude_reasons"] = {f: _exclude_reason(f) for f in out["excluded"]}
236
238
  return res
237
239
 
238
240
 
241
+ def _exclude_reason(path: str) -> str:
242
+ """Why a discovered file was left out of the graph: tool config, a test file, or a `.cg.yaml` exclude."""
243
+ if _TOOL_FILE.search(path):
244
+ return "tool config"
245
+ if _TEST_NAME.search(path):
246
+ return "test file"
247
+ return ".cg.yaml exclude"
248
+
249
+
239
250
  def missing_files(e: dict) -> int:
240
251
  """Discovered files of a language entry that are not in the graph for a reason other than a deliberate exclusion."""
241
252
  return sum(e.get(b, 0) for b in ("parse_failed", "skipped_oversize", "unmapped"))
@@ -308,6 +319,8 @@ def compute(root: str | Path, plugins: dict, scip_imported: bool = False, report
308
319
  status, reason = _status(lang, st)
309
320
  e = {"language": lang, "files": n, "status": status,
310
321
  "by_ext": {x: files[x] for x in exts if files[x]}}
322
+ if lang == "typescript" and not any(x in e["by_ext"] for x in (".ts", ".tsx", ".mts", ".cts")):
323
+ e["label"] = "javascript"
311
324
  if reason:
312
325
  e["reason"] = reason
313
326
  if status in ("skipped", "heuristic", "not_indexed"):
@@ -495,16 +508,22 @@ def blind_spots(cov: dict | None) -> list[dict]:
495
508
  return list((cov or {}).get("blind_spots") or [])
496
509
 
497
510
 
511
+ def _shown_lang(e: dict) -> str:
512
+ """Display name. A TypeScript-plugin entry with no .ts/.tsx/.mts/.cts files reads as javascript; JSON keeps `language`."""
513
+ return e.get("label") or e["language"]
514
+
515
+
498
516
  def _entry_text(e: dict) -> str:
499
517
  """'php 18 exact' / 'python 4 discovered, 2 indexed (exact parser): 1 parse failed, 1 unmapped' /
500
- 'swift 101 heuristic, 8 parsed with syntax errors'."""
518
+ 'javascript 12 discovered, 2 indexed (exact parser): 9 unmapped, 1 excluded'."""
501
519
  pe = e.get("parsed_with_errors")
502
520
  errs = f", {pe} parsed with syntax errors" if pe else ""
521
+ name = _shown_lang(e)
503
522
  if e.get("files_complete") is False:
504
- parts = [f"{e[b]} {BUCKET_SHORT[b]}" for b in ("parse_failed", "skipped_oversize", "unmapped") if e.get(b)]
505
- return (f"{e['language']} {e['files']} discovered, {e['indexed']} indexed ({e['status'].replace('_', ' ')} parser)"
523
+ parts = [f"{e[b]} {BUCKET_SHORT[b]}" for b in BUCKETS if e.get(b)]
524
+ return (f"{name} {e['files']} discovered, {e['indexed']} indexed ({e['status'].replace('_', ' ')} parser)"
506
525
  + (": " + ", ".join(parts) if parts else "") + errs)
507
- return f"{e['language']} {e['files']} {e['status'].replace('_', ' ')}{errs}"
526
+ return f"{name} {e['files']} {e['status'].replace('_', ' ')}{errs}"
508
527
 
509
528
 
510
529
  def realtime_unresolved_lines(e: dict, indent: str = " ") -> list[str]:
@@ -579,11 +598,16 @@ def _paths_lines(e: dict, all_files: bool, indent: str = " ") -> list[str]:
579
598
  out = []
580
599
  for b in BUCKETS:
581
600
  ps = (e.get("paths") or {}).get(b) or []
582
- if not ps or (b == "excluded" and not all_files):
601
+ if not ps:
583
602
  continue
584
603
  show = ps if all_files else ps[:SHOW_PATHS]
585
604
  more = e.get(b, len(ps)) - len(show)
586
- out.append(f"{indent}{BUCKET_SHORT[b]}: " + ", ".join(show) + (f" … +{more} more (--all-files)" if more > 0 else ""))
605
+ if b == "excluded":
606
+ reasons = e.get("exclude_reasons") or {}
607
+ body = ", ".join(f"{p} ({reasons.get(p) or _exclude_reason(p)})" for p in show)
608
+ else:
609
+ body = ", ".join(show)
610
+ out.append(f"{indent}{BUCKET_SHORT[b]}: " + body + (f" … +{more} more (--all-files)" if more > 0 else ""))
587
611
  return out
588
612
 
589
613
 
@@ -720,11 +744,12 @@ def render(covs: dict[str, dict | None], all_files: bool = False) -> str:
720
744
  for e in gaps(cov):
721
745
  any_gap = True
722
746
  exts = ", ".join(f"{k} {v}" for k, v in sorted(e["by_ext"].items()))
747
+ shown = _shown_lang(e)
723
748
  if e.get("files_complete") is False:
724
749
  parts = [f"{e[b]} {BUCKET_SHORT[b]}" for b in BUCKETS if e.get(b)]
725
- line = f" {e['language']}: {e['files']} files ({exts}) {e['indexed']} indexed, " + ", ".join(parts)
750
+ line = f" {shown}: {e['files']} files ({exts}) {e['indexed']} indexed, " + ", ".join(parts)
726
751
  else:
727
- line = f" {e['language']}: {e['files']} files ({exts}) {e['status'].replace('_', ' ')}"
752
+ line = f" {shown}: {e['files']} files ({exts}) {e['status'].replace('_', ' ')}"
728
753
  if e.get("reason"):
729
754
  line += f": {e['reason']}"
730
755
  out.append(line)
@@ -795,7 +820,7 @@ def note(covs: dict[str, dict | None]) -> str:
795
820
  for e in gaps(c):
796
821
  what = (f"{e['indexed']} of {e['files']} files indexed" if e.get("files_complete") is False
797
822
  else f"{e['files']} files, {e['status'].replace('_', ' ')}")
798
- bad.append(f"{e['language']} ({what}{', ' + r if len(covs) > 1 else ''})")
823
+ bad.append(f"{_shown_lang(e)} ({what}{', ' + r if len(covs) > 1 else ''})")
799
824
  bs = [b for c in covs.values() for b in blind_spots(c)]
800
825
  bs_txt = f"; blind spots: {_bs_count(bs)} (see coverage)" if bs else ""
801
826
  nerr = sum(e.get("syntax_error_files", 0) for c in covs.values() for e in (c or {}).get("languages", []))
@@ -956,6 +981,18 @@ def completeness_for(store, node_ids=None, categories=("route", "handler"), whol
956
981
  categories=categories, ids=set(node_ids), files=sc["files"], **kw)
957
982
 
958
983
 
984
+ def _unsupported_text(uns: dict) -> str:
985
+ """`unsupported: sh 3`. A single-repo DB drops a `shop/sh` prefix; a combined graph keeps `api/sh`."""
986
+ keys = list(uns)
987
+ prefixes = {k.partition("/")[0] for k in keys if "/" in k}
988
+ drop = len(prefixes) <= 1
989
+ parts = []
990
+ for k, v in sorted(uns.items()):
991
+ label = k.partition("/")[2] if drop and "/" in k else k
992
+ parts.append(f"{label} {v}")
993
+ return "unsupported: " + ", ".join(parts)
994
+
995
+
959
996
  def possibly_more(comp: dict) -> str:
960
997
  """'1 unmodelled route registration, 2 Python files not indexed' for an incomplete answer, '' when complete."""
961
998
  if comp.get("complete"):
@@ -990,7 +1027,7 @@ def possibly_more(comp: dict) -> str:
990
1027
  parts.append(f"{len(se)} file{'s' if len(se) != 1 else ''} with syntax errors ({x['file']}{pos}"
991
1028
  + (f" +{len(se) - 1}" if len(se) > 1 else "") + ")")
992
1029
  if comp.get("unsupported"):
993
- parts.append("unsupported: " + ", ".join(f"{k} {v}" for k, v in sorted(comp["unsupported"].items())))
1030
+ parts.append(_unsupported_text(comp["unsupported"]))
994
1031
  if comp.get("recorded") is False:
995
1032
  parts.append("coverage not recorded")
996
1033
  return ", ".join(parts)
@@ -292,8 +292,35 @@ def read_spring_datasources(root: Path) -> list:
292
292
  out.append(fact)
293
293
  return out
294
294
 
295
+
296
+ CONNECTION_EDGE_KINDS = ("READS_TABLE", "WRITES_TABLE", "READS_COLUMN", "WRITES_COLUMN", "MENTIONS_COLUMN")
297
+
298
+
299
+ def table_connections(builder) -> int:
300
+ """`attrs.connections` of a table node: `{connection: edge count}` over its table / column edges that carry
301
+ `attrs.connection` (most used first). One table name used on several connections stays one node. Not tied to an ORM:
302
+ a plugin only has to set `attrs.connection` on its table / column edges."""
303
+ counts: dict[str, dict[str, int]] = {}
304
+ for e in builder.edges.values():
305
+ conn = (e.attrs or {}).get("connection")
306
+ if e.kind not in CONNECTION_EDGE_KINDS or not conn:
307
+ continue
308
+ key = e.dst.split(":", 1)[1]
309
+ tid = f"table:{key}" if e.dst.startswith("table:") else f"table:{key.rsplit('.', 1)[0]}"
310
+ counts.setdefault(tid, {})
311
+ counts[tid][conn] = counts[tid].get(conn, 0) + 1
312
+ n = 0
313
+ for tid, c in counts.items():
314
+ node = builder.nodes.get(tid)
315
+ if node is not None:
316
+ node.attrs["connections"] = dict(sorted(c.items(), key=lambda kv: (-kv[1], kv[0])))
317
+ n += 1
318
+ return n
319
+
320
+
295
321
  def attach(builder, root: Path) -> dict:
296
322
  root = Path(root)
323
+ table_connections(builder)
297
324
  envs = {n.id[len("env:"):]: n for n in builder.nodes.values() if n.kind == "env"}
298
325
  conns = [n for n in builder.nodes.values() if n.kind == "connection"]
299
326
  # Spring datasources before the empty-check so a repo with only application*.properties still indexes (#41)
@@ -646,6 +673,16 @@ def attach(builder, root: Path) -> dict:
646
673
  (builder.nodes[nid].attrs or {}).get("confidence") or "resolved",
647
674
  op="table", via="laravel connection")
648
675
  st["tables"] = st.get("tables", 0) + 1
676
+ # a table used on several connections: one CONNECTS_TO per connection that maps to a system, not only the first
677
+ for n in builder.nodes.values():
678
+ if n.kind != "table":
679
+ continue
680
+ for cname in (n.attrs or {}).get("connections") or {}:
681
+ nid = conn_ext.get(f"connection:{cname}")
682
+ if nid:
683
+ builder.add_edge(n.id, nid, "CONNECTS_TO", n.file, n.line,
684
+ (builder.nodes[nid].attrs or {}).get("confidence") or "resolved",
685
+ op="table", via=f"connection {cname}")
649
686
 
650
687
  # ---- ORM tables without a datasource block: attach to the sole SQL system of the project (#41 step 2)
651
688
  # Immich (Kysely + DB_URL), Nest TypeORM (@Entity + DATABASE_URL) when no DataSource fact named them.
@@ -161,7 +161,7 @@ def has_type(host: str) -> bool:
161
161
 
162
162
  def config_path(host: str, scope: str, root: Path) -> Path:
163
163
  """Filesystem path for a host and scope. Claude Code global has no file cg edits."""
164
- root = Path(root)
164
+ root = _child(root)
165
165
  if host == "claude" and scope == "global":
166
166
  raise InstallError("Claude Code global scope is changed with the claude CLI, not a file")
167
167
  if host == "claude-desktop" and scope == "project":