From 66e2e62f58932b203d9d402bcd2802091f8c3d99 Mon Sep 17 00:00:00 2001 From: Sodawyx Date: Tue, 21 Apr 2026 20:25:41 +0800 Subject: [PATCH 1/3] feat(nuitka): add Nuitka --onefile migration design Switches the CLI binary toolchain from PyInstaller to Nuitka so warm invocations hit the payload-hash cache at ~/.agentrun/cache/ and avoid the ~2s per-call re-extraction, unblocking the agent-hot-path scenario. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 26 ++++++-- .gitignore | 6 +- AGENTS.md | 2 +- Makefile | 20 +++--- README.md | 2 +- README_zh.md | 2 +- agentrun.spec | 89 -------------------------- docs/en/index.md | 8 +++ docs/zh/index.md | 8 +++ pyproject.toml | 6 +- scripts/bench-startup.sh | 49 ++++++++++++++ scripts/build-binary.sh | 116 ++++++++++++++++++++++++++++++++++ 12 files changed, 222 insertions(+), 112 deletions(-) delete mode 100644 agentrun.spec create mode 100755 scripts/bench-startup.sh create mode 100755 scripts/build-binary.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 05d0c73..7921776 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,7 +77,7 @@ jobs: include: # Linux builds use ubuntu-22.04 (glibc 2.35) rather than a manylinux # container: manylinux ships a static CPython without libpython*.so, - # which PyInstaller cannot embed. The glibc-2.35 floor still covers + # which Nuitka cannot embed. The glibc-2.35 floor still covers # Ubuntu 22.04+, Debian 12+, RHEL 9+, and all current modern distros. - target: linux-amd64 runner: ubuntu-22.04 @@ -111,23 +111,39 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} - - name: Install project + PyInstaller + - name: Install Nuitka build toolchain (Linux) + if: startsWith(matrix.target, 'linux-') + shell: bash + run: | + sudo apt-get update -qq + sudo apt-get install -y -qq patchelf ccache + + - name: Install project + Nuitka shell: bash run: | python -m pip install --upgrade pip python -m pip install -e . - python -m pip install pyinstaller + python -m pip install "nuitka>=2.4" "zstandard>=0.22" - name: Build binary shell: bash run: | - pyinstaller --clean --noconfirm agentrun.spec + bash scripts/build-binary.sh ls -lh dist/ - name: Smoke test binary shell: bash run: | - ./dist/agentrun${{ matrix.ext }} --version + BIN="./dist/agentrun${{ matrix.ext }}" + "$BIN" --version + "$BIN" --help >/dev/null + "$BIN" config --help >/dev/null + "$BIN" model --help >/dev/null + "$BIN" sandbox --help >/dev/null + "$BIN" skill --help >/dev/null + "$BIN" super-agent --help >/dev/null + "$BIN" tool --help >/dev/null + echo "All 8 subcommand invocations OK on ${{ matrix.target }}" # --- Package (Unix) ----------------------------------------------- - name: Package tar.gz (Unix) diff --git a/.gitignore b/.gitignore index b0eb629..87497df 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,11 @@ venv/ .idea/ .vscode/ *.spec -!agentrun.spec +# Nuitka build artifacts +*.dist/ +*.build/ +*.bin +*.onefile-build/ .coverage coverage.json htmlcov/ diff --git a/AGENTS.md b/AGENTS.md index 061bf6d..4f4a4f6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,7 +20,7 @@ make test # Run all tests .venv/bin/pytest tests/test_cli_basic.py::TestConfigCommands::test_set_and_get -v # Single test # Build standalone binary -make build # PyInstaller binary → dist/ar +make build # Nuitka --onefile binary → dist/agentrun (warm-start cache: ~/.agentrun/cache/) make build-all # macOS + Linux (via Docker) ``` diff --git a/Makefile b/Makefile index e53dd98..fce03d9 100644 --- a/Makefile +++ b/Makefile @@ -5,9 +5,7 @@ VENV := .venv BIN := $(VENV)/bin PIP := $(BIN)/pip PIP_MIRROR := -i https://mirrors.aliyun.com/pypi/simple/ -PYINST := $(BIN)/pyinstaller APP_NAME := agentrun -SPEC := agentrun.spec VERSION := $(shell $(PYTHON) -c "from src.agentrun_cli import __version__; print(__version__)" 2>/dev/null || echo "0.1.0") help: ## Show this help message @@ -21,7 +19,6 @@ install: ## Install the package in editable mode dev: ## Install with dev dependencies $(PYTHON) -m venv $(VENV) $(PIP) install $(PIP_MIRROR) -e ".[dev]" || $(PIP) install $(PIP_MIRROR) -e . - $(PIP) install $(PIP_MIRROR) pyinstaller lint: ## Run ruff linter $(BIN)/ruff check src/ tests/ @@ -45,9 +42,8 @@ clean: ## Remove build artifacts rm -rf build/ dist/ *.spec __pycache__ find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true -build: ## Build binary for the current platform (uses agentrun.spec) - DISABLE_BREAKING_CHANGES_WARNING=1 \ - $(PYINST) --clean --noconfirm $(SPEC) +build: ## Build single-file binary for the current platform (uses Nuitka) + bash scripts/build-binary.sh @echo "" @echo "Binary built: dist/$(APP_NAME)" @ls -lh dist/$(APP_NAME) @@ -55,8 +51,9 @@ build: ## Build binary for the current platform (uses agentrun.spec) build-macos: build ## Alias for build (on macOS, just run 'make build') @echo "macOS binary ready at dist/$(APP_NAME)" -# Cross-compiling Python to Linux is not supported by PyInstaller. -# Use this target inside a Linux environment (Docker / CI). +# Nuitka compiles Python to native C, so cross-compiling is not supported. +# Use this target inside a Linux environment (Docker / CI) to produce a +# Linux binary when you're on a non-Linux host. build-linux: build ## Build Linux binary (run inside Linux or Docker) @echo "Linux binary ready at dist/$(APP_NAME)" @@ -69,10 +66,9 @@ build-all: ## Build for all platforms (macOS local + Linux via Docker) tar cf - --exclude=.venv --exclude=.git --exclude=build --exclude=dist --exclude=__pycache__ --exclude='*.pyc' . | \ docker run --rm -i -v $(PWD)/dist:/out python:3.10-slim sh -c \ "mkdir /build && cd /build && tar xf - && \ - apt-get update -qq && apt-get install -y -qq binutils >/dev/null 2>&1 && \ - pip install $(PIP_MIRROR) -e . && pip install $(PIP_MIRROR) pyinstaller && \ - DISABLE_BREAKING_CHANGES_WARNING=1 \ - pyinstaller --clean --noconfirm $(SPEC) && \ + apt-get update -qq && apt-get install -y -qq binutils patchelf ccache gcc >/dev/null 2>&1 && \ + pip install $(PIP_MIRROR) -e . && pip install $(PIP_MIRROR) nuitka zstandard && \ + bash scripts/build-binary.sh && \ cp dist/$(APP_NAME) /out/$(APP_NAME)" @mkdir -p dist/linux && cp dist/$(APP_NAME) dist/linux/$(APP_NAME) @echo "" diff --git a/README.md b/README.md index 15f902d..3e2a5c0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ agents that you configure declaratively without writing or deploying any runtime - **Multiple output formats** — `json` (default), `table`, `yaml`, and `quiet` for shell piping. - **Agent-friendly** — JSON-by-default output, deterministic exit codes, no interactive prompts when stdin isn't a TTY. - **Rich sandbox primitives** — code execution, file system, process management, and CDP/VNC-backed browser automation. -- **Single-file distribution** — PyInstaller produces standalone `ar` / `agentrun` binaries for Linux, macOS and Windows (x86_64 + arm64). +- **Single-file distribution** — Nuitka `--onefile` produces standalone `ar` / `agentrun` binaries for Linux, macOS and Windows (x86_64 + arm64) with warm-start caching under `~/.agentrun/cache/`. ## Installation diff --git a/README_zh.md b/README_zh.md index caf12c3..addc97f 100644 --- a/README_zh.md +++ b/README_zh.md @@ -17,7 +17,7 @@ Agent)**:一种由平台托管、用户只需声明配置、无需编写或 - **多种输出格式** — 默认 `json`,支持 `table` / `yaml` / `quiet`(适合 shell 管道)。 - **对 Agent 友好** — 默认 JSON 输出、确定性退出码、非 TTY 下不弹交互提示。 - **完整沙箱能力** — 代码执行、文件系统、进程管理、CDP/VNC 浏览器自动化。 -- **单文件分发** — PyInstaller 产出 Linux / macOS / Windows(x86_64 + arm64)上的独立 `ar` / `agentrun` 二进制。 +- **单文件分发** — 基于 Nuitka `--onefile` 产出 Linux / macOS / Windows(x86_64 + arm64)上的独立 `ar` / `agentrun` 二进制,热启动复用 `~/.agentrun/cache/` 缓存。 ## 安装 diff --git a/agentrun.spec b/agentrun.spec deleted file mode 100644 index f4cd6f0..0000000 --- a/agentrun.spec +++ /dev/null @@ -1,89 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- -# -# PyInstaller spec — single source of truth for binary builds. -# Used by `make build` locally and by `.github/workflows/release.yml` in CI. -# Keep the EXCLUDES list in sync with the CLI's actual runtime needs. - -from PyInstaller.utils.hooks import collect_data_files - -# Everything the CLI does NOT need at runtime but gets pulled in transitively -# via agentrun-inner-test[core]. Excluding these keeps the binary small. -EXCLUDES = [ - 'litellm', - 'tablestore', - 'agentrun_mem0ai', - 'agentrun_mem0', - 'alibabacloud_bailian20231229', - 'alibabacloud_gpdb20160503', - 'tiktoken', - 'tokenizers', - 'numpy', - 'grpcio', - 'torch', - 'tensorflow', - 'transformers', - 'PIL', - 'matplotlib', - 'scipy', - 'sklearn', - 'pandas', - 'pytz', - 'pygments', - 'sqlalchemy', - 'Crypto', - 'pycryptodome', - 'rich', - 'markdown_it', - 'mysql', - 'MySQLdb', - 'oss2', - 'posthog', - 'jinja2', - 'qdrant_client', - 'huggingface_hub', - 'hf_xet', - 'fsspec', - 'h2', - 'regex', - 'future', - 'google', -] - -datas = [] -datas += collect_data_files('certifi') - -a = Analysis( - ['src/agentrun_cli/main.py'], - pathex=[], - binaries=[], - datas=datas, - hiddenimports=[], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=EXCLUDES, - noarchive=False, - optimize=0, -) -pyz = PYZ(a.pure) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - a.datas, - [], - name='agentrun', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=False, - upx_exclude=[], - runtime_tmpdir=None, - console=True, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, -) diff --git a/docs/en/index.md b/docs/en/index.md index 5eab1b1..8d56275 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -69,6 +69,14 @@ make build # local binary → dist/agentrun After installation, both `ar` and `agentrun` are available as entry points and behave identically. `ar` is shorter; the examples in this manual use it. +### Binary startup cache + +The prebuilt binary is a Nuitka `--onefile` executable. On first launch it extracts its payload into `~/.agentrun/cache/agentrun-/` (about 20 MB); subsequent launches reuse the cache, bringing warm start-up below 300 ms. + +- **Safe to delete.** Remove `~/.agentrun/cache/` at any time; the next invocation re-extracts. +- **Upgrades.** A new binary version writes to a new subdirectory; old ones stay until you clean them up. +- **Read-only `$HOME`.** If `~/.agentrun/cache/` is not writable, the bootstrap falls back to `$TMPDIR` with full re-extraction on every run (~2 s). Either grant write access or run from a shell where `$HOME` points somewhere writable. + ## Authentication The CLI resolves credentials from three sources, in this order: diff --git a/docs/zh/index.md b/docs/zh/index.md index 0d381c4..2cddf33 100644 --- a/docs/zh/index.md +++ b/docs/zh/index.md @@ -68,6 +68,14 @@ make build # 本地打独立二进制 → dist/agentrun 安装完成后 `ar` 和 `agentrun` 都是入口点,行为完全一致。`ar` 更短,文档里的示例 默认用 `ar`。 +### 二进制启动缓存 + +预编译二进制是一个 Nuitka `--onefile` 可执行文件。首次运行会把内置 payload 解压到 `~/.agentrun/cache/agentrun-/`(约 20 MB),之后每次启动复用缓存,热启动耗时低于 300 ms。 + +- **可以随时删除。**`~/.agentrun/cache/` 删掉后下一次运行自动重建。 +- **升级行为。**新版本二进制会写入新的子目录,老目录保留直到手动清理。 +- **`$HOME` 只读的情况。**若 `~/.agentrun/cache/` 不可写,bootstrap 会回落到 `$TMPDIR` 且每次都完整解压(~2 秒)。请确保目录可写,或从 `$HOME` 指向可写位置的 shell 启动。 + ## 认证 CLI 按以下顺序解析凭证(上面优先): diff --git a/pyproject.toml b/pyproject.toml index 980a259..09079cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,8 @@ Issues = "https://github.com/Serverless-Devs/agentrun-cli/issues" dev = [ "pytest>=8.0.0", "pytest-cov>=6.0.0", "pytest-asyncio>=1.2.0", - "pyinstaller>=6.0.0", + "nuitka>=2.4", + "zstandard>=0.22", "ruff>=0.14.0", "mypy>=1.11.0", "types-PyYAML>=6.0", @@ -48,7 +49,8 @@ dev = [ dev = [ "pytest>=8.0.0", "pytest-cov>=6.0.0", "pytest-asyncio>=1.2.0", - "pyinstaller>=6.0.0", + "nuitka>=2.4", + "zstandard>=0.22", "ruff>=0.14.0", "mypy>=1.11.0", "types-PyYAML>=6.0", diff --git a/scripts/bench-startup.sh b/scripts/bench-startup.sh new file mode 100755 index 0000000..353072b --- /dev/null +++ b/scripts/bench-startup.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Measure agentrun binary cold-start + warm-start times. +# +# Usage: bash scripts/bench-startup.sh [binary-path] +# Default binary: ./dist/agentrun +# +# Prints per-run `real` time and the median of runs 2..10 (warm runs). + +set -euo pipefail + +BINARY="${1:-./dist/agentrun}" +if [ ! -x "$BINARY" ]; then + echo "Binary not found or not executable: $BINARY" >&2 + exit 2 +fi + +echo "=== Benchmark: $BINARY --help ===" +echo "(run 1 = cold; runs 2..10 = warm)" +echo "" + +# Portable high-resolution timer. macOS BSD `date` lacks %N, so use python3 +# (required anyway as a build dep). Returns seconds as a float. +now() { python3 -c 'import time; print(time.perf_counter())'; } + +TIMES=() +for i in $(seq 1 10); do + START=$(now) + "$BINARY" --help >/dev/null + END=$(now) + ELAPSED=$(awk "BEGIN{print $END - $START}") + TIMES+=("$ELAPSED") + printf "Run %2d: %.3f s\n" "$i" "$ELAPSED" +done + +# Stats over runs 2..10 (warm). Report min as well as median: on dev +# machines with on-access AV scanners attached to unsigned binaries the +# scanner adds ~10s to some runs, polluting the median. `min` reflects +# Nuitka's true warm-start cost when the scan is cached; `median` is the +# authoritative figure on clean environments (Linux CI, signed releases). +WARM=("${TIMES[@]:1}") +SORTED=$(printf '%s\n' "${WARM[@]}" | sort -n) +N=$(echo "$SORTED" | wc -l | tr -d ' ') +MID=$(( (N + 1) / 2 )) +MIN=$(echo "$SORTED" | sed -n '1p') +MEDIAN=$(echo "$SORTED" | sed -n "${MID}p") + +echo "" +printf "Warm min (runs 2..10): %.3f s\n" "$MIN" +printf "Warm median (runs 2..10): %.3f s\n" "$MEDIAN" diff --git a/scripts/build-binary.sh b/scripts/build-binary.sh new file mode 100755 index 0000000..88bc894 --- /dev/null +++ b/scripts/build-binary.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +# Build the agentrun CLI as a single-file binary using Nuitka --onefile. +# +# Called by `make build` and by .github/workflows/release.yml. +# Output: ./dist/agentrun (or ./dist/agentrun.exe on Windows). +# +# Exit codes: 0 success, non-zero = Nuitka failure (propagates). + +set -euo pipefail + +# ----- Config ----------------------------------------------------------- +# EXCLUDES: 1:1 port of the old agentrun.spec EXCLUDES list. +# Any transitive dep of agentrun-sdk[core] that the CLI does NOT use at +# runtime goes here. Keep sorted for review clarity. +EXCLUDES="\ +agentrun_mem0,\ +agentrun_mem0ai,\ +alibabacloud_bailian20231229,\ +alibabacloud_gpdb20160503,\ +Crypto,\ +fsspec,\ +future,\ +google,\ +grpcio,\ +h2,\ +hf_xet,\ +huggingface_hub,\ +jinja2,\ +litellm,\ +markdown_it,\ +matplotlib,\ +MySQLdb,\ +mysql,\ +numpy,\ +oss2,\ +pandas,\ +PIL,\ +posthog,\ +pycryptodome,\ +pygments,\ +pytz,\ +qdrant_client,\ +regex,\ +rich,\ +sklearn,\ +scipy,\ +sqlalchemy,\ +tablestore,\ +tensorflow,\ +tiktoken,\ +tokenizers,\ +torch,\ +transformers" + +# Version: read from setuptools-scm generated file if present, else fall +# back to git describe, else "0.0.0+unknown". +VERSION=$(python3 -c "from src.agentrun_cli import __version__; print(__version__)" 2>/dev/null \ + || git describe --tags --always --dirty 2>/dev/null \ + || echo "0.0.0+unknown") + +# Nuitka's --product-version requires a strict N(.N)* form with all numeric +# components. Derive a sanitized variant by stripping PEP 440 pre-release / +# dev / local suffixes and padding to 3 components, so +# "0.1.0rc5.dev2+g1713d9f79.d20260421" normalizes to "0.1.0" and +# "0.3.0rc1" also normalizes to "0.3.0" (stable cache-dir naming). +PRODUCT_VERSION=$(python3 -c " +import re, sys +v = sys.argv[1] +# Drop local segment (anything after '+') and any non-numeric trailing +# components (rc, dev, a, b, post, ...). +v = v.split('+', 1)[0] +parts = v.split('.') +out = [] +for p in parts: + if re.fullmatch(r'[0-9]+', p): + out.append(p) + else: + break +# Pad to 3 numeric components so '0.3.0', '0.3.0rc1', and '0.3.0.dev2' +# all normalize to '0.3.0' (stable cache-dir naming under ~/.agentrun/cache/). +out = (out + ['0', '0', '0'])[:3] +print('.'.join(out)) +" "$VERSION") + +# Cache directory (per design doc, co-located with ~/.agentrun/config.json). +# Nuitka expands {HOME} and {VERSION} at bootstrap time. Each binary +# version gets its own subdirectory so upgrades don't collide. +TEMPDIR_SPEC='{HOME}/.agentrun/cache/agentrun-{VERSION}' + +# Output filename differs on Windows (.exe suffix handled by Nuitka). +mkdir -p dist + +# ----- Build ------------------------------------------------------------ +echo "=== Building agentrun (version: $VERSION) with Nuitka --onefile ===" +python3 -m nuitka \ + --onefile \ + --standalone \ + --assume-yes-for-downloads \ + --output-filename=agentrun \ + --output-dir=dist \ + --include-package=agentrun_cli \ + --include-package-data=certifi \ + --onefile-tempdir-spec="$TEMPDIR_SPEC" \ + --product-name=agentrun \ + --product-version="$PRODUCT_VERSION" \ + --python-flag=-O \ + --nofollow-import-to="$EXCLUDES" \ + --remove-output \ + src/agentrun_cli/main.py + +# ----- Post-build report ------------------------------------------------ +BINARY="dist/agentrun" +[ -f "${BINARY}.exe" ] && BINARY="${BINARY}.exe" +echo "" +echo "=== Build complete ===" +ls -lh "$BINARY" From 196207e93dbc3d353e630d856f7574d18af8189d Mon Sep 17 00:00:00 2001 From: Sodawyx Date: Wed, 22 Apr 2026 14:13:36 +0800 Subject: [PATCH 2/3] perf(release): cache ccache and disable LTO to speed up Nuitka builds Nuitka --onefile compiles all Python to C on every run, which on cold CI runners routinely takes 15+ minutes in the Scons stage. Two mitigations: - Persist ~/.cache/ccache across workflow runs via actions/cache, keyed on target + Python version + hash of pyproject.toml and build-binary.sh so a Nuitka pin bump or flag change buckets into a fresh cache. ccache is content-addressed, so changing Python source invalidates only the .o files whose generated C actually changed. Windows is skipped because MSVC does not integrate with ccache. macOS gains a brew install step. - Pass --lto=no to Nuitka. LTO roughly doubles link time on gcc 11 and the runtime win is not worth paying on every tag push. Also drops the redundant --standalone flag (--onefile implies it) and prints ccache stats after each build for visibility into hit rate. Signed-off-by: Sodawyx --- .github/workflows/release.yml | 35 +++++++++++++++++++++++++++++++++++ scripts/build-binary.sh | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7921776..10a3715 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -118,6 +118,36 @@ jobs: sudo apt-get update -qq sudo apt-get install -y -qq patchelf ccache + - name: Install ccache (macOS) + if: startsWith(matrix.target, 'darwin-') + shell: bash + run: brew install ccache + + # Persist ccache across runs. Key hashes pyproject.toml + build-binary.sh + # so a Nuitka pin bump or a build-script flag change buckets the cache + # into a fresh partition. ccache itself is content-addressed, so stale + # .o reuse is not a concern: if the generated C changes, it misses. + # Skipped on Windows because Nuitka uses MSVC there and ccache does not + # integrate with cl.exe. + - name: Restore ccache + if: ${{ !startsWith(matrix.target, 'windows-') }} + uses: actions/cache@v4 + with: + path: | + ~/.cache/ccache + ~/Library/Caches/ccache + key: ccache-${{ matrix.target }}-py${{ env.PYTHON_VERSION }}-${{ hashFiles('pyproject.toml', 'scripts/build-binary.sh') }} + restore-keys: | + ccache-${{ matrix.target }}-py${{ env.PYTHON_VERSION }}- + ccache-${{ matrix.target }}- + + - name: Configure ccache + if: ${{ !startsWith(matrix.target, 'windows-') }} + shell: bash + run: | + ccache --max-size=2G + ccache --zero-stats + - name: Install project + Nuitka shell: bash run: | @@ -131,6 +161,11 @@ jobs: bash scripts/build-binary.sh ls -lh dist/ + - name: Print ccache stats + if: ${{ !startsWith(matrix.target, 'windows-') }} + shell: bash + run: ccache --show-stats + - name: Smoke test binary shell: bash run: | diff --git a/scripts/build-binary.sh b/scripts/build-binary.sh index 88bc894..63abc7e 100755 --- a/scripts/build-binary.sh +++ b/scripts/build-binary.sh @@ -94,7 +94,6 @@ mkdir -p dist echo "=== Building agentrun (version: $VERSION) with Nuitka --onefile ===" python3 -m nuitka \ --onefile \ - --standalone \ --assume-yes-for-downloads \ --output-filename=agentrun \ --output-dir=dist \ @@ -104,6 +103,7 @@ python3 -m nuitka \ --product-name=agentrun \ --product-version="$PRODUCT_VERSION" \ --python-flag=-O \ + --lto=no \ --nofollow-import-to="$EXCLUDES" \ --remove-output \ src/agentrun_cli/main.py From 346a2e8d4a0dc13dcba1c05c6b53bfe7021673f4 Mon Sep 17 00:00:00 2001 From: Sodawyx Date: Wed, 22 Apr 2026 16:44:45 +0800 Subject: [PATCH 3/3] build(workflow): Temporarily disable Windows build in release workflow This change comments out the Windows AMD64 build configuration due to long compilation times caused by MSVC not being able to use ccache. The build would take over 30 minutes per run on standard GitHub runners. It will be re-enabled once switched to sccache or MinGW-w64. Co-developed-by: Aone Copilot Signed-off-by: Sodawyx --- .github/workflows/release.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10a3715..81d2885 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -95,10 +95,13 @@ jobs: runner: macos-latest ext: '' archive: tar.gz - - target: windows-amd64 - runner: windows-latest - ext: '.exe' - archive: zip + # Windows build temporarily disabled: MSVC path can't use ccache, + # so every run is a cold compile and takes >30 min on the default + # GitHub runner. Re-enable after switching to sccache or MinGW-w64. + # - target: windows-amd64 + # runner: windows-latest + # ext: '.exe' + # archive: zip steps: - uses: actions/checkout@v4