release 0.3.18: fix watch .graphifyignore, codex hook, trae link, Korean README, save-result CLI

This commit is contained in:
Safi
2026-04-09 08:09:36 +01:00
parent 9cfaa3339b
commit 91cbc74bb1
10 changed files with 61 additions and 261 deletions
+9
View File
@@ -2,6 +2,15 @@
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
## 0.3.18 (2026-04-09)
- Fix: `--watch` mode now respects `.graphifyignore``_rebuild_code` was calling `collect_files()` directly instead of `detect()`, bypassing ignore patterns (#120)
- Fix: Codex PreToolUse hook now uses `systemMessage` instead of `additionalContext` — Codex does not support `additionalContext` and was returning an error (#121)
- Fix: Trae link corrected from `trae.com` to `trae.ai` in README, README.zh-CN.md, README.ja-JP.md, README.ko-KR.md (#122)
- Docs: Korean README added (README.ko-KR.md) (#112)
- Refactor: `save_query_result` inline Python blocks in all 6 skill files replaced with `graphify save-result` CLI command — shorter, maintainable, less tokens for LLM (#114)
- Add: `graphify save-result` CLI subcommand — saves Q&A results to memory dir without inline Python
## 0.3.17 (2026-04-08)
- Add: Julia (.jl) support — modules, structs, abstract types, functions, short functions, using/import, call edges, inherits edges via tree-sitter-julia (#98)
+26 -1
View File
@@ -170,7 +170,7 @@ _CODEX_HOOK = {
"type": "command",
"command": (
"[ -f graphify-out/graph.json ] && "
r"""echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":"graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files."}}' """
r"""echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","systemMessage":"graphify: Knowledge graph exists. Read graphify-out/GRAPH_REPORT.md for god nodes and community structure before searching raw files."}}' """
"|| true"
),
}
@@ -388,6 +388,12 @@ def main() -> None:
print(" --dfs use depth-first instead of breadth-first")
print(" --budget N cap output at N tokens (default 2000)")
print(" --graph <path> path to graph.json (default graphify-out/graph.json)")
print(" save-result save a Q&A result to graphify-out/memory/ for graph feedback loop")
print(" --question Q the question asked")
print(" --answer A the answer to save")
print(" --type T query type: query|path_query|explain (default: query)")
print(" --nodes N1 N2 ... source node labels cited in the answer")
print(" --memory-dir DIR memory directory (default: graphify-out/memory)")
print(" benchmark [graph.json] measure token reduction vs naive full-corpus approach")
print(" hook install install post-commit/post-checkout git hooks (all platforms)")
print(" hook uninstall remove git hooks")
@@ -518,6 +524,25 @@ def main() -> None:
start = [nid for _, nid in scored[:5]]
nodes, edges = (_dfs if use_dfs else _bfs)(G, start, depth=2)
print(_subgraph_to_text(G, nodes, edges, token_budget=budget))
elif cmd == "save-result":
# graphify save-result --question Q --answer A --type T [--nodes N1 N2 ...]
import argparse as _ap
p = _ap.ArgumentParser(prog="graphify save-result")
p.add_argument("--question", required=True)
p.add_argument("--answer", required=True)
p.add_argument("--type", dest="query_type", default="query")
p.add_argument("--nodes", nargs="*", default=[])
p.add_argument("--memory-dir", default="graphify-out/memory")
opts = p.parse_args(sys.argv[2:])
from graphify.ingest import save_query_result as _sqr
out = _sqr(
question=opts.question,
answer=opts.answer,
memory_dir=Path(opts.memory_dir),
query_type=opts.query_type,
source_nodes=opts.nodes or None,
)
print(f"Saved to {out}")
elif cmd == "benchmark":
from graphify.benchmark import run_benchmark, print_benchmark
graph_path = sys.argv[2] if len(sys.argv) > 2 else "graphify-out/graph.json"
+3 -36
View File
@@ -894,18 +894,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES, # list of node labels cited, or []
)
print('Query result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -980,18 +969,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES, # list of node labels on the path
)
print('Path result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1057,18 +1035,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+3 -36
View File
@@ -950,18 +950,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES, # list of node labels cited, or []
)
print('Query result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -1036,18 +1025,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES, # list of node labels on the path
)
print('Path result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1113,18 +1091,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+3 -36
View File
@@ -947,18 +947,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES, # list of node labels cited, or []
)
print('Query result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -1033,18 +1022,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES, # list of node labels on the path
)
print('Path result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1110,18 +1088,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+3 -36
View File
@@ -946,18 +946,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES, # list of node labels cited, or []
)
print('Query result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -1032,18 +1021,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES, # list of node labels on the path
)
print('Path result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1109,18 +1087,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+3 -36
View File
@@ -915,18 +915,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES,
)
print('Query result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -1001,18 +990,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES,
)
print('Path result saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1077,18 +1055,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```bash
$(cat .graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
$(cat .graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+3 -36
View File
@@ -937,18 +937,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```powershell
python -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES, # list of node labels cited, or []
)
print('Query result saved to graphify-out/memory/')
"
python -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -1023,18 +1012,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```powershell
python -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES, # list of node labels on the path
)
print('Path result saved to graphify-out/memory/')
"
python -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1100,18 +1078,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```powershell
python -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
python -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+3 -36
View File
@@ -958,18 +958,7 @@ Replace `QUESTION` with the user's actual question, `MODE` with `bfs` or `dfs`,
After writing the answer, save it back into the graph so it improves future queries:
```bash
$(cat graphify-out/.graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='QUESTION',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='query',
source_nodes=SOURCE_NODES, # list of node labels cited, or []
)
print('Query result saved to graphify-out/memory/')
"
$(cat graphify-out/.graphify_python) -m graphify save-result --question "QUESTION" --answer "ANSWER" --type query --nodes NODE1 NODE2
```
Replace `QUESTION` with the question, `ANSWER` with your full answer text, `SOURCE_NODES` with the list of node labels you cited. This closes the feedback loop: the next `--update` will extract this Q&A as a node in the graph.
@@ -1044,18 +1033,7 @@ Replace `NODE_A` and `NODE_B` with the actual concept names from the user. Then
After writing the explanation, save it back:
```bash
$(cat graphify-out/.graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Path from NODE_A to NODE_B',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='path_query',
source_nodes=PATH_NODES, # list of node labels on the path
)
print('Path result saved to graphify-out/memory/')
"
$(cat graphify-out/.graphify_python) -m graphify save-result --question "Path from NODE_A to NODE_B" --answer "ANSWER" --type path_query --nodes NODE_A NODE_B
```
---
@@ -1121,18 +1099,7 @@ Replace `NODE_NAME` with the concept the user asked about. Then write a 3-5 sent
After writing the explanation, save it back:
```bash
$(cat graphify-out/.graphify_python) -c "
from graphify.ingest import save_query_result
from pathlib import Path
save_query_result(
question='Explain NODE_NAME',
answer='ANSWER',
memory_dir=Path('graphify-out/memory'),
query_type='explain',
source_nodes=['NODE_NAME'],
)
print('Explanation saved to graphify-out/memory/')
"
$(cat graphify-out/.graphify_python) -m graphify save-result --question "Explain NODE_NAME" --answer "ANSWER" --type explain --nodes NODE_NAME
```
---
+5 -8
View File
@@ -24,19 +24,16 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
Returns True on success, False on error.
"""
try:
from graphify.extract import collect_files, extract
from graphify.extract import extract
from graphify.detect import detect, FileType
from graphify.build import build_from_json
from graphify.cluster import cluster, score_all
from graphify.analyze import god_nodes, surprising_connections, suggest_questions
from graphify.report import generate
from graphify.export import to_json
code_files = collect_files(watch_path, follow_symlinks=follow_symlinks)
code_files = [
f for f in code_files
if "graphify-out" not in f.parts
and "__pycache__" not in f.parts
]
detected = detect(watch_path, follow_symlinks=follow_symlinks)
code_files = [Path(f) for f in detected[FileType.CODE]]
if not code_files:
print("[graphify watch] No code files found - nothing to rebuild.")
@@ -47,7 +44,7 @@ def _rebuild_code(watch_path: Path, *, follow_symlinks: bool = False) -> bool:
detection = {
"files": {"code": [str(f) for f in code_files], "document": [], "paper": [], "image": []},
"total_files": len(code_files),
"total_words": 0, # not needed during watch rebuild
"total_words": detected.get("total_words", 0),
}
G = build_from_json(result)