From b52e5e171848ef6964ee529401912856e7bf13f1 Mon Sep 17 00:00:00 2001 From: abhay-codes07 Date: Sun, 16 Aug 2026 23:49:35 +0530 Subject: [PATCH] fix(skills): do the temp-file cleanup in Python, not shell rm/find (#2790) Cleanup was the only part of the runbook that shelled out: rm -f graphify-out/.graphify_detect.json ... find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null rm -f graphify-out/.needs_update 2>/dev/null || true On a host that gates the agent's shell, destructive verbs are exactly what the policy withholds. Both calls are denied, the pipeline has no fallback, and ~3 MB of intermediates stay on disk. That is not only clutter: Step B3 and Part C read .graphify_semantic_new.json and .graphify_chunk_*.json unconditionally, so a later --update can merge a stale chunk from a previous run. It is the third reported cause of one symptom -- #1172 was the fish/zsh no-match glob, #464 the Codex/Windows leftovers -- and unlike those, retrying or switching shell does not help, because the cause is a permission policy rather than a shell dialect. The cleanup is now folded into the tail of the Python program each block already runs, so it needs no shell verb on any host and spawns no extra process. That placement is deliberate: appending statements to an existing `-c` body adds no fence, no `$(cat ...)` invocation and no import, which keeps the new sanctioned monolith diff narrow enough to stay reviewable. Two consequences worth stating: - The PowerShell render no longer contains Remove-Item / Get-ChildItem at all, because there is nothing left for the POSIX->PowerShell translator to rewrite. test_powershell_hosts_carry_no_bash_only_shell asserted their presence and now asserts their absence. - Cleanup now runs only when the step's own program succeeds, where the shell form ran unconditionally. On failure the intermediates are kept, which is what you want for debugging a failed step. _is_shell_free_cleanup_line records the change class for --monolith-roundtrip, alongside _is_chunk_cleanup_line which sanctioned the #1172 rewrite of these very lines. --- graphify/skill-agents.md | 12 +- graphify/skill-aider.md | 13 +- graphify/skill-amp.md | 12 +- graphify/skill-claw.md | 12 +- graphify/skill-codex.md | 12 +- graphify/skill-copilot.md | 12 +- graphify/skill-devin.md | 13 +- graphify/skill-droid.md | 12 +- graphify/skill-kilo.md | 12 +- graphify/skill-kiro.md | 12 +- graphify/skill-opencode.md | 12 +- graphify/skill-pi.md | 12 +- graphify/skill-trae.md | 12 +- graphify/skill-vscode.md | 12 +- graphify/skill-windows.md | 12 +- graphify/skill.md | 12 +- graphify/skills/agents/references/update.md | 2 +- graphify/skills/amp/references/update.md | 2 +- graphify/skills/claude/references/update.md | 2 +- graphify/skills/claw/references/update.md | 2 +- graphify/skills/codex/references/update.md | 2 +- graphify/skills/copilot/references/update.md | 2 +- graphify/skills/droid/references/update.md | 2 +- graphify/skills/kilo/references/update.md | 2 +- graphify/skills/kiro/references/update.md | 2 +- graphify/skills/opencode/references/update.md | 2 +- graphify/skills/pi/references/update.md | 2 +- graphify/skills/trae/references/update.md | 2 +- graphify/skills/vscode/references/update.md | 2 +- graphify/skills/windows/references/update.md | 2 +- tests/test_skill_cleanup_is_shell_free.py | 133 ++++++++++++++++++ tests/test_skillgen.py | 12 +- .../expected/graphify__skill-agents.md | 12 +- .../expected/graphify__skill-aider.md | 13 +- .../skillgen/expected/graphify__skill-amp.md | 12 +- .../skillgen/expected/graphify__skill-claw.md | 12 +- .../expected/graphify__skill-codex.md | 12 +- .../expected/graphify__skill-copilot.md | 12 +- .../expected/graphify__skill-devin.md | 13 +- .../expected/graphify__skill-droid.md | 12 +- .../skillgen/expected/graphify__skill-kilo.md | 12 +- .../skillgen/expected/graphify__skill-kiro.md | 12 +- .../expected/graphify__skill-opencode.md | 12 +- tools/skillgen/expected/graphify__skill-pi.md | 12 +- .../skillgen/expected/graphify__skill-trae.md | 12 +- .../expected/graphify__skill-vscode.md | 12 +- .../expected/graphify__skill-windows.md | 12 +- tools/skillgen/expected/graphify__skill.md | 12 +- ...ify__skills__agents__references__update.md | 2 +- ...aphify__skills__amp__references__update.md | 2 +- ...ify__skills__claude__references__update.md | 2 +- ...phify__skills__claw__references__update.md | 2 +- ...hify__skills__codex__references__update.md | 2 +- ...fy__skills__copilot__references__update.md | 2 +- ...hify__skills__droid__references__update.md | 2 +- ...phify__skills__kilo__references__update.md | 2 +- ...phify__skills__kiro__references__update.md | 2 +- ...y__skills__opencode__references__update.md | 2 +- ...raphify__skills__pi__references__update.md | 2 +- ...phify__skills__trae__references__update.md | 2 +- ...ify__skills__vscode__references__update.md | 2 +- ...fy__skills__windows__references__update.md | 2 +- tools/skillgen/fragments/core/aider.md | 13 +- tools/skillgen/fragments/core/core.md | 12 +- tools/skillgen/fragments/core/devin.md | 13 +- .../fragments/references/shared/update.md | 2 +- tools/skillgen/gen.py | 37 +++++ 67 files changed, 494 insertions(+), 172 deletions(-) create mode 100644 tests/test_skill_cleanup_is_shell_free.py diff --git a/graphify/skill-agents.md b/graphify/skill-agents.md index 190827d9ac..e679e69093 100644 --- a/graphify/skill-agents.md +++ b/graphify/skill-agents.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-aider.md b/graphify/skill-aider.md index 4996beb787..4a1a034567 100644 --- a/graphify/skill-aider.md +++ b/graphify/skill-aider.md @@ -346,10 +346,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('.graphify_semantic.json').write_text(json.dumps(merged, indent=2)) +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path(_tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f .graphify_cached.json .graphify_uncached.txt .graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -718,9 +719,13 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.graphify_labels.json']: + Path(_tmp).unlink(missing_ok=True) +for _chunk in Path('.').glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) +Path('graphify-out/.needs_update').unlink(missing_ok=True) " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json; find . -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Tell the user (omit the obsidian line unless --obsidian was given): @@ -865,11 +870,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json .graphify_old.json` -Clean up after: `rm -f .graphify_old.json` --- diff --git a/graphify/skill-amp.md b/graphify/skill-amp.md index 190827d9ac..e679e69093 100644 --- a/graphify/skill-amp.md +++ b/graphify/skill-amp.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-claw.md b/graphify/skill-claw.md index abd2811d23..c28cb3d72a 100644 --- a/graphify/skill-claw.md +++ b/graphify/skill-claw.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-codex.md b/graphify/skill-codex.md index af3f723c78..4b034fe545 100644 --- a/graphify/skill-codex.md +++ b/graphify/skill-codex.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-copilot.md b/graphify/skill-copilot.md index abd2811d23..c28cb3d72a 100644 --- a/graphify/skill-copilot.md +++ b/graphify/skill-copilot.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-devin.md b/graphify/skill-devin.md index f9be846cbf..1a294bae0e 100644 --- a/graphify/skill-devin.md +++ b/graphify/skill-devin.md @@ -409,10 +409,11 @@ merged = { } merged = sanitize_semantic_fragment(merged) Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2)) +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -836,9 +837,13 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.graphify_labels.json', '.graphify_incremental.json', '.graphify_transcripts.json', '.graphify_old.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json graphify-out/.graphify_labels.json graphify-out/.graphify_incremental.json graphify-out/.graphify_transcripts.json graphify-out/.graphify_old.json; find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Tell the user (omit the obsidian line unless --obsidian was given; omit the wiki line unless --wiki was given): @@ -1001,11 +1006,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skill-droid.md b/graphify/skill-droid.md index fd148d485d..fa8df9c4ef 100644 --- a/graphify/skill-droid.md +++ b/graphify/skill-droid.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-kilo.md b/graphify/skill-kilo.md index 3e70b050a4..754e46582f 100644 --- a/graphify/skill-kilo.md +++ b/graphify/skill-kilo.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-kiro.md b/graphify/skill-kiro.md index abd2811d23..c28cb3d72a 100644 --- a/graphify/skill-kiro.md +++ b/graphify/skill-kiro.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-opencode.md b/graphify/skill-opencode.md index 91ced60675..dbb21ace3d 100644 --- a/graphify/skill-opencode.md +++ b/graphify/skill-opencode.md @@ -343,10 +343,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -609,10 +610,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-pi.md b/graphify/skill-pi.md index abd2811d23..c28cb3d72a 100644 --- a/graphify/skill-pi.md +++ b/graphify/skill-pi.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-trae.md b/graphify/skill-trae.md index 050667bc20..286d96c123 100644 --- a/graphify/skill-trae.md +++ b/graphify/skill-trae.md @@ -349,10 +349,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -615,10 +616,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-vscode.md b/graphify/skill-vscode.md index 20c7c0835c..32fe5137ee 100644 --- a/graphify/skill-vscode.md +++ b/graphify/skill-vscode.md @@ -347,10 +347,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -613,10 +614,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill-windows.md b/graphify/skill-windows.md index d631821ec3..273023aae4 100644 --- a/graphify/skill-windows.md +++ b/graphify/skill-windows.md @@ -373,10 +373,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding="utf-8") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached["nodes"])} from cache, {len(new.get("nodes",[]))} new)') '@ | & (Get-Content graphify-out\.graphify_python) - ``` -Clean up temp files: `Remove-Item -Force -ErrorAction SilentlyContinue graphify-out\.graphify_cached.json, graphify-out\.graphify_uncached.txt, graphify-out\.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -639,10 +640,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding="u print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost["total_input_tokens"]:,} input, {cost["total_output_tokens"]:,} output ({len(cost["runs"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) '@ | & (Get-Content graphify-out\.graphify_python) - -Remove-Item -Force -ErrorAction SilentlyContinue graphify-out\.graphify_detect.json, graphify-out\.graphify_extract.json, graphify-out\.graphify_ast.json, graphify-out\.graphify_semantic.json, graphify-out\.graphify_analysis.json -Get-ChildItem graphify-out -Filter '.graphify_chunk_*.json' -File -ErrorAction SilentlyContinue | Remove-Item -Force -Remove-Item -Force -ErrorAction SilentlyContinue graphify-out\.needs_update ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skill.md b/graphify/skill.md index abd2811d23..c28cb3d72a 100644 --- a/graphify/skill.md +++ b/graphify/skill.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/graphify/skills/agents/references/update.md b/graphify/skills/agents/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/agents/references/update.md +++ b/graphify/skills/agents/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/amp/references/update.md b/graphify/skills/amp/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/amp/references/update.md +++ b/graphify/skills/amp/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/claude/references/update.md b/graphify/skills/claude/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/claude/references/update.md +++ b/graphify/skills/claude/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/claw/references/update.md b/graphify/skills/claw/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/claw/references/update.md +++ b/graphify/skills/claw/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/codex/references/update.md b/graphify/skills/codex/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/codex/references/update.md +++ b/graphify/skills/codex/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/copilot/references/update.md b/graphify/skills/copilot/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/copilot/references/update.md +++ b/graphify/skills/copilot/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/droid/references/update.md b/graphify/skills/droid/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/droid/references/update.md +++ b/graphify/skills/droid/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/kilo/references/update.md b/graphify/skills/kilo/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/kilo/references/update.md +++ b/graphify/skills/kilo/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/kiro/references/update.md b/graphify/skills/kiro/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/kiro/references/update.md +++ b/graphify/skills/kiro/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/opencode/references/update.md b/graphify/skills/opencode/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/opencode/references/update.md +++ b/graphify/skills/opencode/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/pi/references/update.md b/graphify/skills/pi/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/pi/references/update.md +++ b/graphify/skills/pi/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/trae/references/update.md b/graphify/skills/trae/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/trae/references/update.md +++ b/graphify/skills/trae/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/vscode/references/update.md b/graphify/skills/vscode/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/vscode/references/update.md +++ b/graphify/skills/vscode/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/graphify/skills/windows/references/update.md b/graphify/skills/windows/references/update.md index 3632fd4126..ab614fd998 100644 --- a/graphify/skills/windows/references/update.md +++ b/graphify/skills/windows/references/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tests/test_skill_cleanup_is_shell_free.py b/tests/test_skill_cleanup_is_shell_free.py new file mode 100644 index 0000000000..0b5b0685fe --- /dev/null +++ b/tests/test_skill_cleanup_is_shell_free.py @@ -0,0 +1,133 @@ +"""The runbook's temp-file cleanup must not depend on a shell. + +Cleanup was the only part of the pipeline that shelled out, with `rm -f` and +`find ... -delete`. On a host that gates the agent's shell, destructive verbs are +exactly what the policy withholds, so both calls were denied, the pipeline had no +fallback, and the intermediates stayed on disk (#2790). That is not just clutter: +Part C and Step B3 read `.graphify_chunk_*.json` and `.graphify_semantic_new.json` +unconditionally, so a stale chunk from a previous run can be merged into the next +`--update`. + +It is the third reported cause of one symptom -- #1172 was the fish/zsh no-match +glob, #464 the Codex/Windows leftovers -- and unlike those, retrying or switching +shell does not help, because the cause is a permission policy. + +These tests assert the property that kills the whole class: no shipped skill asks +a shell to delete anything, and the Python that replaced it actually removes the +files it names. +""" +import re +import subprocess +import sys +from pathlib import Path + +import pytest + +SKILLS_DIR = Path(__file__).resolve().parent.parent / "graphify" +SKILL_FILES = sorted(SKILLS_DIR.glob("skill*.md")) +REFERENCE_FILES = sorted((SKILLS_DIR / "skills").rglob("*.md")) + +# Shell verbs that delete. `cp` and `mkdir` are deliberately absent: they are not +# destructive, so they are not what a permission policy withholds, and #2790 is +# specifically about the delete step. +_DELETE_VERBS = ( + re.compile(r"(? list[str]: + return [ + line.strip() + for line in text.splitlines() + for pat in _DELETE_VERBS + if pat.search(line) + ] + + +@pytest.mark.parametrize("path", SKILL_FILES, ids=lambda p: p.name) +def test_no_shipped_skill_deletes_through_a_shell(path): + assert not _offending(path.read_text(encoding="utf-8")), ( + f"{path.name} deletes through a shell verb; a permission-gated host will " + f"deny it: {_offending(path.read_text(encoding='utf-8'))}" + ) + + +@pytest.mark.parametrize("path", REFERENCE_FILES, ids=lambda p: f"{p.parent.parent.name}/{p.name}") +def test_no_shipped_reference_deletes_through_a_shell(path): + assert not _offending(path.read_text(encoding="utf-8")), ( + f"{path} deletes through a shell verb" + ) + + +def test_every_skill_still_cleans_the_chunk_files(): + """The guard above passes trivially if cleanup were simply deleted. Every + skill that dispatches chunks must still remove them, in Python.""" + checked = 0 + for path in SKILL_FILES: + text = path.read_text(encoding="utf-8") + if ".graphify_chunk_" not in text: + continue + checked += 1 + assert re.search(r"for _chunk in .*glob\('\.graphify_chunk_\*\.json'\):", text), ( + f"{path.name} dispatches chunks but never cleans them up" + ) + assert "_chunk.unlink(missing_ok=True)" in text, path.name + assert checked >= 10, f"expected most skills to dispatch chunks, saw {checked}" + + +# --------------------------------------------------------------------------- +# The replacement actually works +# --------------------------------------------------------------------------- + +_CLEANUP = """ +from pathlib import Path +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) +""" + + +def test_the_cleanup_block_shipped_in_skill_md_is_the_one_under_test(): + """Pin the snippet below to what skill.md actually ships, so this file cannot + drift into testing something the runbook no longer says.""" + text = (SKILLS_DIR / "skill.md").read_text(encoding="utf-8") + for line in _CLEANUP.strip().splitlines()[1:]: # skip the import + assert line in text, f"skill.md no longer contains: {line!r}" + + +def _seed(root: Path) -> None: + out = root / "graphify-out" + out.mkdir(parents=True) + for name in (".graphify_detect.json", ".graphify_extract.json", ".graphify_ast.json", + ".graphify_semantic.json", ".graphify_analysis.json", ".needs_update", + ".graphify_chunk_01.json", ".graphify_chunk_02.json"): + (out / name).write_text("{}", encoding="utf-8") + (out / "graph.json").write_text('{"nodes":[],"links":[]}', encoding="utf-8") + (out / "GRAPH_REPORT.md").write_text("# report\n", encoding="utf-8") + + +def test_cleanup_removes_every_intermediate_and_keeps_the_outputs(tmp_path): + _seed(tmp_path) + subprocess.run([sys.executable, "-c", _CLEANUP], cwd=tmp_path, check=True) + + left = sorted(p.name for p in (tmp_path / "graphify-out").iterdir()) + assert left == ["GRAPH_REPORT.md", "graph.json"], left + + +def test_cleanup_is_idempotent_when_nothing_is_there(tmp_path): + """`rm -f` tolerated missing files; `unlink(missing_ok=True)` must too, or a + --no-viz / cluster-only run that never wrote a chunk would crash Step 9.""" + (tmp_path / "graphify-out").mkdir() + subprocess.run([sys.executable, "-c", _CLEANUP], cwd=tmp_path, check=True) + subprocess.run([sys.executable, "-c", _CLEANUP], cwd=tmp_path, check=True) + + +def test_cleanup_does_not_need_the_output_dir_to_exist(tmp_path): + """glob() on a missing directory yields nothing rather than raising.""" + subprocess.run([sys.executable, "-c", _CLEANUP], cwd=tmp_path, check=True) diff --git a/tests/test_skillgen.py b/tests/test_skillgen.py index cf116869f2..a640aa265b 100644 --- a/tests/test_skillgen.py +++ b/tests/test_skillgen.py @@ -403,9 +403,15 @@ def test_powershell_hosts_carry_no_bash_only_shell(): assert "'@ | & (Get-Content graphify-out\\.graphify_python) -" in core, ( f"[{key}] missing the here-string stdin python invocation" ) - # Cleanup went through Remove-Item / Get-ChildItem, not rm/find. - assert "Remove-Item -Force -ErrorAction SilentlyContinue" in core - assert "Get-ChildItem graphify-out -Filter '.graphify_chunk_*.json'" in core + # Cleanup no longer goes through a shell at all (#2790): it is folded + # into the tail of the Python program each block already runs, so there + # is nothing left for the translator to turn into Remove-Item, and a + # host that gates destructive verbs has nothing to deny. + assert "Remove-Item" not in core, f"[{key}] cleanup still uses a shell verb" + assert "Get-ChildItem" not in core, f"[{key}] cleanup still uses a shell verb" + assert "for _chunk in _out.glob('.graphify_chunk_*.json'):" in core, ( + f"[{key}] lost the Python chunk cleanup" + ) def test_windows_and_posix_cores_have_step_and_2490_parity(): diff --git a/tools/skillgen/expected/graphify__skill-agents.md b/tools/skillgen/expected/graphify__skill-agents.md index 190827d9ac..e679e69093 100644 --- a/tools/skillgen/expected/graphify__skill-agents.md +++ b/tools/skillgen/expected/graphify__skill-agents.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-aider.md b/tools/skillgen/expected/graphify__skill-aider.md index 4996beb787..4a1a034567 100644 --- a/tools/skillgen/expected/graphify__skill-aider.md +++ b/tools/skillgen/expected/graphify__skill-aider.md @@ -346,10 +346,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('.graphify_semantic.json').write_text(json.dumps(merged, indent=2)) +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path(_tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f .graphify_cached.json .graphify_uncached.txt .graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -718,9 +719,13 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.graphify_labels.json']: + Path(_tmp).unlink(missing_ok=True) +for _chunk in Path('.').glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) +Path('graphify-out/.needs_update').unlink(missing_ok=True) " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json; find . -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Tell the user (omit the obsidian line unless --obsidian was given): @@ -865,11 +870,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json .graphify_old.json` -Clean up after: `rm -f .graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skill-amp.md b/tools/skillgen/expected/graphify__skill-amp.md index 190827d9ac..e679e69093 100644 --- a/tools/skillgen/expected/graphify__skill-amp.md +++ b/tools/skillgen/expected/graphify__skill-amp.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-claw.md b/tools/skillgen/expected/graphify__skill-claw.md index abd2811d23..c28cb3d72a 100644 --- a/tools/skillgen/expected/graphify__skill-claw.md +++ b/tools/skillgen/expected/graphify__skill-claw.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-codex.md b/tools/skillgen/expected/graphify__skill-codex.md index af3f723c78..4b034fe545 100644 --- a/tools/skillgen/expected/graphify__skill-codex.md +++ b/tools/skillgen/expected/graphify__skill-codex.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-copilot.md b/tools/skillgen/expected/graphify__skill-copilot.md index abd2811d23..c28cb3d72a 100644 --- a/tools/skillgen/expected/graphify__skill-copilot.md +++ b/tools/skillgen/expected/graphify__skill-copilot.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-devin.md b/tools/skillgen/expected/graphify__skill-devin.md index f9be846cbf..1a294bae0e 100644 --- a/tools/skillgen/expected/graphify__skill-devin.md +++ b/tools/skillgen/expected/graphify__skill-devin.md @@ -409,10 +409,11 @@ merged = { } merged = sanitize_semantic_fragment(merged) Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2)) +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -836,9 +837,13 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.graphify_labels.json', '.graphify_incremental.json', '.graphify_transcripts.json', '.graphify_old.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json graphify-out/.graphify_labels.json graphify-out/.graphify_incremental.json graphify-out/.graphify_transcripts.json graphify-out/.graphify_old.json; find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Tell the user (omit the obsidian line unless --obsidian was given; omit the wiki line unless --wiki was given): @@ -1001,11 +1006,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skill-droid.md b/tools/skillgen/expected/graphify__skill-droid.md index fd148d485d..fa8df9c4ef 100644 --- a/tools/skillgen/expected/graphify__skill-droid.md +++ b/tools/skillgen/expected/graphify__skill-droid.md @@ -348,10 +348,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -614,10 +615,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-kilo.md b/tools/skillgen/expected/graphify__skill-kilo.md index 3e70b050a4..754e46582f 100644 --- a/tools/skillgen/expected/graphify__skill-kilo.md +++ b/tools/skillgen/expected/graphify__skill-kilo.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-kiro.md b/tools/skillgen/expected/graphify__skill-kiro.md index abd2811d23..c28cb3d72a 100644 --- a/tools/skillgen/expected/graphify__skill-kiro.md +++ b/tools/skillgen/expected/graphify__skill-kiro.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-opencode.md b/tools/skillgen/expected/graphify__skill-opencode.md index 91ced60675..dbb21ace3d 100644 --- a/tools/skillgen/expected/graphify__skill-opencode.md +++ b/tools/skillgen/expected/graphify__skill-opencode.md @@ -343,10 +343,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -609,10 +610,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-pi.md b/tools/skillgen/expected/graphify__skill-pi.md index abd2811d23..c28cb3d72a 100644 --- a/tools/skillgen/expected/graphify__skill-pi.md +++ b/tools/skillgen/expected/graphify__skill-pi.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-trae.md b/tools/skillgen/expected/graphify__skill-trae.md index 050667bc20..286d96c123 100644 --- a/tools/skillgen/expected/graphify__skill-trae.md +++ b/tools/skillgen/expected/graphify__skill-trae.md @@ -349,10 +349,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -615,10 +616,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-vscode.md b/tools/skillgen/expected/graphify__skill-vscode.md index 20c7c0835c..32fe5137ee 100644 --- a/tools/skillgen/expected/graphify__skill-vscode.md +++ b/tools/skillgen/expected/graphify__skill-vscode.md @@ -347,10 +347,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -613,10 +614,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill-windows.md b/tools/skillgen/expected/graphify__skill-windows.md index d631821ec3..273023aae4 100644 --- a/tools/skillgen/expected/graphify__skill-windows.md +++ b/tools/skillgen/expected/graphify__skill-windows.md @@ -373,10 +373,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding="utf-8") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached["nodes"])} from cache, {len(new.get("nodes",[]))} new)') '@ | & (Get-Content graphify-out\.graphify_python) - ``` -Clean up temp files: `Remove-Item -Force -ErrorAction SilentlyContinue graphify-out\.graphify_cached.json, graphify-out\.graphify_uncached.txt, graphify-out\.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -639,10 +640,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding="u print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost["total_input_tokens"]:,} input, {cost["total_output_tokens"]:,} output ({len(cost["runs"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) '@ | & (Get-Content graphify-out\.graphify_python) - -Remove-Item -Force -ErrorAction SilentlyContinue graphify-out\.graphify_detect.json, graphify-out\.graphify_extract.json, graphify-out\.graphify_ast.json, graphify-out\.graphify_semantic.json, graphify-out\.graphify_analysis.json -Get-ChildItem graphify-out -Filter '.graphify_chunk_*.json' -File -ErrorAction SilentlyContinue | Remove-Item -Force -Remove-Item -Force -ErrorAction SilentlyContinue graphify-out\.needs_update ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skill.md b/tools/skillgen/expected/graphify__skill.md index abd2811d23..c28cb3d72a 100644 --- a/tools/skillgen/expected/graphify__skill.md +++ b/tools/skillgen/expected/graphify__skill.md @@ -351,10 +351,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -617,10 +618,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/expected/graphify__skills__agents__references__update.md b/tools/skillgen/expected/graphify__skills__agents__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__agents__references__update.md +++ b/tools/skillgen/expected/graphify__skills__agents__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__amp__references__update.md b/tools/skillgen/expected/graphify__skills__amp__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__amp__references__update.md +++ b/tools/skillgen/expected/graphify__skills__amp__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__claude__references__update.md b/tools/skillgen/expected/graphify__skills__claude__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__claude__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claude__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__claw__references__update.md b/tools/skillgen/expected/graphify__skills__claw__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__claw__references__update.md +++ b/tools/skillgen/expected/graphify__skills__claw__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__codex__references__update.md b/tools/skillgen/expected/graphify__skills__codex__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__codex__references__update.md +++ b/tools/skillgen/expected/graphify__skills__codex__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__copilot__references__update.md b/tools/skillgen/expected/graphify__skills__copilot__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__copilot__references__update.md +++ b/tools/skillgen/expected/graphify__skills__copilot__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__droid__references__update.md b/tools/skillgen/expected/graphify__skills__droid__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__droid__references__update.md +++ b/tools/skillgen/expected/graphify__skills__droid__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__kilo__references__update.md b/tools/skillgen/expected/graphify__skills__kilo__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__kilo__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kilo__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__kiro__references__update.md b/tools/skillgen/expected/graphify__skills__kiro__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__kiro__references__update.md +++ b/tools/skillgen/expected/graphify__skills__kiro__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__opencode__references__update.md b/tools/skillgen/expected/graphify__skills__opencode__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__opencode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__opencode__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__pi__references__update.md b/tools/skillgen/expected/graphify__skills__pi__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__pi__references__update.md +++ b/tools/skillgen/expected/graphify__skills__pi__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__trae__references__update.md b/tools/skillgen/expected/graphify__skills__trae__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__trae__references__update.md +++ b/tools/skillgen/expected/graphify__skills__trae__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__vscode__references__update.md b/tools/skillgen/expected/graphify__skills__vscode__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__vscode__references__update.md +++ b/tools/skillgen/expected/graphify__skills__vscode__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/expected/graphify__skills__windows__references__update.md b/tools/skillgen/expected/graphify__skills__windows__references__update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/expected/graphify__skills__windows__references__update.md +++ b/tools/skillgen/expected/graphify__skills__windows__references__update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/fragments/core/aider.md b/tools/skillgen/fragments/core/aider.md index 4996beb787..4a1a034567 100644 --- a/tools/skillgen/fragments/core/aider.md +++ b/tools/skillgen/fragments/core/aider.md @@ -346,10 +346,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('.graphify_semantic.json').write_text(json.dumps(merged, indent=2)) +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path(_tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f .graphify_cached.json .graphify_uncached.txt .graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -718,9 +719,13 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.graphify_labels.json']: + Path(_tmp).unlink(missing_ok=True) +for _chunk in Path('.').glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) +Path('graphify-out/.needs_update').unlink(missing_ok=True) " -rm -f .graphify_detect.json .graphify_extract.json .graphify_ast.json .graphify_semantic.json .graphify_analysis.json .graphify_labels.json; find . -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Tell the user (omit the obsidian line unless --obsidian was given): @@ -865,11 +870,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json .graphify_old.json` -Clean up after: `rm -f .graphify_old.json` --- diff --git a/tools/skillgen/fragments/core/core.md b/tools/skillgen/fragments/core/core.md index c527a12563..f5ac8a9a98 100644 --- a/tools/skillgen/fragments/core/core.md +++ b/tools/skillgen/fragments/core/core.md @@ -286,10 +286,11 @@ merged = { 'output_tokens': new.get('output_tokens', 0), } Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2, ensure_ascii=False), encoding=\"utf-8\") +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -552,10 +553,13 @@ cost_path.write_text(json.dumps(cost, indent=2, ensure_ascii=False), encoding=\" print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json -find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Replace INPUT_PATH with the actual path (same value used in Steps 4-5) so the manifest is relativized to the scan root. diff --git a/tools/skillgen/fragments/core/devin.md b/tools/skillgen/fragments/core/devin.md index f9be846cbf..1a294bae0e 100644 --- a/tools/skillgen/fragments/core/devin.md +++ b/tools/skillgen/fragments/core/devin.md @@ -409,10 +409,11 @@ merged = { } merged = sanitize_semantic_fragment(merged) Path('graphify-out/.graphify_semantic.json').write_text(json.dumps(merged, indent=2)) +for _tmp in ['.graphify_cached.json', '.graphify_uncached.txt', '.graphify_semantic_new.json']: + Path('graphify-out', _tmp).unlink(missing_ok=True) print(f'Extraction complete - {len(deduped)} nodes, {len(all_edges)} edges ({len(cached[\"nodes\"])} from cache, {len(new.get(\"nodes\",[]))} new)') " ``` -Clean up temp files: `rm -f graphify-out/.graphify_cached.json graphify-out/.graphify_uncached.txt graphify-out/.graphify_semantic_new.json` #### Part C - Merge AST + semantic into final extraction @@ -836,9 +837,13 @@ cost_path.write_text(json.dumps(cost, indent=2)) print(f'This run: {input_tok:,} input tokens, {output_tok:,} output tokens') print(f'All time: {cost[\"total_input_tokens\"]:,} input, {cost[\"total_output_tokens\"]:,} output ({len(cost[\"runs\"])} runs)') + +_out = Path('graphify-out') +for _tmp in ['.graphify_detect.json', '.graphify_extract.json', '.graphify_ast.json', '.graphify_semantic.json', '.graphify_analysis.json', '.graphify_labels.json', '.graphify_incremental.json', '.graphify_transcripts.json', '.graphify_old.json', '.needs_update']: + (_out / _tmp).unlink(missing_ok=True) +for _chunk in _out.glob('.graphify_chunk_*.json'): + _chunk.unlink(missing_ok=True) " -rm -f graphify-out/.graphify_detect.json graphify-out/.graphify_extract.json graphify-out/.graphify_ast.json graphify-out/.graphify_semantic.json graphify-out/.graphify_analysis.json graphify-out/.graphify_labels.json graphify-out/.graphify_incremental.json graphify-out/.graphify_transcripts.json graphify-out/.graphify_old.json; find graphify-out -maxdepth 1 -name '.graphify_chunk_*.json' -delete 2>/dev/null -rm -f graphify-out/.needs_update 2>/dev/null || true ``` Tell the user (omit the obsidian line unless --obsidian was given; omit the wiki line unless --wiki was given): @@ -1001,11 +1006,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/fragments/references/shared/update.md b/tools/skillgen/fragments/references/shared/update.md index 3632fd4126..ab614fd998 100644 --- a/tools/skillgen/fragments/references/shared/update.md +++ b/tools/skillgen/fragments/references/shared/update.md @@ -191,11 +191,11 @@ if old_data: print('New nodes:', ', '.join(n['label'] for n in diff['new_nodes'][:5])) if diff['new_edges']: print('New edges:', len(diff['new_edges'])) +Path('graphify-out/.graphify_old.json').unlink(missing_ok=True) " ``` Before the merge step, save the old graph: `cp graphify-out/graph.json graphify-out/.graphify_old.json` -Clean up after: `rm -f graphify-out/.graphify_old.json` --- diff --git a/tools/skillgen/gen.py b/tools/skillgen/gen.py index 09e19ede00..5407ed1eb6 100644 --- a/tools/skillgen/gen.py +++ b/tools/skillgen/gen.py @@ -919,6 +919,42 @@ def _is_chunk_cleanup_line(line: str) -> bool: return ".graphify_chunk_*.json" in line or ("find " in line and "-name '.graphify_chunk_" in line) +def _is_shell_free_cleanup_line(line: str) -> bool: + """Whether a line belongs to the shell-free rewrite of the temp-file cleanup. + + The cleanup steps were the only part of the runbook that shelled out, using + ``rm -f`` and ``find ... -delete``. Hosts that gate the agent's shell deny + destructive verbs as a matter of policy, so the cleanup silently did nothing + and a stale ``.graphify_chunk_*.json`` survived into the next ``--update``, + where Part C reads it unconditionally (graphify #2790). That is the third + reported cause of the same symptom, after the fish/zsh glob (#1172, see + :func:`_is_chunk_cleanup_line`) and the Codex/Windows leftovers (#464). + + The fix folds the cleanup into the tail of the Python program each block + already runs, so no shell verb is involved on any host and nothing new is + spawned. That deliberately adds no fence, no ``$(cat ...) -c`` invocation and + no import — only statements that name graphify's own intermediates — which is + what keeps this predicate narrow enough to be worth having. + + Both sides are matched so the multiset diff classifies the change: the removed + ``rm -f`` (bare command or inside a prose code span) and the added Python. + """ + s = line.strip() + if "rm -f " in s and (".graphify_" in s or ".needs_update" in s): + return True + if s == "_out = Path('graphify-out')" or s == "_chunk.unlink(missing_ok=True)": + return True + if s.startswith("for _tmp in [") and s.endswith("]:"): + return True + if s.startswith("for _chunk in ") and s.endswith("glob('.graphify_chunk_*.json'):"): + return True + if s.endswith(".unlink(missing_ok=True)") and ( + "_tmp" in s or ".graphify_" in s or ".needs_update" in s + ): + return True + return False + + def _is_trigger_line(line: str) -> bool: """Whether a line is the non-spec ``trigger:`` frontmatter field (#1180). @@ -1150,6 +1186,7 @@ def _is_community_label_export_fix_line(line: str) -> bool: _is_enum_line, _is_frontmatter_description_line, _is_chunk_cleanup_line, + _is_shell_free_cleanup_line, _is_directed_fix_line, _is_content_scope_fix_line, _is_cache_unlink_fix_line,