From d1fc11b6859ed2b05d1c6ffebfb990f154f013ef Mon Sep 17 00:00:00 2001 From: cklam12345 Date: Sat, 11 Jul 2026 15:13:40 -0700 Subject: [PATCH] Add `wisdom --version` and stale-install self-check (0.3.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a `--version`/`-V`/`version` command that prints the version baked into the running code (_CODE_VERSION), independent of whatever distribution metadata resolves on sys.path. Also warns when the running code and the installed wisdomgraph distribution disagree — the "wisdom on PATH is an old shim" trap we hit during 0.3.2 testing, where the console script ran 0.2.0 while the repo was newer. The warning goes to stderr and is skipped for the `mcp` command so it never touches the JSON-RPC stdio stream. A test asserts _CODE_VERSION matches pyproject.toml so the two can't drift. Co-Authored-By: Claude Opus 4.8 --- pyproject.toml | 2 +- tests/test_mcp.py | 53 ++++++++++++++++++++++++++++++++++++++++++++++ wisdom/__main__.py | 51 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 01f38c2..b55e72e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "wisdomgraph" -version = "0.3.2" +version = "0.3.3" description = "Graph-native persistent cognition for AI agents using Neo4j, DIKW, and MCP" readme = "README.md" license = {text = "MIT"} diff --git a/tests/test_mcp.py b/tests/test_mcp.py index 36cc3e4..660bec2 100644 --- a/tests/test_mcp.py +++ b/tests/test_mcp.py @@ -844,3 +844,56 @@ def test_try_autostart_local_starts_backend_when_docker_present(): patch("wisdom.local.up") as up: assert mcp._try_autostart_local() is True up.assert_called_once_with(connect=True) + + +# ── version / stale-install self-check ───────────────────────────────────────── + +def test_version_command_prints_code_version(monkeypatch, capsys): + import wisdom.__main__ as m + + monkeypatch.setattr(sys, "argv", ["wisdom", "--version"]) + m.main() + assert f"wisdomgraph {m._CODE_VERSION}" in capsys.readouterr().out + + +def test_code_version_matches_pyproject(): + import re + from pathlib import Path + import wisdom.__main__ as m + + root = Path(__file__).resolve().parent.parent + text = (root / "pyproject.toml").read_text(encoding="utf-8") + match = re.search(r'(?m)^version\s*=\s*"([^"]+)"', text) + assert match, "version not found in pyproject.toml" + assert match.group(1) == m._CODE_VERSION, "bump _CODE_VERSION to match pyproject.toml" + + +def test_warn_if_stale_warns_on_version_mismatch(capsys): + import wisdom.__main__ as m + + with patch.object(m, "_dist_version", return_value="0.2.0"): + m._warn_if_stale() + err = capsys.readouterr().err + assert "0.2.0" in err + assert "pip install -U wisdomgraph" in err + + +def test_warn_if_stale_silent_when_matching_or_unknown(capsys): + import wisdom.__main__ as m + + with patch.object(m, "_dist_version", return_value=m._CODE_VERSION): + m._warn_if_stale() + with patch.object(m, "_dist_version", return_value="unknown"): + m._warn_if_stale() + assert capsys.readouterr().err == "" + + +def test_main_skips_stale_check_for_mcp(monkeypatch): + import wisdom.__main__ as m + + monkeypatch.setattr(sys, "argv", ["wisdom", "mcp"]) + with patch.object(m, "_warn_if_stale") as warn, \ + patch("wisdom.mcp.run_mcp_server") as run: + m.main() + warn.assert_not_called() + run.assert_called_once() diff --git a/wisdom/__main__.py b/wisdom/__main__.py index 667747b..f5d0449 100644 --- a/wisdom/__main__.py +++ b/wisdom/__main__.py @@ -8,6 +8,11 @@ import sys from pathlib import Path +# Baked into the source so it identifies the code actually running, independent +# of whatever distribution metadata happens to resolve on sys.path. Keep in sync +# with pyproject.toml (guarded by test_code_version_matches_pyproject). +_CODE_VERSION = "0.3.3" + try: from importlib.metadata import version as _pkg_version __version__ = _pkg_version("wisdomgraph") @@ -15,6 +20,41 @@ __version__ = "unknown" +def _dist_version() -> str: + """Version of the installed `wisdomgraph` distribution metadata (may differ + from the running code if more than one install is on PATH).""" + try: + from importlib.metadata import version + return version("wisdomgraph") + except Exception: + return "unknown" + + +def _print_version() -> None: + print(f"wisdomgraph {_CODE_VERSION}") + dist = _dist_version() + if dist not in (_CODE_VERSION, "unknown"): + print( + f" note: installed distribution metadata reports {dist} — " + "more than one wisdomgraph install is on PATH.", + file=sys.stderr, + ) + + +def _warn_if_stale() -> None: + """Warn when the running code and the installed distribution disagree — the + classic 'wisdom on PATH is an old shim' trap.""" + dist = _dist_version() + if dist not in (_CODE_VERSION, "unknown"): + print( + f"warning: this 'wisdom' runs code v{_CODE_VERSION} but the installed " + f"wisdomgraph distribution is v{dist} — you likely have more than one " + "install on PATH.", + file=sys.stderr, + ) + print(" Fix: pip install -U wisdomgraph (check with: which -a wisdom)", file=sys.stderr) + + # ── Hook / registration strings ────────────────────────────────────────────── _SETTINGS_HOOK = { @@ -380,6 +420,15 @@ def main() -> None: cmd = sys.argv[1] + if cmd in ("--version", "-V", "version"): + _print_version() + return + + # Surface stale-install mismatches, but never on `mcp` — that speaks JSON-RPC + # over stdio and its stderr is reserved for the host's logs. + if cmd != "mcp": + _warn_if_stale() + if cmd == "install": default_p = "windows" if _platform_mod.system() == "Windows" else "claude" chosen = default_p @@ -635,6 +684,8 @@ def _print_explain(result: dict) -> None: def _print_help() -> None: print("Usage: wisdom ") print() + print(" --version print the running wisdomgraph version") + print() print("Setup:") print(" quickstart [--storage local|aura|existing] [--host claude|codex|all|none]") print(" doctor check Neo4j, local backend, and MCP host readiness")