fix #821 #818 #820: universal help guard, --version flag, Ollama num_ctx fallback

- Universal -h/--help/-? guard after cmd dispatch: any help flag anywhere in
  argv stops execution and prints "Run 'graphify --help'" instead of triggering
  the subcommand — cursor/kiro/gemini install --help no longer silently installs;
  benchmark --help no longer crashes with FileNotFoundError (#821)
- --version / -v / version subcommand: print graphify {__version__} and exit (#818)
- GRAPHIFY_OLLAMA_NUM_CTX=<invalid> now falls through to auto-derived num_ctx
  instead of hardcoding 131072 (the cap that causes OOM on constrained VRAM);
  pinned num_ctx < estimated input now triggers an explicit truncation warning
  with a suggested --token-budget correction (#820)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Safi
2026-05-11 21:18:48 +01:00
co-authored by Claude Sonnet 4.6
parent dd465afd2c
commit 094d8ba731
4 changed files with 49 additions and 6 deletions
+7
View File
@@ -2,6 +2,13 @@
Full release notes with details on each version: [GitHub Releases](https://github.com/safishamsi/graphify/releases)
## 0.7.15 (2026-05-11)
- Fix: `-h`/`--help`/`-?` in any position now stops execution — previously `graphify cursor install --help` silently installed into Cursor; `graphify benchmark --help` crashed with FileNotFoundError (#821)
- Fix: `--version`, `-v`, and `graphify version` now print the installed version and exit (#818)
- Fix: `GRAPHIFY_OLLAMA_NUM_CTX=<invalid>` no longer falls back to hardcoded 131072 (which exhausted VRAM) — it now falls through to the auto-derived value and prints a warning (#820)
- Fix: when `GRAPHIFY_OLLAMA_NUM_CTX` is set smaller than the estimated chunk size, graphify now warns explicitly that Ollama will silently truncate the prompt and suggests a corrected `--token-budget` (#820)
## 0.7.14 (2026-05-11)
- Fix: `_make_id` and `_normalize_id` now apply NFKC Unicode normalization before ID generation -- composed/decomposed forms of the same character (e.g. `é` typed vs pasted from a PDF) now produce the same node ID; switched from `.lower()` to `.casefold()` for correct Turkish/German/Greek case folding; both functions are now byte-for-byte equivalent (#811)
+16 -1
View File
@@ -1122,7 +1122,11 @@ def main() -> None:
for skill_dst in {Path.home() / cfg["skill_dst"] for cfg in _PLATFORM_CONFIG.values()}:
_check_skill_version(skill_dst)
if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
if len(sys.argv) >= 2 and sys.argv[1] in ("-v", "--version", "version"):
print(f"graphify {__version__}")
return
if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help", "-?"):
print("Usage: graphify <command>")
print()
print("Commands:")
@@ -1227,6 +1231,17 @@ def main() -> None:
return
cmd = sys.argv[1]
# Universal help guard: -h/--help/-? anywhere after the command shows help
# and stops — prevents flags from silently triggering destructive subcommands
# (e.g. "cursor install --help" was silently installing into Cursor, #821).
# Exempt: free-text commands (user string may contain these tokens), and
# "install"/"uninstall" which have their own per-subcommand help handlers.
_FREE_TEXT_CMDS = {"query", "explain", "path", "save-result", "install", "uninstall"}
if cmd not in _FREE_TEXT_CMDS and any(a in {"-h", "--help", "-?"} for a in sys.argv[2:]):
print(f"Run 'graphify --help' for full usage.")
return
if cmd == "install":
# Default to windows platform on Windows, claude elsewhere
default_platform = "windows" if platform.system() == "Windows" else "claude"
+25 -4
View File
@@ -289,17 +289,38 @@ def _call_openai_compat(
# Capped at 131072 (enough for the default 60k token_budget); env var wins.
if backend == "ollama":
num_ctx_raw = os.environ.get("GRAPHIFY_OLLAMA_NUM_CTX", "").strip()
# Auto-derive num_ctx from actual chunk size regardless — used as the
# fallback and for the mismatch check below.
estimated_input = len(user_message) // _CHARS_PER_TOKEN + 400
auto_num_ctx = min(estimated_input + max_completion_tokens + 2000, 131072)
auto_num_ctx = max(auto_num_ctx, 8192)
if num_ctx_raw:
try:
num_ctx = int(num_ctx_raw)
except ValueError:
num_ctx = 131072
# Bad env var: fall through to auto-derivation (not 131072 —
# hardcoding the cap is what causes OOM on constrained VRAM).
print(
f"[graphify] GRAPHIFY_OLLAMA_NUM_CTX={num_ctx_raw!r} is not a valid integer; "
f"using auto-derived value ({auto_num_ctx}).",
file=sys.stderr,
)
num_ctx = auto_num_ctx
else:
# Warn when the pinned value is smaller than the estimated input —
# Ollama silently truncates the prompt and returns empty responses.
if num_ctx < estimated_input:
print(
f"[graphify] warning: GRAPHIFY_OLLAMA_NUM_CTX={num_ctx} is smaller than "
f"the estimated chunk input (~{estimated_input} tokens). Ollama will "
f"silently truncate the prompt and return empty responses. "
f"Try --token-budget {max(1024, num_ctx // 3)} or increase NUM_CTX.",
file=sys.stderr,
)
else:
# Estimate input tokens: user_message chars / 4 (standard BPE
# heuristic) + 400 for the system prompt, then add output headroom.
estimated_input = len(user_message) // _CHARS_PER_TOKEN + 400
num_ctx = min(estimated_input + max_completion_tokens + 2000, 131072)
num_ctx = max(num_ctx, 8192) # floor: never under-allocate badly
num_ctx = auto_num_ctx
keep_alive = os.environ.get("GRAPHIFY_OLLAMA_KEEP_ALIVE", "30m")
kwargs["extra_body"] = {"options": {"num_ctx": num_ctx}, "keep_alive": keep_alive}
resp = client.chat.completions.create(**kwargs)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "graphifyy"
version = "0.7.14"
version = "0.7.15"
description = "AI coding assistant skill (Claude Code, Codex, OpenCode, Cursor, Gemini CLI, Aider, OpenClaw, Factory Droid, Trae, Hermes, Kiro, Pi, Google Antigravity) - turn any folder of code, docs, papers, images, or videos into a queryable knowledge graph"
readme = "README.md"
license = { file = "LICENSE" }