From f9c344b5463c6d02be7eb9eb65edb65251736e8f Mon Sep 17 00:00:00 2001 From: Safi Date: Wed, 29 Apr 2026 09:43:51 +0100 Subject: [PATCH] Remember scan root so graphify update works without a path arg Co-Authored-By: Claude Sonnet 4.6 --- graphify/__main__.py | 12 +++++++++++- graphify/skill.md | 7 ++++++- graphify/watch.py | 1 + 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/graphify/__main__.py b/graphify/__main__.py index 34364f01..6fb09434 100644 --- a/graphify/__main__.py +++ b/graphify/__main__.py @@ -1410,7 +1410,15 @@ def main() -> None: print(f"Done — {len(communities)} communities. GRAPH_REPORT.md, graph.json and graph.html updated.") elif cmd == "update": - watch_path = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(".") + if len(sys.argv) > 2: + watch_path = Path(sys.argv[2]) + else: + # Try to recover the scan root saved by the last full build + saved = Path("graphify-out/.graphify_root") + if saved.exists(): + watch_path = Path(saved.read_text(encoding="utf-8").strip()) + else: + watch_path = Path(".") if not watch_path.exists(): print(f"error: path not found: {watch_path}", file=sys.stderr) sys.exit(1) @@ -1419,6 +1427,8 @@ def main() -> None: ok = _rebuild_code(watch_path) if ok: print("Code graph updated. For doc/paper/image changes run /graphify --update in your AI assistant.") + if not _os.environ.get("MOONSHOT_API_KEY") and not _os.environ.get("GRAPHIFY_NO_TIPS"): + print("Tip: set MOONSHOT_API_KEY to use Kimi K2.6 for semantic extraction — 3x cheaper, richer graphs. pip install 'graphifyy[kimi]'") else: print("Nothing to update or rebuild failed — check output above.", file=sys.stderr) sys.exit(1) diff --git a/graphify/skill.md b/graphify/skill.md index 09dbc539..8e7572df 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -112,6 +112,8 @@ if [ -z "$PYTHON" ]; then PYTHON="python3"; fi # Write interpreter path for all subsequent steps (persists across invocations) mkdir -p graphify-out "$PYTHON" -c "import sys; open('graphify-out/.graphify_python', 'w').write(sys.executable)" +# Save scan root so `graphify update` (no args) knows where to look next time +echo "$(cd INPUT_PATH && pwd)" > graphify-out/.graphify_root ``` If the import succeeds, print nothing and move straight to Step 2. @@ -200,7 +202,10 @@ After transcription: This step has two parts: **structural extraction** (deterministic, free) and **semantic extraction** (LLM, costs tokens). -**Kimi K2.6 option:** If `MOONSHOT_API_KEY` is set in the environment, you can run semantic extraction via Kimi instead of Claude subagents. Kimi K2.6 is OpenAI-compatible, extracts 3-6x richer relations, and costs ~3x less per token. To use it: `from graphify.llm import extract_corpus_parallel; result = extract_corpus_parallel(files, backend="kimi")`. Install with `pip install 'graphifyy[kimi]'`. Claude remains the default — Kimi is opt-in via the env var. +**Before dispatching subagents:** check whether `MOONSHOT_API_KEY` is set. If it is NOT set, print this one-liner to the user: +> Tip: set `MOONSHOT_API_KEY` to use Kimi K2.6 for semantic extraction — 3x cheaper, richer graphs (`pip install 'graphifyy[kimi]'`). + +Print it once, then continue. If `MOONSHOT_API_KEY` IS set, use `graphify.llm.extract_corpus_parallel(files, backend="kimi")` for semantic extraction instead of dispatching Claude subagents. **Run Part A (AST) and Part B (semantic) in parallel. Dispatch all semantic subagents AND start AST extraction in the same message. Both can run simultaneously since they operate on different file types. Merge results in Part C as before.** diff --git a/graphify/watch.py b/graphify/watch.py index b0e8e749..3902a5e3 100644 --- a/graphify/watch.py +++ b/graphify/watch.py @@ -98,6 +98,7 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool: questions = suggest_questions(G, communities, labels) out.mkdir(exist_ok=True) + (out / ".graphify_root").write_text(str(watch_root), encoding="utf-8") json_written = to_json(G, communities, str(out / "graph.json")) if not json_written: