diff --git a/overlays/opencode.nix b/overlays/opencode.nix new file mode 100644 index 0000000..cb5c076 --- /dev/null +++ b/overlays/opencode.nix @@ -0,0 +1,3 @@ +final: prev: { + opencode = final.callPackage ./opencode/default.nix { }; +} \ No newline at end of file diff --git a/overlays/opencode/default.nix b/overlays/opencode/default.nix new file mode 100644 index 0000000..7591ffd --- /dev/null +++ b/overlays/opencode/default.nix @@ -0,0 +1,196 @@ +{ + lib, + stdenv, + stdenvNoCC, + buildGoModule, + bun, + fetchFromGitHub, + makeBinaryWrapper, + models-dev, + nix-update-script, + testers, + writableTmpDirAsHomeHook, +}: + +let + opencode-node-modules-hash = { + "aarch64-darwin" = "sha256-LNp9sLhNUUC4ujLYPvfPx423GlXuIS0Z2H512H5oY8s="; + "aarch64-linux" = "sha256-xeKZwNV4ScF9p1vAcVR+vk4BiEpUH+AOGb7DQ2vLl1I="; + "x86_64-darwin" = "sha256-4NaHXeWf57dGVV+KP3mBSIUkbIApT19BuADT0E4X+rg="; + "x86_64-linux" = "sha256-7Hc3FJcg2dA8AvGQlS082fO1ehGBMPXWPF8N+sAHh2I="; + }; + bun-target = { + "aarch64-darwin" = "bun-darwin-arm64"; + "aarch64-linux" = "bun-linux-arm64"; + "x86_64-darwin" = "bun-darwin-x64"; + "x86_64-linux" = "bun-linux-x64"; + }; +in +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "opencode"; + version = "0.4.1"; + src = fetchFromGitHub { + owner = "sst"; + repo = "opencode"; + tag = "v${finalAttrs.version}"; + hash = "sha256-LEFmfsqhCuGcRK7CEPZb6EZfjOHAyYpUHptXu04fjpQ="; + }; + + tui = buildGoModule { + pname = "opencode-tui"; + inherit (finalAttrs) version src; + + modRoot = "packages/tui"; + + vendorHash = "sha256-jGaTgKyAvBMt8Js5JrPFUayhVt3QhgyclFoNatoHac4="; + + subPackages = [ "cmd/opencode" ]; + + env.CGO_ENABLED = 0; + + ldflags = [ + "-s" + "-X=main.Version=${finalAttrs.version}" + ]; + + installPhase = '' + runHook preInstall + + install -Dm755 $GOPATH/bin/opencode $out/bin/tui + + runHook postInstall + ''; + }; + + node_modules = stdenvNoCC.mkDerivation { + pname = "opencode-node_modules"; + inherit (finalAttrs) version src; + + impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ + "GIT_PROXY_COMMAND" + "SOCKS_SERVER" + ]; + + nativeBuildInputs = [ + bun + writableTmpDirAsHomeHook + ]; + + dontConfigure = true; + + buildPhase = '' + runHook preBuild + + export BUN_INSTALL_CACHE_DIR=$(mktemp -d) + + bun install \ + --filter=opencode \ + --force \ + --frozen-lockfile \ + --no-progress + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/node_modules + cp -R ./node_modules $out + + runHook postInstall + ''; + + # Required else we get errors that our fixed-output derivation references store paths + dontFixup = true; + + outputHash = opencode-node-modules-hash.${stdenvNoCC.hostPlatform.system}; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }; + + nativeBuildInputs = [ + bun + makeBinaryWrapper + models-dev + ]; + + patches = [ + # Patch `packages/opencode/src/provider/models-macro.ts` to get contents of + # `_api.json` from the file bundled with `bun build`. + ./local-models-dev.patch + ]; + + configurePhase = '' + runHook preConfigure + + cp -R ${finalAttrs.node_modules}/node_modules . + + runHook postConfigure + ''; + + env.MODELS_DEV_API_JSON = "${models-dev}/dist/_api.json"; + + buildPhase = '' + runHook preBuild + + bun build \ + --define OPENCODE_TUI_PATH="'${finalAttrs.tui}/bin/tui'" \ + --define OPENCODE_VERSION="'${finalAttrs.version}'" \ + --compile \ + --target=${bun-target.${stdenvNoCC.hostPlatform.system}} \ + --outfile=opencode \ + ./packages/opencode/src/index.ts \ + + runHook postBuild + ''; + + dontStrip = true; + + installPhase = '' + runHook preInstall + + install -Dm755 opencode $out/bin/opencode + + runHook postInstall + ''; + + # Add runtime dependencies for libstdc++.so.6 + postFixup = '' + wrapProgram $out/bin/opencode \ + --set LD_LIBRARY_PATH "${lib.makeLibraryPath [ stdenv.cc.cc.lib ]}" + ''; + + passthru = { + tests.version = testers.testVersion { + package = finalAttrs.finalPackage; + command = "HOME=$(mktemp -d) opencode --version"; + inherit (finalAttrs) version; + }; + updateScript = nix-update-script { + extraArgs = [ + "--subpackage" + "tui" + "--subpackage" + "node_modules" + ]; + }; + }; + + meta = { + description = "AI coding agent built for the terminal"; + longDescription = '' + OpenCode is a terminal-based agent that can build anything. + It combines a TypeScript/JavaScript core with a Go-based TUI + to provide an interactive AI coding experience. + ''; + homepage = "https://github.com/sst/opencode"; + license = lib.licenses.mit; + platforms = lib.platforms.unix; + maintainers = with lib.maintainers; [ + zestsystem + delafthi + ]; + mainProgram = "opencode"; + }; +}) diff --git a/overlays/opencode/local-models-dev.patch b/overlays/opencode/local-models-dev.patch new file mode 100644 index 0000000..6c2c18e --- /dev/null +++ b/overlays/opencode/local-models-dev.patch @@ -0,0 +1,20 @@ +diff --git i/packages/opencode/src/provider/models-macro.ts w/packages/opencode/src/provider/models-macro.ts +index 91a0348..4f60069 100644 +--- i/packages/opencode/src/provider/models-macro.ts ++++ w/packages/opencode/src/provider/models-macro.ts +@@ -1,4 +1,15 @@ + export async function data() { ++ const localApiJsonPath = process.env.MODELS_DEV_API_JSON ++ ++ // Try to read from local file if path is provided ++ if (localApiJsonPath) { ++ const localFile = Bun.file(localApiJsonPath) ++ if (await localFile.exists()) { ++ return await localFile.text() ++ } ++ } ++ ++ // Fallback to fetching from remote URL + const json = await fetch("https://models.dev/api.json").then((x) => x.text()) + return json + } diff --git a/profiles/nixos/packages.nix b/profiles/nixos/packages.nix index 8c148ed..0daec7c 100644 --- a/profiles/nixos/packages.nix +++ b/profiles/nixos/packages.nix @@ -1,2 +1,4 @@ {pkgs}: -with pkgs; [] +with pkgs; [ + wl-clipboard +]