From b1a7293842a2ea5a4cfe528544277d3eac78a757 Mon Sep 17 00:00:00 2001 From: swapnil <78632212+swapnilpaliwal-sd@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:15:59 -0700 Subject: [PATCH 1/2] cli: axiomcode --version prints the installed version (#1352) The Node launcher answers it before looking for bash, so it works on a machine where bash cannot be found; bin/axiomcode answers it the same way from a checkout. With other arguments --version stays the build option. --help now prints the header up to its closing rule rather than a fixed line range, which the new lines would have cut short. --- bin/axiomcode | 9 ++++++++- bin/axiomcode.js | 10 +++++++++- tests/cli_version.py | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 tests/cli_version.py diff --git a/bin/axiomcode b/bin/axiomcode index 08ac8014..649bdad6 100755 --- a/bin/axiomcode +++ b/bin/axiomcode @@ -33,6 +33,8 @@ # Run the test suites. # mcp Serve the graph to an agent as MCP tools over stdio. Any MCP client # can start it as: npx -y @axiomcode/code-graph mcp +# --version Print the installed version. (After , --version V is the +# build option above.) # ───────────────────────────────────────────────────────────────────────────── set -eu # RESOLVE $0 THROUGH SYMLINKS BEFORE THE WALK. npm installs a `bin` entry as a link in @@ -77,7 +79,7 @@ QUERY="$ROOT/plugins/axiomcode/skills/axiomcode/scripts/axiomcode" query_verbs(){ [ -f "$QUERY" ] && bash "$QUERY" --verbs 2>/dev/null | grep -vx tests || true; } is_query_verb(){ query_verbs | grep -qx -- "$1"; } usage(){ - sed -n '3,35p' "$0" | sed 's/^# \{0,1\}//' + awk 'NR > 2 && /^# ─/ {exit} NR > 2' "$0" | sed 's/^# \{0,1\}//' if [ -f "$QUERY" ]; then echo echo 'ASKING THE GRAPH — `axiomcode help ` for any one of them:' @@ -88,6 +90,11 @@ die(){ echo "axiomcode: $*" >&2; exit 2; } need_parser(){ [ -f "$PARSER" ] || { echo "axiomcode: parser not built at $PARSER — run: npm install && npm run build" >&2; exit 1; }; } cmd="${1:-}" +# Alone, --version asks which release this is. With other arguments it stays the build option that stamps the +# source version, which a build takes after , so the two never meet. +if [ "$cmd" = --version ] && [ $# -eq 1 ]; then + sed -n 's/^ "version": "\(.*\)",$/\1/p' "$ROOT/package.json"; exit 0 +fi # A query verb goes to the frontend before anything else. `help ` too, so one `help` covers # both halves of the command. case "$cmd" in diff --git a/bin/axiomcode.js b/bin/axiomcode.js index 4a0f6c73..72a1fc1a 100755 --- a/bin/axiomcode.js +++ b/bin/axiomcode.js @@ -29,12 +29,20 @@ function fail(msg) { process.exit(127); } +// `axiomcode --version` is answered here, before bash is looked for: it is what a user runs to check an install, +// including one whose bash cannot be found. bin/axiomcode answers it the same way when run from a checkout. +const args = process.argv.slice(2); +if (args.length === 1 && args[0] === '--version') { + process.stdout.write(`${require('../package.json').version}\n`); + process.exit(0); +} + const { bash, error } = findBash(); if (error) fail(error); const py = findPython(); // AXIOMCODE_BASH too, for the builds Python starts: a bare `bash` from Python on Windows is WSL's or nothing. const env = { ...(py.exe ? withPython(process.env, py) : process.env), AXIOMCODE_BASH: bash }; -const r = spawnSync(bash, [path.join(__dirname, 'axiomcode'), ...process.argv.slice(2)], { stdio: 'inherit', env }); +const r = spawnSync(bash, [path.join(__dirname, 'axiomcode'), ...args], { stdio: 'inherit', env }); if (r.error) fail(`could not start bash: ${r.error.message}`); // Die of the same signal the CLI died of, so a caller sees what really happened. if (r.signal) process.kill(process.pid, r.signal); diff --git a/tests/cli_version.py b/tests/cli_version.py new file mode 100644 index 00000000..94757043 --- /dev/null +++ b/tests/cli_version.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""tests/cli_version.py — `axiomcode --version` prints the package version (#1352). + +It is answered by the Node launcher before bash is looked for, so it is checked there with no bash on PATH, +and by bin/axiomcode for a checkout. With other arguments --version is still the build option, not this. + + python3 tests/cli_version.py +""" +import json, os, shutil, subprocess, sys, tempfile + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +VERSION = json.load(open(os.path.join(ROOT, 'package.json')))['version'] + +fails, checked = [], [] +def check(why, cond, detail=''): + checked.append(why) + print(('ok ' if cond else 'FAIL ') + why + (f'\n {detail}' if not cond and detail else '')) + if not cond: + fails.append(why) + + +node = shutil.which('node') +with tempfile.TemporaryDirectory() as only_node: + os.symlink(node, os.path.join(only_node, 'node')) + r = subprocess.run([node, os.path.join(ROOT, 'bin', 'axiomcode.js'), '--version'], capture_output=True, text=True, + env=dict(os.environ, PATH=only_node, AXIOMCODE_BASH=''), timeout=30) + check('the installed command prints the package version, with no bash on PATH', + r.returncode == 0 and r.stdout == VERSION + '\n', f'rc={r.returncode} out={r.stdout!r} err={r.stderr[-200:]!r}') + +r = subprocess.run(['bash', os.path.join(ROOT, 'bin', 'axiomcode'), '--version'], capture_output=True, text=True, timeout=30) +check('bin/axiomcode prints the same version', r.returncode == 0 and r.stdout == VERSION + '\n', f'rc={r.returncode} out={r.stdout!r}') + +r = subprocess.run(['bash', os.path.join(ROOT, 'bin', 'axiomcode'), '--version', 'v9'], capture_output=True, text=True, timeout=30) +check('--version with a value is not taken for the version query', r.returncode != 0 and VERSION not in r.stdout, + f'rc={r.returncode} out={r.stdout!r}') + +print() +print(f"{len(checked) - len(fails)} of {len(checked)} check(s) held" if not fails else f"{len(fails)} FAILED: " + '; '.join(fails)) +sys.exit(1 if fails else 0) From b930be5bb153fd1444d8182699b17043dcf5620b Mon Sep 17 00:00:00 2001 From: swapnil <78632212+swapnilpaliwal-sd@users.noreply.github.com> Date: Fri, 25 Sep 2026 20:16:08 -0700 Subject: [PATCH 2/2] version 0.1.2 --- gemini-extension.json | 2 +- package.json | 12 ++++++------ plugins/axiomcode/.claude-plugin/plugin.json | 2 +- plugins/axiomcode/.codex-plugin/plugin.json | 2 +- plugins/axiomcode/.cursor-plugin/plugin.json | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gemini-extension.json b/gemini-extension.json index bdc7980f..defcedc6 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.1.1", + "version": "0.1.2", "description": "Ask your repository how its code connects: who calls this, what breaks if I change it, which tests an edit reaches, how A reaches B. Answers come from a resolved call graph and are verified against it; nothing is guessed.", "contextFileName": "plugins/axiomcode/AGENTS.md", "mcpServers": { diff --git a/package.json b/package.json index 7315e065..b38548c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axiomcode/code-graph", - "version": "0.1.1", + "version": "0.1.2", "description": "AxiomCode Graph: a resolved call graph of your codebase grounded in formal methods, so you and your coding agents can see who calls what, what a change breaks, and which tests it reaches.", "repository": { "type": "git", @@ -30,11 +30,11 @@ ], "license": "FSL-1.1-Apache-2.0", "optionalDependencies": { - "@axiomcode/engine-darwin-arm64": "0.1.1", - "@axiomcode/engine-darwin-x64": "0.1.1", - "@axiomcode/engine-linux-x64": "0.1.1", - "@axiomcode/engine-linux-arm64": "0.1.1", - "@axiomcode/engine-win32-x64": "0.1.1" + "@axiomcode/engine-darwin-arm64": "0.1.2", + "@axiomcode/engine-darwin-x64": "0.1.2", + "@axiomcode/engine-linux-x64": "0.1.2", + "@axiomcode/engine-linux-arm64": "0.1.2", + "@axiomcode/engine-win32-x64": "0.1.2" }, "bin": { "axiomcode": "bin/axiomcode.js" diff --git a/plugins/axiomcode/.claude-plugin/plugin.json b/plugins/axiomcode/.claude-plugin/plugin.json index 514bde66..28f13b63 100644 --- a/plugins/axiomcode/.claude-plugin/plugin.json +++ b/plugins/axiomcode/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "axiomcode", "description": "Ask your repository how its code connects: who calls this, what breaks if I change it, which tests an edit reaches, how A reaches B. Answers come from a resolved call graph and are verified against it; nothing is guessed.", - "version": "0.1.1", + "version": "0.1.2", "author": { "name": "AxiomCode" } diff --git a/plugins/axiomcode/.codex-plugin/plugin.json b/plugins/axiomcode/.codex-plugin/plugin.json index 811f1fb2..f4d18b77 100644 --- a/plugins/axiomcode/.codex-plugin/plugin.json +++ b/plugins/axiomcode/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.1.1", + "version": "0.1.2", "description": "Ask your repository how its code connects: who calls this, what breaks if I change it, which tests an edit reaches, how A reaches B. Answers come from a resolved call graph and are verified against it; nothing is guessed.", "author": { "name": "AxiomCode", "url": "https://github.com/AxiomCodeAI/axiomcodegraph" }, "homepage": "https://github.com/AxiomCodeAI/axiomcodegraph", diff --git a/plugins/axiomcode/.cursor-plugin/plugin.json b/plugins/axiomcode/.cursor-plugin/plugin.json index 229f4d27..a8f886ec 100644 --- a/plugins/axiomcode/.cursor-plugin/plugin.json +++ b/plugins/axiomcode/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.1.1", + "version": "0.1.2", "description": "Ask your repository how its code connects: who calls this, what breaks if I change it, which tests an edit reaches, how A reaches B. Answers come from a resolved call graph and are verified against it; nothing is guessed. Java, TypeScript, Python, JavaScript.", "author": { "name": "AxiomCode" }, "homepage": "https://github.com/AxiomCodeAI/axiomcodegraph",