Feat/zip installer#1629
Open
fengyca wants to merge 95 commits into
Open
Conversation
added 30 commits
June 29, 2026 12:38
…deps The spec mistakenly used tree-sitter-objc>=0.3,<0.5 in the windows-offline extra, conflicting with the main dependencies pin of >=3.0,<4.0. Aligned the extra to >=3.0,<4.0 so 'uv pip install graphifyy[windows-offline]' can resolve. Plan document updated to match.
Code review follow-ups for path_win: - Drop the unused 'current' parameter from _build_set_command / _build_unset_command (the PS script reads the current PATH itself; the Python-side parameter was dead from day one). - Strengthen test_add_to_user_path_is_idempotent: assert the two PS commands are byte-identical AND contain the '-notcontains' dedup filter. The previous assertion (call_count == 2) was a smoke test that would have stayed green even if the dedup filter were removed. - Use a raw docstring (r"""..""") to silence the DeprecationWarning: invalid escape sequence '\S' from the 'HKLM\SYSTEM' / 'HKCU\Environment' references.
…rmat)
Code review follow-up for skill_copy: KNOWN_HOSTS has 21 entries, but
_BODY_BY_HOST had only 19. cursor and gemini fell through to the
Claude-bundle fallback, which would write a SKILL.md into directories
the host doesn't recognize (.mdc for cursor, GEMINI.md section for
gemini) — silent failure.
Fix: add _UNSUPPORTED_IN_OFFLINE_INSTALLER = {"cursor", "gemini"}.
copy_skill prints a note to stderr and returns without writing or
mkdir-ing, so the user can run 'graphify install cursor' (or gemini)
after the offline installer to register the real config.
Test added: test_copy_skill_skips_cursor_and_gemini.
…rse) argparse on Python 3.10 applies %-formatting to help strings; %LOCALAPPDATA% collapses into 'L' and crashes with 'unsupported format character'. Python 3.11+ no longer does this, so the fix is %% escape (works on both).
added 30 commits
July 3, 2026 09:52
windows-2022 and windows-2025 runners ship Visual Studio Enterprise 2022 (C:\Program Files\Microsoft Visual Studio\2022\Enterprise), not BuildTools, so the hard-coded BuildTools path check failed with 'MSVC 2022 Build Tools not found in expected paths'. Replace the two hard-coded paths with a vswhere.exe lookup filtered by the C++ x86/x64 workload component. This covers Enterprise / Community / BuildTools / Professional uniformly and still fails fast (avoids a 20+ minute Nuitka run that then dies on cl.exe) when no MSVC is present.
`tools/build_windows_installer.sh` used bash process substitution
(`<($PYTHON ...)`) to feed the parsed windows-offline dependency list
into `pip download --requirement`. Under Git Bash on Windows the
substituted path is `/proc/<pid>/fd/NN`, but the Windows Python
interpreter that pip invokes cannot open that path (no /proc
filesystem in MSYS), so the run died with:
ERROR: Could not open requirements file: [Errno 2] No such file or
directory: '/proc/<pid>/fd/NN'
Pipe the dependency list to a real `mktemp` file first and pass that
file to `--requirement`. `trap 'rm -f' EXIT` cleans it up.
Reproduced on the windows-2022 runner used by the
build-windows-installer workflow; fix is local to the build script
and does not affect runtime behaviour.
…eter
`tools/build_windows_installer.sh` hard-coded
`pip download --python-version 3.10` but the offline venv is built
from whatever `$PYTHON` (defaults to `python`) resolves to. On the
current windows-2022 image `python` is 3.12.10, so the wheelhouse
ended up full of cp310 wheels that the cp312 venv's pip refused with
ERROR: Could not find a version that satisfies the requirement
numpy>=1.21 (from graphifyy) (from versions: none)
ERROR: No matching distribution found for numpy>=1.21
because cp312 pip cannot read cp310 wheels under `--no-index
--find-links`.
Detect the interpreter version up front and feed it into both the
wheel download and the wheelhouse cache path
(`wheelhouse-windows-cp312/` vs the old `wheelhouse-windows/`).
Versioning the cache also keeps a stale cp310 tree from poisoning a
later cp312 build.
`tools/build_windows_installer.sh` builds a clean venv from
`--no-index --find-links $WHEELHOUSE`, then runs the three Nuitka
compilations inside it (`python -m nuitka ...`). The wheelhouse is
populated from the `windows-offline` extra plus graphifyy itself, so
it had every runtime wheel — but Nuitka itself lives in the `dev`
group, not in `windows-offline`, and was therefore not pulled into
the wheelhouse. The venv ended up with no Nuitka and the build died
at the first compile with
.venv-offline-build/Scripts/python.exe: No module named nuitka
Append `nuitka>=4.1` to the wheel requirement and list `nuitka`
alongside `graphifyy` in the venv install. Drop `--no-deps` from
`pip download` so ordered-set (Nuitka's runtime transitive) is
fetched into the wheelhouse too — with `--no-deps` the offline venv
would install Nuitka but not ordered-set, and Nuitka's first
`import ordered_set` would No-module-name-ordered-set.
No runtime effect: Nuitka is only used to compile the bundled
`graphify.exe`, `graphify-mcp.exe` and `graphify-installer.exe`.
`pip download --python-version X --platform Y` refuses to follow
transitive dependencies: the only way to let it do so under those
constraints is `--only-binary=:all:`, which is stricter than the
offline-installer build needs. So instead of dropping --no-deps (the
previous attempt), keep --no-deps and list the build-tool deps
explicitly in $WHEEL_REQ:
nuitka>=4.1
ordered-set>=4.1 # nuitka required transitive
zstandard>=0.18 # optional in nuitka; dev group lists it for
# compressed onefile output
Without ordered-set, `python -m nuitka` dies in the offline venv with
No-module-named-ordered-set. Without zstandard, the resulting
graphify*.exe is ~30% larger (Nuitka falls back to an uncompressed
onefile blob).
The venv install line was already updated to include 'nuitka' in the
previous commit, so no further change there.
Reproduced on the windows-2022 runner used by
build-windows-installer.
When the offline venv installs graphifyy from the wheelhouse, pip
transitively pulls matplotlib. matplotlib 3.11's wheel METADATA
declares `Requires-Dist: setuptools`, and pip under
`--no-index --find-links $WHEELHOUSE` does not fall back to the
setuptools already in the venv's site-packages — that venv is built
from the wheelhouse and only, so pip treats the build as fully
offline. Result:
Looking in links: .../wheelhouse-windows-cp312
ERROR: Could not find a version that satisfies the requirement
setuptools>=42 (from versions: none)
ERROR: No matching distribution found for setuptools>=42
`wheel` is added for the same reason — PEP 517 build isolation pulls
it in for some wheels even when we are installing prebuilt ones.
Pin matches the project's own dev group: setuptools>=68 (the
`[build-system]` requires floor) and wheel>=0.40. The lower bound
(>=68 for setuptools) lines up with what `pip wheel .` already
needs on the host side, so the venv and the host agree on the floor.
The previous several commits added setuptools, wheel, ordered-set and zstandard to the wheelhouse one by one, each in response to a new `Could not find a version that satisfies the requirement X (from versions: none)` failure during `pip install --no-index --find-links $WHEELHOUSE`. The pattern is whack-a-mole: any time a wheel in the tree declares a runtime or build-time Requires-Dist, pip under --no-index refuses to consider packages already bootstrapped into the venv's site-packages (packaging, pip itself, etc.) and the build dies. The wheelhouse is a build-time concern only. It is not bundled inside the produced .exe — graphify/installer/ only edits the user PATH and copies SKILL.md to detected host directories, and never re-runs pip install at runtime. So the offline venv does not need to model a fully air-gapped end-user install; it just needs to be a working interpreter for the three `python -m nuitka ...` compiles. Drop --no-index from the venv install. Keep --find-links so the wheelhouse is still the *preferred* source — pip checks it first and only falls through to PyPI / already-installed packages for whatever is missing. Future transitive dep additions (matplotlib asking for setuptools, wheel asking for packaging, anything asking for pep517-style build-isolation helpers, …) no longer break the build. Also drop the now-unused setuptools / wheel explicit entries in the venv install list — pip will still find them via --find-links or PyPI fallback if needed.
The bare `graphifyy` `dependencies` block is the code-only runtime
(networkx, numpy, rapidfuzz, tree-sitter-*). The packages the .exe
actually bundles at runtime — anthropic, mcp, starlette, graspologic,
matplotlib, watchdog, tree-sitter-sql, tree-sitter-hcl, jieba — all
live in optional-dependencies, grouped under the `windows-offline`
extra. The Nuitka invocations below list every one of them via
--include-module=... so they get statically compiled into the .exe,
but Nuitka still imports each module to walk its source, and an
`import anthropic` against a venv where the anthropic wheel was never
installed dies with
FATAL: Error, failed to locate module 'anthropic' that you asked
to include.
Switch the venv install from `graphifyy` to
`graphifyy[windows-offline]`. `--find-links $WHEELHOUSE` still
makes the wheelhouse the preferred source so the previously downloaded
cp312 win_amd64 wheels are picked first; only the `[windows-offline]`
extra listing is consulted, not its platform restriction.
…ocal wheel
A single `pip install --find-links $WHEELHOUSE
'graphifyy[windows-offline]' nuitka` makes pip re-resolve graphifyy
itself; pip then picks the *highest available* version, which on PyPI
is currently 0.9.5. The wheel we just built in $WHEELHOUSE is 0.9.1.
The 0.9.5 release on PyPI does not declare a `windows-offline` extra
in its METADATA, so pip logs
WARNING: graphifyy 0.9.5 does not provide the extra 'windows-offline'
and silently drops every package the extra would have pulled in. The
venv ends up with no anthropic / mcp / starlette / graspologic /
matplotlib / watchdog / tree-sitter-sql / tree-sitter-hcl / jieba, and
the first Nuitka compile then dies with
FATAL: Error, failed to locate module 'anthropic' that you asked
to include.
Split the install into three pip calls so pip never re-resolves
graphifyy from PyPI:
1. Install the local graphifyy wheel by exact file path
($WHEELHOUSE/graphifyy-*.whl, --no-deps). A file path is a hard
pin: pip cannot upgrade to a different version.
2. Install the windows-offline extra's *contents* explicitly, as a
flat list of package names with the same version pins the extra
uses. This avoids consulting graphifyy's METADATA at all.
3. Install Nuitka, --no-deps, against the wheelhouse copy.
When [project.optional-dependencies.windows-offline] is updated in
pyproject.toml, mirror the changes here in the explicit list.
graspologic's `python_version < '3.13'` marker is honoured
implicitly: pip only installs it on the cp312 venv (true) and skips it
on a future cp313 venv (false).
Previous commit split venv install into 3 pip calls but kept
`--no-deps` on the first call (`pip install --no-deps
$WHEELHOUSE/graphifyy-*.whl`). That makes pip install the graphifyy
wheel *without* its main `dependencies` block (networkx, numpy,
rapidfuzz, tree-sitter-*). The second pip call (the explicit
[windows-offline] list) installs only the optional-dependency
packages (anthropic, mcp, starlette, graspologic, tree-sitter-sql,
tree-sitter-hcl, jieba, watchdog, matplotlib), not the main deps.
Result: venv has graphifyy, anthropic, mcp, ... but no networkx /
numpy / rapidfuzz / tree-sitter-*. The first Nuitka compile that
hits a `--include-module=rapidfuzz` then dies with
FATAL: Error, failed to locate module 'rapidfuzz' that you asked
to include.
Drop --no-deps on the graphifyy install. The file-path pin still
prevents pip from upgrading to PyPI's 0.9.5, and pip will resolve
each main dep against the wheelhouse (the [windows-offline] extra
in pyproject.toml lists every main dep, so the wheels are already
on disk). The --no-deps stays on the nuitka install since we never
want pip to follow its transitive deps.
Reproduced on windows-2022 via build-windows-installer.yml
workflow_dispatch.
`--mode=standalone` / `--mode=onefile` on Windows needs Dependency
Walker (depends.exe) so Nuitka can walk the DLL imports of every
.pyd. On the first run on a clean runner Nuitka prompts:
Fully automatic, cached. Proceed and download? [Yes]/No :
In a non-interactive CI environment (default-non-interactive) Nuitka
treats the empty answer as 'no' and aborts with
FATAL: Nuitka does not work in '--mode=standalone' or
'--mode=onefile' on Windows without dependency walker.
Pipe 'Yes' into stdin via `< <(printf 'Yes\\n')` on each of the
three `python -m nuitka` invocations. The download is cached, so
subsequent runs find the binary in the user cache and do not prompt
again.
Reproduced on windows-2022 via build-windows-installer.yml
workflow_dispatch.
…s & project agent config install.bat: - add step 2 pre-cleanup (graphify uninstall claude) for idempotent re-runs - bump step counter from 1/4 to 1/5 - resolve wheel filename via CMD for-loop glob (pip's own glob is fragile on paths with parentheses or other special characters) uninstall.bat: - mirror install.bat Python detection (prefer system, fall back to embedded) - run 'graphify uninstall' (no platform arg) so gf-* and code-pipeline bundled skills are removed alongside the platform SKILL.md - keep installer files in place after uninstall for future re-use __main__.py: - introduce _BundledSkill dataclass and _BUNDLED_SKILLS tuple - new _uninstall_bundled_skills() helper used by _remove_skill_file() Project agent tooling migration: - replace AGENTS.md with CLAUDE.md (richer Claude Code instructions) - add .opencode/ (opencode plugin injecting graph reminder into bash calls) Tests: - update test_agents_platform.py and test_install_references.py to match the new step counts and uninstall behavior
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.