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.
- {cg_code_graph-0.21.2/cg_code_graph.egg-info → cg_code_graph-0.22.0}/PKG-INFO +2 -2
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/README.md +1 -1
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/__init__.py +1 -1
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/cli.py +23 -8
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/indexer.py +17 -1
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/link.py +14 -1
- cg_code_graph-0.22.0/cg_code_graph/mcp_graphs.py +438 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/mcp_install.py +233 -13
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/mcp_server.py +200 -6
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/platforms.py +32 -3
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/plugin.py +55 -14
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/query.py +41 -6
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0/cg_code_graph.egg-info}/PKG-INFO +2 -2
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/SOURCES.txt +8 -0
- cg_code_graph-0.22.0/tests/test_issue_202.py +79 -0
- cg_code_graph-0.22.0/tests/test_issue_205.py +36 -0
- cg_code_graph-0.22.0/tests/test_issue_206.py +32 -0
- cg_code_graph-0.22.0/tests/test_issue_208.py +45 -0
- cg_code_graph-0.22.0/tests/test_issue_210.py +51 -0
- cg_code_graph-0.22.0/tests/test_issue_211_used_at.py +71 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mcp_install.py +1 -1
- cg_code_graph-0.22.0/tests/test_mcp_multi_graph.py +282 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/LICENSE +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/MANIFEST.in +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/__main__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/affected.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/agent_rules.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/agents.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/aitools.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/android_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/apple_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/apps.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/blindspots.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/bridges.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/brokers.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/concepts.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/config.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/cache.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/detect.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/env.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/extractors.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/fsutil.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/generated.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/model.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/paths.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/redact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/store.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/core/syntax_errors.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/coverage.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/dart_isolates.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/doctor.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/explore.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/external.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/graphql.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/guard_facts.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/hooks.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/insecure_transport.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/jobs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/lint_async.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/local_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/local_sockets.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/parity.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/parity_structure.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/payload.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plans.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/platform_scan.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/astro/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/astro/content.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/astro/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/cfamily/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/cfamily/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/cfamily/syntax.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/bridges.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/extractor/bin/extract.dart +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/extractor/pubspec.lock +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/extractor/pubspec.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/http.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/models.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/dart/program.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/extras.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/models.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/schemas.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/shapes.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/django/urls.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/express/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/express/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/flutter/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/flutter/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/java/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/java/exact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/java/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/jvm/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/jvm/interop.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/jvm/spring.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/exact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/kotlin/reparse.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/broadcast.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/massassign.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/tests.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/laravel/values.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/gates.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/runner.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/scipread.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/native/ts.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nest/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nest/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nextjs/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nextjs/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nuxt/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/nuxt/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/external.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/extractor/composer.json +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/extractor/composer.lock +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/extractor/extract.php +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/gating.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/http_client.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/inline_guards.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/php/strings.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/aitools.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/external.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/fields.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/refs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/roots.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/socketio.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/subproc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/tests.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/python/values.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/pyweb/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/pyweb/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/pyweb/values.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/cargo.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/rust/syntax.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/importer.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/scip.proto +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/scip/scip_pb2.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/stubs/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/stubs/plugins.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/baseurl.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/exact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/indexstore.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/swift/packages.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/baseurl.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/extract.mjs +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/fw.mjs +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/package-lock.json +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/package.json +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/extractor/rr.mjs +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/nav.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/plugin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/ts/react_router.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/tsweb/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/tsweb/common.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/plugins/tsweb/data.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/c_cpp.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/common.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/dart.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/django-ninja.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/django.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/djangorestframework.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/express.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/java.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/kotlin.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/laravel.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/nest.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/nextjs.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/nuxt.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/php.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/python.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/react-router.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/rust.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/spring.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/swift.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/presets/typescript.yaml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/process_runs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/builtin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/matchers.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/protocols/view.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime_events.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime_native.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/realtime_ws.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/roundtrip.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/routes.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/rpc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/sdk_systems.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/sockets.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/ssrf_input.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/starters.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/surface.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/tests_index.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/udp_apps.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/__init__.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/graph.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/server.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/app.css +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/app.js +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/index.html +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/layered.js +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/VERSIONS.txt +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/cose-base.js +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/cytoscape-fcose.js +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/cytoscape.min.js +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/static/vendor/layout-base.js +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/tools/package-lock.json +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/tools/package.json +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/viz/tools/shoot.mjs +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/watch.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/webhook_subs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/webhooks.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph/xcode.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/dependency_links.txt +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/entry_points.txt +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/requires.txt +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/cg_code_graph.egg-info/top_level.txt +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/pyproject.toml +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/setup.cfg +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_affected.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_agents_install.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_agents_md.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ai_tools.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_android_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_apple_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_astro.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_astro_content.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_astro_server.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_bridges.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_bridges_pigeon_monorepo.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_brokers.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cache_clean.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cache_invalidation.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cache_migration.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_channels_tests.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_cli_output.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_completeness.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_config_extras.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_coverage.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_coverage_ts_hint.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_dart_isolates.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_db_connections.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_dispatch_interfaces.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_django_flutter.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_docs_languages.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_docs_links.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_echo_ref.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_echo_wrapper.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_elysia.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_enum_constants.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_env.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_explore.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_external.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_fp_batch.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_gating.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_generated.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_graphql.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_hooks.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_impact_overrides.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_index_isolation.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_inherited_overrides.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_inline_guards.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_192.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_203.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_207.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_209.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_issue_211.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_java.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_java_exact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_jobs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_js_refs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_js_runtime.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_binding.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_exact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_fields.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_mixed.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_nav_consts.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_kotlin_props.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_laravel_determinism.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_laravel_resources.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_lint_async.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_listing_files.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_local_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_local_sockets.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mass_assignment.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mcp.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_mcp_index.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_native_cfamily.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_native_concurrency.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_native_rust.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_nuxt_import_dirs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_nuxt_rootsrc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_packaging.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_parity.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_parity_structure.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_php_http.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_php_props.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_plain_js.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_plans.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platform_gaps.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platform_type_variants.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platforms.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_platforms_apple.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_presets_config.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_process_ipc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_process_runs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_protocols.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_app_tests_module.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_collection_chains.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_compat.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_entry_refs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_fields.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_infer_cycles.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_roots.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_subprocess_tests.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_tests.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_web_hosts.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_web_routes.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_python_web_routes_more.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_react_router.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_readers_writers_specs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_realtime.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_realtime_native.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_redact_salt.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_request_keys.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_roundtrip.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_route_tables.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_routes_search_explain.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_rpc.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_scip_health.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sdk_external.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sdk_external_infra.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sdk_external_mail.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_snippet.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_sockets.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_spring.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ssrf.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_starters_budget.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_surface.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_surface_transport.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_binding.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_exact.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_facts.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_fields.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_modules.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_more.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_nav_values.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_parse_errors.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_props.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_sdk.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_testing.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_swift_values.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_tests_scope.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_fields.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_fields_js_vue.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_file_specs.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_frameworks.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_node_http.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_nuxt.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_ts_src_tsconfig.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_unguarded.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_values.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_viz.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_vue_nav.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_watch.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_webhooks.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_webhooks_152.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_webhooks_152b.py +0 -0
- {cg_code_graph-0.21.2 → cg_code_graph-0.22.0}/tests/test_websockets.py +0 -0
- {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.
|
|
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.
|
|
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
|
-
|
|
679
|
-
|
|
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
|
-
|
|
684
|
-
|
|
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
|
-
|
|
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)
|