diff --git a/.github/scripts/version.mjs b/.github/scripts/version.mjs index 7d5cbc2a3..13331f5ac 100755 --- a/.github/scripts/version.mjs +++ b/.github/scripts/version.mjs @@ -4,9 +4,10 @@ // // The release version is package.json's `version`. It is repeated in the engine // pins (optionalDependencies — each engine package is published under the same -// version as this one), the vendored parser, and every agent plugin manifest a -// marketplace reads. A release where they disagree ships a plugin that reports a -// version nobody can install, or an install that pins engines that were never +// version as this one) and every agent plugin manifest a marketplace reads. The +// vendored parser keeps its own version: it moves only when the parser changes. +// A release where they disagree ships a plugin that reports a version nobody can +// install, or an install that pins engines that were never // published. // // node .github/scripts/version.mjs check every manifest agrees @@ -24,7 +25,6 @@ const root = join(dirname(fileURLToPath(import.meta.url)), '..', '..'); // reading the file, so a fifth platform is covered without editing this list. const MANIFESTS = [ 'package.json', - 'parser/package.json', 'gemini-extension.json', 'plugins/axiomcode/.claude-plugin/plugin.json', 'plugins/axiomcode/.codex-plugin/plugin.json', diff --git a/gemini-extension.json b/gemini-extension.json index aeb7b99bb..bdc7980f4 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.1.0", + "version": "0.1.1", "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 aee53b533..0248c3abe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axiomcode/code-graph", - "version": "0.1.0", + "version": "0.1.1", "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.0", - "@axiomcode/engine-darwin-x64": "0.1.0", - "@axiomcode/engine-linux-x64": "0.1.0", - "@axiomcode/engine-linux-arm64": "0.1.0", - "@axiomcode/engine-win32-x64": "0.1.0" + "@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" }, "bin": { "axiomcode": "bin/axiomcode.js" diff --git a/plugins/axiomcode/.claude-plugin/plugin.json b/plugins/axiomcode/.claude-plugin/plugin.json index 16f99e472..514bde667 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.0", + "version": "0.1.1", "author": { "name": "AxiomCode" } diff --git a/plugins/axiomcode/.codex-plugin/plugin.json b/plugins/axiomcode/.codex-plugin/plugin.json index 57d2e99ff..811f1fb2b 100644 --- a/plugins/axiomcode/.codex-plugin/plugin.json +++ b/plugins/axiomcode/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.1.0", + "version": "0.1.1", "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 d7a2d38e1..229f4d275 100644 --- a/plugins/axiomcode/.cursor-plugin/plugin.json +++ b/plugins/axiomcode/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.1.0", + "version": "0.1.1", "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", diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-build b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-build index 12ab8e8a9..5a92793d1 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-build +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-build @@ -24,6 +24,9 @@ if [ -z "${AXIOMCODE_ENGINE:-}" ]; then E="$H"; while [ "$E" != "/" ] && [ ! -x # not, since it is not in git -- and that clone was taken over the built engine `npm i -g` installed. An # unbuilt checkout is still used when nothing else is found, so a developer keeps the "parser not built" # advice; an engine named in AXIOMCODE_ENGINE is used as given whenever it is one. +# python3's sqlite3 module, not the sqlite3 CLI: python3 is a stated requirement, the CLI is not, and stock Ubuntu +# and Git for Windows ship without it. +has_symbols() { python3 -c 'import sqlite3, sys; sys.exit(0 if sqlite3.connect(sys.argv[1]).execute("SELECT 1 FROM sqlite_master WHERE name=?", ("symbols",)).fetchone() else 1)' "$1" 2>/dev/null; } engine_ok() { [ -x "$1/bin/axiomcode" ] && [ -d "$1/graph" ] && [ -f "$1/package.json" ]; } engine_built() { engine_ok "$1" && [ -f "$1/parser/dist/index.js" ]; } if ! { if [ -n "$ENGINE_SET" ]; then engine_ok "$AXIOMCODE_ENGINE"; else engine_built "$AXIOMCODE_ENGINE"; fi; }; then @@ -150,11 +153,11 @@ BASE_SAVED="" # from the edit, is. A commit that changed no file moves the stamp, not the graph. if [ -f "$OUT/graph.sqlite" ] && [ -f "$OUT/stamp" ] && python3 "$H/ax_fresh.py" uptodate "$REPO" "$LANG_ARG" "${AXIOMCODE_SRC:-}" "${STAMP#"$PREFIX"}"; then if [ "$(cat "$OUT/stamp")" != "$STAMP" ]; then echo "$STAMP" > "$OUT/stamp"; INDEXED_TREE="$OLD_INDEXED"; set_base "$OLD_INDEXED"; PREV=""; keep_base_graph; commit_base; fi - sqlite3 "$OUT/graph.sqlite" "SELECT 1 FROM sqlite_master WHERE name='symbols'" | grep -q 1 || python3 "$H/axiomcode-index" "$REPO" + has_symbols "$OUT/graph.sqlite" || python3 "$H/axiomcode-index" "$REPO" echo "graph up to date ($LANG_ARG) at $OUT/graph.sqlite"; exit 0 fi if [ ! -f "$OUT/files.json" ] && [ -f "$OUT/stamp" ] && [ "$(cat "$OUT/stamp")" = "$STAMP" ] && [ -f "$OUT/graph.sqlite" ] && [ -z "$(cd "$REPO" && git status --porcelain 2>/dev/null | head -1)" ]; then - sqlite3 "$OUT/graph.sqlite" "SELECT 1 FROM sqlite_master WHERE name='symbols'" | grep -q 1 || python3 "$H/axiomcode-index" "$REPO" + has_symbols "$OUT/graph.sqlite" || python3 "$H/axiomcode-index" "$REPO" python3 "$H/axiomcode-impact" --warm "$REPO" || true # export the graph's facts now (~9 s on 1,373 files): the first # query pays it otherwise, and for the plugin that first query is inside hooks/changes.py's timeout=14, several at once. python3 "$H/dl_program.py" || true # compile the query rules once, here where ~20 s is noise against the build: @@ -214,8 +217,14 @@ AXIOMCODE_INDEX_DB="$DB" python3 "$H/axiomcode-index" "$REPO" || { restore; echo # the tree and commit it describes. Written before the swap: a write to the live graph later would change its mtime, # which keys the impact-facts cache, and cost the next query a re-export. REASON="$(printf %s "${AXIOMCODE_REFRESH_REASON:-axiomcode index}" | tr -d "'")" -sqlite3 "$DB" "DELETE FROM index_meta WHERE key IN ('refreshed_at','refresh_reason','refreshed_tree','refreshed_commit'); - INSERT INTO index_meta VALUES ('refreshed_at','$(date -u +%Y-%m-%dT%H:%M:%SZ)'),('refresh_reason','$REASON'),('refreshed_tree','$INDEXED_TREE'),('refreshed_commit','$HEAD_SHA');" 2>/dev/null || true +python3 - "$DB" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$REASON" "$INDEXED_TREE" "$HEAD_SHA" <<'PY' 2>/dev/null || true +import sqlite3, sys +db, at, reason, tree, commit = sys.argv[1:6] +with sqlite3.connect(db) as c: + c.execute("DELETE FROM index_meta WHERE key IN ('refreshed_at','refresh_reason','refreshed_tree','refreshed_commit')") + c.executemany("INSERT INTO index_meta VALUES (?,?)", [('refreshed_at', at), ('refresh_reason', reason), + ('refreshed_tree', tree), ('refreshed_commit', commit)]) +PY echo "$STAMP" > "$OUT/stamp" if [ -n "$INDEXED_TREE" ]; then echo "$INDEXED_TREE" > "$OUT/indexed-tree"; else rm -f "$OUT/indexed-tree"; fi set_base "$INDEXED_TREE" @@ -223,7 +232,13 @@ point "$DB"; rm -f "$OUT/.live.sqlite" if [ -f "$OUT/.files.json.new" ]; then mv "$OUT/.files.json.new" "$OUT/files.json"; else rm -f "$OUT/files.json"; fi keep_base_graph; commit_base rm -rf "$PREV" -sqlite3 -column "$OUT/graph.sqlite" "SELECT tier, count(*) AS edges FROM call_edges GROUP BY tier ORDER BY edges DESC;" +python3 - "$OUT/graph.sqlite" <<'PY' +import sqlite3, sys +rows = sqlite3.connect(sys.argv[1]).execute("SELECT tier, count(*) FROM call_edges GROUP BY tier ORDER BY 2 DESC").fetchall() +w = max([len('tier')] + [len(t) for t, _ in rows]) +print(f"{'tier':<{w}} edges") +for t, n in rows: print(f"{t:<{w}} {n}") +PY python3 "$H/axiomcode-impact" --warm "$REPO" || true # export the graph's facts now (~9 s on 1,373 files): the first # query pays it otherwise, and for the plugin that first query is inside hooks/changes.py's timeout=14, several at once. python3 "$H/dl_program.py" || true # compile the query rules once, here where ~20 s is noise against the build: