From cede5b6ca6e964866db80f03526fd0266fc40f34 Mon Sep 17 00:00:00 2001 From: Safi Date: Fri, 10 Apr 2026 18:41:48 +0100 Subject: [PATCH] Fix #188: collect_files() now respects .graphifyignore; fix #195: skill.md requires general-purpose subagent type for extraction dispatch Co-Authored-By: Claude Sonnet 4.6 --- graphify/extract.py | 12 ++++++++++-- graphify/skill-codex.md | 6 ++++-- graphify/skill-copilot.md | 6 ++++-- graphify/skill-droid.md | 6 ++++-- graphify/skill-opencode.md | 6 ++++-- graphify/skill-trae.md | 6 ++++-- graphify/skill-windows.md | 6 ++++-- graphify/skill.md | 14 +++++++++----- 8 files changed, 43 insertions(+), 19 deletions(-) diff --git a/graphify/extract.py b/graphify/extract.py index 65e62c6..feaa399 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -2668,7 +2668,7 @@ def extract(paths: list[Path]) -> dict: } -def collect_files(target: Path, *, follow_symlinks: bool = False) -> list[Path]: +def collect_files(target: Path, *, follow_symlinks: bool = False, root: Path | None = None) -> list[Path]: if target.is_file(): return [target] _EXTENSIONS = { @@ -2678,12 +2678,20 @@ def collect_files(target: Path, *, follow_symlinks: bool = False) -> list[Path]: ".lua", ".toc", ".zig", ".ps1", ".m", ".mm", } + from graphify.detect import _load_graphifyignore, _is_ignored + ignore_root = root if root is not None else target + patterns = _load_graphifyignore(ignore_root) + + def _ignored(p: Path) -> bool: + return bool(patterns and _is_ignored(p, ignore_root, patterns)) + if not follow_symlinks: results: list[Path] = [] for ext in sorted(_EXTENSIONS): results.extend( p for p in target.rglob(f"*{ext}") if not any(part.startswith(".") for part in p.parts) + and not _ignored(p) ) return sorted(results) # Walk with symlink following + cycle detection @@ -2701,7 +2709,7 @@ def collect_files(target: Path, *, follow_symlinks: bool = False) -> list[Path]: continue for fname in filenames: p = dp / fname - if p.suffix in _EXTENSIONS and not fname.startswith("."): + if p.suffix in _EXTENSIONS and not fname.startswith(".") and not _ignored(p): results.append(p) return sorted(results) diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index 94d4158..c75a407 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -305,10 +305,12 @@ Output exactly this JSON (no other text): **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```bash diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index 9812247..1bd26f0 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -301,10 +301,12 @@ Output exactly this JSON (no other text): **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```bash diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index 49197ff..9799720 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -302,10 +302,12 @@ Output exactly this JSON (no other text): **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```bash diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 7e86c6f..d2200f6 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -301,10 +301,12 @@ Output exactly this JSON (no other text): **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```bash diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index fdbb3eb..89b34c6 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -298,10 +298,12 @@ Accumulate nodes/edges/hyperedges across all results and write to `.graphify_sem **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```bash diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index 9d7bc6b..2016f8d 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -291,10 +291,12 @@ Output exactly this JSON (no other text): **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```powershell diff --git a/graphify/skill.md b/graphify/skill.md index 5a6d137..c9fdb85 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -238,11 +238,13 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2 Call the Agent tool multiple times IN THE SAME RESPONSE - one call per chunk. This is the only way they run in parallel. If you make one Agent call, wait, then make another, you are doing it sequentially and defeating the purpose. +**IMPORTANT - subagent type:** Always use `subagent_type="general-purpose"`. Do NOT use `Explore` - it is read-only and cannot write chunk files to disk, which silently drops extraction results. General-purpose has Write and Bash access which the subagent needs. + Concrete example for 3 chunks: ``` -[Agent tool call 1: files 1-15] -[Agent tool call 2: files 16-30] -[Agent tool call 3: files 31-45] +[Agent tool call 1: files 1-15, subagent_type="general-purpose"] +[Agent tool call 2: files 16-30, subagent_type="general-purpose"] +[Agent tool call 3: files 31-45, subagent_type="general-purpose"] ``` All three in one message. Not three separate messages. @@ -304,10 +306,12 @@ Output exactly this JSON (no other text): **Step B3 - Collect, cache, and merge** Wait for all subagents. For each result: -- If a subagent returned valid JSON with `nodes` and `edges`, include it and save each file's nodes/edges to the cache +- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal +- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache +- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip. - If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort -If more than half the chunks failed, stop and tell the user. +If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used. Save new results to cache: ```bash