Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion bin/axiomcode
Original file line number Diff line number Diff line change
Expand Up @@ -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 <src-dir>, --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
Expand Down Expand Up @@ -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 <verb>` for any one of them:'
Expand All @@ -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 <src-dir>, 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 <verb>` too, so one `help` covers
# both halves of the command.
case "$cmd" in
Expand Down
10 changes: 9 additions & 1 deletion bin/axiomcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion gemini-extension.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion plugins/axiomcode/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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"
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/axiomcode/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
2 changes: 1 addition & 1 deletion plugins/axiomcode/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
39 changes: 39 additions & 0 deletions tests/cli_version.py
Original file line number Diff line number Diff line change
@@ -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)
Loading