graphifyy 0.9.74__tar.gz → 0.9.76__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.
- {graphifyy-0.9.74/graphifyy.egg-info → graphifyy-0.9.76}/PKG-INFO +17 -2
- {graphifyy-0.9.74 → graphifyy-0.9.76}/README.md +14 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/__main__.py +3 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/analyze.py +13 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/build.py +41 -4
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/cache.py +46 -5
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/cli.py +138 -34
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/cross_repo_calls.py +1 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/cross_repo_types.py +1 -1
- graphifyy-0.9.76/graphify/csharp_dispatch.py +39 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/dedup.py +39 -32
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/detect.py +43 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/export.py +29 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extract.py +253 -41
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/bash.py +48 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/dart.py +40 -15
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/elixir.py +37 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/engine.py +408 -4
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/json_config.py +45 -9
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/pascal.py +32 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/rust.py +52 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/vbnet.py +12 -3
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/zig.py +45 -6
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/hooks.py +73 -2
- graphifyy-0.9.74/graphify/csharp_dispatch.py → graphifyy-0.9.76/graphify/interface_dispatch.py +40 -35
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/llm.py +7 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/serve.py +103 -22
- graphifyy-0.9.76/graphify/swift_dispatch.py +46 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76/graphifyy.egg-info}/PKG-INFO +17 -2
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphifyy.egg-info/SOURCES.txt +13 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/pyproject.toml +3 -2
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_analyze.py +54 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cache.py +32 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cli_export.py +103 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cpp_nested_and_cli.py +39 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cross_repo_member_calls.py +1 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cross_repo_shared_types.py +1 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_interface_dispatch.py +4 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_partial_classes.py +89 -1
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_dart.py +84 -2
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_dedup.py +82 -14
- graphifyy-0.9.76/tests/test_dedup_shrink_refuses_force_write.py +209 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_detect.py +161 -0
- graphifyy-0.9.76/tests/test_elixir_unqualified_call_scope.py +182 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extract.py +639 -16
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hollow_chunks_arm_shrink_guard.py +2 -2
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hook_guard.py +46 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hooks.py +64 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_incomplete_build_guard.py +3 -2
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_inferred_confidence_rubric.py +72 -12
- graphifyy-0.9.76/tests/test_json_schema_config.py +227 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_languages.py +152 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_llm_backends.py +20 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_loose_sibling_import_resolution.py +8 -4
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_merge_graphs_cli.py +81 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_partial_extraction_warning.py +63 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pascal.py +46 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_path_cli.py +208 -0
- graphifyy-0.9.76/tests/test_php_language_construct_calls.py +258 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_python_import_resolution.py +96 -0
- graphifyy-0.9.76/tests/test_rust_macro_rules.py +93 -0
- graphifyy-0.9.76/tests/test_scala_context_bounds.py +139 -0
- graphifyy-0.9.76/tests/test_scala_top_level_binding.py +139 -0
- graphifyy-0.9.76/tests/test_scala_type_definition.py +135 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_serve.py +24 -0
- graphifyy-0.9.76/tests/test_stat_index_multi_root.py +110 -0
- graphifyy-0.9.76/tests/test_svelte_extraction.py +205 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_swift_cross_file_calls.py +3 -3
- graphifyy-0.9.76/tests/test_swift_protocol_dispatch.py +266 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_vbnet_extractor.py +36 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/LICENSE +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/LICENSE-MIT +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/NOTICE +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/__init__.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/_minhash.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/affected.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/always_on/agents-md.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/always_on/antigravity-rules.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/always_on/claude-md.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/always_on/gemini-md.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/always_on/kiro-steering.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/always_on/vscode-instructions.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/benchmark.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/callflow_html.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/cargo_introspect.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/cluster.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/command-kilo.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/diagnostics.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/exporters/__init__.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/exporters/base.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/exporters/graphdb.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/exporters/html.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/__init__.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/apex.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/base.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/blade.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/cobol.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/commonlisp.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/csharp.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/dm.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/erlang.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/fortran.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/go.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/julia.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/markdown.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/models.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/objc.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/ocaml.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/pascal_forms.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/powershell.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/r.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/razor.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/robot.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/sln.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/solidity.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/sql.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/terraform.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/extractors/verilog.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/file_slice.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/global_graph.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/google_workspace.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/ids.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/install.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/manifest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/manifest_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/markdown_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/mcp_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/multigraph_compat.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/pascal_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/paths.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/pg_introspect.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/prs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/querylog.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/reflect.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/report.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/resolver_registry.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/ruby_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/scip_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/security.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/semantic_cleanup.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-agents.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-aider.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-amp.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-claw.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-codex.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-copilot.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-devin.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-droid.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-kilo.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-kiro.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-opencode.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-pi.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-trae.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-vscode.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill-windows.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skill.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/agents/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/amp/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claude/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/claw/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/codex/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/copilot/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/droid/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kilo/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/kiro/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/opencode/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/pi/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/trae/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/vscode/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/add-watch.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/exports.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/extraction-spec.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/github-and-merge.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/hooks.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/query.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/transcribe.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/skills/windows/references/update.md +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/symbol_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/transcribe.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/tree_html.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/validate.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/watch.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphify/wiki.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphifyy.egg-info/dependency_links.txt +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphifyy.egg-info/entry_points.txt +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphifyy.egg-info/requires.txt +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/graphifyy.egg-info/top_level.txt +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/setup.cfg +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_affected_cli.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_affected_member_seed.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_agents_platform.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_anthropic_custom_endpoint.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_antigravity_install.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_apm_fallback_version.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_architecture_doc.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_astro_extraction.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_astro_import_ids.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_atomic_canvas_export.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_atomic_version_stamp.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_atomic_writes.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_backend_env_isolation.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_backend_extras.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_benchmark.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_benchmark_raw_graph.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_blade_extractor.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_build.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_build_merge_dedup_scope.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_build_merge_hyperedges_and_prune.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_build_merge_shrink_guard.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_builtin_global_type_refs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_callflow_html.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cargo_introspect.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cargo_missing_manifest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_carried_hyperedge_remap.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_case_sensitive_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_charmap_encoding.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_chunking.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cjs_module_extension.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_claude_cli_backend.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_claude_md.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cli_broken_pipe.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cli_help.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cluster.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cluster_exclude_hubs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cobol_extractor.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_codebuddy.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_community_hub_labels.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_community_labels_skill.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_confidence.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_corrupt_graph_json.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cpp_method_declarations.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cpp_objc_cross_file_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cpp_preprocess.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cross_extension_reexport_self_cycle.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cross_language_call_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_cross_repo_external_call_guards.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_call_site_generic_args.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_enum_members.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_field_generic_args.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_generic_callsites.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_member_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_member_nodes.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_object_creation.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_tuple_type_refs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_csharp_type_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_dedup_remaps_hyperedges.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_dedup_survivor_richness.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_definition_file_portability.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_devin.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_docx_to_markdown.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_dotnet.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_duplicate_annotation_edges.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_elixir_import_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_erlang_extractor.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_evidence_binding.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_explain_cli.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_export.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_export_control_characters.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_export_idempotent_writes.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_export_path_length.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_external_stub_endpoints.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extract_cache_location.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extract_cli.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extract_code_only_cli.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extract_php_closures.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extraction_spec_ids.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_extractors_registry.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_falkordb_integration.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_file_label_disambiguation.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_file_node_id_spec.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_file_slice.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_file_truncation_warning.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_forwarding_review_findings.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_gemini_hook.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_global_add_tag_inference.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_global_graph.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_go_builtin_call_targets.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_go_import_repoint.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_go_interface_methods.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_go_qualified_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_god_nodes_cli.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_god_nodes_exclude_hubs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_google_workspace.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_graphdb_push_indexes.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_home_sandbox.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hook_chain_survives_skip.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hook_guard_token_match.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hook_out_of_project_paths.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hook_strict.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hyperedge_member_shapes.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hyperedge_roundtrip.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_hypergraph.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_id_normalization_contract.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ignore_file_encoding.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_image_vision.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_import_extension_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_import_self_loops.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_imported_export_forwarding.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_incremental.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_incremental_mtime_collision.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_arrow_single_param_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_block_scoped_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_catch_binding_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_external_import_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_for_of_binding_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_function_expression_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_call_nested_closure_shadow.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_dispatch.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_dispatch_assign_return.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_indirect_dispatch_getattr.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ingest_url_type.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_inherited_field_receivers.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_injection_sentinel_coverage.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install_references.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install_roundtrip.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install_strings.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install_upgrade.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install_version_stamp.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_install_version_warning.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_issue_3405_python_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_issue_3472_source_file_collision.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_java_enum_members.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_java_member_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_java_type_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_callback_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_destructured_export.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_dynamic_import_affected.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_dynamic_imports.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_exported_fn_call_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_exported_scalar_bindings.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_import_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_module_level_anonymous_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_js_this_member_expressions.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_jsconfig_baseurl.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_jsx_component_usage_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_kotlin_grammar.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_kotlin_object_literal.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_label_retry.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_labeling.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_language_resolvers.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_llm_parser.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_llm_parser_reasoning.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_long_path_hashing.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_lua_import.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_lua_method_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_manifest_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_manifest_tomli_required.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_markdown_code_spans.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_mcp_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_merge_chunks_validation.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_minhash.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_multigraph_compat.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_multigraph_diagnostics.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_multilang.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_no_dedup_flag.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_node_id_canonical.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_non_regular_files.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_non_string_node_ids.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_objc_category_interfaces.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_objc_field_table_remap.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_objc_member_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_objc_property_ivar_receivers.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_obsidian_dangling_member.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_obsidian_filename_cap.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_obsidian_unicode_tags.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_obsidian_vault_migration.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ocaml.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_office_incremental.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_office_limits.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ollama.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ollama_retry_cap.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_openai_custom_endpoint.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_out_dir_evidence.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_oversized_document_slicing.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_owned_type_sources.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_package_json_subpath_imports.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_partial_cache.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pascal_call_scoping.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pascal_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_paths.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pdf_extra_warning.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pdf_slicing.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pdf_token_estimate.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pg_introspect.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_phantom_cross_package_call.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_phantom_external_import.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_php_object_creation.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_php_type_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pin_hash_seed.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_pipeline.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_provider_registry.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_prs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_prune_sweeps_orphans.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_python_decorators.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_python_parse_memoization.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_python_underscore_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_query_cli.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_query_induced_edges.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_query_mcp_direction.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_query_names_its_graph.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_querylog.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_r_extractor.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_rationale.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_read_hook.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_reflect.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_relation_collapse_precedence.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_replace_or_append_section.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_report.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_report_gap_thresholds.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_resolve_memoization.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ruby_bare_self_send_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ruby_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_rust_builtin_type_hubs.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_rust_self_member_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_scala_abstract_methods.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_scala_self_type.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_scip_ingest.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_search_hook.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_security.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_semantic_cache_basename_recovery.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_semantic_cache_out_root.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_semantic_cleanup.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_semantic_fragment_sanitize.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_semantic_id_remap_root.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_semantic_similarity.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_serve_http.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_settings_merge.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_skill_auto_refresh.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_skill_version_warning.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_skillgen.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_skillgen_input_path_injection.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_solidity_extractor.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_source_key_memoization.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_sourceless_call_targets.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_src_layout_import_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_stale_prune.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_stat_index_husk.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_stat_index_portability.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_swift_builtin_noise.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_swift_computed_properties.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_swift_import_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_swift_protocol_requirements.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_symbol_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_terraform.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_terraform_modules.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_trailing_newline_not_a_syntax_error.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_transcribe.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_tree_html.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_abstract_methods.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_decorators.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_generators.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_import_require.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_import_type_arguments.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_inheritance.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_namespace.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_new_expression_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_parse_warning.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_ts_receiver_member_calls.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_type_only_import_cycles.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_typescript_enum_members.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_typescript_module_extensions.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_uninstall_scope.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_uninstall_symlink.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_unmapped_at_alias_resolution.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_unverified_semantic_shrink.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_validate.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_vue_extraction.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_walk_python_tree_iterative.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_watch.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_watch_manifest_location.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_wheel_packaging.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_wiki.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_wiki_link_filename_parity.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_wiki_truncation_indicator.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_word_count_cache.py +0 -0
- {graphifyy-0.9.74 → graphifyy-0.9.76}/tests/test_zero_node_no_cache.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphifyy
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.76
|
|
4
4
|
Summary: AI coding assistant skill (Claude Code, CodeBuddy, Codex, OpenCode, Kilo Code, Cursor, Gemini CLI, Aider, OpenClaw, Factory Droid, Trae, Hermes, Kiro, Pi, Devin CLI, Google Antigravity) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
|
-
Project-URL: Homepage, https://
|
|
6
|
+
Project-URL: Homepage, https://graphify.com
|
|
7
|
+
Project-URL: Documentation, https://docs.graphify.com
|
|
7
8
|
Project-URL: Repository, https://github.com/Graphify-Labs/graphify
|
|
8
9
|
Project-URL: Issues, https://github.com/Graphify-Labs/graphify/issues
|
|
9
10
|
Keywords: claude,claude-code,codex,opencode,kilo,cursor,gemini,aider,kiro,pi,devin,knowledge-graph,rag,graphrag,obsidian,community-detection,tree-sitter,leiden,llm
|
|
@@ -170,6 +171,7 @@ Dynamic: license-file
|
|
|
170
171
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue" alt="License: Apache-2.0"/></a>
|
|
171
172
|
<a href="https://pepy.tech/project/graphifyy"><img src="https://img.shields.io/pepy/dt/graphifyy?color=blue&label=downloads" alt="Downloads"/></a>
|
|
172
173
|
<a href="https://docs.graphify.com"><img src="https://img.shields.io/badge/Docs-docs.graphify.com-0b7285?style=flat&logo=readthedocs&logoColor=white" alt="Docs"/></a>
|
|
174
|
+
<a href="https://smithery.ai/servers/graphify/graphify"><img src="https://img.shields.io/badge/Smithery-MCP%20server-5c4ee5?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTEyIDJMMiA3djEwbDEwIDUgMTAtNVY3eiIvPjwvc3ZnPg==" alt="Smithery"/></a>
|
|
173
175
|
<a href="https://discord.gg/XDnKVpzdXB"><img src="https://img.shields.io/badge/Discord-Join-5865F2?style=flat&logo=discord&logoColor=white" alt="Discord"/></a>
|
|
174
176
|
<a href="https://www.youtube.com/@graphifylabs"><img src="https://img.shields.io/badge/YouTube-Graphify%20Labs-FF0000?style=flat&logo=youtube&logoColor=white" alt="YouTube"/></a>
|
|
175
177
|
<a href="https://www.linkedin.com/company/graphify-labs"><img src="https://img.shields.io/badge/LinkedIn-Graphify%20Labs-0077B5?logo=linkedin" alt="LinkedIn"/></a>
|
|
@@ -662,6 +664,19 @@ python -m graphify.serve graphify-out/graph.json --transport http --host 0.0.0.0
|
|
|
662
664
|
|
|
663
665
|
The MCP server gives your assistant structured access: `query_graph`, `get_node`, `get_neighbors`, `shortest_path`, `list_prs`, `get_pr_impact`, `triage_prs`.
|
|
664
666
|
|
|
667
|
+
### One-click install (VS Code · Smithery)
|
|
668
|
+
|
|
669
|
+
Prefer not to edit MCP config by hand? Register the graphify MCP server in one step. Run `/graphify` first so a `graphify-out/graph.json` exists in the workspace; the server reads it on launch.
|
|
670
|
+
|
|
671
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=graphify&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22graphifyy%5Bmcp%5D%22%2C%22graphify-mcp%22%5D%7D)
|
|
672
|
+
|
|
673
|
+
The button adds a `graphify` server that launches with `uvx --from "graphifyy[mcp]" graphify-mcp` (no API key, no prior install). Or install via [Smithery](https://smithery.ai/servers/graphify/graphify) for Claude, Cursor, VS Code, and other clients:
|
|
674
|
+
|
|
675
|
+
```bash
|
|
676
|
+
# pick your client (claude, cursor, vscode, windsurf, ...)
|
|
677
|
+
npx -y @smithery/cli install graphify/graphify --client claude
|
|
678
|
+
```
|
|
679
|
+
|
|
665
680
|
### Shared HTTP server
|
|
666
681
|
|
|
667
682
|
`--transport stdio` (the default) spawns one local server per developer. `--transport http` serves the same tools over the MCP Streamable HTTP transport, so a single shared process can serve the graph for the whole team — clients point their IDE MCP config at `http://<host>:8080/mcp` instead of running graphify locally.
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue" alt="License: Apache-2.0"/></a>
|
|
21
21
|
<a href="https://pepy.tech/project/graphifyy"><img src="https://img.shields.io/pepy/dt/graphifyy?color=blue&label=downloads" alt="Downloads"/></a>
|
|
22
22
|
<a href="https://docs.graphify.com"><img src="https://img.shields.io/badge/Docs-docs.graphify.com-0b7285?style=flat&logo=readthedocs&logoColor=white" alt="Docs"/></a>
|
|
23
|
+
<a href="https://smithery.ai/servers/graphify/graphify"><img src="https://img.shields.io/badge/Smithery-MCP%20server-5c4ee5?style=flat&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTEyIDJMMiA3djEwbDEwIDUgMTAtNVY3eiIvPjwvc3ZnPg==" alt="Smithery"/></a>
|
|
23
24
|
<a href="https://discord.gg/XDnKVpzdXB"><img src="https://img.shields.io/badge/Discord-Join-5865F2?style=flat&logo=discord&logoColor=white" alt="Discord"/></a>
|
|
24
25
|
<a href="https://www.youtube.com/@graphifylabs"><img src="https://img.shields.io/badge/YouTube-Graphify%20Labs-FF0000?style=flat&logo=youtube&logoColor=white" alt="YouTube"/></a>
|
|
25
26
|
<a href="https://www.linkedin.com/company/graphify-labs"><img src="https://img.shields.io/badge/LinkedIn-Graphify%20Labs-0077B5?logo=linkedin" alt="LinkedIn"/></a>
|
|
@@ -512,6 +513,19 @@ python -m graphify.serve graphify-out/graph.json --transport http --host 0.0.0.0
|
|
|
512
513
|
|
|
513
514
|
The MCP server gives your assistant structured access: `query_graph`, `get_node`, `get_neighbors`, `shortest_path`, `list_prs`, `get_pr_impact`, `triage_prs`.
|
|
514
515
|
|
|
516
|
+
### One-click install (VS Code · Smithery)
|
|
517
|
+
|
|
518
|
+
Prefer not to edit MCP config by hand? Register the graphify MCP server in one step. Run `/graphify` first so a `graphify-out/graph.json` exists in the workspace; the server reads it on launch.
|
|
519
|
+
|
|
520
|
+
[](https://insiders.vscode.dev/redirect/mcp/install?name=graphify&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22graphifyy%5Bmcp%5D%22%2C%22graphify-mcp%22%5D%7D)
|
|
521
|
+
|
|
522
|
+
The button adds a `graphify` server that launches with `uvx --from "graphifyy[mcp]" graphify-mcp` (no API key, no prior install). Or install via [Smithery](https://smithery.ai/servers/graphify/graphify) for Claude, Cursor, VS Code, and other clients:
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
# pick your client (claude, cursor, vscode, windsurf, ...)
|
|
526
|
+
npx -y @smithery/cli install graphify/graphify --client claude
|
|
527
|
+
```
|
|
528
|
+
|
|
515
529
|
### Shared HTTP server
|
|
516
530
|
|
|
517
531
|
`--transport stdio` (the default) spawns one local server per developer. `--transport http` serves the same tools over the MCP Streamable HTTP transport, so a single shared process can serve the graph for the whole team — clients point their IDE MCP config at `http://<host>:8080/mcp` instead of running graphify locally.
|
|
@@ -760,6 +760,9 @@ def _run_cli() -> None:
|
|
|
760
760
|
print(" merge-driver <base> <current> <other> git merge driver: union-merge two graph.json files (set up via hook install)")
|
|
761
761
|
print(" merge-graphs <g1> <g2> merge two or more graph.json files into one cross-repo graph")
|
|
762
762
|
print(" --out <path> output path (default: graphify-out/merged-graph.json)")
|
|
763
|
+
print(" --previous <path> restore the previous merged clustering's community ids")
|
|
764
|
+
print(" (by node id) instead of each input's own per-source ids,")
|
|
765
|
+
print(" so a later cluster-only run reuses labels correctly")
|
|
763
766
|
print(" --branch <branch> checkout a specific branch (default: repo default)")
|
|
764
767
|
print(" --out <dir> clone to a custom directory (default: ~/.graphify/repos/<owner>/<repo>)")
|
|
765
768
|
print(" add <url> fetch a URL and save it to ./raw, then update the graph")
|
|
@@ -468,6 +468,9 @@ def suggest_questions(
|
|
|
468
468
|
Generate questions the graph is uniquely positioned to answer.
|
|
469
469
|
Based on: AMBIGUOUS edges, bridge nodes, underexplored god nodes, isolated nodes.
|
|
470
470
|
Each question has a 'type', 'question', and 'why' field.
|
|
471
|
+
Interleave question types before applying top_n so an abundant early type
|
|
472
|
+
cannot crowd out later signals. Preserve the existing order within each type
|
|
473
|
+
and category generation order when the limit is smaller than the type count.
|
|
471
474
|
"""
|
|
472
475
|
if community_labels:
|
|
473
476
|
community_labels = {int(k) if isinstance(k, str) else k: v for k, v in community_labels.items()}
|
|
@@ -583,7 +586,16 @@ def suggest_questions(
|
|
|
583
586
|
),
|
|
584
587
|
}]
|
|
585
588
|
|
|
586
|
-
|
|
589
|
+
from itertools import zip_longest
|
|
590
|
+
|
|
591
|
+
by_type: dict[str, list[dict]] = {}
|
|
592
|
+
for question in questions:
|
|
593
|
+
by_type.setdefault(question["type"], []).append(question)
|
|
594
|
+
diversified = [
|
|
595
|
+
question for row in zip_longest(*by_type.values())
|
|
596
|
+
for question in row if question is not None
|
|
597
|
+
]
|
|
598
|
+
return diversified[:top_n]
|
|
587
599
|
|
|
588
600
|
|
|
589
601
|
def graph_diff(G_old: nx.Graph, G_new: nx.Graph) -> dict:
|
|
@@ -70,9 +70,12 @@ _CONFIDENCE_RANK: dict[str, int] = {"EXTRACTED": 3, "INFERRED": 2, "AMBIGUOUS":
|
|
|
70
70
|
# on-disk graph.json (written by the incremental update path) keep the edge with
|
|
71
71
|
# no matching node — an undeclared endpoint every loader materialises as an
|
|
72
72
|
# attribute-less phantom (#2873). For these relations we instead mint a typed
|
|
73
|
-
# external stub node so every edge endpoint resolves.
|
|
74
|
-
#
|
|
75
|
-
#
|
|
73
|
+
# external stub node so every edge endpoint resolves. `calls` is intentionally
|
|
74
|
+
# NOT in this set: a `calls` edge to an external target only survives when the
|
|
75
|
+
# module was also imported (its import edge pre-mints the stub, see the Python
|
|
76
|
+
# external-call resolution in #3793); a `calls` edge to a never-imported target
|
|
77
|
+
# is still dropped as a phantom (#3156). External stubs stay out of god-node
|
|
78
|
+
# ranking regardless (analyze._is_concept_node filters source_file="").
|
|
76
79
|
_EXTERNAL_STUB_RELATIONS: frozenset[str] = frozenset(
|
|
77
80
|
{"imports", "imports_from", "re_exports"}
|
|
78
81
|
)
|
|
@@ -1564,6 +1567,7 @@ def build(
|
|
|
1564
1567
|
combined["input_tokens"] += ext.get("input_tokens", 0)
|
|
1565
1568
|
combined["output_tokens"] += ext.get("output_tokens", 0)
|
|
1566
1569
|
_root = str(Path(root).resolve()) if root else None
|
|
1570
|
+
_dedup_collapsed = 0
|
|
1567
1571
|
if dedup and combined["nodes"]:
|
|
1568
1572
|
# Numeric ids must be str before dedup, which keys on them and would
|
|
1569
1573
|
# raise TypeError in _pick_winner's regex search (#2326). build_from_json
|
|
@@ -1585,6 +1589,7 @@ def build(
|
|
|
1585
1589
|
n["source_file"] = _norm_source_file(n["source_file"], _root)
|
|
1586
1590
|
if "definition_file" in n:
|
|
1587
1591
|
n["definition_file"] = _norm_source_file(n["definition_file"], _root)
|
|
1592
|
+
_before_dedup = len(combined["nodes"])
|
|
1588
1593
|
combined["nodes"], combined["edges"] = deduplicate_entities(
|
|
1589
1594
|
combined["nodes"], combined["edges"], communities={},
|
|
1590
1595
|
dedup_llm_backend=dedup_llm_backend, root=_root,
|
|
@@ -1593,7 +1598,28 @@ def build(
|
|
|
1593
1598
|
hyperedges=combined.get("hyperedges"),
|
|
1594
1599
|
protected_ids=protected_ids,
|
|
1595
1600
|
)
|
|
1596
|
-
|
|
1601
|
+
_dedup_collapsed = _before_dedup - len(combined["nodes"])
|
|
1602
|
+
G = build_from_json(combined, directed=directed, root=_root)
|
|
1603
|
+
# CLI reads this to tell a dedup shrink from a file deletion (#3774).
|
|
1604
|
+
# Popped before to_json so it is not stored in graph.json.
|
|
1605
|
+
if _dedup_collapsed:
|
|
1606
|
+
G.graph["_dedup_collapsed"] = _dedup_collapsed
|
|
1607
|
+
return G
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
def take_shrink_accounting(G) -> tuple[int, int]:
|
|
1611
|
+
"""Read and remove the #3774 counters.
|
|
1612
|
+
|
|
1613
|
+
``build`` / ``build_merge`` stash these on ``G.graph`` for the extract
|
|
1614
|
+
CLI. ``to_json`` also removes them so any other writer cannot persist
|
|
1615
|
+
them into graph.json.
|
|
1616
|
+
"""
|
|
1617
|
+
attrs = getattr(G, "graph", None)
|
|
1618
|
+
if not isinstance(attrs, dict):
|
|
1619
|
+
return 0, 0
|
|
1620
|
+
collapsed = int(attrs.pop("_dedup_collapsed", 0) or 0)
|
|
1621
|
+
pruned = int(attrs.pop("_pruned_node_count", 0) or 0)
|
|
1622
|
+
return collapsed, pruned
|
|
1597
1623
|
|
|
1598
1624
|
|
|
1599
1625
|
def _norm_label(label: str | None) -> str:
|
|
@@ -2249,6 +2275,17 @@ def build_merge(
|
|
|
2249
2275
|
if orphaned:
|
|
2250
2276
|
G.remove_nodes_from(orphaned)
|
|
2251
2277
|
n_nodes += len(orphaned)
|
|
2278
|
+
# Excuse only saved nodes this prune removed (#3774). A stub minted
|
|
2279
|
+
# in this run and then orphaned was never in graph.json, so counting
|
|
2280
|
+
# it would hide a dedup shrink. The print below still uses n_nodes,
|
|
2281
|
+
# which includes that stub.
|
|
2282
|
+
_disk_ids = {
|
|
2283
|
+
n.get("id") for n in _disk_nodes
|
|
2284
|
+
if isinstance(n, dict) and n.get("id") is not None
|
|
2285
|
+
}
|
|
2286
|
+
G.graph["_pruned_node_count"] = sum(
|
|
2287
|
+
1 for nid in (*to_remove, *orphaned) if nid in _disk_ids
|
|
2288
|
+
)
|
|
2252
2289
|
|
|
2253
2290
|
# Report only the prune entries that ACTUALLY matched something — not
|
|
2254
2291
|
# len(prune_sources), which counted every entry as pruned-from even
|
|
@@ -36,7 +36,7 @@ except Exception:
|
|
|
36
36
|
_EXTRACTOR_VERSION = "unknown"
|
|
37
37
|
|
|
38
38
|
# Bump when AST cache-key semantics change independently of the package version.
|
|
39
|
-
_AST_CACHE_SCHEMA =
|
|
39
|
+
_AST_CACHE_SCHEMA = 5 # Python receiver-shadow facts in persisted raw calls.
|
|
40
40
|
|
|
41
41
|
# Version dirs already swept this process — cleanup runs once per (base, version).
|
|
42
42
|
_cleaned_ast_dirs: set[str] = set()
|
|
@@ -205,6 +205,14 @@ _stat_index_root: Path | None = None
|
|
|
205
205
|
# (cache_root, #1774) — the two differ under --out and must not be conflated.
|
|
206
206
|
_stat_index_anchor: Path | None = None
|
|
207
207
|
_stat_index_dirty: bool = False
|
|
208
|
+
_stat_index_atexit_registered: bool = False
|
|
209
|
+
# The resolved on-disk path for the CURRENTLY bound root, captured at bind
|
|
210
|
+
# time (#3989). A mid-process root switch must flush the OUTGOING root to
|
|
211
|
+
# the file it was actually loaded from, not wherever the live _GRAPHIFY_OUT
|
|
212
|
+
# happens to point by the time the switch is detected — a caller following
|
|
213
|
+
# the documented one-root-per-call pattern (set _GRAPHIFY_OUT, then call)
|
|
214
|
+
# has already moved it on to the NEW root before the switch is noticed.
|
|
215
|
+
_stat_index_path: Path | None = None
|
|
208
216
|
|
|
209
217
|
|
|
210
218
|
# Filesystem mtime granularity, in nanoseconds. A stat signature only proves a
|
|
@@ -328,8 +336,31 @@ def _stat_index_file(root: Path) -> Path:
|
|
|
328
336
|
|
|
329
337
|
def _ensure_stat_index(root: Path, cache_root: "Path | None" = None) -> None:
|
|
330
338
|
global _stat_index, _stat_index_root, _stat_index_anchor, _stat_index_dirty
|
|
339
|
+
global _stat_index_atexit_registered, _stat_index_path
|
|
340
|
+
new_root = Path(cache_root if cache_root is not None else root).resolve()
|
|
331
341
|
if _stat_index_root is not None:
|
|
332
|
-
|
|
342
|
+
if _stat_index_root == new_root:
|
|
343
|
+
return
|
|
344
|
+
# A later call in the same process named a DIFFERENT cache root
|
|
345
|
+
# (#3989): the index was bound to the first root ever seen and never
|
|
346
|
+
# re-bound, so every root after the first served (on read) whatever
|
|
347
|
+
# the first root's file happened to contain, and (on write/exit)
|
|
348
|
+
# deposited its own freshly-computed entries into the FIRST root's
|
|
349
|
+
# file instead of its own — silently poisoning one project's
|
|
350
|
+
# stat-index.json with paths from a completely different project.
|
|
351
|
+
# Flush the outgoing root's own pending entries to its own file
|
|
352
|
+
# before switching, then load the new root fresh, so each root's
|
|
353
|
+
# file only ever holds that root's own entries.
|
|
354
|
+
warnings.warn(
|
|
355
|
+
f"stat index switched from cache root {str(_stat_index_root)!r} to "
|
|
356
|
+
f"{str(new_root)!r} within one process; each root's "
|
|
357
|
+
"stat-index.json now only reflects its own files, but library "
|
|
358
|
+
"callers crossing project roots in one process should still use "
|
|
359
|
+
"a fresh process per root to avoid losing the fastpath (#3989).",
|
|
360
|
+
RuntimeWarning,
|
|
361
|
+
stacklevel=3,
|
|
362
|
+
)
|
|
363
|
+
_flush_stat_index()
|
|
333
364
|
# _stat_index_root determines the cache FILE location, so honoring an
|
|
334
365
|
# explicit cache_root keeps detect()'s word-count cache under the requested
|
|
335
366
|
# --out dir instead of polluting the scanned corpus with a stray
|
|
@@ -337,9 +368,10 @@ def _ensure_stat_index(root: Path, cache_root: "Path | None" = None) -> None:
|
|
|
337
368
|
# in-memory keys stay absolute, but the on-disk index stores in-anchor keys
|
|
338
369
|
# relative so a moved/cloned corpus still hits (#2199) — same load/save
|
|
339
370
|
# re-anchoring the detect manifest uses.
|
|
340
|
-
_stat_index_root =
|
|
371
|
+
_stat_index_root = new_root
|
|
341
372
|
_stat_index_anchor = Path(root).resolve()
|
|
342
373
|
p = _stat_index_file(_stat_index_root)
|
|
374
|
+
_stat_index_path = p
|
|
343
375
|
_stat_index = {}
|
|
344
376
|
if p.exists():
|
|
345
377
|
try:
|
|
@@ -357,14 +389,23 @@ def _ensure_stat_index(root: Path, cache_root: "Path | None" = None) -> None:
|
|
|
357
389
|
_stat_index[_stat_key_to_absolute(k, _stat_index_anchor)] = v
|
|
358
390
|
except (json.JSONDecodeError, OSError):
|
|
359
391
|
_stat_index = {}
|
|
360
|
-
|
|
392
|
+
_stat_index_dirty = False
|
|
393
|
+
if not _stat_index_atexit_registered:
|
|
394
|
+
atexit.register(_flush_stat_index)
|
|
395
|
+
_stat_index_atexit_registered = True
|
|
361
396
|
|
|
362
397
|
|
|
363
398
|
def _flush_stat_index() -> None:
|
|
364
399
|
global _stat_index_dirty, _stat_index_root
|
|
365
400
|
if not _stat_index_dirty or _stat_index_root is None:
|
|
366
401
|
return
|
|
367
|
-
|
|
402
|
+
# Use the path captured when this root was bound (#3989), not a fresh
|
|
403
|
+
# _stat_index_file(_stat_index_root) call: a mid-process root switch runs
|
|
404
|
+
# this to flush the OUTGOING root, by which point a caller following the
|
|
405
|
+
# documented set-_GRAPHIFY_OUT-then-call pattern has already pointed
|
|
406
|
+
# _GRAPHIFY_OUT at the NEW root, and re-deriving here would flush the old
|
|
407
|
+
# root's entries into the new root's file instead of its own.
|
|
408
|
+
p = _stat_index_path if _stat_index_path is not None else _stat_index_file(_stat_index_root)
|
|
368
409
|
# Build the on-disk form (#2199): prune entries whose file is gone (the
|
|
369
410
|
# index otherwise grows without bound), then store in-anchor keys as
|
|
370
411
|
# forward-slash relative paths so the index survives a corpus move/clone.
|
|
@@ -81,6 +81,29 @@ _GEMINI_NUDGE_TEXT = (
|
|
|
81
81
|
)
|
|
82
82
|
|
|
83
83
|
|
|
84
|
+
_DEFAULT_NUDGE_GRAPH = "graphify-out/graph.json"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _nudge_for_out(nudge: str) -> str:
|
|
88
|
+
"""Name the effective graph.json in a hook-guard reminder (#4040).
|
|
89
|
+
|
|
90
|
+
The reminder constants spell the default ``graphify-out/graph.json``. When
|
|
91
|
+
``GRAPHIFY_OUT`` points elsewhere, the reminder must name the graph that was
|
|
92
|
+
actually found. Default output dir: returned byte-identical.
|
|
93
|
+
"""
|
|
94
|
+
from graphify.paths import out_path
|
|
95
|
+
try:
|
|
96
|
+
ref = out_path("graph.json").as_posix()
|
|
97
|
+
except Exception:
|
|
98
|
+
return nudge
|
|
99
|
+
if ref == _DEFAULT_NUDGE_GRAPH:
|
|
100
|
+
return nudge
|
|
101
|
+
d = json.loads(nudge)
|
|
102
|
+
out = d["hookSpecificOutput"]
|
|
103
|
+
out["additionalContext"] = out["additionalContext"].replace(_DEFAULT_NUDGE_GRAPH, ref)
|
|
104
|
+
return json.dumps(d, ensure_ascii=False, separators=(",", ":")) + "\n"
|
|
105
|
+
|
|
106
|
+
|
|
84
107
|
def _default_graph_path() -> str:
|
|
85
108
|
return str(Path(_GRAPHIFY_OUT) / "graph.json")
|
|
86
109
|
|
|
@@ -867,7 +890,7 @@ def _run_hook_guard(kind: str, strict: bool = False) -> None:
|
|
|
867
890
|
is_grep_tool = not cmd_str and bool(t.get("pattern"))
|
|
868
891
|
is_bash_search = bool(cmd_str) and _bash_invokes_search(cmd_str)
|
|
869
892
|
if (is_grep_tool or is_bash_search) and out_path("graph.json").is_file():
|
|
870
|
-
sys.stdout.write(_SEARCH_NUDGE)
|
|
893
|
+
sys.stdout.write(_nudge_for_out(_SEARCH_NUDGE))
|
|
871
894
|
elif kind == "read":
|
|
872
895
|
vals = [str(t.get("file_path") or ""), str(t.get("pattern") or ""), str(t.get("path") or "")]
|
|
873
896
|
tails = [
|
|
@@ -977,7 +1000,7 @@ def _run_hook_guard(kind: str, strict: bool = False) -> None:
|
|
|
977
1000
|
except Exception:
|
|
978
1001
|
pass
|
|
979
1002
|
if stale:
|
|
980
|
-
sys.stdout.write(_READ_NUDGE_STALE)
|
|
1003
|
+
sys.stdout.write(_nudge_for_out(_READ_NUDGE_STALE))
|
|
981
1004
|
return
|
|
982
1005
|
# Strict block: Read tool only, first time per session, not recently
|
|
983
1006
|
# oriented, and the file is demonstrably indexed.
|
|
@@ -988,7 +1011,7 @@ def _run_hook_guard(kind: str, strict: bool = False) -> None:
|
|
|
988
1011
|
and _mark_session_denied(str(d.get("session_id") or "")):
|
|
989
1012
|
sys.stdout.write(_READ_DENY)
|
|
990
1013
|
return
|
|
991
|
-
sys.stdout.write(_READ_NUDGE)
|
|
1014
|
+
sys.stdout.write(_nudge_for_out(_READ_NUDGE))
|
|
992
1015
|
except Exception:
|
|
993
1016
|
pass
|
|
994
1017
|
|
|
@@ -1605,7 +1628,7 @@ def dispatch_command(cmd: str) -> None:
|
|
|
1605
1628
|
file=sys.stderr,
|
|
1606
1629
|
)
|
|
1607
1630
|
sys.exit(1)
|
|
1608
|
-
from graphify.serve import
|
|
1631
|
+
from graphify.serve import _resolve_path_endpoint
|
|
1609
1632
|
from networkx.readwrite import json_graph
|
|
1610
1633
|
import networkx as _nx
|
|
1611
1634
|
|
|
@@ -1656,16 +1679,15 @@ def dispatch_command(cmd: str) -> None:
|
|
|
1656
1679
|
G = json_graph.node_link_graph(_raw, edges="links")
|
|
1657
1680
|
except TypeError:
|
|
1658
1681
|
G = json_graph.node_link_graph(_raw)
|
|
1659
|
-
src_scored =
|
|
1660
|
-
tgt_scored =
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
tgt_nid = _pick_scored_endpoint(G, tgt_scored, target_label)
|
|
1682
|
+
src_nid, src_scored, src_err = _resolve_path_endpoint(G, source_label)
|
|
1683
|
+
tgt_nid, tgt_scored, tgt_err = _resolve_path_endpoint(G, target_label)
|
|
1684
|
+
for _label, _nid, _err in (
|
|
1685
|
+
(source_label, src_nid, src_err),
|
|
1686
|
+
(target_label, tgt_nid, tgt_err),
|
|
1687
|
+
):
|
|
1688
|
+
if _err or _nid is None:
|
|
1689
|
+
print(_err or f"No node matching '{_label}' found.", file=sys.stderr)
|
|
1690
|
+
sys.exit(1)
|
|
1669
1691
|
# Ambiguity guard: when both queries resolve to the same node, the
|
|
1670
1692
|
# shortest path is trivially zero hops, which is almost never what the
|
|
1671
1693
|
# caller wanted (see bug #828).
|
|
@@ -1711,6 +1733,20 @@ def dispatch_command(cmd: str) -> None:
|
|
|
1711
1733
|
_dg.add_edges_from(sorted(
|
|
1712
1734
|
(d.get("_src", u), d.get("_tgt", v)) for u, v, d in G.edges(data=True)
|
|
1713
1735
|
))
|
|
1736
|
+
# A `contains` edge only runs file -> symbol; there is no
|
|
1737
|
+
# stored edge back out to the containing file, so a route that
|
|
1738
|
+
# reaches a symbol (via an `imports`/`calls`/`references` hop)
|
|
1739
|
+
# can never continue on to the file that defines it, and a
|
|
1740
|
+
# file-to-file dependency routed through a shared symbol finds
|
|
1741
|
+
# no path at all even though both halves of the route exist
|
|
1742
|
+
# (#3878). Add the implied reverse hop for traversal only — the
|
|
1743
|
+
# printed segment still recovers the real stored `contains`
|
|
1744
|
+
# edge and its true direction from G, same as any other hop.
|
|
1745
|
+
_dg.add_edges_from(sorted(
|
|
1746
|
+
(d.get("_tgt", v), d.get("_src", u))
|
|
1747
|
+
for u, v, d in G.edges(data=True)
|
|
1748
|
+
if d.get("relation") == "contains"
|
|
1749
|
+
))
|
|
1714
1750
|
path_nodes = _nx.shortest_path(_dg, src_nid, tgt_nid)
|
|
1715
1751
|
except (_nx.NetworkXNoPath, _nx.NodeNotFound):
|
|
1716
1752
|
if undirected:
|
|
@@ -1768,7 +1804,7 @@ def dispatch_command(cmd: str) -> None:
|
|
|
1768
1804
|
if len(sys.argv) < 3:
|
|
1769
1805
|
print('Usage: graphify explain "<node>" [--graph path]', file=sys.stderr)
|
|
1770
1806
|
sys.exit(1)
|
|
1771
|
-
from graphify.serve import _find_node, find_node_ambiguity
|
|
1807
|
+
from graphify.serve import _ambiguity_message, _find_node, find_node_ambiguity
|
|
1772
1808
|
from networkx.readwrite import json_graph
|
|
1773
1809
|
|
|
1774
1810
|
label = sys.argv[2]
|
|
@@ -1797,14 +1833,7 @@ def dispatch_command(cmd: str) -> None:
|
|
|
1797
1833
|
sys.exit(0)
|
|
1798
1834
|
rivals = find_node_ambiguity(G, label)
|
|
1799
1835
|
if rivals:
|
|
1800
|
-
print(
|
|
1801
|
-
for rival in rivals:
|
|
1802
|
-
print(f" {G.nodes[rival].get('source_file') or rival}")
|
|
1803
|
-
print(f" id: {rival}")
|
|
1804
|
-
print(
|
|
1805
|
-
f"Retry with path::symbol using one of the paths above (e.g. "
|
|
1806
|
-
f"<path>::{label}) or the full node id."
|
|
1807
|
-
)
|
|
1836
|
+
print(_ambiguity_message(G, label, rivals))
|
|
1808
1837
|
sys.exit(1)
|
|
1809
1838
|
nid = matches[0]
|
|
1810
1839
|
d = G.nodes[nid]
|
|
@@ -2358,7 +2387,8 @@ def dispatch_command(cmd: str) -> None:
|
|
|
2358
2387
|
# a report and labels describing a clustering graph.json does not contain
|
|
2359
2388
|
# are worse than no run at all (#2436).
|
|
2360
2389
|
if not to_json(G, communities, str(out / "graph.json"),
|
|
2361
|
-
community_labels=labels, built_at_commit=_commit
|
|
2390
|
+
community_labels=labels, built_at_commit=_commit,
|
|
2391
|
+
original_links=_raw.get("links") or _raw.get("edges") or []):
|
|
2362
2392
|
if not stale_marker_preexisted:
|
|
2363
2393
|
_clear_html_stale_marker()
|
|
2364
2394
|
print(
|
|
@@ -2663,20 +2693,48 @@ def dispatch_command(cmd: str) -> None:
|
|
|
2663
2693
|
args = sys.argv[2:]
|
|
2664
2694
|
graph_paths: list[Path] = []
|
|
2665
2695
|
out_path = Path(_GRAPHIFY_OUT) / "merged-graph.json"
|
|
2696
|
+
previous_path: "Path | None" = None
|
|
2666
2697
|
i = 0
|
|
2667
2698
|
while i < len(args):
|
|
2668
2699
|
if args[i] == "--out" and i + 1 < len(args):
|
|
2669
2700
|
out_path = Path(args[i + 1])
|
|
2670
2701
|
i += 2
|
|
2702
|
+
elif args[i] == "--previous" and i + 1 < len(args):
|
|
2703
|
+
previous_path = Path(args[i + 1])
|
|
2704
|
+
i += 2
|
|
2671
2705
|
else:
|
|
2672
2706
|
graph_paths.append(Path(args[i]))
|
|
2673
2707
|
i += 1
|
|
2674
2708
|
if len(graph_paths) < 2:
|
|
2675
2709
|
print(
|
|
2676
|
-
"Usage: graphify merge-graphs <graph1.json> <graph2.json> [...]
|
|
2710
|
+
"Usage: graphify merge-graphs <graph1.json> <graph2.json> [...] "
|
|
2711
|
+
"[--out merged.json] [--previous previous-merged-graph.json]",
|
|
2677
2712
|
file=sys.stderr,
|
|
2678
2713
|
)
|
|
2679
2714
|
sys.exit(1)
|
|
2715
|
+
# Each input numbers its own communities from 0, so the merged output
|
|
2716
|
+
# carries per-source ids (offset since #3014) that have no relation to
|
|
2717
|
+
# the previous MERGED clustering .graphify_labels.json was written
|
|
2718
|
+
# against. cluster-only's label-reuse remap reads this file's
|
|
2719
|
+
# `community` field as "the previous clustering" and silently mismatches
|
|
2720
|
+
# almost every community when it is actually per-source ids (#3858).
|
|
2721
|
+
# --previous restores the real previous merged `community` onto each
|
|
2722
|
+
# node that survives the merge (by id), so a subsequent cluster-only
|
|
2723
|
+
# run remaps against the clustering its labels were actually built
|
|
2724
|
+
# from. Per-source ids stay available in `local_community` regardless.
|
|
2725
|
+
previous_community: dict[str, int] = {}
|
|
2726
|
+
if previous_path is not None:
|
|
2727
|
+
if not previous_path.exists():
|
|
2728
|
+
print(f"error: --previous file not found: {previous_path}", file=sys.stderr)
|
|
2729
|
+
sys.exit(1)
|
|
2730
|
+
try:
|
|
2731
|
+
_prev_raw = json.loads(previous_path.read_text(encoding="utf-8"))
|
|
2732
|
+
except (json.JSONDecodeError, OSError, UnicodeDecodeError) as e:
|
|
2733
|
+
print(f"error: --previous file is not readable JSON: {previous_path} ({e})", file=sys.stderr)
|
|
2734
|
+
sys.exit(1)
|
|
2735
|
+
for _n in _prev_raw.get("nodes", []):
|
|
2736
|
+
if isinstance(_n, dict) and isinstance(_n.get("community"), int) and _n.get("id"):
|
|
2737
|
+
previous_community[_n["id"]] = _n["community"]
|
|
2680
2738
|
import networkx as _nx
|
|
2681
2739
|
from networkx.readwrite import json_graph as _jg
|
|
2682
2740
|
from graphify.build import prefix_graph_for_global as _prefix, distinct_repo_tags as _repo_tags
|
|
@@ -2781,6 +2839,18 @@ def dispatch_command(cmd: str) -> None:
|
|
|
2781
2839
|
call_links = _link_calls(merged)
|
|
2782
2840
|
if call_links:
|
|
2783
2841
|
print(f" resolved {call_links} member call(s) across repos")
|
|
2842
|
+
if previous_path is not None:
|
|
2843
|
+
_restored = 0
|
|
2844
|
+
for _nid, _data in merged.nodes(data=True):
|
|
2845
|
+
if _nid in previous_community:
|
|
2846
|
+
_data["community"] = previous_community[_nid]
|
|
2847
|
+
_restored += 1
|
|
2848
|
+
else:
|
|
2849
|
+
_data.pop("community", None)
|
|
2850
|
+
print(
|
|
2851
|
+
f" restored the previous merged community on {_restored} node(s) "
|
|
2852
|
+
f"from {previous_path}"
|
|
2853
|
+
)
|
|
2784
2854
|
# Drop whatever compose left behind (the last input's list, possibly
|
|
2785
2855
|
# with internal duplicates) so attach_hyperedges dedups the full
|
|
2786
2856
|
# collection by id from a clean slate.
|
|
@@ -3283,7 +3353,8 @@ def dispatch_command(cmd: str) -> None:
|
|
|
3283
3353
|
"[--model M] [--mode deep] [--out DIR|--output DIR] [--google-workspace] [--no-cluster] "
|
|
3284
3354
|
"[--no-gitignore] [--code-only] [--no-dedup] "
|
|
3285
3355
|
"[--max-workers N] [--token-budget N] [--max-concurrency N] "
|
|
3286
|
-
"[--api-timeout S] [--postgres DSN] [--cargo] [--allow-partial]
|
|
3356
|
+
"[--api-timeout S] [--postgres DSN] [--cargo] [--allow-partial] "
|
|
3357
|
+
"[--allow-dedup-shrink] [--timing]",
|
|
3287
3358
|
file=sys.stderr,
|
|
3288
3359
|
)
|
|
3289
3360
|
sys.exit(1)
|
|
@@ -3305,6 +3376,9 @@ def dispatch_command(cmd: str) -> None:
|
|
|
3305
3376
|
cli_postgres_dsn: str | None = None
|
|
3306
3377
|
cli_cargo: bool = False
|
|
3307
3378
|
cli_allow_partial: bool = False
|
|
3379
|
+
# --allow-dedup-shrink: write a graph that is smaller because dedup
|
|
3380
|
+
# merged nodes. A deleted file does not need this flag (#3774).
|
|
3381
|
+
cli_allow_dedup_shrink: bool = False
|
|
3308
3382
|
no_cluster = False
|
|
3309
3383
|
dedup_llm = False
|
|
3310
3384
|
# --no-dedup: skip entity deduplication entirely. On an incremental
|
|
@@ -3433,6 +3507,8 @@ def dispatch_command(cmd: str) -> None:
|
|
|
3433
3507
|
force = True; i += 1
|
|
3434
3508
|
elif a == "--allow-partial":
|
|
3435
3509
|
cli_allow_partial = True; i += 1
|
|
3510
|
+
elif a == "--allow-dedup-shrink":
|
|
3511
|
+
cli_allow_dedup_shrink = True; i += 1
|
|
3436
3512
|
elif a == "--timing":
|
|
3437
3513
|
cli_timing = True; i += 1
|
|
3438
3514
|
else:
|
|
@@ -4598,15 +4674,17 @@ def dispatch_command(cmd: str) -> None:
|
|
|
4598
4674
|
_backup(graphify_out)
|
|
4599
4675
|
_invalidate_file_manifest_for_db_graph()
|
|
4600
4676
|
# force=True bypasses the #479 shrink guard entirely. A full build
|
|
4601
|
-
# legitimately shrinks
|
|
4602
|
-
# force=True — EXCEPT
|
|
4603
|
-
#
|
|
4604
|
-
#
|
|
4605
|
-
#
|
|
4677
|
+
# legitimately shrinks when files were deleted, so a complete run keeps
|
|
4678
|
+
# force=True — EXCEPT:
|
|
4679
|
+
# * extraction was incomplete (a pass crashed or a chunk came back
|
|
4680
|
+
# empty). Fall back to the shrink guard unless --allow-partial.
|
|
4681
|
+
# * dedup merged nodes and the saved graph would shrink by more than
|
|
4682
|
+
# this run's deletions (#3774). Refuse the write before to_json unless
|
|
4683
|
+
# --allow-dedup-shrink. --allow-partial does not accept that shrink.
|
|
4606
4684
|
#
|
|
4607
|
-
# Both write paths are guarded
|
|
4608
|
-
# #479 check, and the `--no-cluster` raw-dump path
|
|
4609
|
-
# shrink check against the existing file
|
|
4685
|
+
# Both write paths are guarded for an incomplete extraction: the clustered
|
|
4686
|
+
# path here via to_json's #479 check, and the `--no-cluster` raw-dump path
|
|
4687
|
+
# above via the same shrink check against the existing file.
|
|
4610
4688
|
#
|
|
4611
4689
|
# Trade-off: this reuses to_json's coarse node-count guard, not the
|
|
4612
4690
|
# source-aware _check_shrink that watch/update use. On an incremental run
|
|
@@ -4614,7 +4692,33 @@ def dispatch_command(cmd: str) -> None:
|
|
|
4614
4692
|
# failure can therefore be refused here — recoverable by re-running or
|
|
4615
4693
|
# passing --allow-partial (the good graph is preserved and the manifest
|
|
4616
4694
|
# is not stamped, so the retry re-extracts).
|
|
4695
|
+
from graphify.build import take_shrink_accounting as _take_shrink_accounting
|
|
4696
|
+
_dedup_collapsed, _pruned_nodes = _take_shrink_accounting(G)
|
|
4617
4697
|
_force_write = cli_allow_partial or not _extraction_incomplete
|
|
4698
|
+
_dedup_shrink_counts: tuple[int, int] | None = None
|
|
4699
|
+
if (
|
|
4700
|
+
not _extraction_incomplete
|
|
4701
|
+
and not no_dedup
|
|
4702
|
+
and not cli_allow_dedup_shrink
|
|
4703
|
+
and _dedup_collapsed > 0
|
|
4704
|
+
):
|
|
4705
|
+
from graphify.export import existing_graph_node_count as _existing_graph_node_count
|
|
4706
|
+
_existing_n = _existing_graph_node_count(graph_json_path)
|
|
4707
|
+
_new_n = G.number_of_nodes()
|
|
4708
|
+
if isinstance(_existing_n, int) and _new_n < _existing_n - _pruned_nodes:
|
|
4709
|
+
_dedup_shrink_counts = (_existing_n, _new_n)
|
|
4710
|
+
if _dedup_shrink_counts is not None:
|
|
4711
|
+
# Refuse before to_json. to_json's own refusal tells the caller to
|
|
4712
|
+
# pass force=True, which is not this flag (#3774).
|
|
4713
|
+
_old_n, _new_n = _dedup_shrink_counts
|
|
4714
|
+
print(
|
|
4715
|
+
f"[graphify extract] error: dedup merged {_dedup_collapsed} "
|
|
4716
|
+
f"node(s); writing would shrink the graph from {_old_n} nodes "
|
|
4717
|
+
f"to {_new_n} nodes. Refusing to overwrite {graph_json_path}. "
|
|
4718
|
+
"Pass --allow-dedup-shrink to write the smaller graph.",
|
|
4719
|
+
file=sys.stderr,
|
|
4720
|
+
)
|
|
4721
|
+
sys.exit(1)
|
|
4618
4722
|
# Stamp provenance from the ANALYSED repo, not the shell's cwd: without
|
|
4619
4723
|
# this, to_json's fallback asks `git rev-parse HEAD` in whatever repo the
|
|
4620
4724
|
# command was invoked from, so `graphify extract <target>` run from
|
|
@@ -235,7 +235,7 @@ def link_cross_repo_member_calls(merged: "nx.Graph") -> int:
|
|
|
235
235
|
relation="calls",
|
|
236
236
|
context="cross_repo",
|
|
237
237
|
confidence="INFERRED",
|
|
238
|
-
confidence_score=0.
|
|
238
|
+
confidence_score=0.85,
|
|
239
239
|
source_file=str(caller_data.get("source_file") or ""),
|
|
240
240
|
source_location=entry.get("line"),
|
|
241
241
|
weight=1.0,
|
|
@@ -65,7 +65,7 @@ def link_shared_type_declarations(merged: "nx.Graph") -> int:
|
|
|
65
65
|
relation=SHARED_TYPE_RELATION,
|
|
66
66
|
context="cross_repo",
|
|
67
67
|
confidence="INFERRED",
|
|
68
|
-
confidence_score=0.
|
|
68
|
+
confidence_score=0.85,
|
|
69
69
|
source_file=str(merged.nodes[left].get("source_file") or ""),
|
|
70
70
|
weight=1.0,
|
|
71
71
|
_src=left,
|