diff --git a/pkgs/by-name/co/codex-acp/hashes.json b/pkgs/by-name/co/codex-acp/hashes.json deleted file mode 100644 index c816627693e9..000000000000 --- a/pkgs/by-name/co/codex-acp/hashes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": "0.9.4", - "hash": "sha256-sVmy7t1+z88WmYuupVmUA3GYA2kkv3nY7Z3Ic99f5UY=", - "cargoHash": "sha256-Ik6pewc6f+cmVKiqVj1g0h7cIxLhE6xOd9p/ySo/EPg=", - "codexRev": "c34b30a3c128bb75fcec27ef838c93c99b92fc61", - "codexSrcHash": "sha256-SnJHiecKNCHhkiMpbsEwpUarpKLpxn1JOHLHy2vgRog=", - "nodeVersionHash": "sha256-q/bOpgF6/0K3MDKXAC+bi1Rb/vCHNhKZpNDbhyYH+oc=" -} diff --git a/pkgs/by-name/co/codex-acp/package.nix b/pkgs/by-name/co/codex-acp/package.nix index 7d2b617c86f9..7345807cca2b 100644 --- a/pkgs/by-name/co/codex-acp/package.nix +++ b/pkgs/by-name/co/codex-acp/package.nix @@ -7,53 +7,56 @@ pkg-config, openssl, libcap, + librusty_v8 ? fetchurl { + name = "librusty_v8-146.4.0"; + url = "https://github.com/denoland/rusty_v8/releases/download/v146.4.0/librusty_v8_release_${stdenv.hostPlatform.rust.rustcTarget}.a.gz"; + hash = + { + x86_64-linux = "sha256-5ktNmeSuKTouhGJEqJuAF4uhA4LBP7WRwfppaPUpEVM="; + aarch64-linux = "sha256-2/FlsHyBvbBUvARrQ9I+afz3vMGkwbW0d2mDpxBi7Ng="; + x86_64-darwin = "sha256-YwzSQPG77NsHFBfcGDh6uBz2fFScHFFaC0/Pnrpke7c="; + aarch64-darwin = "sha256-v+LJvjKlbChUbw+WWCXuaPv2BkBfMQzE4XtEilaM+Yo="; + } + .${stdenv.hostPlatform.system}; + meta = { + version = "146.4.0"; + sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ]; + }; + }, }: let - versionData = builtins.fromJSON (builtins.readFile ./hashes.json); - inherit (versionData) - version - hash - cargoHash - codexRev - codexSrcHash - nodeVersionHash - ; - - # codex-core uses include_str!("../../../../node-version.txt"), so we need - # to place node-version.txt at the vendored workspace root. - nodeVersionFile = fetchurl { - url = "https://raw.githubusercontent.com/zed-industries/codex/${codexRev}/codex-rs/node-version.txt"; - hash = nodeVersionHash; - }; - - # codex-linux-sandbox compiles a patched bubblewrap source tree from - # codex-rs/vendor/bubblewrap. Cargo vendoring flattens workspace layout, - # so this directory must be provided explicitly. + # codex-acp 0.12.0 pins openai/codex rust-v0.124.0 in Cargo.lock. + codexRev = "e9fb49366c93a1478ec71cc41ecee415a197d036"; codexSrc = fetchFromGitHub { - owner = "zed-industries"; + owner = "openai"; repo = "codex"; rev = codexRev; - hash = codexSrcHash; + hash = "sha256-YFnzzwCm9/b30qLDMbkf/rEizuTjeqdCgoBZeS0wNBo="; }; in -rustPlatform.buildRustPackage { +rustPlatform.buildRustPackage (finalAttrs: { pname = "codex-acp"; - inherit version; + version = "0.12.0"; src = fetchFromGitHub { owner = "zed-industries"; repo = "codex-acp"; - rev = "v${version}"; - inherit hash; + tag = "v${finalAttrs.version}"; + hash = "sha256-qPqg95FpXHBtyHBJtrfJUwu9GokfmOJgKgqLKQ48u+8="; }; - inherit cargoHash; + cargoHash = "sha256-/BZ82qiTy/mPwhf5v5CFrNSB6AxCRFdmHB72L0+KjJw="; - preBuild = '' - cp ${nodeVersionFile} "$NIX_BUILD_TOP/codex-acp-${version}-vendor/node-version.txt" + # fetchCargoVendor only keeps the individual git crate subtrees, so restore + # the workspace-root file that codex-core includes via ../../../../node-version.txt. + postPatch = '' + cp ${codexSrc}/codex-rs/node-version.txt "$cargoDepsCopy/source-git-0/node-version.txt" ''; - env = lib.optionalAttrs stdenv.hostPlatform.isLinux { + env = { + RUSTY_V8_ARCHIVE = librusty_v8; + } + // lib.optionalAttrs stdenv.hostPlatform.isLinux { CODEX_BWRAP_SOURCE_DIR = "${codexSrc}/codex-rs/vendor/bubblewrap"; }; @@ -70,16 +73,14 @@ rustPlatform.buildRustPackage { doCheck = false; - passthru.updateScript = ./update.py; - meta = { description = "An ACP-compatible coding agent powered by Codex"; homepage = "https://github.com/zed-industries/codex-acp"; - changelog = "https://github.com/zed-industries/codex-acp/releases/tag/v${version}"; + changelog = "https://github.com/zed-industries/codex-acp/releases/tag/v${finalAttrs.version}"; license = lib.licenses.asl20; maintainers = with lib.maintainers; [ tlvince ]; platforms = lib.platforms.unix; sourceProvenance = with lib.sourceTypes; [ fromSource ]; mainProgram = "codex-acp"; }; -} +}) diff --git a/pkgs/by-name/co/codex-acp/update.py b/pkgs/by-name/co/codex-acp/update.py deleted file mode 100755 index 38ef25c5ab45..000000000000 --- a/pkgs/by-name/co/codex-acp/update.py +++ /dev/null @@ -1,216 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -I nixpkgs=./. -i python3 -p python3 nix cacert - -"""Update script for codex-acp package. - -codex-acp depends on crates from zed-industries/codex via a git dependency. -To keep the Nix expression up to date, we need to: -- update codex-acp source hash, -- extract the pinned codex git revision from Cargo.lock, -- refresh node-version.txt hash for that codex revision, -- refresh codex source hash for vendored bubblewrap on Linux, -- recompute cargoHash. -""" - -from __future__ import annotations - -import json -import os -import re -import subprocess -import tarfile -import tempfile -import urllib.request -from pathlib import Path - -SCRIPT_DIR = Path(__file__).resolve().parent -NIXPKGS_ROOT = SCRIPT_DIR.parents[4] -HASHES_FILE = SCRIPT_DIR / "hashes.json" - -OWNER = "zed-industries" -REPO = "codex-acp" -DUMMY_CARGO_HASH = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" -ANSI_ESCAPE_RE = re.compile(r"\x1b\[[0-9;]*m") - - -def run(cmd: list[str], cwd: Path | None = None) -> str: - result = subprocess.run( - cmd, - cwd=str(cwd) if cwd else None, - check=False, - capture_output=True, - text=True, - ) - if result.returncode != 0: - output = result.stderr.strip() or result.stdout.strip() - msg = f"Command failed ({result.returncode}): {' '.join(cmd)}" - if output: - msg = f"{msg}\n{output}" - raise RuntimeError(msg) - return result.stdout.strip() - - -def github_request(url: str) -> dict: - headers = { - "Accept": "application/vnd.github+json", - } - token = os.environ.get("GITHUB_TOKEN") - if token: - headers["Authorization"] = f"Bearer {token}" - - req = urllib.request.Request(url, headers=headers) - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode("utf-8")) - - -def fetch_latest_release(owner: str, repo: str) -> str: - data = github_request(f"https://api.github.com/repos/{owner}/{repo}/releases/latest") - tag_name = data["tag_name"] - return tag_name[1:] if tag_name.startswith("v") else tag_name - - -def version_key(version: str) -> tuple[int, ...]: - parts = re.findall(r"\d+", version) - return tuple(int(part) for part in parts) - - -def should_update(current: str, latest: str) -> bool: - return version_key(latest) > version_key(current) - - -def load_hashes(path: Path) -> dict[str, str]: - with path.open() as f: - return json.load(f) - - -def save_hashes(path: Path, data: dict[str, str]) -> None: - with path.open("w") as f: - json.dump(data, f, indent=2) - f.write("\n") - - -def prefetch_sri(url: str, *, unpack: bool = False) -> str: - cmd = ["nix-prefetch-url", "--type", "sha256"] - if unpack: - cmd.append("--unpack") - cmd.append(url) - - raw_hash = run(cmd, cwd=NIXPKGS_ROOT) - return run( - [ - "nix", - "--extra-experimental-features", - "nix-command", - "hash", - "to-sri", - "--type", - "sha256", - raw_hash, - ], - cwd=NIXPKGS_ROOT, - ) - - -def extract_codex_rev_from_tarball(tag: str) -> str: - """Extract zed-industries/codex git revision from codex-acp Cargo.lock.""" - url = f"https://github.com/{OWNER}/{REPO}/archive/refs/tags/{tag}.tar.gz" - - with tempfile.TemporaryDirectory() as tmpdir: - tarball_path = Path(tmpdir) / "source.tar.gz" - urllib.request.urlretrieve(url, tarball_path) - - with tarfile.open(tarball_path, "r:gz") as tar: - for member in tar.getmembers(): - if not member.name.endswith("Cargo.lock"): - continue - cargo_lock = tar.extractfile(member) - if cargo_lock is None: - continue - - content = cargo_lock.read().decode("utf-8") - match = re.search(r"zed-industries/codex\?branch=acp#([a-f0-9]+)", content) - if match: - return match.group(1) - - raise RuntimeError("Could not extract codex git revision from Cargo.lock") - - -def calculate_dependency_hash(attr_path: str) -> str: - result = subprocess.run( - ["nix-build", "--no-out-link", "-A", attr_path], - cwd=str(NIXPKGS_ROOT), - check=False, - capture_output=True, - text=True, - ) - output = ANSI_ESCAPE_RE.sub("", f"{result.stdout}\n{result.stderr}") - - match = re.search(r"got:\s*(sha256-[A-Za-z0-9+/=]+)", output) - if match: - return match.group(1) - - if result.returncode == 0: - raise RuntimeError("nix-build unexpectedly succeeded with placeholder cargoHash") - - raise RuntimeError("Failed to parse cargoHash from nix-build output") - - -def main() -> None: - data = load_hashes(HASHES_FILE) - current = data["version"] - latest = fetch_latest_release(OWNER, REPO) - - print(f"Current: {current}, Latest: {latest}") - - if not should_update(current, latest): - print("Already up to date") - return - - tag = f"v{latest}" - print(f"Updating codex-acp to {latest}...") - - source_url = f"https://github.com/{OWNER}/{REPO}/archive/refs/tags/{tag}.tar.gz" - print("Calculating source hash...") - source_hash = prefetch_sri(source_url, unpack=True) - print(f" hash: {source_hash}") - - print("Extracting codex git revision from Cargo.lock...") - codex_rev = extract_codex_rev_from_tarball(tag) - print(f" codexRev: {codex_rev}") - - codex_src_url = f"https://github.com/zed-industries/codex/archive/{codex_rev}.tar.gz" - print("Calculating codex source hash...") - codex_src_hash = prefetch_sri(codex_src_url, unpack=True) - print(f" codexSrcHash: {codex_src_hash}") - - node_version_url = ( - f"https://raw.githubusercontent.com/zed-industries/codex/{codex_rev}/" - "codex-rs/node-version.txt" - ) - print("Calculating node-version.txt hash...") - node_version_hash = prefetch_sri(node_version_url, unpack=False) - print(f" nodeVersionHash: {node_version_hash}") - - data = { - "version": latest, - "hash": source_hash, - "cargoHash": DUMMY_CARGO_HASH, - "codexRev": codex_rev, - "codexSrcHash": codex_src_hash, - "nodeVersionHash": node_version_hash, - } - save_hashes(HASHES_FILE, data) - - print("Calculating cargoHash...") - attr_path = os.environ.get("UPDATE_NIX_ATTR_PATH", "codex-acp") - cargo_hash = calculate_dependency_hash(attr_path) - print(f" cargoHash: {cargo_hash}") - - data["cargoHash"] = cargo_hash - save_hashes(HASHES_FILE, data) - - print(f"Updated to {latest}") - - -if __name__ == "__main__": - main()