graphify-sfdx 0.1.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.
- graphify_sfdx-0.1.0/LICENSE +22 -0
- graphify_sfdx-0.1.0/NOTICE +8 -0
- graphify_sfdx-0.1.0/PKG-INFO +345 -0
- graphify_sfdx-0.1.0/README.md +207 -0
- graphify_sfdx-0.1.0/graphify/__init__.py +28 -0
- graphify_sfdx-0.1.0/graphify/__main__.py +4717 -0
- graphify_sfdx-0.1.0/graphify/_minhash.py +107 -0
- graphify_sfdx-0.1.0/graphify/affected.py +177 -0
- graphify_sfdx-0.1.0/graphify/always_on/agents-md.md +12 -0
- graphify_sfdx-0.1.0/graphify/always_on/antigravity-rules.md +14 -0
- graphify_sfdx-0.1.0/graphify/always_on/claude-md.md +9 -0
- graphify_sfdx-0.1.0/graphify/always_on/gemini-md.md +9 -0
- graphify_sfdx-0.1.0/graphify/always_on/kiro-steering.md +5 -0
- graphify_sfdx-0.1.0/graphify/always_on/vscode-instructions.md +17 -0
- graphify_sfdx-0.1.0/graphify/analyze.py +732 -0
- graphify_sfdx-0.1.0/graphify/benchmark.py +155 -0
- graphify_sfdx-0.1.0/graphify/build.py +555 -0
- graphify_sfdx-0.1.0/graphify/cache.py +475 -0
- graphify_sfdx-0.1.0/graphify/callflow_html.py +2020 -0
- graphify_sfdx-0.1.0/graphify/cargo_introspect.py +98 -0
- graphify_sfdx-0.1.0/graphify/cluster.py +272 -0
- graphify_sfdx-0.1.0/graphify/command-kilo.md +15 -0
- graphify_sfdx-0.1.0/graphify/dedup.py +474 -0
- graphify_sfdx-0.1.0/graphify/detect.py +1425 -0
- graphify_sfdx-0.1.0/graphify/diagnostics.py +390 -0
- graphify_sfdx-0.1.0/graphify/export.py +1516 -0
- graphify_sfdx-0.1.0/graphify/extract.py +12396 -0
- graphify_sfdx-0.1.0/graphify/global_graph.py +182 -0
- graphify_sfdx-0.1.0/graphify/google_workspace.py +223 -0
- graphify_sfdx-0.1.0/graphify/hooks.py +457 -0
- graphify_sfdx-0.1.0/graphify/ingest.py +331 -0
- graphify_sfdx-0.1.0/graphify/llm.py +2167 -0
- graphify_sfdx-0.1.0/graphify/manifest.py +4 -0
- graphify_sfdx-0.1.0/graphify/mcp_ingest.py +392 -0
- graphify_sfdx-0.1.0/graphify/multigraph_compat.py +212 -0
- graphify_sfdx-0.1.0/graphify/pg_introspect.py +142 -0
- graphify_sfdx-0.1.0/graphify/prs.py +751 -0
- graphify_sfdx-0.1.0/graphify/querylog.py +70 -0
- graphify_sfdx-0.1.0/graphify/report.py +218 -0
- graphify_sfdx-0.1.0/graphify/salesforce/__init__.py +282 -0
- graphify_sfdx-0.1.0/graphify/salesforce/__main__.py +8 -0
- graphify_sfdx-0.1.0/graphify/salesforce/apex_enhanced.py +324 -0
- graphify_sfdx-0.1.0/graphify/salesforce/cli.py +179 -0
- graphify_sfdx-0.1.0/graphify/salesforce/constants.py +143 -0
- graphify_sfdx-0.1.0/graphify/salesforce/cpq.py +168 -0
- graphify_sfdx-0.1.0/graphify/salesforce/cpq_data.py +298 -0
- graphify_sfdx-0.1.0/graphify/salesforce/flow.py +247 -0
- graphify_sfdx-0.1.0/graphify/salesforce/flow_cpq_loops.py +140 -0
- graphify_sfdx-0.1.0/graphify/salesforce/governor_limits.py +264 -0
- graphify_sfdx-0.1.0/graphify/salesforce/lwc.py +217 -0
- graphify_sfdx-0.1.0/graphify/salesforce/mdt_mapping.py +164 -0
- graphify_sfdx-0.1.0/graphify/salesforce/metadata.py +311 -0
- graphify_sfdx-0.1.0/graphify/salesforce/neo4j_sf.py +222 -0
- graphify_sfdx-0.1.0/graphify/salesforce/objects.py +430 -0
- graphify_sfdx-0.1.0/graphify/salesforce/order_of_execution.py +110 -0
- graphify_sfdx-0.1.0/graphify/salesforce/permission_analysis.py +109 -0
- graphify_sfdx-0.1.0/graphify/salesforce/pipeline.py +89 -0
- graphify_sfdx-0.1.0/graphify/salesforce/profiles.py +193 -0
- graphify_sfdx-0.1.0/graphify/salesforce/query.py +252 -0
- graphify_sfdx-0.1.0/graphify/salesforce/release_sync.py +136 -0
- graphify_sfdx-0.1.0/graphify/salesforce/validate_sf.py +193 -0
- graphify_sfdx-0.1.0/graphify/salesforce/validation_cpq.py +175 -0
- graphify_sfdx-0.1.0/graphify/salesforce/viz.py +139 -0
- graphify_sfdx-0.1.0/graphify/scip_ingest.py +363 -0
- graphify_sfdx-0.1.0/graphify/security.py +457 -0
- graphify_sfdx-0.1.0/graphify/semantic_cleanup.py +319 -0
- graphify_sfdx-0.1.0/graphify/serve.py +1394 -0
- graphify_sfdx-0.1.0/graphify/skill-aider.md +1245 -0
- graphify_sfdx-0.1.0/graphify/skill-amp.md +614 -0
- graphify_sfdx-0.1.0/graphify/skill-claw.md +617 -0
- graphify_sfdx-0.1.0/graphify/skill-codex.md +614 -0
- graphify_sfdx-0.1.0/graphify/skill-copilot.md +617 -0
- graphify_sfdx-0.1.0/graphify/skill-devin.md +1372 -0
- graphify_sfdx-0.1.0/graphify/skill-droid.md +614 -0
- graphify_sfdx-0.1.0/graphify/skill-kilo.md +626 -0
- graphify_sfdx-0.1.0/graphify/skill-kiro.md +617 -0
- graphify_sfdx-0.1.0/graphify/skill-opencode.md +609 -0
- graphify_sfdx-0.1.0/graphify/skill-pi.md +617 -0
- graphify_sfdx-0.1.0/graphify/skill-trae.md +615 -0
- graphify_sfdx-0.1.0/graphify/skill-vscode.md +613 -0
- graphify_sfdx-0.1.0/graphify/skill-windows.md +652 -0
- graphify_sfdx-0.1.0/graphify/skill.md +617 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/amp/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/claude/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/extraction-spec.md +29 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/claw/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/extraction-spec.md +29 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/codex/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/copilot/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/droid/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/kilo/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/extraction-spec.md +29 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/kiro/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/opencode/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/extraction-spec.md +29 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/pi/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/hooks.md +35 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/trae/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/vscode/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/add-watch.md +56 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/exports.md +87 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/extraction-spec.md +68 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/github-and-merge.md +46 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/hooks.md +33 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/query.md +303 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/transcribe.md +48 -0
- graphify_sfdx-0.1.0/graphify/skills/windows/references/update.md +179 -0
- graphify_sfdx-0.1.0/graphify/symbol_resolution.py +538 -0
- graphify_sfdx-0.1.0/graphify/transcribe.py +184 -0
- graphify_sfdx-0.1.0/graphify/tree_html.py +582 -0
- graphify_sfdx-0.1.0/graphify/validate.py +79 -0
- graphify_sfdx-0.1.0/graphify/watch.py +908 -0
- graphify_sfdx-0.1.0/graphify/wiki.py +282 -0
- graphify_sfdx-0.1.0/graphify_sfdx.egg-info/PKG-INFO +345 -0
- graphify_sfdx-0.1.0/graphify_sfdx.egg-info/SOURCES.txt +287 -0
- graphify_sfdx-0.1.0/graphify_sfdx.egg-info/dependency_links.txt +1 -0
- graphify_sfdx-0.1.0/graphify_sfdx.egg-info/entry_points.txt +5 -0
- graphify_sfdx-0.1.0/graphify_sfdx.egg-info/requires.txt +134 -0
- graphify_sfdx-0.1.0/graphify_sfdx.egg-info/top_level.txt +1 -0
- graphify_sfdx-0.1.0/pyproject.toml +146 -0
- graphify_sfdx-0.1.0/setup.cfg +4 -0
- graphify_sfdx-0.1.0/tests/test_affected_cli.py +155 -0
- graphify_sfdx-0.1.0/tests/test_analyze.py +723 -0
- graphify_sfdx-0.1.0/tests/test_anthropic_custom_endpoint.py +34 -0
- graphify_sfdx-0.1.0/tests/test_antigravity_install.py +28 -0
- graphify_sfdx-0.1.0/tests/test_astro_extraction.py +143 -0
- graphify_sfdx-0.1.0/tests/test_backend_extras.py +41 -0
- graphify_sfdx-0.1.0/tests/test_benchmark.py +183 -0
- graphify_sfdx-0.1.0/tests/test_build.py +561 -0
- graphify_sfdx-0.1.0/tests/test_cache.py +422 -0
- graphify_sfdx-0.1.0/tests/test_callflow_html.py +187 -0
- graphify_sfdx-0.1.0/tests/test_cargo_introspect.py +365 -0
- graphify_sfdx-0.1.0/tests/test_charmap_encoding.py +330 -0
- graphify_sfdx-0.1.0/tests/test_chunking.py +452 -0
- graphify_sfdx-0.1.0/tests/test_claude_cli_backend.py +257 -0
- graphify_sfdx-0.1.0/tests/test_claude_md.py +136 -0
- graphify_sfdx-0.1.0/tests/test_cli_export.py +436 -0
- graphify_sfdx-0.1.0/tests/test_cluster.py +100 -0
- graphify_sfdx-0.1.0/tests/test_codebuddy.py +341 -0
- graphify_sfdx-0.1.0/tests/test_confidence.py +192 -0
- graphify_sfdx-0.1.0/tests/test_cpp_preprocess.py +32 -0
- graphify_sfdx-0.1.0/tests/test_dart.py +640 -0
- graphify_sfdx-0.1.0/tests/test_dedup.py +270 -0
- graphify_sfdx-0.1.0/tests/test_detect.py +1494 -0
- graphify_sfdx-0.1.0/tests/test_devin.py +309 -0
- graphify_sfdx-0.1.0/tests/test_dotnet.py +160 -0
- graphify_sfdx-0.1.0/tests/test_explain_cli.py +56 -0
- graphify_sfdx-0.1.0/tests/test_export.py +263 -0
- graphify_sfdx-0.1.0/tests/test_extract.py +1300 -0
- graphify_sfdx-0.1.0/tests/test_extract_cli.py +237 -0
- graphify_sfdx-0.1.0/tests/test_falkordb_integration.py +91 -0
- graphify_sfdx-0.1.0/tests/test_file_node_id_spec.py +151 -0
- graphify_sfdx-0.1.0/tests/test_global_graph.py +339 -0
- graphify_sfdx-0.1.0/tests/test_google_workspace.py +129 -0
- graphify_sfdx-0.1.0/tests/test_hooks.py +335 -0
- graphify_sfdx-0.1.0/tests/test_hypergraph.py +205 -0
- graphify_sfdx-0.1.0/tests/test_image_vision.py +345 -0
- graphify_sfdx-0.1.0/tests/test_import_extension_resolution.py +529 -0
- graphify_sfdx-0.1.0/tests/test_incremental.py +74 -0
- graphify_sfdx-0.1.0/tests/test_ingest.py +68 -0
- graphify_sfdx-0.1.0/tests/test_install.py +972 -0
- graphify_sfdx-0.1.0/tests/test_install_references.py +516 -0
- graphify_sfdx-0.1.0/tests/test_install_roundtrip.py +318 -0
- graphify_sfdx-0.1.0/tests/test_install_strings.py +135 -0
- graphify_sfdx-0.1.0/tests/test_install_upgrade.py +272 -0
- graphify_sfdx-0.1.0/tests/test_java_type_resolution.py +100 -0
- graphify_sfdx-0.1.0/tests/test_js_import_resolution.py +565 -0
- graphify_sfdx-0.1.0/tests/test_labeling.py +280 -0
- graphify_sfdx-0.1.0/tests/test_languages.py +1718 -0
- graphify_sfdx-0.1.0/tests/test_llm_backends.py +748 -0
- graphify_sfdx-0.1.0/tests/test_llm_parser.py +146 -0
- graphify_sfdx-0.1.0/tests/test_mcp_ingest.py +331 -0
- graphify_sfdx-0.1.0/tests/test_minhash.py +101 -0
- graphify_sfdx-0.1.0/tests/test_multigraph_compat.py +56 -0
- graphify_sfdx-0.1.0/tests/test_multigraph_diagnostics.py +460 -0
- graphify_sfdx-0.1.0/tests/test_multilang.py +489 -0
- graphify_sfdx-0.1.0/tests/test_obsidian_dangling_member.py +50 -0
- graphify_sfdx-0.1.0/tests/test_obsidian_filename_cap.py +73 -0
- graphify_sfdx-0.1.0/tests/test_office_limits.py +90 -0
- graphify_sfdx-0.1.0/tests/test_ollama.py +118 -0
- graphify_sfdx-0.1.0/tests/test_openai_custom_endpoint.py +46 -0
- graphify_sfdx-0.1.0/tests/test_pascal.py +322 -0
- graphify_sfdx-0.1.0/tests/test_path_cli.py +48 -0
- graphify_sfdx-0.1.0/tests/test_pg_introspect.py +278 -0
- graphify_sfdx-0.1.0/tests/test_pipeline.py +158 -0
- graphify_sfdx-0.1.0/tests/test_provider_registry.py +164 -0
- graphify_sfdx-0.1.0/tests/test_prs.py +403 -0
- graphify_sfdx-0.1.0/tests/test_python_import_resolution.py +86 -0
- graphify_sfdx-0.1.0/tests/test_query_cli.py +70 -0
- graphify_sfdx-0.1.0/tests/test_querylog.py +178 -0
- graphify_sfdx-0.1.0/tests/test_rationale.py +263 -0
- graphify_sfdx-0.1.0/tests/test_read_hook.py +80 -0
- graphify_sfdx-0.1.0/tests/test_report.py +63 -0
- graphify_sfdx-0.1.0/tests/test_salesforce.py +1918 -0
- graphify_sfdx-0.1.0/tests/test_scip_ingest.py +1670 -0
- graphify_sfdx-0.1.0/tests/test_security.py +383 -0
- graphify_sfdx-0.1.0/tests/test_semantic_cleanup.py +344 -0
- graphify_sfdx-0.1.0/tests/test_semantic_similarity.py +194 -0
- graphify_sfdx-0.1.0/tests/test_serve.py +572 -0
- graphify_sfdx-0.1.0/tests/test_serve_http.py +232 -0
- graphify_sfdx-0.1.0/tests/test_skillgen.py +796 -0
- graphify_sfdx-0.1.0/tests/test_swift_import_resolution.py +85 -0
- graphify_sfdx-0.1.0/tests/test_symbol_resolution.py +1019 -0
- graphify_sfdx-0.1.0/tests/test_terraform.py +158 -0
- graphify_sfdx-0.1.0/tests/test_transcribe.py +147 -0
- graphify_sfdx-0.1.0/tests/test_ts_inheritance.py +91 -0
- graphify_sfdx-0.1.0/tests/test_validate.py +87 -0
- graphify_sfdx-0.1.0/tests/test_watch.py +864 -0
- graphify_sfdx-0.1.0/tests/test_wheel_packaging.py +71 -0
- graphify_sfdx-0.1.0/tests/test_wiki.py +212 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Safi Shamsi
|
|
4
|
+
Copyright (c) 2026 JeremyKo95
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
graphify-sf is a derivative work based on "graphify"
|
|
2
|
+
(https://github.com/safishamsi/graphify), originally licensed under MIT.
|
|
3
|
+
|
|
4
|
+
Original work: Copyright (c) 2026 Safi Shamsi
|
|
5
|
+
Modifications: Copyright (c) 2026 JeremyKo95 <sukun9512@gmail.com>
|
|
6
|
+
|
|
7
|
+
Salesforce-specific adaptations (LWC/Apex/CPQ/Governor Limit handling)
|
|
8
|
+
are contributed by JeremyKo95.
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: graphify-sfdx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Salesforce-aware knowledge graph: parse SFDX metadata (Apex, Flow, LWC, CPQ, Governor Limits, Order-of-Execution) into a queryable NetworkX graph — fully offline, no org connection required.
|
|
5
|
+
Author-email: JeremyKo95 <sukun9512@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Safi Shamsi
|
|
9
|
+
Copyright (c) 2026 JeremyKo95
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Homepage, https://github.com/JeremyKo95/graphify-sf
|
|
30
|
+
Project-URL: Repository, https://github.com/JeremyKo95/graphify-sf
|
|
31
|
+
Project-URL: Issues, https://github.com/JeremyKo95/graphify-sf/issues
|
|
32
|
+
Keywords: salesforce,sfdx,apex,flow,lwc,cpq,governor-limits,knowledge-graph,rag,graphrag,community-detection,tree-sitter,leiden,mcp
|
|
33
|
+
Requires-Python: >=3.10
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
License-File: NOTICE
|
|
37
|
+
Requires-Dist: networkx>=3.4
|
|
38
|
+
Requires-Dist: numpy>=1.21
|
|
39
|
+
Requires-Dist: rapidfuzz>=3.0
|
|
40
|
+
Requires-Dist: tree-sitter<0.26,>=0.23.0
|
|
41
|
+
Requires-Dist: tree-sitter-python<0.26,>=0.23
|
|
42
|
+
Requires-Dist: tree-sitter-javascript<0.26,>=0.23
|
|
43
|
+
Requires-Dist: tree-sitter-typescript<0.25,>=0.23
|
|
44
|
+
Requires-Dist: tree-sitter-go<0.26,>=0.23
|
|
45
|
+
Requires-Dist: tree-sitter-rust<0.25,>=0.23
|
|
46
|
+
Requires-Dist: tree-sitter-java<0.25,>=0.23
|
|
47
|
+
Requires-Dist: tree-sitter-groovy<0.3,>=0.1
|
|
48
|
+
Requires-Dist: tree-sitter-c<0.25,>=0.23
|
|
49
|
+
Requires-Dist: tree-sitter-cpp<0.25,>=0.23
|
|
50
|
+
Requires-Dist: tree-sitter-ruby<0.25,>=0.23
|
|
51
|
+
Requires-Dist: tree-sitter-c-sharp<0.25,>=0.23
|
|
52
|
+
Requires-Dist: tree-sitter-kotlin<2.0,>=1.0
|
|
53
|
+
Requires-Dist: tree-sitter-scala<0.27,>=0.23
|
|
54
|
+
Requires-Dist: tree-sitter-php<0.25,>=0.23
|
|
55
|
+
Requires-Dist: tree-sitter-swift<0.9,>=0.7
|
|
56
|
+
Requires-Dist: tree-sitter-lua<0.6,>=0.2
|
|
57
|
+
Requires-Dist: tree-sitter-zig<2.0,>=1.0
|
|
58
|
+
Requires-Dist: tree-sitter-powershell<0.28,>=0.26
|
|
59
|
+
Requires-Dist: tree-sitter-elixir<0.5,>=0.3
|
|
60
|
+
Requires-Dist: tree-sitter-objc<4.0,>=3.0
|
|
61
|
+
Requires-Dist: tree-sitter-julia<0.25,>=0.23
|
|
62
|
+
Requires-Dist: tree-sitter-verilog<2.0,>=1.0
|
|
63
|
+
Requires-Dist: tree-sitter-fortran<0.8,>=0.6
|
|
64
|
+
Requires-Dist: tree-sitter-bash<0.27,>=0.23
|
|
65
|
+
Requires-Dist: tree-sitter-json<0.26,>=0.23
|
|
66
|
+
Provides-Extra: mcp
|
|
67
|
+
Requires-Dist: mcp; extra == "mcp"
|
|
68
|
+
Provides-Extra: neo4j
|
|
69
|
+
Requires-Dist: neo4j; extra == "neo4j"
|
|
70
|
+
Provides-Extra: falkordb
|
|
71
|
+
Requires-Dist: falkordb; extra == "falkordb"
|
|
72
|
+
Provides-Extra: pdf
|
|
73
|
+
Requires-Dist: pypdf; extra == "pdf"
|
|
74
|
+
Requires-Dist: markdownify; extra == "pdf"
|
|
75
|
+
Provides-Extra: watch
|
|
76
|
+
Requires-Dist: watchdog; extra == "watch"
|
|
77
|
+
Provides-Extra: svg
|
|
78
|
+
Requires-Dist: matplotlib; extra == "svg"
|
|
79
|
+
Requires-Dist: numpy>=2.0; python_version >= "3.13" and extra == "svg"
|
|
80
|
+
Provides-Extra: leiden
|
|
81
|
+
Requires-Dist: graspologic; python_version < "3.13" and extra == "leiden"
|
|
82
|
+
Provides-Extra: office
|
|
83
|
+
Requires-Dist: python-docx; extra == "office"
|
|
84
|
+
Requires-Dist: openpyxl; extra == "office"
|
|
85
|
+
Provides-Extra: google
|
|
86
|
+
Requires-Dist: openpyxl; extra == "google"
|
|
87
|
+
Provides-Extra: postgres
|
|
88
|
+
Requires-Dist: psycopg[binary]; extra == "postgres"
|
|
89
|
+
Provides-Extra: video
|
|
90
|
+
Requires-Dist: faster-whisper; python_version >= "3.11" and extra == "video"
|
|
91
|
+
Requires-Dist: yt-dlp; extra == "video"
|
|
92
|
+
Provides-Extra: kimi
|
|
93
|
+
Requires-Dist: openai; extra == "kimi"
|
|
94
|
+
Requires-Dist: tiktoken; extra == "kimi"
|
|
95
|
+
Provides-Extra: ollama
|
|
96
|
+
Requires-Dist: openai; extra == "ollama"
|
|
97
|
+
Provides-Extra: bedrock
|
|
98
|
+
Requires-Dist: boto3; extra == "bedrock"
|
|
99
|
+
Provides-Extra: anthropic
|
|
100
|
+
Requires-Dist: anthropic; extra == "anthropic"
|
|
101
|
+
Provides-Extra: gemini
|
|
102
|
+
Requires-Dist: openai; extra == "gemini"
|
|
103
|
+
Requires-Dist: tiktoken; extra == "gemini"
|
|
104
|
+
Provides-Extra: openai
|
|
105
|
+
Requires-Dist: openai; extra == "openai"
|
|
106
|
+
Requires-Dist: tiktoken; extra == "openai"
|
|
107
|
+
Provides-Extra: chinese
|
|
108
|
+
Requires-Dist: jieba; extra == "chinese"
|
|
109
|
+
Provides-Extra: sql
|
|
110
|
+
Requires-Dist: tree-sitter-sql; extra == "sql"
|
|
111
|
+
Provides-Extra: dm
|
|
112
|
+
Requires-Dist: tree-sitter-dm; extra == "dm"
|
|
113
|
+
Provides-Extra: terraform
|
|
114
|
+
Requires-Dist: tree-sitter-hcl; extra == "terraform"
|
|
115
|
+
Provides-Extra: all
|
|
116
|
+
Requires-Dist: mcp; extra == "all"
|
|
117
|
+
Requires-Dist: neo4j; extra == "all"
|
|
118
|
+
Requires-Dist: falkordb; extra == "all"
|
|
119
|
+
Requires-Dist: pypdf; extra == "all"
|
|
120
|
+
Requires-Dist: markdownify; extra == "all"
|
|
121
|
+
Requires-Dist: watchdog; extra == "all"
|
|
122
|
+
Requires-Dist: graspologic; python_version < "3.13" and extra == "all"
|
|
123
|
+
Requires-Dist: python-docx; extra == "all"
|
|
124
|
+
Requires-Dist: openpyxl; extra == "all"
|
|
125
|
+
Requires-Dist: faster-whisper; python_version >= "3.11" and extra == "all"
|
|
126
|
+
Requires-Dist: yt-dlp; extra == "all"
|
|
127
|
+
Requires-Dist: matplotlib; extra == "all"
|
|
128
|
+
Requires-Dist: numpy>=2.0; python_version >= "3.13" and extra == "all"
|
|
129
|
+
Requires-Dist: openai; extra == "all"
|
|
130
|
+
Requires-Dist: tiktoken; extra == "all"
|
|
131
|
+
Requires-Dist: boto3; extra == "all"
|
|
132
|
+
Requires-Dist: anthropic; extra == "all"
|
|
133
|
+
Requires-Dist: tree-sitter-sql; extra == "all"
|
|
134
|
+
Requires-Dist: jieba; extra == "all"
|
|
135
|
+
Requires-Dist: tree-sitter-dm; extra == "all"
|
|
136
|
+
Requires-Dist: tree-sitter-hcl; extra == "all"
|
|
137
|
+
Dynamic: license-file
|
|
138
|
+
|
|
139
|
+
# graphify-sf
|
|
140
|
+
|
|
141
|
+
> ⚡ A **Salesforce-native** knowledge-graph library — turn any Enterprise (CPQ)
|
|
142
|
+
> Salesforce org's metadata into a token-minimized graph for onboarding, analysis,
|
|
143
|
+
> impact review, and development.
|
|
144
|
+
> Inspired by [graphify](https://github.com/safishamsi/graphify); rebuilt in Python
|
|
145
|
+
> for Apex, Flow, LWC, CPQ data, and the realities of Governor Limits.
|
|
146
|
+
|
|
147
|
+
[](./LICENSE)
|
|
148
|
+
[](#)
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## What it is
|
|
153
|
+
|
|
154
|
+
`graphify-sf` is a **Python library** (not an on-platform package). It statically
|
|
155
|
+
parses a Salesforce metadata repository — and CPQ rule **data** — into a NetworkX
|
|
156
|
+
knowledge graph, runs Salesforce-aware analysis passes, then serves a
|
|
157
|
+
**token-minimized** view so an LLM (or a person) can answer "what breaks if I change
|
|
158
|
+
X?", "how is a Quote created from an Opportunity?", or "where are the Governor-Limit
|
|
159
|
+
risks?" without reading the raw org.
|
|
160
|
+
|
|
161
|
+
The North Star: **any Enterprise CPQ org → SF-specific KB graph → token-minimized
|
|
162
|
+
consumption → onboarding, analysis, impact review, and development.**
|
|
163
|
+
|
|
164
|
+
## Capabilities
|
|
165
|
+
|
|
166
|
+
- **Parsers** (`graphify/salesforce/`): Apex (regex, ADR-019), Flow (typed record
|
|
167
|
+
tags), LWC (`@wire` + imperative Apex), Custom Object/Field, Profile/Permission Set,
|
|
168
|
+
Validation Rule, Record Type, Permission Set Group, Workflow, **Custom Metadata
|
|
169
|
+
records, Sharing Rules, Custom Labels, Custom Settings**.
|
|
170
|
+
- **CPQ rule data ingest** (`cpq_data.py`): SBQQ Price/Product Rules, Conditions,
|
|
171
|
+
Actions from **SFDX JSON or Gearset `*.gs.json`**, plus **JavaScript QCP** custom
|
|
172
|
+
scripts — the logic that lives as data records, not metadata.
|
|
173
|
+
- **`__mdt` field mappings** (`mdt_mapping.py`): turns mapping records (e.g.
|
|
174
|
+
`Opportunity_To_Quote_Mapping__mdt`) into traversable `maps_to` field→field edges so
|
|
175
|
+
impact follows the Opp→Quote boundary.
|
|
176
|
+
- **Analysis passes** (whole-graph): Order of Execution, Governor Limits, recursive
|
|
177
|
+
triggers, Profile/FLS permission impact, Flow↔CPQ infinite loops, CPQ↔Validation
|
|
178
|
+
Rule conflicts.
|
|
179
|
+
- **Token-minimized consumption** (`pipeline.py`/`query.py`/`cli.py`/`viz.py`): Leiden
|
|
180
|
+
community clustering, `token_budget`-bounded queries, an MCP server, and a focused
|
|
181
|
+
self-contained HTML visualization.
|
|
182
|
+
|
|
183
|
+
Every node/edge carries a `confidence` (EXTRACTED / INFERRED / AMBIGUOUS) so you know
|
|
184
|
+
what is certain vs. heuristic. See [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md),
|
|
185
|
+
[`docs/ADR.md`](./docs/ADR.md), and [`docs/PRD.md`](./docs/PRD.md).
|
|
186
|
+
|
|
187
|
+
## Install
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
pip install -e .
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Requires Python 3.11+. `networkx` is required; `graspologic` (Leiden), `mcp` (serve),
|
|
194
|
+
and `tree-sitter` are optional and degrade gracefully when absent.
|
|
195
|
+
|
|
196
|
+
## Quick start
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# 1. Extract + enrich a graph (optionally merge CPQ rule data)
|
|
200
|
+
python -m graphify.salesforce extract path/to/sf-repo \
|
|
201
|
+
--output-dir graphify-out --cpq-data path/to/cpq-records
|
|
202
|
+
|
|
203
|
+
# 2. Ask SF-aware questions (token-bounded)
|
|
204
|
+
python -m graphify.salesforce impact <node-id> --direction downstream
|
|
205
|
+
python -m graphify.salesforce violations --severity HIGH
|
|
206
|
+
python -m graphify.salesforce cpq-chain SBQQ__Quote__c
|
|
207
|
+
python -m graphify.salesforce ooe Opportunity
|
|
208
|
+
|
|
209
|
+
# 3. Visualize a focused subgraph (self-contained HTML)
|
|
210
|
+
python -m graphify.salesforce viz graphify-out/graph.json --focus <node-id>
|
|
211
|
+
|
|
212
|
+
# 4. Serve over MCP for an LLM client
|
|
213
|
+
python -m graphify.serve graphify-out/graph.json
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Run the test suite with `pytest tests/test_salesforce.py -v`.
|
|
217
|
+
|
|
218
|
+
## Use it from an AI agent (Claude, Copilot, Cursor, …)
|
|
219
|
+
|
|
220
|
+
The point of `graphify-sf` is that an agent answers Salesforce questions from the
|
|
221
|
+
**graph** instead of reading raw metadata — so it stays accurate and token-cheap. The
|
|
222
|
+
flow is always: **extract once → expose the graph → the agent queries it.**
|
|
223
|
+
|
|
224
|
+
### Step 1 — build the graph (once per org snapshot)
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
python -m graphify.salesforce extract path/to/sf-repo \
|
|
228
|
+
--output-dir graphify-out --cpq-data path/to/cpq-records
|
|
229
|
+
# → graphify-out/graph.json
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Re-run after a metadata pull to refresh it.
|
|
233
|
+
|
|
234
|
+
### Option A — MCP server (recommended)
|
|
235
|
+
|
|
236
|
+
Serve the graph over MCP; the agent gets token-bounded Salesforce tools
|
|
237
|
+
(`sf_impact`, `sf_violations`, `sf_cpq_chain`, `sf_ooe`) plus the base graph tools
|
|
238
|
+
(`query_graph`, `graph_stats`, `god_nodes`, `shortest_path`, `get_neighbors`, …).
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# stdio transport (default — what desktop agents launch)
|
|
242
|
+
python -m graphify.serve graphify-out/graph.json
|
|
243
|
+
# or the console script after `pip install -e .`
|
|
244
|
+
graphify-mcp graphify-out/graph.json
|
|
245
|
+
# shared HTTP transport (team / remote)
|
|
246
|
+
python -m graphify.serve graphify-out/graph.json --transport http --port 8080
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Claude Code** — one command (use an absolute path to `graph.json`):
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
claude mcp add graphify-sf -- python -m graphify.serve /abs/path/to/graphify-out/graph.json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Claude Desktop / Cursor / Windsurf** — add to the MCP config
|
|
256
|
+
(`claude_desktop_config.json`, `.cursor/mcp.json`, …); they share this shape:
|
|
257
|
+
|
|
258
|
+
```json
|
|
259
|
+
{
|
|
260
|
+
"mcpServers": {
|
|
261
|
+
"graphify-sf": {
|
|
262
|
+
"command": "python",
|
|
263
|
+
"args": ["-m", "graphify.serve", "/abs/path/to/graphify-out/graph.json"]
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**VS Code / GitHub Copilot** — `.vscode/mcp.json` uses the `servers` key:
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"servers": {
|
|
274
|
+
"graphify-sf": {
|
|
275
|
+
"type": "stdio",
|
|
276
|
+
"command": "python",
|
|
277
|
+
"args": ["-m", "graphify.serve", "/abs/path/to/graphify-out/graph.json"]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Then just ask, e.g. *"What breaks if I change `Opportunity.Amount`? Use graphify-sf."*
|
|
284
|
+
|
|
285
|
+
### Option B — no MCP (CLI the agent shells out to)
|
|
286
|
+
|
|
287
|
+
For agents that run shell commands but have no MCP, point them at the CLI — each
|
|
288
|
+
command prints a token-bounded answer to stdout:
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
python -m graphify.salesforce impact <node-id> --direction downstream
|
|
292
|
+
python -m graphify.salesforce violations --severity HIGH
|
|
293
|
+
python -m graphify.salesforce cpq-chain SBQQ__Quote__c
|
|
294
|
+
python -m graphify.salesforce ooe Opportunity
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Tell the agent to use it on every task
|
|
298
|
+
|
|
299
|
+
Drop a short rule into the agent's project-instructions file — `CLAUDE.md` (Claude
|
|
300
|
+
Code), `.github/copilot-instructions.md` (Copilot), `.cursorrules` (Cursor), or
|
|
301
|
+
`AGENTS.md`:
|
|
302
|
+
|
|
303
|
+
```markdown
|
|
304
|
+
## Salesforce knowledge graph
|
|
305
|
+
Before answering Salesforce impact / CPQ / Order-of-Execution / Governor-Limit
|
|
306
|
+
questions, consult the graphify-sf graph instead of reading raw metadata:
|
|
307
|
+
- If the `graphify-sf` MCP server is connected, call `sf_impact` / `sf_violations` /
|
|
308
|
+
`sf_cpq_chain` / `sf_ooe`.
|
|
309
|
+
- Otherwise run `python -m graphify.salesforce <impact|violations|cpq-chain|ooe> …`.
|
|
310
|
+
Rebuild it with `python -m graphify.salesforce extract <repo> --cpq-data <dir>`
|
|
311
|
+
after pulling fresh metadata.
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Coverage
|
|
315
|
+
|
|
316
|
+
| Area | Module | Status |
|
|
317
|
+
|---|---|---|
|
|
318
|
+
| Core parsers (Apex/Flow/LWC/Objects/Profiles) | `apex_enhanced`, `flow`, `lwc`, `objects`, `profiles` | ✅ |
|
|
319
|
+
| Metadata coverage (RecordType/PSG/Workflow/Custom Metadata/Sharing/Label/Setting) | `metadata`, `objects` | ✅ |
|
|
320
|
+
| CPQ rule data (SFDX + Gearset + JS QCP) | `cpq_data` | ✅ |
|
|
321
|
+
| `__mdt` field mapping (Opp→Quote) | `mdt_mapping` | ✅ |
|
|
322
|
+
| Token-minimized consumption (cluster/query/CLI/viz/MCP) | `pipeline`, `query`, `cli`, `viz` | ✅ |
|
|
323
|
+
| Neo4j export | `neo4j_sf` | ✅ |
|
|
324
|
+
| Apex cross-class call resolution | tree-sitter promotion | ⏸ deferred (ADR-019) |
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Inspiration & Credits
|
|
329
|
+
|
|
330
|
+
This project stands on the shoulders of [**graphify**](https://github.com/safishamsi/graphify)
|
|
331
|
+
by **[Safi Shamsi](https://github.com/safishamsi)**. The core idea, architecture, and
|
|
332
|
+
API ergonomics are theirs — `graphify-sf` is an independent, Salesforce-tailored
|
|
333
|
+
adaptation built with deep respect for the original work. If you need a
|
|
334
|
+
platform-agnostic solution, please use and support the upstream project.
|
|
335
|
+
|
|
336
|
+
> 본 프로젝트는 [graphify](https://github.com/safishamsi/graphify)의 아이디어와 아키텍처에서
|
|
337
|
+
> 출발했습니다. 핵심 개념에 대한 모든 공로는 원작자에게 있으며, `graphify-sf`는 이를 Salesforce
|
|
338
|
+
> 플랫폼(Apex/Flow/LWC/CPQ) 환경에 맞게 재구현한 독립적인 파생 프로젝트입니다. 원작자의 노고에
|
|
339
|
+
> 깊이 감사드립니다. 범용 환경이 필요하다면 원본 프로젝트를 사용하시길 권장합니다.
|
|
340
|
+
|
|
341
|
+
> The upstream project's original README is preserved in this repo as [`README.upstream.md`](./README.upstream.md).
|
|
342
|
+
|
|
343
|
+
## License
|
|
344
|
+
|
|
345
|
+
MIT © Safi Shamsi (graphify) · MIT © JeremyKo95 (graphify-sf). See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# graphify-sf
|
|
2
|
+
|
|
3
|
+
> ⚡ A **Salesforce-native** knowledge-graph library — turn any Enterprise (CPQ)
|
|
4
|
+
> Salesforce org's metadata into a token-minimized graph for onboarding, analysis,
|
|
5
|
+
> impact review, and development.
|
|
6
|
+
> Inspired by [graphify](https://github.com/safishamsi/graphify); rebuilt in Python
|
|
7
|
+
> for Apex, Flow, LWC, CPQ data, and the realities of Governor Limits.
|
|
8
|
+
|
|
9
|
+
[](./LICENSE)
|
|
10
|
+
[](#)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What it is
|
|
15
|
+
|
|
16
|
+
`graphify-sf` is a **Python library** (not an on-platform package). It statically
|
|
17
|
+
parses a Salesforce metadata repository — and CPQ rule **data** — into a NetworkX
|
|
18
|
+
knowledge graph, runs Salesforce-aware analysis passes, then serves a
|
|
19
|
+
**token-minimized** view so an LLM (or a person) can answer "what breaks if I change
|
|
20
|
+
X?", "how is a Quote created from an Opportunity?", or "where are the Governor-Limit
|
|
21
|
+
risks?" without reading the raw org.
|
|
22
|
+
|
|
23
|
+
The North Star: **any Enterprise CPQ org → SF-specific KB graph → token-minimized
|
|
24
|
+
consumption → onboarding, analysis, impact review, and development.**
|
|
25
|
+
|
|
26
|
+
## Capabilities
|
|
27
|
+
|
|
28
|
+
- **Parsers** (`graphify/salesforce/`): Apex (regex, ADR-019), Flow (typed record
|
|
29
|
+
tags), LWC (`@wire` + imperative Apex), Custom Object/Field, Profile/Permission Set,
|
|
30
|
+
Validation Rule, Record Type, Permission Set Group, Workflow, **Custom Metadata
|
|
31
|
+
records, Sharing Rules, Custom Labels, Custom Settings**.
|
|
32
|
+
- **CPQ rule data ingest** (`cpq_data.py`): SBQQ Price/Product Rules, Conditions,
|
|
33
|
+
Actions from **SFDX JSON or Gearset `*.gs.json`**, plus **JavaScript QCP** custom
|
|
34
|
+
scripts — the logic that lives as data records, not metadata.
|
|
35
|
+
- **`__mdt` field mappings** (`mdt_mapping.py`): turns mapping records (e.g.
|
|
36
|
+
`Opportunity_To_Quote_Mapping__mdt`) into traversable `maps_to` field→field edges so
|
|
37
|
+
impact follows the Opp→Quote boundary.
|
|
38
|
+
- **Analysis passes** (whole-graph): Order of Execution, Governor Limits, recursive
|
|
39
|
+
triggers, Profile/FLS permission impact, Flow↔CPQ infinite loops, CPQ↔Validation
|
|
40
|
+
Rule conflicts.
|
|
41
|
+
- **Token-minimized consumption** (`pipeline.py`/`query.py`/`cli.py`/`viz.py`): Leiden
|
|
42
|
+
community clustering, `token_budget`-bounded queries, an MCP server, and a focused
|
|
43
|
+
self-contained HTML visualization.
|
|
44
|
+
|
|
45
|
+
Every node/edge carries a `confidence` (EXTRACTED / INFERRED / AMBIGUOUS) so you know
|
|
46
|
+
what is certain vs. heuristic. See [`docs/ARCHITECTURE.md`](./docs/ARCHITECTURE.md),
|
|
47
|
+
[`docs/ADR.md`](./docs/ADR.md), and [`docs/PRD.md`](./docs/PRD.md).
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -e .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Requires Python 3.11+. `networkx` is required; `graspologic` (Leiden), `mcp` (serve),
|
|
56
|
+
and `tree-sitter` are optional and degrade gracefully when absent.
|
|
57
|
+
|
|
58
|
+
## Quick start
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# 1. Extract + enrich a graph (optionally merge CPQ rule data)
|
|
62
|
+
python -m graphify.salesforce extract path/to/sf-repo \
|
|
63
|
+
--output-dir graphify-out --cpq-data path/to/cpq-records
|
|
64
|
+
|
|
65
|
+
# 2. Ask SF-aware questions (token-bounded)
|
|
66
|
+
python -m graphify.salesforce impact <node-id> --direction downstream
|
|
67
|
+
python -m graphify.salesforce violations --severity HIGH
|
|
68
|
+
python -m graphify.salesforce cpq-chain SBQQ__Quote__c
|
|
69
|
+
python -m graphify.salesforce ooe Opportunity
|
|
70
|
+
|
|
71
|
+
# 3. Visualize a focused subgraph (self-contained HTML)
|
|
72
|
+
python -m graphify.salesforce viz graphify-out/graph.json --focus <node-id>
|
|
73
|
+
|
|
74
|
+
# 4. Serve over MCP for an LLM client
|
|
75
|
+
python -m graphify.serve graphify-out/graph.json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Run the test suite with `pytest tests/test_salesforce.py -v`.
|
|
79
|
+
|
|
80
|
+
## Use it from an AI agent (Claude, Copilot, Cursor, …)
|
|
81
|
+
|
|
82
|
+
The point of `graphify-sf` is that an agent answers Salesforce questions from the
|
|
83
|
+
**graph** instead of reading raw metadata — so it stays accurate and token-cheap. The
|
|
84
|
+
flow is always: **extract once → expose the graph → the agent queries it.**
|
|
85
|
+
|
|
86
|
+
### Step 1 — build the graph (once per org snapshot)
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python -m graphify.salesforce extract path/to/sf-repo \
|
|
90
|
+
--output-dir graphify-out --cpq-data path/to/cpq-records
|
|
91
|
+
# → graphify-out/graph.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Re-run after a metadata pull to refresh it.
|
|
95
|
+
|
|
96
|
+
### Option A — MCP server (recommended)
|
|
97
|
+
|
|
98
|
+
Serve the graph over MCP; the agent gets token-bounded Salesforce tools
|
|
99
|
+
(`sf_impact`, `sf_violations`, `sf_cpq_chain`, `sf_ooe`) plus the base graph tools
|
|
100
|
+
(`query_graph`, `graph_stats`, `god_nodes`, `shortest_path`, `get_neighbors`, …).
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# stdio transport (default — what desktop agents launch)
|
|
104
|
+
python -m graphify.serve graphify-out/graph.json
|
|
105
|
+
# or the console script after `pip install -e .`
|
|
106
|
+
graphify-mcp graphify-out/graph.json
|
|
107
|
+
# shared HTTP transport (team / remote)
|
|
108
|
+
python -m graphify.serve graphify-out/graph.json --transport http --port 8080
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Claude Code** — one command (use an absolute path to `graph.json`):
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
claude mcp add graphify-sf -- python -m graphify.serve /abs/path/to/graphify-out/graph.json
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Claude Desktop / Cursor / Windsurf** — add to the MCP config
|
|
118
|
+
(`claude_desktop_config.json`, `.cursor/mcp.json`, …); they share this shape:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"mcpServers": {
|
|
123
|
+
"graphify-sf": {
|
|
124
|
+
"command": "python",
|
|
125
|
+
"args": ["-m", "graphify.serve", "/abs/path/to/graphify-out/graph.json"]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**VS Code / GitHub Copilot** — `.vscode/mcp.json` uses the `servers` key:
|
|
132
|
+
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"servers": {
|
|
136
|
+
"graphify-sf": {
|
|
137
|
+
"type": "stdio",
|
|
138
|
+
"command": "python",
|
|
139
|
+
"args": ["-m", "graphify.serve", "/abs/path/to/graphify-out/graph.json"]
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Then just ask, e.g. *"What breaks if I change `Opportunity.Amount`? Use graphify-sf."*
|
|
146
|
+
|
|
147
|
+
### Option B — no MCP (CLI the agent shells out to)
|
|
148
|
+
|
|
149
|
+
For agents that run shell commands but have no MCP, point them at the CLI — each
|
|
150
|
+
command prints a token-bounded answer to stdout:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python -m graphify.salesforce impact <node-id> --direction downstream
|
|
154
|
+
python -m graphify.salesforce violations --severity HIGH
|
|
155
|
+
python -m graphify.salesforce cpq-chain SBQQ__Quote__c
|
|
156
|
+
python -m graphify.salesforce ooe Opportunity
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Tell the agent to use it on every task
|
|
160
|
+
|
|
161
|
+
Drop a short rule into the agent's project-instructions file — `CLAUDE.md` (Claude
|
|
162
|
+
Code), `.github/copilot-instructions.md` (Copilot), `.cursorrules` (Cursor), or
|
|
163
|
+
`AGENTS.md`:
|
|
164
|
+
|
|
165
|
+
```markdown
|
|
166
|
+
## Salesforce knowledge graph
|
|
167
|
+
Before answering Salesforce impact / CPQ / Order-of-Execution / Governor-Limit
|
|
168
|
+
questions, consult the graphify-sf graph instead of reading raw metadata:
|
|
169
|
+
- If the `graphify-sf` MCP server is connected, call `sf_impact` / `sf_violations` /
|
|
170
|
+
`sf_cpq_chain` / `sf_ooe`.
|
|
171
|
+
- Otherwise run `python -m graphify.salesforce <impact|violations|cpq-chain|ooe> …`.
|
|
172
|
+
Rebuild it with `python -m graphify.salesforce extract <repo> --cpq-data <dir>`
|
|
173
|
+
after pulling fresh metadata.
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Coverage
|
|
177
|
+
|
|
178
|
+
| Area | Module | Status |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| Core parsers (Apex/Flow/LWC/Objects/Profiles) | `apex_enhanced`, `flow`, `lwc`, `objects`, `profiles` | ✅ |
|
|
181
|
+
| Metadata coverage (RecordType/PSG/Workflow/Custom Metadata/Sharing/Label/Setting) | `metadata`, `objects` | ✅ |
|
|
182
|
+
| CPQ rule data (SFDX + Gearset + JS QCP) | `cpq_data` | ✅ |
|
|
183
|
+
| `__mdt` field mapping (Opp→Quote) | `mdt_mapping` | ✅ |
|
|
184
|
+
| Token-minimized consumption (cluster/query/CLI/viz/MCP) | `pipeline`, `query`, `cli`, `viz` | ✅ |
|
|
185
|
+
| Neo4j export | `neo4j_sf` | ✅ |
|
|
186
|
+
| Apex cross-class call resolution | tree-sitter promotion | ⏸ deferred (ADR-019) |
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Inspiration & Credits
|
|
191
|
+
|
|
192
|
+
This project stands on the shoulders of [**graphify**](https://github.com/safishamsi/graphify)
|
|
193
|
+
by **[Safi Shamsi](https://github.com/safishamsi)**. The core idea, architecture, and
|
|
194
|
+
API ergonomics are theirs — `graphify-sf` is an independent, Salesforce-tailored
|
|
195
|
+
adaptation built with deep respect for the original work. If you need a
|
|
196
|
+
platform-agnostic solution, please use and support the upstream project.
|
|
197
|
+
|
|
198
|
+
> 본 프로젝트는 [graphify](https://github.com/safishamsi/graphify)의 아이디어와 아키텍처에서
|
|
199
|
+
> 출발했습니다. 핵심 개념에 대한 모든 공로는 원작자에게 있으며, `graphify-sf`는 이를 Salesforce
|
|
200
|
+
> 플랫폼(Apex/Flow/LWC/CPQ) 환경에 맞게 재구현한 독립적인 파생 프로젝트입니다. 원작자의 노고에
|
|
201
|
+
> 깊이 감사드립니다. 범용 환경이 필요하다면 원본 프로젝트를 사용하시길 권장합니다.
|
|
202
|
+
|
|
203
|
+
> The upstream project's original README is preserved in this repo as [`README.upstream.md`](./README.upstream.md).
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT © Safi Shamsi (graphify) · MIT © JeremyKo95 (graphify-sf). See [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""graphify - extract · build · cluster · analyze · report."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def __getattr__(name):
|
|
5
|
+
# Lazy imports so `graphify install` works before heavy deps are in place.
|
|
6
|
+
_map = {
|
|
7
|
+
"extract": ("graphify.extract", "extract"),
|
|
8
|
+
"collect_files": ("graphify.extract", "collect_files"),
|
|
9
|
+
"build_from_json": ("graphify.build", "build_from_json"),
|
|
10
|
+
"cluster": ("graphify.cluster", "cluster"),
|
|
11
|
+
"score_all": ("graphify.cluster", "score_all"),
|
|
12
|
+
"cohesion_score": ("graphify.cluster", "cohesion_score"),
|
|
13
|
+
"god_nodes": ("graphify.analyze", "god_nodes"),
|
|
14
|
+
"surprising_connections": ("graphify.analyze", "surprising_connections"),
|
|
15
|
+
"suggest_questions": ("graphify.analyze", "suggest_questions"),
|
|
16
|
+
"generate": ("graphify.report", "generate"),
|
|
17
|
+
"to_json": ("graphify.export", "to_json"),
|
|
18
|
+
"to_html": ("graphify.export", "to_html"),
|
|
19
|
+
"to_svg": ("graphify.export", "to_svg"),
|
|
20
|
+
"to_canvas": ("graphify.export", "to_canvas"),
|
|
21
|
+
"to_wiki": ("graphify.wiki", "to_wiki"),
|
|
22
|
+
}
|
|
23
|
+
if name in _map:
|
|
24
|
+
import importlib
|
|
25
|
+
mod_name, attr = _map[name]
|
|
26
|
+
mod = importlib.import_module(mod_name)
|
|
27
|
+
return getattr(mod, attr)
|
|
28
|
+
raise AttributeError(f"module 'graphify' has no attribute {name!r}")
|