diff --git a/.github/e2e/windows-cases.txt b/.github/e2e/windows-cases.txt index 7d80bd52..87b152db 100644 --- a/.github/e2e/windows-cases.txt +++ b/.github/e2e/windows-cases.txt @@ -26,6 +26,7 @@ no-name-yet one-row-per-dependent path-crosses-framework-and-byname path-through-interface +quoted-literal-text receiver-from-an-importlib-module registration-key route-table-reaches-view diff --git a/README.md b/README.md index b68e651f..88b6335e 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ established relationships that could lead to false positives. AxiomCode Graph is two parts. The **engine** (`@axiomcode/code-graph` on npm) parses a repository and builds its graph; it also provides the `axiomcode` command and an MCP server. The **plugin** (`plugins/axiomcode/`) is the -agent-facing frontend: a skill, four MCP tools, and hooks. Install the engine first. +agent-facing frontend: a skill, five MCP tools, and hooks. Install the engine first. Requirements: **Node ≥ 22.13** and **Python 3** (`python3`, or `python` / `py` on Windows). On Windows, also [Git for Windows](https://git-scm.com/download/win): the CLI runs under its bash. The engine ships as a prebuilt @@ -139,7 +139,7 @@ your platform. No Soufflé and no compiler are needed, with one exception: > `sudo apt install build-essential python3`. The full `node:*` Docker images already include them. Before every release, the exact packages that ship are installed without Soufflé and run end to end (every CLI verb, -five languages) on macOS arm64 and x64, Linux x64 and arm64, and Windows x64. Check an install with +six language engines, including HTML/CSS) on macOS arm64 and x64, Linux x64 and arm64, and Windows x64. Check an install with `axiomcode --version`. ### Installation @@ -262,7 +262,7 @@ looked up again in the graph before you see it; the `verified:` line is that che ### Support for agents -Every agent below gets the four MCP tools and the skill; the hooks, which keep the graph current and report what an +Every agent below gets the five MCP tools and the skill; the hooks, which keep the graph current and report what an edit breaks, run where the last column says so. No hook annotates the agent's own reads and searches. | Agent | Hooks | @@ -353,8 +353,10 @@ hooks and the MCP server's timer never rebuild a graph another axiomcode built ( ## Graph output -The graph is one SQLite database, `.axiomcode/out/graph.sqlite`, with the **same schema for -every language** and its documentation inside it (`schema_guide`, `schema_queries`, `schema_vocab`). The main +Each language has its own SQLite database: the main language at `.axiomcode/out/graph.sqlite`, and other +languages at `.axiomcode/lang//out/graph.sqlite`. The CLI queries all of them; calls are not followed +across languages. Each database has the **same schema for every language** and its documentation inside it +(`schema_guide`, `schema_queries`, `schema_vocab`). The main tables are `call_edges` (one row per call site and possible target), `methods`, `types`, `call_sites`, `field_access`, `type_use`, and `unresolved_sites`, the calls the engine declares it could not resolve. diff --git a/bin/axiomcode b/bin/axiomcode index b5225e77..8236bff0 100755 --- a/bin/axiomcode +++ b/bin/axiomcode @@ -55,6 +55,10 @@ set -eu if [ -n "${AXIOMCODE_ARGV+x}" ]; then set --; while IFS= read -r -d $'\x1f' _a; do set -- "$@" "$_a"; done < <(printf '%s' "$AXIOMCODE_ARGV"); unset AXIOMCODE_ARGV _a fi +# and Git Bash's runtime rewrites an argument that looks like a POSIX path as it starts a native program, so +# `impact '"/orders/{code}"'` reached Python as "C:/Program Files/Git/orders/{code}". A quoted query is never a path: +# an argument that starts with a quote is left as written, and every other one (a repository path) is converted as before. +case "${OSTYPE:-}" in msys*|cygwin*) export MSYS2_ARG_CONV_EXCL="\"${MSYS2_ARG_CONV_EXCL:+;$MSYS2_ARG_CONV_EXCL}";; esac # RESOLVE $0 THROUGH SYMLINKS BEFORE THE WALK. npm installs a `bin` entry as a link in # node_modules/.bin, so under `npx axiomcode` or a global install $0 is that link and # dirname "$0" is .bin/, a directory this package does not live under. The walk below then diff --git a/gemini-extension.json b/gemini-extension.json index dad92592..ae6411e4 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.2.1", + "version": "0.2.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 17f29b52..0d7c265c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@axiomcode/code-graph", - "version": "0.2.1", + "version": "0.2.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", @@ -31,11 +31,11 @@ ], "license": "FSL-1.1-Apache-2.0", "optionalDependencies": { - "@axiomcode/engine-darwin-arm64": "0.2.1", - "@axiomcode/engine-darwin-x64": "0.2.1", - "@axiomcode/engine-linux-x64": "0.2.1", - "@axiomcode/engine-linux-arm64": "0.2.1", - "@axiomcode/engine-win32-x64": "0.2.1" + "@axiomcode/engine-darwin-arm64": "0.2.2", + "@axiomcode/engine-darwin-x64": "0.2.2", + "@axiomcode/engine-linux-x64": "0.2.2", + "@axiomcode/engine-linux-arm64": "0.2.2", + "@axiomcode/engine-win32-x64": "0.2.2" }, "bin": { "axiomcode": "bin/axiomcode.js" diff --git a/plugins/axiomcode/.claude-plugin/plugin.json b/plugins/axiomcode/.claude-plugin/plugin.json index 7e4ba77b..6e2eae13 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.2.1", + "version": "0.2.2", "author": { "name": "AxiomCode" } diff --git a/plugins/axiomcode/.codex-plugin/plugin.json b/plugins/axiomcode/.codex-plugin/plugin.json index f7780f51..0348a6a3 100644 --- a/plugins/axiomcode/.codex-plugin/plugin.json +++ b/plugins/axiomcode/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.2.1", + "version": "0.2.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 ce390864..74ce345e 100644 --- a/plugins/axiomcode/.cursor-plugin/plugin.json +++ b/plugins/axiomcode/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "axiomcode", - "version": "0.2.1", + "version": "0.2.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", diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode index 8fea778c..669ee227 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode @@ -86,6 +86,10 @@ if [ -n "${AXIOMCODE_ARGV+x}" ]; then set --; while IFS= read -r -d $'\x1f' _a; do set -- "$@" "$_a"; done < <(printf '%s' "$AXIOMCODE_ARGV"); unset AXIOMCODE_ARGV _a fi +# and Git Bash's runtime rewrites an argument that looks like a POSIX path as it starts a native program, so +# `impact '"/orders/{code}"'` reached Python as "C:/Program Files/Git/orders/{code}". A quoted query is never a path: +# an argument that starts with a quote is left as written, and every other one (a repository path) is converted as before. +case "${OSTYPE:-}" in msys*|cygwin*) export MSYS2_ARG_CONV_EXCL="\"${MSYS2_ARG_CONV_EXCL:+;$MSYS2_ARG_CONV_EXCL}";; esac H="${0//\\//}"; case "$H" in */*) H="${H%/*}";; *) H=.;; esac; H="$(cd "${H:-/}" && pwd)" # no `dirname`: see bin/axiomcode # PYTHON UNDER ANOTHER NAME (#1331). Every verb runs `python3`, which a python.org install on Windows does not diff --git a/tests/mcp_docs.py b/tests/mcp_docs.py index 90092481..42a40d23 100644 --- a/tests/mcp_docs.py +++ b/tests/mcp_docs.py @@ -26,7 +26,7 @@ [os.path.join(ROOT, 'plugins', 'axiomcode', 'AGENTS.md')] + \ sorted(glob.glob(os.path.join(ROOT, 'plugins', 'axiomcode', 'rules', '*.mdc'))) -VERB = r'(find|impact|path|tests)' +VERB = r'(context|impact|link|path|tests)' # a tool named: a call `impact(`, the Claude Code name mcp__plugin_axiomcode_axiomcode__impact, MCP `impact`, or a command # in backticks (`axiomcode impact x`); `path:line: …` is an answer's shape, not the tool MENTION = re.compile(r'`(?:axiomcode )?' + VERB + r'(?:[ \t][^`\n]*)?`|\bmcp__plugin_axiomcode_axiomcode__' + VERB + r'\b' @@ -130,7 +130,7 @@ def controls(tools): got = len(mismatches(documented(text), fake, 'control')) if got != want: bad.append(f"control {text!r}: {got} mismatch(es), want {want}") - if set(tools) != {'impact', 'path', 'tests'}: + if set(tools) != {'context', 'impact', 'link', 'path', 'tests'}: bad.append(f"the server listed {sorted(tools)}; the MCP tools were not read") return bad