diff --git a/pkgs/by-name/op/opencode/bundle.ts b/pkgs/by-name/op/opencode/bundle.ts new file mode 100644 index 000000000000..768e3e204e21 --- /dev/null +++ b/pkgs/by-name/op/opencode/bundle.ts @@ -0,0 +1,38 @@ +#!/usr/bin/env bun + +import solidPlugin from "./node_modules/@opentui/solid/scripts/solid-plugin" +import fs from "fs" + +const version = process.env.OPENCODE_VERSION! +const channel = process.env.OPENCODE_CHANNEL! + +const result = await Bun.build({ + target: "bun", + outdir: "./dist", + entrypoints: [ + "./src/index.ts", + "./src/cli/cmd/tui/worker.ts" + ], + plugins: [solidPlugin], + naming: { + entry: "[dir]/[name].js" + }, + define: { + OPENCODE_VERSION: JSON.stringify(version), + OPENCODE_CHANNEL: JSON.stringify(channel), + }, + external: [ + "@opentui/core-*", + ], +}) + +if (!result.success) { + console.error("Bundle failed:", result.logs) + process.exit(1) +} + +// Move worker file to worker.ts at the dist root so the code can find it +if (fs.existsSync("./dist/cli/cmd/tui/worker.js")) { + fs.renameSync("./dist/cli/cmd/tui/worker.js", "./dist/worker.ts") + fs.rmdirSync("./dist/cli/cmd/tui", { recursive: true }) +} diff --git a/pkgs/by-name/op/opencode/hashes.json b/pkgs/by-name/op/opencode/hashes.json deleted file mode 100644 index 24ab419ee9bc..000000000000 --- a/pkgs/by-name/op/opencode/hashes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "node_modules": { - "aarch64-linux": "sha256-uqOotHS6p5mLBmh3f7lka9boXBz7trTKuGahGfOSTD4=", - "x86_64-linux": "sha256-qlVlP5ayYTuf/uZIW7lk8wKYxArB0jOHmw94yK9v9Bg=", - "aarch64-darwin": "sha256-dDKVLmE33P9epJFmsUluDjtyVL5jT87atpv8qbEFy7o=", - "x86_64-darwin": "sha256-eBsU9hSf1tRfp8ErZtmM731YVtVRZ8ovQ5nYmokaPD0=" - } -} diff --git a/pkgs/by-name/op/opencode/package.nix b/pkgs/by-name/op/opencode/package.nix index 3f28f7940ca0..6fd34ea50097 100644 --- a/pkgs/by-name/op/opencode/package.nix +++ b/pkgs/by-name/op/opencode/package.nix @@ -11,20 +11,19 @@ testers, writableTmpDirAsHomeHook, }: - -stdenvNoCC.mkDerivation (finalAttrs: { +let pname = "opencode"; - version = "1.0.78"; + version = "1.0.105"; src = fetchFromGitHub { owner = "sst"; repo = "opencode"; - tag = "v${finalAttrs.version}"; - hash = "sha256-o+rNkij9niggHkA+TtexTbrXLK0I9Ol1Cp9NC/wEuAk="; + tag = "v${version}"; + hash = "sha256-mwiEOsJ2prQYzN0gd0+iEfelNt1qv+K7slbF2Rk9eng="; }; node_modules = stdenvNoCC.mkDerivation { - pname = "opencode-node_modules"; - inherit (finalAttrs) version src; + pname = "${pname}-node_modules"; + inherit version src; impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ "GIT_PROXY_COMMAND" @@ -43,24 +42,32 @@ stdenvNoCC.mkDerivation (finalAttrs: { export BUN_INSTALL_CACHE_DIR=$(mktemp -d) - # NOTE: Without `--linker=hoisted` the necessary platform specific packages are not created, i.e. `@parcel/watcher--` and `@opentui/core--` bun install \ + --cpu="*" \ --filter=./packages/opencode \ --force \ --frozen-lockfile \ --ignore-scripts \ - --linker=hoisted \ --no-progress \ + --os="*" \ --production + bun run ./nix/scripts/canonicalize-node-modules.ts + bun run ./nix/scripts/normalize-bun-binaries.ts + runHook postBuild ''; installPhase = '' runHook preInstall - mkdir -p $out/node_modules - cp -R ./node_modules $out + mkdir -p $out + while IFS= read -r dir; do + rel="''${dir#./}" + dest="$out/$rel" + mkdir -p "$(dirname "$dest")" + cp -R "$dir" "$dest" + done < <(find . -type d -name node_modules -prune | sort) runHook postInstall ''; @@ -68,10 +75,18 @@ stdenvNoCC.mkDerivation (finalAttrs: { # NOTE: Required else we get errors that our fixed-output derivation references store paths dontFixup = true; - outputHash = (lib.importJSON ./hashes.json).node_modules.${stdenvNoCC.hostPlatform.system}; + outputHash = "sha256-3N7iWxc5vt81EhyTDWYHMVTZ1KbLz1y4wzSYJt5fQCE="; outputHashAlgo = "sha256"; outputHashMode = "recursive"; }; +in +stdenvNoCC.mkDerivation (finalAttrs: { + inherit + pname + version + src + node_modules + ; nativeBuildInputs = [ bun @@ -80,30 +95,14 @@ stdenvNoCC.mkDerivation (finalAttrs: { ]; patches = [ - # NOTE: Skip npm pack commands in build.ts since packages are already in node_modules - ./skip-npm-pack.patch + # NOTE: Relax Bun version check to be a warning instead of an error + ./relax-bun-version-check.patch ]; - postPatch = '' - # don't require a specifc bun version - substituteInPlace packages/script/src/index.ts \ - --replace-fail "if (process.versions.bun !== expectedBunVersion)" "if (false)" - ''; - configurePhase = '' runHook preConfigure - cd packages/opencode - cp -R ${finalAttrs.node_modules}/. . - - chmod -R u+w ./node_modules - # Make symlinks absolute to avoid issues with bun build - rm ./node_modules/@opencode-ai/script - ln -s $(pwd)/../../packages/script ./node_modules/@opencode-ai/script - rm -f ./node_modules/@opencode-ai/sdk - ln -s $(pwd)/../../packages/sdk/js ./node_modules/@opencode-ai/sdk - rm -f ./node_modules/@opencode-ai/plugin - ln -s $(pwd)/../../packages/plugin ./node_modules/@opencode-ai/plugin + cp -R ${node_modules}/. . runHook postConfigure ''; @@ -112,10 +111,30 @@ stdenvNoCC.mkDerivation (finalAttrs: { env.OPENCODE_VERSION = finalAttrs.version; env.OPENCODE_CHANNEL = "stable"; + preBuild = '' + chmod -R u+w ./packages/opencode/node_modules + pushd ./packages/opencode/node_modules/@parcel/ + for pkg in ../../../../node_modules/.bun/@parcel+watcher-*; do + linkName=$(basename "$pkg" | sed 's/@.*+\(.*\)@.*/\1/') + ln -sf "$pkg/node_modules/@parcel/$linkName" "$linkName" + done + popd + + pushd ./packages/opencode/node_modules/@opentui/ + for pkg in ../../../../node_modules/.bun/@opentui+core-*; do + linkName=$(basename "$pkg" | sed 's/@.*+\(.*\)@.*/\1/') + ln -sf "$pkg/node_modules/@opentui/$linkName" "$linkName" + done + popd + ''; + buildPhase = '' runHook preBuild - bun run ./script/build.ts --single + + cd ./packages/opencode + cp ${./bundle.ts} ./bundle.ts + bun run ./bundle.ts runHook postBuild ''; @@ -125,19 +144,53 @@ stdenvNoCC.mkDerivation (finalAttrs: { installPhase = '' runHook preInstall - install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode + mkdir -p $out/lib/opencode + # Copy the bundled dist directory + cp -r dist $out/lib/opencode/ - runHook postInstall - ''; + # Fix WASM paths in worker.ts - use absolute paths to the installed location + # Main wasm is tree-sitter-.wasm, language wasms are tree-sitter--.wasm + main_wasm=$(find "$out/lib/opencode/dist" -maxdepth 1 -name 'tree-sitter-[a-z0-9]*.wasm' -print -quit) - postInstall = '' - wrapProgram $out/bin/opencode \ + substituteInPlace $out/lib/opencode/dist/worker.ts \ + --replace-fail 'module2.exports = "../../../tree-sitter-' 'module2.exports = "'"$out"'/lib/opencode/dist/tree-sitter-' \ + --replace-fail 'new URL("tree-sitter.wasm", import.meta.url).href' "\"$main_wasm\"" + + # Copy only the native modules we need (marked as external in bundle.ts) + mkdir -p $out/lib/opencode/node_modules/.bun + mkdir -p $out/lib/opencode/node_modules/@opentui + + # Copy @opentui/core platform-specific packages + for pkg in ../../node_modules/.bun/@opentui+core-*; do + if [ -d "$pkg" ]; then + cp -r "$pkg" $out/lib/opencode/node_modules/.bun/$(basename "$pkg") + fi + done + + mkdir -p $out/bin + makeWrapper ${lib.getExe bun} $out/bin/opencode \ + --add-flags "run" \ + --add-flags "$out/lib/opencode/dist/index.js" \ --prefix PATH : ${ lib.makeBinPath [ fzf ripgrep ] - } + } \ + --argv0 opencode + + runHook postInstall + ''; + + postInstall = '' + # Add symlinks for platform-specific native modules + for pkg in $out/lib/opencode/node_modules/.bun/@opentui+core-*; do + if [ -d "$pkg" ]; then + pkgName=$(basename "$pkg" | sed 's/@opentui+\(core-[^@]*\)@.*/\1/') + ln -sf ../.bun/$(basename "$pkg")/node_modules/@opentui/$pkgName \ + $out/lib/opencode/node_modules/@opentui/$pkgName + fi + done ''; passthru = { @@ -163,11 +216,12 @@ stdenvNoCC.mkDerivation (finalAttrs: { ''; homepage = "https://github.com/sst/opencode"; license = lib.licenses.mit; - platforms = lib.platforms.unix; - mainProgram = "opencode"; - badPlatforms = [ - # Problems with bun >= 1.3.2, see https://github.com/oven-sh/bun/issues/24645 - lib.systems.inspect.patterns.isDarwin + platforms = [ + "aarch64-linux" + "x86_64-linux" + "aarch64-darwin" + "x86_64-darwin" ]; + mainProgram = "opencode"; }; }) diff --git a/pkgs/by-name/op/opencode/relax-bun-version-check.patch b/pkgs/by-name/op/opencode/relax-bun-version-check.patch new file mode 100644 index 000000000000..5d14f166a15c --- /dev/null +++ b/pkgs/by-name/op/opencode/relax-bun-version-check.patch @@ -0,0 +1,28 @@ +From 0e07ea8225f5667e39c6aa59eea726266f0afab0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= +Date: Thu, 13 Nov 2025 10:16:31 +0100 +Subject: [PATCH] Change Bun version check from error to warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim +--- + packages/script/src/index.ts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/packages/script/src/index.ts b/packages/script/src/index.ts +index 141d2b75..de06d0dc 100644 +--- a/packages/script/src/index.ts ++++ b/packages/script/src/index.ts +@@ -10,7 +10,7 @@ if (!expectedBunVersion) { + } + + if (process.versions.bun !== expectedBunVersion) { +- throw new Error(`This script requires bun@${expectedBunVersion}, but you are using bun@${process.versions.bun}`) ++ console.warn(`Warning: This script expects bun@${expectedBunVersion}, but you are using bun@${process.versions.bun}`) + } + + const CHANNEL = process.env["OPENCODE_CHANNEL"] ?? (await $`git branch --show-current`.text().then((x) => x.trim())) +-- +2.51.0 diff --git a/pkgs/by-name/op/opencode/skip-npm-pack.patch b/pkgs/by-name/op/opencode/skip-npm-pack.patch deleted file mode 100644 index 7b912be349ae..000000000000 --- a/pkgs/by-name/op/opencode/skip-npm-pack.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git i/packages/opencode/script/build.ts w/packages/opencode/script/build.ts -index 502baed..f854e99 100755 ---- i/packages/opencode/script/build.ts -+++ w/packages/opencode/script/build.ts -@@ -77,14 +77,19 @@ const allTargets: { - ] - - const targets = singleFlag -- ? allTargets.filter((item) => item.os === process.platform && item.arch === process.arch) -+ ? allTargets.filter((item) => -+ item.os === process.platform && -+ item.arch === process.arch && -+ item.avx2 !== false && -+ item.abi === undefined -+ ).slice(0, 1) - : allTargets - - await $`rm -rf dist` - - const binaries: Record = {} --await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}` --await $`bun install --os="*" --cpu="*" @parcel/watcher@${pkg.dependencies["@parcel/watcher"]}` -+// Skip bun install - packages already installed in node_modules by Nix -+// Skip bun install - packages already installed in node_modules by Nix - for (const item of targets) { - const name = [ - pkg.name,