From 7ef9b58d477e040094526504f9cee296c20ee969 Mon Sep 17 00:00:00 2001 From: swapnil <78632212+swapnilpaliwal-sd@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:20:24 -0700 Subject: [PATCH] Windows: a path on another drive is outside the repository, not an error relpath raises across drives on Windows, so a --library whose compiled IR sits in the user cache on C: while the repository is on D: (as on GitHub's runner) failed the whole index. axiomcode-index and axiomcode-graph read it as outside the repository, as a `..` path is; a link or a changed file given absolutely on another drive is kept as given. no_exec's control starts Git Bash, not a bare `bash` (WSL on GitHub's image). Co-Authored-By: Claude Opus 5.5 --- plugins/axiomcode/skills/axiomcode/scripts/ax_links.py | 4 +++- .../axiomcode/skills/axiomcode/scripts/axiomcode-changed | 3 ++- .../axiomcode/skills/axiomcode/scripts/axiomcode-graph | 4 +++- .../axiomcode/skills/axiomcode/scripts/axiomcode-index | 8 ++++++-- tests/no_exec.py | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/plugins/axiomcode/skills/axiomcode/scripts/ax_links.py b/plugins/axiomcode/skills/axiomcode/scripts/ax_links.py index b5054a3a8..cbbad69a3 100644 --- a/plugins/axiomcode/skills/axiomcode/scripts/ax_links.py +++ b/plugins/axiomcode/skills/axiomcode/scripts/ax_links.py @@ -1119,7 +1119,9 @@ def site_arg(repo, s): m = re.fullmatch(r'(.+?):(\d+)(?::(\d+))?', s or '') if not m: return None, None, None f = m.group(1) - if os.path.isabs(f): f = os.path.relpath(os.path.realpath(f), repo) + if os.path.isabs(f): + try: f = os.path.relpath(os.path.realpath(f), repo) + except ValueError: pass # another drive (Windows): not in this repository, kept as given f = f[2:] if f.startswith('./') else f return f.replace(os.sep, '/'), int(m.group(2)), (int(m.group(3)) if m.group(3) else None) diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-changed b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-changed index c367928e1..906403914 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-changed +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-changed @@ -413,7 +413,8 @@ class Changed: out.sort(); return out def rel(self, f): f = os.path.realpath(f) if os.path.exists(f) else f - r = os.path.relpath(f, self.repo) if os.path.isabs(f) else f + try: r = os.path.relpath(f, self.repo) if os.path.isabs(f) else f + except ValueError: r = f # another drive (Windows): outside the repository, kept as given return r.replace(os.sep, '/') # ── the two texts of a file ──────────────────────────────────────────────────────────────────────────────── def texts(self, rel, mode, rng): diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-graph b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-graph index 6ad4f2497..59aa8c2e1 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-graph +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-graph @@ -91,7 +91,9 @@ def export(repo, page=None, how=''): def rel(p, src=src): a = p if os.path.isabs(p) else os.path.join(src, p) a = os.path.realpath(a) if os.path.exists(a) else os.path.normpath(a) - r = os.path.relpath(a, repo).replace(os.sep, '/'); return p.lstrip('/') if r.startswith('..') else r + try: r = os.path.relpath(a, repo).replace(os.sep, '/') + except ValueError: r = '..' # another drive (Windows): outside, as axiomcode-index reads it + return p.replace(os.sep, '/').lstrip('/') if r.startswith('..') else r # ── declarations: types and methods, with the display names the query skill uses when the index is there ── owners.update({r['id']: r['owner_type_id'] for r in q("SELECT id, owner_type_id FROM methods WHERE provenance='client'")}) diff --git a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-index b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-index index 9add01cd3..8d260cab6 100755 --- a/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-index +++ b/plugins/axiomcode/skills/axiomcode/scripts/axiomcode-index @@ -54,8 +54,12 @@ def rel(p): if not p: return p a = p if os.path.isabs(p) else os.path.join(SRC, p) a = os.path.realpath(a) if os.path.exists(a) else os.path.normpath(a) - r = os.path.relpath(a, REPO).replace(os.sep, '/') # '/' on every platform: every reader splits on it - return p.lstrip('/') if r.startswith('..') else r + # ON ANOTHER DRIVE (Windows) a path has no form relative to the repository: relpath raised, and a --library whose + # compiled IR sits in the user cache on C: while the repository is on D: failed the whole index. It is outside the + # repository, as a `..` path is, and is kept as written. + try: r = os.path.relpath(a, REPO).replace(os.sep, '/') # '/' on every platform: every reader splits on it + except ValueError: r = '..' + return p.replace(os.sep, '/').lstrip('/') if r.startswith('..') else r # never DEGRADE: an index built from the IR must not be rebuilt without it (the intermediates are routinely cleaned # to save disk). If only newer tables are missing, add them empty and keep everything else. prev = {r[0]: r[1] for r in c.execute("SELECT key, value FROM index_meta")} if c.execute("SELECT 1 FROM sqlite_master WHERE name='index_meta'").fetchone() else {} diff --git a/tests/no_exec.py b/tests/no_exec.py index 6c7e18f6c..e227f3ea6 100644 --- a/tests/no_exec.py +++ b/tests/no_exec.py @@ -79,7 +79,7 @@ def main(): open(os.path.join(site, 'sitecustomize.py'), 'w').write(WINDOWS_EXEC % SCRIPTS) plain = dict(os.environ) win = dict(plain, PYTHONPATH=site + os.pathsep + os.environ.get('PYTHONPATH', '')) - ax = ['bash', os.path.join(SCRIPTS, 'axiomcode')] + ax = [os.environ.get('AXIOMCODE_BASH') or 'bash', os.path.join(SCRIPTS, 'axiomcode')] # Windows: a bare `bash` is WSL's checks = [ # (why, argv, what the answer holds, exit status 0?) ('impact answers', ax + ['impact', 'Rates.rate', repo], 'Quote.total', True), ('impact --json answers', ax + ['impact', 'Rates.rate', repo, '--json'], '"Quote.total', True),