graphitect 0.2.0__py3-none-any.whl
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/__init__.py +30 -0
- graphify/__main__.py +757 -0
- graphify/_minhash.py +107 -0
- graphify/affected.py +318 -0
- graphify/always_on/agents-md.md +12 -0
- graphify/always_on/antigravity-rules.md +14 -0
- graphify/always_on/claude-md.md +9 -0
- graphify/always_on/gemini-md.md +9 -0
- graphify/always_on/kiro-steering.md +5 -0
- graphify/always_on/vscode-instructions.md +17 -0
- graphify/analyze.py +769 -0
- graphify/benchmark.py +152 -0
- graphify/build.py +2300 -0
- graphify/cache.py +1746 -0
- graphify/callflow_html.py +2051 -0
- graphify/cargo_introspect.py +109 -0
- graphify/cli.py +4745 -0
- graphify/cluster.py +409 -0
- graphify/command-kilo.md +15 -0
- graphify/cross_repo_calls.py +216 -0
- graphify/cross_repo_types.py +75 -0
- graphify/csharp_dispatch.py +154 -0
- graphify/dedup.py +1213 -0
- graphify/detect.py +2566 -0
- graphify/diagnostics.py +406 -0
- graphify/export.py +1349 -0
- graphify/exporters/__init__.py +1 -0
- graphify/exporters/base.py +14 -0
- graphify/exporters/graphdb.py +173 -0
- graphify/exporters/html.py +637 -0
- graphify/extract.py +7856 -0
- graphify/extractors/MIGRATION.md +107 -0
- graphify/extractors/__init__.py +66 -0
- graphify/extractors/apex.py +215 -0
- graphify/extractors/base.py +85 -0
- graphify/extractors/bash.py +579 -0
- graphify/extractors/blade.py +53 -0
- graphify/extractors/commonlisp.py +540 -0
- graphify/extractors/csharp.py +448 -0
- graphify/extractors/dart.py +564 -0
- graphify/extractors/dm.py +494 -0
- graphify/extractors/elixir.py +241 -0
- graphify/extractors/engine.py +6509 -0
- graphify/extractors/fortran.py +311 -0
- graphify/extractors/go.py +527 -0
- graphify/extractors/json_config.py +240 -0
- graphify/extractors/julia.py +289 -0
- graphify/extractors/markdown.py +408 -0
- graphify/extractors/models.py +131 -0
- graphify/extractors/objc.py +566 -0
- graphify/extractors/ocaml.py +289 -0
- graphify/extractors/pascal.py +688 -0
- graphify/extractors/pascal_forms.py +196 -0
- graphify/extractors/powershell.py +522 -0
- graphify/extractors/razor.py +192 -0
- graphify/extractors/resolution.py +3584 -0
- graphify/extractors/robot.py +296 -0
- graphify/extractors/rust.py +470 -0
- graphify/extractors/sln.py +92 -0
- graphify/extractors/sql.py +720 -0
- graphify/extractors/terraform.py +181 -0
- graphify/extractors/verilog.py +329 -0
- graphify/extractors/zig.py +181 -0
- graphify/file_slice.py +246 -0
- graphify/global_graph.py +194 -0
- graphify/google_workspace.py +237 -0
- graphify/hooks.py +933 -0
- graphify/ids.py +93 -0
- graphify/ingest.py +358 -0
- graphify/install.py +2366 -0
- graphify/llm.py +3544 -0
- graphify/manifest.py +4 -0
- graphify/manifest_ingest.py +311 -0
- graphify/mcp_ingest.py +386 -0
- graphify/multigraph_compat.py +212 -0
- graphify/pascal_resolution.py +129 -0
- graphify/paths.py +436 -0
- graphify/pg_introspect.py +165 -0
- graphify/prs.py +770 -0
- graphify/querylog.py +80 -0
- graphify/reflect.py +882 -0
- graphify/report.py +346 -0
- graphify/resolver_registry.py +85 -0
- graphify/ruby_resolution.py +242 -0
- graphify/scip_ingest.py +363 -0
- graphify/security.py +460 -0
- graphify/semantic_cleanup.py +336 -0
- graphify/serve.py +2608 -0
- graphify/skill-agents.md +710 -0
- graphify/skill-aider.md +1283 -0
- graphify/skill-amp.md +710 -0
- graphify/skill-claw.md +713 -0
- graphify/skill-codex.md +710 -0
- graphify/skill-copilot.md +713 -0
- graphify/skill-devin.md +1410 -0
- graphify/skill-droid.md +710 -0
- graphify/skill-kilo.md +722 -0
- graphify/skill-kiro.md +713 -0
- graphify/skill-opencode.md +705 -0
- graphify/skill-pi.md +713 -0
- graphify/skill-trae.md +711 -0
- graphify/skill-vscode.md +709 -0
- graphify/skill-windows.md +755 -0
- graphify/skill.md +713 -0
- graphify/skills/agents/references/add-watch.md +56 -0
- graphify/skills/agents/references/exports.md +87 -0
- graphify/skills/agents/references/extraction-spec.md +70 -0
- graphify/skills/agents/references/github-and-merge.md +46 -0
- graphify/skills/agents/references/hooks.md +33 -0
- graphify/skills/agents/references/query.md +311 -0
- graphify/skills/agents/references/transcribe.md +52 -0
- graphify/skills/agents/references/update.md +210 -0
- graphify/skills/amp/references/add-watch.md +56 -0
- graphify/skills/amp/references/exports.md +87 -0
- graphify/skills/amp/references/extraction-spec.md +70 -0
- graphify/skills/amp/references/github-and-merge.md +46 -0
- graphify/skills/amp/references/hooks.md +33 -0
- graphify/skills/amp/references/query.md +311 -0
- graphify/skills/amp/references/transcribe.md +52 -0
- graphify/skills/amp/references/update.md +210 -0
- graphify/skills/claude/references/add-watch.md +56 -0
- graphify/skills/claude/references/exports.md +87 -0
- graphify/skills/claude/references/extraction-spec.md +70 -0
- graphify/skills/claude/references/github-and-merge.md +46 -0
- graphify/skills/claude/references/hooks.md +33 -0
- graphify/skills/claude/references/query.md +311 -0
- graphify/skills/claude/references/transcribe.md +52 -0
- graphify/skills/claude/references/update.md +210 -0
- graphify/skills/claw/references/add-watch.md +56 -0
- graphify/skills/claw/references/exports.md +87 -0
- graphify/skills/claw/references/extraction-spec.md +31 -0
- graphify/skills/claw/references/github-and-merge.md +46 -0
- graphify/skills/claw/references/hooks.md +33 -0
- graphify/skills/claw/references/query.md +311 -0
- graphify/skills/claw/references/transcribe.md +52 -0
- graphify/skills/claw/references/update.md +210 -0
- graphify/skills/codex/references/add-watch.md +56 -0
- graphify/skills/codex/references/exports.md +87 -0
- graphify/skills/codex/references/extraction-spec.md +31 -0
- graphify/skills/codex/references/github-and-merge.md +46 -0
- graphify/skills/codex/references/hooks.md +33 -0
- graphify/skills/codex/references/query.md +311 -0
- graphify/skills/codex/references/transcribe.md +52 -0
- graphify/skills/codex/references/update.md +210 -0
- graphify/skills/copilot/references/add-watch.md +56 -0
- graphify/skills/copilot/references/exports.md +87 -0
- graphify/skills/copilot/references/extraction-spec.md +70 -0
- graphify/skills/copilot/references/github-and-merge.md +46 -0
- graphify/skills/copilot/references/hooks.md +33 -0
- graphify/skills/copilot/references/query.md +311 -0
- graphify/skills/copilot/references/transcribe.md +52 -0
- graphify/skills/copilot/references/update.md +210 -0
- graphify/skills/droid/references/add-watch.md +56 -0
- graphify/skills/droid/references/exports.md +87 -0
- graphify/skills/droid/references/extraction-spec.md +70 -0
- graphify/skills/droid/references/github-and-merge.md +46 -0
- graphify/skills/droid/references/hooks.md +33 -0
- graphify/skills/droid/references/query.md +311 -0
- graphify/skills/droid/references/transcribe.md +52 -0
- graphify/skills/droid/references/update.md +210 -0
- graphify/skills/kilo/references/add-watch.md +56 -0
- graphify/skills/kilo/references/exports.md +87 -0
- graphify/skills/kilo/references/extraction-spec.md +70 -0
- graphify/skills/kilo/references/github-and-merge.md +46 -0
- graphify/skills/kilo/references/hooks.md +33 -0
- graphify/skills/kilo/references/query.md +311 -0
- graphify/skills/kilo/references/transcribe.md +52 -0
- graphify/skills/kilo/references/update.md +210 -0
- graphify/skills/kiro/references/add-watch.md +56 -0
- graphify/skills/kiro/references/exports.md +87 -0
- graphify/skills/kiro/references/extraction-spec.md +31 -0
- graphify/skills/kiro/references/github-and-merge.md +46 -0
- graphify/skills/kiro/references/hooks.md +33 -0
- graphify/skills/kiro/references/query.md +311 -0
- graphify/skills/kiro/references/transcribe.md +52 -0
- graphify/skills/kiro/references/update.md +210 -0
- graphify/skills/opencode/references/add-watch.md +56 -0
- graphify/skills/opencode/references/exports.md +87 -0
- graphify/skills/opencode/references/extraction-spec.md +70 -0
- graphify/skills/opencode/references/github-and-merge.md +46 -0
- graphify/skills/opencode/references/hooks.md +33 -0
- graphify/skills/opencode/references/query.md +311 -0
- graphify/skills/opencode/references/transcribe.md +52 -0
- graphify/skills/opencode/references/update.md +210 -0
- graphify/skills/pi/references/add-watch.md +56 -0
- graphify/skills/pi/references/exports.md +87 -0
- graphify/skills/pi/references/extraction-spec.md +31 -0
- graphify/skills/pi/references/github-and-merge.md +46 -0
- graphify/skills/pi/references/hooks.md +33 -0
- graphify/skills/pi/references/query.md +311 -0
- graphify/skills/pi/references/transcribe.md +52 -0
- graphify/skills/pi/references/update.md +210 -0
- graphify/skills/trae/references/add-watch.md +56 -0
- graphify/skills/trae/references/exports.md +87 -0
- graphify/skills/trae/references/extraction-spec.md +70 -0
- graphify/skills/trae/references/github-and-merge.md +46 -0
- graphify/skills/trae/references/hooks.md +35 -0
- graphify/skills/trae/references/query.md +311 -0
- graphify/skills/trae/references/transcribe.md +52 -0
- graphify/skills/trae/references/update.md +210 -0
- graphify/skills/vscode/references/add-watch.md +56 -0
- graphify/skills/vscode/references/exports.md +87 -0
- graphify/skills/vscode/references/extraction-spec.md +70 -0
- graphify/skills/vscode/references/github-and-merge.md +46 -0
- graphify/skills/vscode/references/hooks.md +33 -0
- graphify/skills/vscode/references/query.md +311 -0
- graphify/skills/vscode/references/transcribe.md +52 -0
- graphify/skills/vscode/references/update.md +210 -0
- graphify/skills/windows/references/add-watch.md +56 -0
- graphify/skills/windows/references/exports.md +87 -0
- graphify/skills/windows/references/extraction-spec.md +70 -0
- graphify/skills/windows/references/github-and-merge.md +46 -0
- graphify/skills/windows/references/hooks.md +33 -0
- graphify/skills/windows/references/query.md +311 -0
- graphify/skills/windows/references/transcribe.md +52 -0
- graphify/skills/windows/references/update.md +210 -0
- graphify/symbol_resolution.py +556 -0
- graphify/transcribe.py +186 -0
- graphify/tree_html.py +603 -0
- graphify/validate.py +95 -0
- graphify/watch.py +2280 -0
- graphify/wiki.py +405 -0
- graphitect/__init__.py +28 -0
- graphitect/__main__.py +4 -0
- graphitect/_vendor/__init__.py +2 -0
- graphitect/_vendor/archify/LICENSE +22 -0
- graphitect/_vendor/archify/SKILL.md +137 -0
- graphitect/_vendor/archify/THIRD_PARTY_NOTICES.md +69 -0
- graphitect/_vendor/archify/assets/JetBrainsMono-OFL.txt +93 -0
- graphitect/_vendor/archify/assets/template.html +14935 -0
- graphitect/_vendor/archify/bin/archify.mjs +2091 -0
- graphitect/_vendor/archify/bin/open-artifact.mjs +86 -0
- graphitect/_vendor/archify/bin/preview.mjs +653 -0
- graphitect/_vendor/archify/bin/visual-check.mjs +829 -0
- graphitect/_vendor/archify/brand-marks/README.md +31 -0
- graphitect/_vendor/archify/brand-marks/catalog.json +131 -0
- graphitect/_vendor/archify/delta/architecture-delta.mjs +1221 -0
- graphitect/_vendor/archify/examples/agent-run.lifecycle.json +60 -0
- graphitect/_vendor/archify/examples/agent-tool-call.workflow.json +94 -0
- graphitect/_vendor/archify/examples/async-job-roundtrip.sequence.json +61 -0
- graphitect/_vendor/archify/examples/brand-aware-delivery.architecture.json +47 -0
- graphitect/_vendor/archify/examples/cache-miss-request.sequence.json +82 -0
- graphitect/_vendor/archify/examples/checkout-platform.base.architecture.json +31 -0
- graphitect/_vendor/archify/examples/checkout-platform.head.architecture.json +31 -0
- graphitect/_vendor/archify/examples/dataflow-product-analytics.html +15045 -0
- graphitect/_vendor/archify/examples/deployment-release.lifecycle.json +49 -0
- graphitect/_vendor/archify/examples/event-stream.dataflow.json +57 -0
- graphitect/_vendor/archify/examples/incident-response.workflow.json +64 -0
- graphitect/_vendor/archify/examples/lifecycle-agent-run.html +14980 -0
- graphitect/_vendor/archify/examples/product-analytics.dataflow.json +76 -0
- graphitect/_vendor/archify/examples/production-deployment.architecture.json +71 -0
- graphitect/_vendor/archify/examples/release-delivery.workflow.json +62 -0
- graphitect/_vendor/archify/examples/sequence-cache-miss-request.html +15060 -0
- graphitect/_vendor/archify/examples/web-app-rendered.html +15009 -0
- graphitect/_vendor/archify/examples/web-app.architecture.json +46 -0
- graphitect/_vendor/archify/examples/workflow-agent-tool-call-rendered.html +15051 -0
- graphitect/_vendor/archify/migrations/workflow-v2.mjs +279 -0
- graphitect/_vendor/archify/package-lock.json +149 -0
- graphitect/_vendor/archify/package.json +39 -0
- graphitect/_vendor/archify/recipes/scenarios.mjs +391 -0
- graphitect/_vendor/archify/references/authoring-contract.md +243 -0
- graphitect/_vendor/archify/references/brand-marks.md +65 -0
- graphitect/_vendor/archify/references/delivery-contract.md +120 -0
- graphitect/_vendor/archify/references/viewer-runtime.md +45 -0
- graphitect/_vendor/archify/renderers/architecture/grid.mjs +62 -0
- graphitect/_vendor/archify/renderers/architecture/render-architecture.mjs +1078 -0
- graphitect/_vendor/archify/renderers/dataflow/README.md +104 -0
- graphitect/_vendor/archify/renderers/dataflow/render-dataflow.mjs +483 -0
- graphitect/_vendor/archify/renderers/lifecycle/README.md +115 -0
- graphitect/_vendor/archify/renderers/lifecycle/render-lifecycle.mjs +561 -0
- graphitect/_vendor/archify/renderers/sequence/README.md +114 -0
- graphitect/_vendor/archify/renderers/sequence/render-sequence.mjs +464 -0
- graphitect/_vendor/archify/renderers/shared/brand-marks.mjs +563 -0
- graphitect/_vendor/archify/renderers/shared/cli.mjs +218 -0
- graphitect/_vendor/archify/renderers/shared/desktop-readability.mjs +26 -0
- graphitect/_vendor/archify/renderers/shared/diagnostics.mjs +127 -0
- graphitect/_vendor/archify/renderers/shared/engineering-profiles.mjs +157 -0
- graphitect/_vendor/archify/renderers/shared/generated-brand-marks.mjs +2003 -0
- graphitect/_vendor/archify/renderers/shared/generated-validators.mjs +13 -0
- graphitect/_vendor/archify/renderers/shared/geometry.mjs +1423 -0
- graphitect/_vendor/archify/renderers/shared/i18n.mjs +595 -0
- graphitect/_vendor/archify/renderers/shared/layout-report.mjs +40 -0
- graphitect/_vendor/archify/renderers/shared/legend.mjs +217 -0
- graphitect/_vendor/archify/renderers/shared/output-path.mjs +340 -0
- graphitect/_vendor/archify/renderers/shared/repository-evidence.mjs +238 -0
- graphitect/_vendor/archify/renderers/shared/repository-location.mjs +58 -0
- graphitect/_vendor/archify/renderers/shared/text-fit.mjs +49 -0
- graphitect/_vendor/archify/renderers/shared/utils.mjs +232 -0
- graphitect/_vendor/archify/renderers/shared/validator.mjs +86 -0
- graphitect/_vendor/archify/renderers/workflow/README.md +223 -0
- graphitect/_vendor/archify/renderers/workflow/render-workflow.mjs +35 -0
- graphitect/_vendor/archify/renderers/workflow/workflow-compiler.mjs +4400 -0
- graphitect/_vendor/archify/renderers/workflow/workflow-migration-geometry.mjs +144 -0
- graphitect/_vendor/archify/schemas/README.md +211 -0
- graphitect/_vendor/archify/schemas/architecture.schema.json +178 -0
- graphitect/_vendor/archify/schemas/common.schema.json +115 -0
- graphitect/_vendor/archify/schemas/dataflow.schema.json +243 -0
- graphitect/_vendor/archify/schemas/lifecycle.schema.json +266 -0
- graphitect/_vendor/archify/schemas/sequence.schema.json +223 -0
- graphitect/_vendor/archify/schemas/workflow.schema.json +428 -0
- graphitect/_vendor/archify/scripts/check-render-output.mjs +836 -0
- graphitect/_vendor/archify/scripts/check-update.mjs +1667 -0
- graphitect/_vendor/archify/scripts/generate-brand-marks.mjs +141 -0
- graphitect/_vendor/archify/scripts/generate-validators.mjs +66 -0
- graphitect/_vendor/archify/scripts/render-examples.mjs +26 -0
- graphitect/_vendor/archify/scripts/update-contract.mjs +182 -0
- graphitect/_vendor/archify/skill-release.json +10 -0
- graphitect/cli.py +981 -0
- graphitect/deliver/__init__.py +5 -0
- graphitect/deliver/archify_adapter.py +1877 -0
- graphitect/deliver/archify_ir.py +160 -0
- graphitect/deliver/archify_repair.py +135 -0
- graphitect/deliver/doc_compiler.py +916 -0
- graphitect/ground/__init__.py +5 -0
- graphitect/ground/describe_source.py +27 -0
- graphitect/ground/fullread_source.py +56 -0
- graphitect/ground/graphify_source.py +107 -0
- graphitect/models.py +118 -0
- graphitect/skill/SKILL.md +80 -0
- graphitect/skill/agents/openai.yaml +4 -0
- graphitect/synthesize/__init__.py +5 -0
- graphitect/synthesize/engine.py +281 -0
- graphitect/synthesize/llm_backend.py +331 -0
- graphitect/synthesize/questions.py +139 -0
- graphitect/synthesize/rubric.py +104 -0
- graphitect-0.2.0.dist-info/METADATA +284 -0
- graphitect-0.2.0.dist-info/RECORD +336 -0
- graphitect-0.2.0.dist-info/WHEEL +5 -0
- graphitect-0.2.0.dist-info/entry_points.txt +2 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE +21 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-ARCHIFY-MIT +22 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-APACHE-2.0 +202 -0
- graphitect-0.2.0.dist-info/licenses/LICENSE-GRAPHIFY-MIT +21 -0
- graphitect-0.2.0.dist-info/licenses/NOTICE-ARCHIFY-THIRD-PARTY.md +69 -0
- graphitect-0.2.0.dist-info/licenses/NOTICE-GRAPHIFY +8 -0
- graphitect-0.2.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# graphify reference: incremental update and cluster-only
|
|
2
|
+
|
|
3
|
+
Load this only when the user passed `--update` or `--cluster-only`. A first-time full build never reads this file.
|
|
4
|
+
|
|
5
|
+
## For --update (incremental re-extraction)
|
|
6
|
+
|
|
7
|
+
Use when you've added or modified files since the last run. Only re-extracts changed files - saves tokens and time.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
11
|
+
import sys, json
|
|
12
|
+
from graphify.detect import detect_incremental, save_manifest
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
result = detect_incremental(Path('INPUT_PATH'))
|
|
16
|
+
new_total = result.get('new_total', 0)
|
|
17
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
18
|
+
Path('graphify-out/.graphify_incremental.json').write_text(json.dumps(result, ensure_ascii=False), encoding=\"utf-8\")
|
|
19
|
+
deleted = list(result.get('deleted_files', []))
|
|
20
|
+
if new_total == 0 and not deleted:
|
|
21
|
+
print('No files changed since last run. Nothing to update.')
|
|
22
|
+
raise SystemExit(0)
|
|
23
|
+
if deleted:
|
|
24
|
+
print(f'{len(deleted)} deleted file(s) to prune.')
|
|
25
|
+
if new_total > 0:
|
|
26
|
+
print(f'{new_total} new/changed file(s) to re-extract.')
|
|
27
|
+
"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then populate `.graphify_detect.json` so Steps 3A–6 (which read it unconditionally) see the right state for an incremental run. `files` carries the changed subset (drives Step 3A AST + Step 3B0 cache check on only what changed); `all_files` carries the full corpus for any step that needs corpus-wide context:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
34
|
+
import json
|
|
35
|
+
from pathlib import Path
|
|
36
|
+
r = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
|
37
|
+
Path('graphify-out/.graphify_detect.json').write_text(json.dumps({
|
|
38
|
+
'files': r.get('new_files', {}),
|
|
39
|
+
'all_files': r.get('files', {}),
|
|
40
|
+
'total_files': r.get('new_total', 0),
|
|
41
|
+
'total_words': r.get('total_words', 0),
|
|
42
|
+
'skipped_sensitive': r.get('skipped_sensitive', []),
|
|
43
|
+
'needs_graph': True,
|
|
44
|
+
}, ensure_ascii=False), encoding=\"utf-8\")
|
|
45
|
+
"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If new files exist, first check whether all changed files are code files:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
52
|
+
import json
|
|
53
|
+
from pathlib import Path
|
|
54
|
+
|
|
55
|
+
result = json.loads(open('graphify-out/.graphify_incremental.json', encoding='utf-8').read()) if Path('graphify-out/.graphify_incremental.json').exists() else {}
|
|
56
|
+
code_exts = {'.py','.ts','.js','.go','.rs','.java','.cpp','.c','.rb','.swift','.kt','.cs','.scala','.php','.cc','.cxx','.hpp','.h','.kts','.lua','.toc','.f','.F','.f90','.F90','.f95','.F95','.f03','.F03','.f08','.F08'}
|
|
57
|
+
new_files = result.get('new_files', {})
|
|
58
|
+
all_changed = [f for files in new_files.values() for f in files]
|
|
59
|
+
code_only = all(Path(f).suffix.lower() in code_exts for f in all_changed)
|
|
60
|
+
print('code_only:', code_only)
|
|
61
|
+
"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If `code_only` is True: print `[graphify update] Code-only changes detected - skipping semantic extraction (no LLM needed)`, run only Step 3A (AST) on the changed files, skip Step 3B entirely (no subagents), then go straight to merge and Steps 4–8.
|
|
65
|
+
|
|
66
|
+
If `code_only` is False (any changed file is a doc/paper/image/video): **first, if any changed file is in `new_files['video']`, run `references/transcribe.md` (Step 2.5) on those files, then rewrite `.graphify_detect.json` to move the resulting transcript paths into `files['document']` and drop `files['video']`** — otherwise raw `.mp4/.mp3` paths are fed to semantic subagents as unreadable media (#1392). Then run the full Steps 3A–3C pipeline as normal.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
If no new files exist (only deletions), create an empty extraction so the merge step can prune:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
if [ ! -f graphify-out/.graphify_extract.json ]; then
|
|
73
|
+
echo '[graphify update] Only deletions -- creating empty extraction for merge.'
|
|
74
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
75
|
+
import json
|
|
76
|
+
from pathlib import Path
|
|
77
|
+
Path('graphify-out/.graphify_extract.json').write_text(json.dumps({'nodes':[],'edges':[],'hyperedges':[],'input_tokens':0,'output_tokens':0}), encoding='utf-8')
|
|
78
|
+
"
|
|
79
|
+
fi
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
Then:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
87
|
+
import json
|
|
88
|
+
from pathlib import Path
|
|
89
|
+
from graphify.build import build_merge
|
|
90
|
+
from graphify.detect import save_manifest
|
|
91
|
+
|
|
92
|
+
# Load new extraction and incremental state
|
|
93
|
+
new_extraction = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
|
94
|
+
incremental = json.loads(Path('graphify-out/.graphify_incremental.json').read_text(encoding=\"utf-8\"))
|
|
95
|
+
deleted = list(incremental.get('deleted_files', []))
|
|
96
|
+
# prune_sources is ONLY for genuinely DELETED files. Changed/re-extracted files are
|
|
97
|
+
# handled by build_merge's replace-on-re-extract (#1344): every source_file in
|
|
98
|
+
# new_chunks is dropped from the base before merge, so old/stale nodes don't survive.
|
|
99
|
+
# Do NOT add `changed` here: with root= passed, prune_set relativizes to the same base
|
|
100
|
+
# as the freshly merged nodes and would DELETE the re-extracted content (#1178 is moot
|
|
101
|
+
# now that replace — not the dedup pass — reconciles changed files).
|
|
102
|
+
prune = list(deleted) or None
|
|
103
|
+
|
|
104
|
+
# Use build_merge() — reads graph.json directly without NetworkX round-trip
|
|
105
|
+
# so edge direction (calls, implements, imports) is always preserved (#801).
|
|
106
|
+
# Pass root= so prune_sources (absolute paths from detect_incremental) are
|
|
107
|
+
# relativized to match the graph's relative source_file values; without it
|
|
108
|
+
# nothing is pruned and stale nodes accumulate on every update (#1361).
|
|
109
|
+
# directed=IS_DIRECTED: replace IS_DIRECTED with True if --directed was given, else
|
|
110
|
+
# False. Without it a --directed --update silently rebuilds undirected and collapses
|
|
111
|
+
# reciprocal A<->B edges (#1392).
|
|
112
|
+
G = build_merge(
|
|
113
|
+
[new_extraction],
|
|
114
|
+
graph_path='graphify-out/graph.json',
|
|
115
|
+
prune_sources=prune,
|
|
116
|
+
root='INPUT_PATH',
|
|
117
|
+
directed=IS_DIRECTED,
|
|
118
|
+
)
|
|
119
|
+
print(f'[graphify update] Merged: {G.number_of_nodes()} nodes, {G.number_of_edges()} edges')
|
|
120
|
+
|
|
121
|
+
# Write merged result back to .graphify_extract.json so Step 4 sees the full graph
|
|
122
|
+
merged_out = {
|
|
123
|
+
'nodes': [{'id': n, **d} for n, d in G.nodes(data=True)],
|
|
124
|
+
'edges': [
|
|
125
|
+
# Explicit source/target last so they win over any stale attrs in d.
|
|
126
|
+
{**{k: val for k, val in d.items() if k not in ('_src', '_tgt', 'source', 'target')},
|
|
127
|
+
'source': d.get('_src', u), 'target': d.get('_tgt', v)}
|
|
128
|
+
for u, v, d in G.edges(data=True)
|
|
129
|
+
],
|
|
130
|
+
# G.graph["hyperedges"] holds hyperedges from both existing graph.json
|
|
131
|
+
# and new_extraction (build_merge combines them). Falling back to
|
|
132
|
+
# new_extraction only would silently drop prior-run hyperedges (#801).
|
|
133
|
+
'hyperedges': list(G.graph.get('hyperedges', [])),
|
|
134
|
+
'input_tokens': new_extraction.get('input_tokens', 0),
|
|
135
|
+
'output_tokens': new_extraction.get('output_tokens', 0),
|
|
136
|
+
}
|
|
137
|
+
Path('graphify-out/.graphify_extract.json').write_text(json.dumps(merged_out, ensure_ascii=False), encoding=\"utf-8\")
|
|
138
|
+
print(f'[graphify update] Merged extraction written ({len(merged_out[\"nodes\"])} nodes, {len(merged_out[\"edges\"])} edges)')
|
|
139
|
+
|
|
140
|
+
# Save manifest so next --update diffs against today's state, not the
|
|
141
|
+
# prior run's baseline (prevents ghost-node reports on subsequent updates).
|
|
142
|
+
# root= matches the build_merge call above so the manifest keys stay relative to
|
|
143
|
+
# the scan root — portable across clones/machines, so --update keeps matching
|
|
144
|
+
# cached files instead of missing every one after a move (#1417).
|
|
145
|
+
#
|
|
146
|
+
# Only stamp semantic files (docs/papers/images) that ACTUALLY produced output
|
|
147
|
+
# THIS run (new_extraction is this run's fresh extraction, read above before the
|
|
148
|
+
# merge overwrote the file): a changed doc whose chunk failed must stay unstamped
|
|
149
|
+
# so the next --update re-queues it, otherwise it is marked done and its content
|
|
150
|
+
# is lost forever (#2015). Mirrors the library extract path
|
|
151
|
+
# (cli._stamped_manifest_files + clear_semantic + scan_corpus).
|
|
152
|
+
from graphify.cli import _stamped_manifest_files
|
|
153
|
+
_manifest_files = _stamped_manifest_files(incremental['files'], new_extraction, Path('INPUT_PATH'))
|
|
154
|
+
# Changed semantic files dispatched this run but NOT stamped had their chunk fail
|
|
155
|
+
# or be omitted; clear any stale semantic_hash so they are re-queued (#1948).
|
|
156
|
+
_sem_types = ('document', 'paper', 'image')
|
|
157
|
+
_dispatched = {f for t, fl in incremental.get('new_files', {}).items() if t in _sem_types for f in fl}
|
|
158
|
+
_stamped = {f for fl in _manifest_files.values() for f in fl}
|
|
159
|
+
_cleared = _dispatched - _stamped
|
|
160
|
+
# scan_corpus = the RAW full corpus so in-root files newly excluded since last run
|
|
161
|
+
# are dropped rather than masquerading as deletions; untouched rows preserved (#1908).
|
|
162
|
+
_scan = {f for fl in incremental['files'].values() for f in fl}
|
|
163
|
+
save_manifest(_manifest_files, root='INPUT_PATH', scan_corpus=_scan, clear_semantic=_cleared or None)
|
|
164
|
+
print('[graphify update] Manifest saved.')
|
|
165
|
+
"
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Then run Steps 4–8 on the merged graph as normal.
|
|
169
|
+
|
|
170
|
+
After Step 4, show the graph diff:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
174
|
+
import json
|
|
175
|
+
from graphify.analyze import graph_diff
|
|
176
|
+
from graphify.build import build_from_json
|
|
177
|
+
from networkx.readwrite import json_graph
|
|
178
|
+
import networkx as nx
|
|
179
|
+
from pathlib import Path
|
|
180
|
+
|
|
181
|
+
# Load old graph (before update) from backup written before merge
|
|
182
|
+
old_data = json.loads(Path('graphify-out/.graphify_old.json').read_text(encoding=\"utf-8\")) if Path('graphify-out/.graphify_old.json').exists() else None
|
|
183
|
+
new_extract = json.loads(Path('graphify-out/.graphify_extract.json').read_text(encoding=\"utf-8\"))
|
|
184
|
+
G_new = build_from_json(new_extract, directed=IS_DIRECTED)
|
|
185
|
+
|
|
186
|
+
if old_data:
|
|
187
|
+
G_old = json_graph.node_link_graph(old_data, edges='links')
|
|
188
|
+
diff = graph_diff(G_old, G_new)
|
|
189
|
+
print(diff['summary'])
|
|
190
|
+
if diff['new_nodes']:
|
|
191
|
+
print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5]))
|
|
192
|
+
if diff['new_edges']:
|
|
193
|
+
print('New edges:', len(diff['new_edges']))
|
|
194
|
+
"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json`
|
|
198
|
+
Clean up after: `rm -f graphify-out/.graphify_old.json`
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## For --cluster-only
|
|
203
|
+
|
|
204
|
+
Skip Steps 1–3. Re-run clustering on the existing graph:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
graphify cluster-only .
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
`graphify cluster-only .` is **self-contained**: it re-clusters, names communities, and regenerates `GRAPH_REPORT.md`, `graph.json`, and `graph.html` from the existing graph. **Do not re-run Steps 5–9** — they read intermediate files (`.graphify_extract.json`, `.graphify_detect.json`, `.graphify_analysis.json`) that a prior build's cleanup (Step 9) already deleted, so they raise `FileNotFoundError` (#1392). When it finishes, present the refreshed `GRAPH_REPORT.md` summary as usual.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# graphify reference: add a URL and watch a folder
|
|
2
|
+
|
|
3
|
+
Load this when the user ran `/graphify add <url>` or passed `--watch`. Neither is part of the default build.
|
|
4
|
+
|
|
5
|
+
## For /graphify add
|
|
6
|
+
|
|
7
|
+
Fetch a URL and add it to the corpus, then update the graph.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
$(cat graphify-out/.graphify_python) -c "
|
|
11
|
+
import sys
|
|
12
|
+
from graphify.ingest import ingest
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
out = ingest('URL', Path('./raw'), author='AUTHOR', contributor='CONTRIBUTOR')
|
|
17
|
+
print(f'Saved to {out}')
|
|
18
|
+
except ValueError as e:
|
|
19
|
+
print(f'error: {e}', file=sys.stderr)
|
|
20
|
+
sys.exit(1)
|
|
21
|
+
except RuntimeError as e:
|
|
22
|
+
print(f'error: {e}', file=sys.stderr)
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Replace `URL` with the actual URL, `AUTHOR` with the user's name if provided, `CONTRIBUTOR` likewise. If the command exits with an error, tell the user what went wrong - do not silently continue. After a successful save, automatically run the `--update` pipeline on `./raw` to merge the new file into the existing graph.
|
|
28
|
+
|
|
29
|
+
Supported URL types (auto-detected):
|
|
30
|
+
- YouTube / any video URL → audio downloaded via yt-dlp, transcribed to `.txt` on next run (requires `pip install 'graphifyy[video]'`)
|
|
31
|
+
- Twitter/X → fetched via oEmbed, saved as `.md` with tweet text and author
|
|
32
|
+
- arXiv → abstract + metadata saved as `.md`
|
|
33
|
+
- PDF → downloaded as `.pdf`
|
|
34
|
+
- Images (.png/.jpg/.webp) → downloaded, Claude vision extracts on next run
|
|
35
|
+
- Any webpage → converted to markdown via html2text
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## For --watch
|
|
40
|
+
|
|
41
|
+
Start a background watcher that monitors a folder and auto-updates the graph when files change.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
$(cat graphify-out/.graphify_python) -m graphify.watch INPUT_PATH --debounce 3
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Replace INPUT_PATH with the folder to watch. Behavior depends on what changed:
|
|
48
|
+
|
|
49
|
+
- **Code files only (.py, .ts, .go, etc.):** re-runs AST extraction + rebuild + cluster immediately, no LLM needed. `graph.json` and `GRAPH_REPORT.md` are updated automatically.
|
|
50
|
+
- **Docs, papers, or images:** writes a `graphify-out/needs_update` flag and prints a notification to run `/graphify --update` (LLM semantic re-extraction required).
|
|
51
|
+
|
|
52
|
+
Debounce (default 3s): waits until file activity stops before triggering, so a wave of parallel agent writes doesn't trigger a rebuild per file.
|
|
53
|
+
|
|
54
|
+
Press Ctrl+C to stop.
|
|
55
|
+
|
|
56
|
+
For agentic workflows: run `--watch` in a background terminal. Code changes from agent waves are picked up automatically between waves. If agents are also writing docs or notes, you'll need a manual `/graphify --update` after those waves.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# graphify reference: extra exports and benchmark
|
|
2
|
+
|
|
3
|
+
Load this when the user passed one of the export flags (`--wiki`, `--neo4j`, `--neo4j-push`, `--falkordb`, `--falkordb-push`, `--svg`, `--graphml`, `--mcp`), or when the corpus is large enough for the token-reduction benchmark. Each step runs only for its own flag.
|
|
4
|
+
|
|
5
|
+
### Step 6b - Wiki (only if --wiki flag)
|
|
6
|
+
|
|
7
|
+
**Only run this step if `--wiki` was explicitly given in the original command.**
|
|
8
|
+
|
|
9
|
+
Run this before Step 9 (cleanup) so `.graphify_labels.json` is still available.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
graphify export wiki
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Step 7 - Neo4j export (only if --neo4j or --neo4j-push flag)
|
|
16
|
+
|
|
17
|
+
**If `--neo4j`** - generate a Cypher file for manual import:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
graphify export neo4j
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**If `--neo4j-push <uri>`** - push directly to a running Neo4j instance. Ask the user for credentials if not provided:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
graphify export neo4j --push bolt://localhost:7687 --user neo4j --password PASSWORD
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Default URI is `bolt://localhost:7687`, default user is `neo4j`. Uses MERGE - safe to re-run without creating duplicates.
|
|
30
|
+
|
|
31
|
+
### Step 7a - FalkorDB export (only if --falkordb or --falkordb-push flag)
|
|
32
|
+
|
|
33
|
+
**If `--falkordb`** - generate a Cypher file. The statements are OpenCypher, but FalkorDB's `GRAPH.QUERY` runs one statement at a time (no bulk script import like Neo4j's `cypher-shell`), so prefer `--falkordb-push` to load a graph. Use this only when you want the portable `cypher.txt` artifact:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
graphify export falkordb
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**If `--falkordb-push <uri>`** - push directly to a running FalkorDB instance. Credentials are optional; ask the user only if the instance requires auth:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
graphify export falkordb --push falkordb://localhost:6379
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Default URI is `falkordb://localhost:6379` (the scheme is informational - `redis://` or a bare `host:port` work too), auth is optional, and the target graph defaults to `graphify`. Uses MERGE - safe to re-run without creating duplicates.
|
|
46
|
+
|
|
47
|
+
### Step 7b - SVG export (only if --svg flag)
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
graphify export svg
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Step 7c - GraphML export (only if --graphml flag)
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
graphify export graphml
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Step 7d - MCP server (only if --mcp flag)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
$(cat graphify-out/.graphify_python) -m graphify.serve graphify-out/graph.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This starts a stdio MCP server that exposes tools: `query_graph`, `get_node`, `get_neighbors`, `get_community`, `god_nodes`, `graph_stats`, `shortest_path`. Add to Claude Desktop or any MCP-compatible agent orchestrator so other agents can query the graph live.
|
|
66
|
+
|
|
67
|
+
To configure in Claude Desktop, add to `claude_desktop_config.json`. Claude Desktop can't run `$(...)`, and under `uv tool install` the system `python3` can't import graphify — so set `command` to the **absolute interpreter path** printed by `cat graphify-out/.graphify_python`:
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"graphify": {
|
|
72
|
+
"command": "<absolute path from: cat graphify-out/.graphify_python>",
|
|
73
|
+
"args": ["-m", "graphify.serve", "/absolute/path/to/graphify-out/graph.json"]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Step 8 - Token reduction benchmark (only if total_words > 5000)
|
|
80
|
+
|
|
81
|
+
If `total_words` from `graphify-out/.graphify_detect.json` is greater than 5,000, run:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
graphify benchmark
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Print the output directly in chat. If `total_words <= 5000`, skip silently - the graph value is structural clarity, not token compression, for small corpora.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# graphify reference: extraction subagent prompt (compact)
|
|
2
|
+
|
|
3
|
+
Load this in Step 3 Part B when the corpus has at least one doc, paper, or image chunk. A pure-code corpus skips Part B and never reads this file. Each semantic subagent receives the prompt below verbatim (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, and DEEP_MODE).
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
You are a graphify extraction subagent. Read the files listed and extract a knowledge graph fragment.
|
|
7
|
+
Output ONLY valid JSON matching the schema below - no explanation, no markdown fences, no preamble.
|
|
8
|
+
|
|
9
|
+
Files (chunk CHUNK_NUM of TOTAL_CHUNKS):
|
|
10
|
+
FILE_LIST
|
|
11
|
+
|
|
12
|
+
Rules:
|
|
13
|
+
- EXTRACTED: relationship explicit in source (import, call, citation)
|
|
14
|
+
- INFERRED: reasonable inference (shared structure, implied dependency)
|
|
15
|
+
- AMBIGUOUS: uncertain — flag it, do not omit
|
|
16
|
+
- Code files: semantic edges AST cannot find. Do not re-extract imports. When adding `calls` edges: source is the caller, target is the callee, never reversed; keep `calls` within one language.
|
|
17
|
+
- Doc/paper files: named concepts, entities, citations. Store rationale (WHY decisions were made) as a `rationale` attribute on the relevant node, not as a separate node. Use `file_type:"rationale"` for concept-like nodes (ideas, principles, mechanisms) and `file_type:"concept"` for named concepts. `file_type` MUST be one of exactly these six values: `code`, `document`, `paper`, `image`, `rationale`, `concept`. Any other value is invalid and will be rejected.
|
|
18
|
+
- Image files: use vision — understand what the image IS, not just OCR
|
|
19
|
+
- DEEP_MODE (if --mode deep): be aggressive with INFERRED edges — indirect deps, shared assumptions, latent couplings. Mark uncertain ones AMBIGUOUS instead of omitting.
|
|
20
|
+
- Semantic similarity: if two concepts solve the same problem or represent the same idea without a structural link (no import, call, or citation), add a `semantically_similar_to` edge marked INFERRED with confidence_score 0.6-0.95. Non-obvious cross-file links only.
|
|
21
|
+
- Hyperedges: if 3+ nodes share a concept, flow, or pattern not captured by pairwise edges, add a hyperedge to a top-level `hyperedges` array. Use sparingly. Max 3 per chunk.
|
|
22
|
+
- If a file has YAML frontmatter (--- ... ---), copy source_url, captured_at, author, contributor onto every node from that file.
|
|
23
|
+
- confidence_score is REQUIRED on every edge — never omit it, never use 0.5 as a default. EXTRACTED = 1.0 always. INFERRED: pick exactly ONE of 0.95 (direct structural evidence), 0.85 (strong inference), 0.75 (reasonable inference), 0.65 (weak inference), 0.55 (speculative but plausible) — never 0.5; if none fit, mark the edge AMBIGUOUS. AMBIGUOUS = 0.1-0.3.
|
|
24
|
+
|
|
25
|
+
Node ID format: lowercase, only `[a-z0-9_]`, no dots or slashes. Format `{stem}_{entity}` where stem is the full repo-relative path with the extension dropped, every segment joined with `_` (each lowercased with non-alphanumeric chars replaced by `_`) and entity is the symbol name similarly normalized. Use every directory level, not just the immediate parent. `src/auth/session.py` + `ValidateToken` → `src_auth_session_validatetoken`. Top-level files use just the filename stem. This must match the AST extractor's ID. Never append chunk or sequence suffixes — IDs must be deterministic from the label alone.
|
|
26
|
+
|
|
27
|
+
Output exactly this JSON (no other text):
|
|
28
|
+
{"nodes":[{"id":"auth_session_validatetoken","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"<FILE_LIST path verbatim>","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to|rationale_for","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"<FILE_LIST path verbatim>","source_location":null,"weight":1.0}],"hyperedges":[{"id":"snake_case_id","label":"Human Readable Label","nodes":["node_id1","node_id2","node_id3"],"relation":"participate_in|implement|form","confidence":"EXTRACTED|INFERRED","confidence_score":0.75,"source_file":"<FILE_LIST path verbatim>"}],"input_tokens":0,"output_tokens":0}
|
|
29
|
+
|
|
30
|
+
source_file RULE: set source_file to the FILE_LIST path for that file VERBATIM (absolute, no shortening to basename, no re-relativizing, no separator change). Keeps full build and --update on one base so build_merge's replace matches instead of duplicating.
|
|
31
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# graphify reference: GitHub clone and cross-repo merge
|
|
2
|
+
|
|
3
|
+
Load this when the user passed one or more `https://github.com/...` URLs, or named several local subfolders to merge into one graph.
|
|
4
|
+
|
|
5
|
+
### Step 0 - Clone GitHub repo(s) (only if a GitHub URL was given)
|
|
6
|
+
|
|
7
|
+
**Single repo:**
|
|
8
|
+
```bash
|
|
9
|
+
LOCAL_PATH=$(graphify clone <github-url> [--branch <branch>])
|
|
10
|
+
# Use LOCAL_PATH as the target for all subsequent steps
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Multiple repos (cross-repo graph):**
|
|
14
|
+
```bash
|
|
15
|
+
# Clone each repo, run the full pipeline on each, then merge
|
|
16
|
+
graphify clone <url1> # → ~/.graphify/repos/<owner1>/<repo1>
|
|
17
|
+
graphify clone <url2> # → ~/.graphify/repos/<owner2>/<repo2>
|
|
18
|
+
# Run /graphify on each local path to produce their graph.json files
|
|
19
|
+
# Then merge:
|
|
20
|
+
graphify merge-graphs \
|
|
21
|
+
~/.graphify/repos/<owner1>/<repo1>/graphify-out/graph.json \
|
|
22
|
+
~/.graphify/repos/<owner2>/<repo2>/graphify-out/graph.json \
|
|
23
|
+
--out graphify-out/cross-repo-graph.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Graphify clones into `~/.graphify/repos/<owner>/<repo>` and reuses existing clones on repeat runs. Each node in the merged graph carries a `repo` attribute so you can filter by origin.
|
|
27
|
+
|
|
28
|
+
**Multiple local subfolders (monorepo or multi-service layout):**
|
|
29
|
+
|
|
30
|
+
The skill pipeline writes all intermediate and final outputs to `graphify-out/` in the current working directory. Running the skill on each subfolder separately will clobber the same output dir. Instead, use the CLI directly for each subfolder — it places `graphify-out/` *inside* the scanned path:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
graphify extract ./core/ # → ./core/graphify-out/graph.json
|
|
34
|
+
graphify extract ./service/ # → ./service/graphify-out/graph.json
|
|
35
|
+
graphify extract ./platform/ # → ./platform/graphify-out/graph.json
|
|
36
|
+
# Add --backend gemini|kimi|openai|deepseek|claude-cli depending on which API key you have set
|
|
37
|
+
|
|
38
|
+
# Then merge at the project root:
|
|
39
|
+
graphify merge-graphs \
|
|
40
|
+
./core/graphify-out/graph.json \
|
|
41
|
+
./service/graphify-out/graph.json \
|
|
42
|
+
./platform/graphify-out/graph.json \
|
|
43
|
+
--out graphify-out/graph.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Once `graphify-out/graph.json` exists, the fast path above takes over: any codebase question runs `graphify query` directly on the merged graph — no re-extraction, no size gate.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# graphify reference: commit hook and native CLAUDE.md integration
|
|
2
|
+
|
|
3
|
+
Load this when the user asked to install the post-commit hook or wire graphify into a project's CLAUDE.md.
|
|
4
|
+
|
|
5
|
+
## For git commit hook
|
|
6
|
+
|
|
7
|
+
Install a post-commit hook that auto-rebuilds the graph after every commit. No background process needed - triggers once per commit, works with any editor.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
graphify hook install # install
|
|
11
|
+
graphify hook uninstall # remove
|
|
12
|
+
graphify hook status # check
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
After every `git commit`, the hook detects which code files changed (via `git diff HEAD~1`), re-runs AST extraction on those files, and rebuilds `graph.json` and `GRAPH_REPORT.md`. Doc/image changes are ignored by the hook - run `/graphify --update` manually for those.
|
|
16
|
+
|
|
17
|
+
If a post-commit hook already exists, graphify appends to it rather than replacing it.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## For native CLAUDE.md integration
|
|
22
|
+
|
|
23
|
+
Run once per project to make graphify always-on in Claude Code sessions:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
graphify claude install
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This writes a `## graphify` section to the local `CLAUDE.md` that instructs Claude to check the graph before answering codebase questions and rebuild it after code changes. No manual `/graphify` needed in future sessions.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
graphify claude uninstall # remove the section
|
|
33
|
+
```
|