diff --git a/home-modules/dev.nix b/home-modules/dev.nix index c847c7d..12e5d9b 100644 --- a/home-modules/dev.nix +++ b/home-modules/dev.nix @@ -84,7 +84,6 @@ nodejs_24 codex claude-code - oh-my-pi winbox4 amdgpu_top dua diff --git a/overlays/pkgs.nix b/overlays/pkgs.nix index 9b4ccf5..36bfd09 100644 --- a/overlays/pkgs.nix +++ b/overlays/pkgs.nix @@ -3,7 +3,6 @@ [ bun2nix.overlays.default (final: prev: { - oh-my-pi = final.callPackage ../pkgs/oh-my-pi { inherit (final) bun2nix; }; opencode-claude-auth = prev.callPackage ../pkgs/opencode-claude-auth { }; opencode-antigravity-auth = final.callPackage ../pkgs/opencode-antigravity-auth { inherit (final) bun2nix; }; # NetworkManager 1.57.4-dev: adds ipv4.clat (CLAT/464XLAT) needed for IPv6-mostly. diff --git a/pkgs/oh-my-pi/default.nix b/pkgs/oh-my-pi/default.nix deleted file mode 100644 index e40c862..0000000 --- a/pkgs/oh-my-pi/default.nix +++ /dev/null @@ -1,221 +0,0 @@ -{ bun2nix, fetchFromGitHub, fetchurl, fetchzip, runCommand, python3, pkgs, stdenv, ... }: - -# NOTE: This derivation works around two open bun2nix bugs. Remove the -# workarounds and simplify once they are fixed upstream. -# -# Bug 1 — missing .npm manifest cache files -# https://github.com/nix-community/bun2nix/issues/77 -# -# bun's install cache requires two kinds of entries per package: -# - the extracted package directory (e.g. handlebars@4.7.9@@@1/) -# - a hashed .npm manifest file (e.g. 02dd05ab1686ff3a.npm) -# bun2nix only provides the former. bun therefore fetches the manifest from -# the registry during the "Resolving" phase, which fails in the Nix sandbox. -# -# Workaround: pass --offline to bun install. This tells bun to skip manifest -# fetches and trust the lockfile for resolution instead. -# -# Bug 2 — catalog: specifiers still trigger network resolution with --offline -# https://github.com/nix-community/bun2nix/issues/77 (same thread) -# -# bun2nix's bunResolveCatalogRefs rewrites "catalog:" specifiers in -# package.json to the version *range* from the catalog table (e.g. "^1.3.14") -# rather than the exact pinned version from bun.lock's packages section. -# Even with --offline, bun reads the catalog table from bun.lock and tries to -# resolve those ranges, hitting the network. -# -# Workaround: the Python script below pre-processes the source before the -# build. It pins every dep in every workspace package.json to the exact -# version from bun.lock's packages section (so no ranges remain for bun to -# resolve), and strips the catalog/catalogs keys from bun.lock entirely. -# -# bun.lock is JSONC (trailing-comma JSON) so we parse it with Python's stdlib -# json after stripping trailing commas with a regex. -# -# Additionally, oh-my-pi's bun.lock was generated with bun >=1.3.14 which uses -# a different Wyhash seed for cache keys than nixpkgs's bun 1.3.13. Bumping bun -# globally breaks other packages (e.g. opencode), so instead we patch the -# generated wrapper script in postInstall to reference bun 1.3.14 directly. -# Hashes from https://github.com/NixOS/nixpkgs/pull/519796 - -let - version = "15.2.1"; - - # bun 1.3.14 — needed for correct cache key hashes; scoped to this package. - bun_1_3_14 = pkgs.bun.overrideAttrs (_: { - version = "1.3.14"; - src = - let - sources = { - "aarch64-darwin" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-darwin-aarch64.zip"; - hash = "sha256-2LliIYKK1vl6x6wKt+lYcjQa92MAHogD6CZ2UsJlJiA="; - }; - "aarch64-linux" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-aarch64.zip"; - hash = "sha256-on/7Y6gxA3WDbg1vZorhf6jY0YuIw3yCHGUzGXOhmjs="; - }; - "x86_64-darwin" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-darwin-x64-baseline.zip"; - hash = "sha256-PjWtb1OXGpg0v55nhuKt9ytfGSHMmpxf3gc9KXKUQHY="; - }; - "x86_64-linux" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v1.3.14/bun-linux-x64.zip"; - hash = "sha256-lR7iruhV8IWVruxiJSJqKY0/6oOj3NZGXAnLzN9+hI8="; - }; - }; - in - sources.${stdenv.hostPlatform.system} or (throw "bun 1.3.14 not available for ${stdenv.hostPlatform.system}"); - }); - - src = fetchFromGitHub { - owner = "can1357"; - repo = "oh-my-pi"; - rev = "v${version}"; - hash = "sha256-fztQJrhDG5ZbTlgqoHA96eCgwYm5WIna3mAPlCDWYLM="; - }; - - # The workspace source for @oh-my-pi/pi-natives has no pre-built .node - # binaries — those only exist in the npm tarball. Fetch it so we can copy - # the platform binaries into packages/natives/native/ before the build. - piNativesTarball = fetchzip { - url = "https://registry.npmjs.org/@oh-my-pi/pi-natives/-/pi-natives-${version}.tgz"; - hash = "sha256-mEEnvTNxWFVSs1An61K83sSjUJ5bz4yrluwZvz1+6fg="; - stripRoot = false; - }; - - srcWithBunNix = runCommand "oh-my-pi-src" { - nativeBuildInputs = [ bun2nix bun_1_3_14 python3 ]; - } '' - cp -r ${src} $out - chmod -R u+w $out - - # Copy pre-built .node binaries from the npm tarball into the workspace - # source so the runtime can load the native addon without building Rust. - cp ${piNativesTarball}/package/native/*.node $out/packages/natives/native/ - - bun2nix --lock-file $out/bun.lock --output-file $out/bun.nix - - python3 - "$out" << 'EOF' -import sys, re, json, os - -root = sys.argv[1] -lock_path = os.path.join(root, "bun.lock") - -raw = open(lock_path).read() -lock = json.loads(re.sub(r',(\s*[}\]])', r'\1', raw)) - -packages = lock.get("packages", {}) -catalog = lock.get("catalog", {}) -catalogs = lock.get("catalogs", {}) - -# Build name -> exact resolved version from the packages section. -resolved = {} -for name, entry in packages.items(): - if isinstance(entry, list) and entry and isinstance(entry[0], str): - spec = entry[0] - if spec.startswith(name + "@"): - resolved[name] = spec[len(name) + 1:] - -def pin(name, spec): - """Pin a dep specifier to its exact resolved version from bun.lock.""" - if not isinstance(spec, str): - return spec - # catalog: specifiers — resolve via catalog table then pinned version. - if spec.startswith("catalog:"): - cname = spec[len("catalog:"):] - table = catalog if cname == "" else catalogs.get(cname, {}) - rv = resolved.get(name) - cv = table.get(name) - if isinstance(rv, str) and rv.startswith("workspace:"): - return "workspace:*" - if isinstance(rv, str): - return rv - if isinstance(cv, str): - return cv - return spec - # Any npm version range — pin to exact resolved version. - if not spec.startswith(("workspace:", "file:", "link:", "git", "http", "/")): - rv = resolved.get(name) - if isinstance(rv, str) and rv.startswith("workspace:"): - return "workspace:*" - if isinstance(rv, str): - return rv - return spec - -sections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"] - -def rewrite(holder): - for sec in sections: - deps = holder.get(sec) - if isinstance(deps, dict): - for name in list(deps): - deps[name] = pin(name, deps[name]) - -# Rewrite bun.lock workspaces and drop the catalog tables. -for ws in lock.get("workspaces", {}).values(): - rewrite(ws) -lock.pop("catalog", None) -lock.pop("catalogs", None) -open(lock_path, "w").write(json.dumps(lock, indent=2) + "\n") - -# Rewrite each workspace package.json (root "" included). -for ws_dir in lock.get("workspaces", {}): - pkg_path = os.path.join(root, ws_dir, "package.json") - if not os.path.exists(pkg_path): - continue - pkg = json.loads(open(pkg_path).read()) - rewrite(pkg) - open(pkg_path, "w").write(json.dumps(pkg, indent=2) + "\n") -EOF - ''; -in - -(bun2nix.writeBunApplication { - pname = "omp"; - inherit version; - - src = srcWithBunNix; - - # oh-my-pi requires bun >=1.3.14 at runtime. writeBunApplication prepends - # pkgs.bun (1.3.13) to PATH in the startup script, so we use an absolute - # path to bun 1.3.14 instead of relying on PATH resolution. - # - # writeBunApplication's installPhase does `cd $out/share/$pname` before - # exec, so $PWD is always the store path. OLDPWD is set by bash's cd to the - # user's original directory. We cd back so omp's process.cwd() is correct, - # and use an absolute path to the entry point so bun resolves modules from - # the store regardless of cwd. - # At this point the wrapper has already done `cd $out/share/omp`, so $PWD - # is the store package dir and OLDPWD is the user's original directory. - # Capture the store dir, cd back to the user's dir so omp's process.cwd() - # is correct, then exec bun with an absolute path so module resolution - # still works from the store. - startScript = '' - _omp_pkg="$PWD" - cd "''${OLDPWD:-$PWD}" - exec ${bun_1_3_14}/bin/bun run "$_omp_pkg/packages/coding-agent/src/cli.ts" "$@" - ''; - - dontUseBunBuild = true; - dontUseBunCheck = true; - - # --offline: workaround for Bug 1 above (missing .npm manifest cache files). - bunInstallFlags = [ "--offline" "--linker=isolated" "--ignore-scripts" ]; - - # Generate the docs index embedded into the binary at build time. - # The prepack script reads docs/**/*.md and emits docs-index.generated.ts. - postBunNodeModulesInstallPhase = '' - ${bun_1_3_14}/bin/bun run packages/coding-agent/scripts/generate-docs-index.ts - ''; - - bunDeps = bun2nix.fetchBunDeps { - bunNix = "${srcWithBunNix}/bun.nix"; - }; - - meta = { - description = "AI coding agent for the terminal — batteries included"; - homepage = "https://omp.sh"; - mainProgram = "omp"; - }; -})