summaryrefslogtreecommitdiffhomepage
path: root/nix/opencode.nix
diff options
context:
space:
mode:
authorCaleb Norton <[email protected]>2026-01-18 11:14:13 -0600
committerGitHub <[email protected]>2026-01-18 11:14:13 -0600
commitdac099a4892689d11abedb0fcc1098b50e0958c8 (patch)
treeb47a7a4bae294e0d4222fac21605a380d54b3341 /nix/opencode.nix
parent5009f10406c15c4b69c04fa626756ee7bf81b300 (diff)
downloadopencode-dac099a4892689d11abedb0fcc1098b50e0958c8.tar.gz
opencode-dac099a4892689d11abedb0fcc1098b50e0958c8.zip
feat(nix): overhaul nix flake and packages (#9032)
Diffstat (limited to 'nix/opencode.nix')
-rw-r--r--nix/opencode.nix211
1 files changed, 121 insertions, 90 deletions
diff --git a/nix/opencode.nix b/nix/opencode.nix
index 714aabe09..4d6f8e9b4 100644
--- a/nix/opencode.nix
+++ b/nix/opencode.nix
@@ -2,60 +2,115 @@
lib,
stdenvNoCC,
bun,
- ripgrep,
+ sysctl,
makeBinaryWrapper,
+ models-dev,
+ ripgrep,
+ installShellFiles,
+ versionCheckHook,
+ writableTmpDirAsHomeHook,
+ rev ? "dirty",
}:
-args:
let
- inherit (args) scripts;
- mkModules =
- attrs:
- args.mkNodeModules (
- attrs
- // {
- canonicalizeScript = scripts + "/canonicalize-node-modules.ts";
- normalizeBinsScript = scripts + "/normalize-bun-binaries.ts";
- }
- );
+ packageJson = lib.pipe ../packages/opencode/package.json [
+ builtins.readFile
+ builtins.fromJSON
+ ];
in
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "opencode";
- inherit (args) version src;
+ version = "${packageJson.version}-${rev}";
+
+ src = lib.fileset.toSource {
+ root = ../.;
+ fileset = lib.fileset.intersection (lib.fileset.fromSource (lib.sources.cleanSource ../.)) (
+ lib.fileset.unions [
+ ../packages
+ ../bun.lock
+ ../package.json
+ ../patches
+ ../install
+ ]
+ );
+ };
- node_modules = mkModules {
+ node_modules = stdenvNoCC.mkDerivation {
+ pname = "${finalAttrs.pname}-node_modules";
inherit (finalAttrs) version src;
+
+ impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
+ "GIT_PROXY_COMMAND"
+ "SOCKS_SERVER"
+ ];
+
+ nativeBuildInputs = [
+ bun
+ ];
+
+ dontConfigure = true;
+
+ buildPhase = ''
+ runHook preBuild
+ export HOME=$(mktemp -d)
+ export BUN_INSTALL_CACHE_DIR=$(mktemp -d)
+ bun install \
+ --cpu="${if stdenvNoCC.hostPlatform.isAarch64 then "arm64" else "x64"}" \
+ --os="${if stdenvNoCC.hostPlatform.isLinux then "linux" else "darwin"}" \
+ --frozen-lockfile \
+ --ignore-scripts \
+ --no-progress \
+ --linker=isolated
+ bun --bun ${./scripts/canonicalize-node-modules.ts}
+ bun --bun ${./scripts/normalize-bun-binaries.ts}
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out
+ find . -type d -name node_modules -exec cp -R --parents {} $out \;
+
+ runHook postInstall
+ '';
+
+ dontFixup = true;
+
+ outputHashAlgo = "sha256";
+ outputHashMode = "recursive";
+ outputHash =
+ (lib.pipe ./hashes.json [
+ builtins.readFile
+ builtins.fromJSON
+ ]).nodeModules.${stdenvNoCC.hostPlatform.system};
};
nativeBuildInputs = [
bun
+ installShellFiles
makeBinaryWrapper
+ models-dev
+ writableTmpDirAsHomeHook
];
- env.MODELS_DEV_API_JSON = args.modelsDev;
- env.OPENCODE_VERSION = args.version;
- env.OPENCODE_CHANNEL = "stable";
- dontConfigure = true;
+ configurePhase = ''
+ runHook preConfigure
- buildPhase = ''
- runHook preBuild
+ cp -R ${finalAttrs.node_modules}/. .
- cp -r ${finalAttrs.node_modules}/node_modules .
- cp -r ${finalAttrs.node_modules}/packages .
+ runHook postConfigure
+ '';
- (
- cd packages/opencode
+ env.MODELS_DEV_API_JSON = "${models-dev}/dist/_api.json";
+ env.OPENCODE_VERSION = finalAttrs.version;
+ env.OPENCODE_CHANNEL = "local";
- chmod -R u+w ./node_modules
- mkdir -p ./node_modules/@opencode-ai
- rm -f ./node_modules/@opencode-ai/{script,sdk,plugin}
- ln -s $(pwd)/../../packages/script ./node_modules/@opencode-ai/script
- ln -s $(pwd)/../../packages/sdk/js ./node_modules/@opencode-ai/sdk
- ln -s $(pwd)/../../packages/plugin ./node_modules/@opencode-ai/plugin
+ buildPhase = ''
+ runHook preBuild
- cp ${./bundle.ts} ./bundle.ts
- chmod +x ./bundle.ts
- bun run ./bundle.ts
- )
+ cd ./packages/opencode
+ bun --bun ./script/build.ts --single --skip-install
+ bun --bun ./script/schema.ts schema.json
runHook postBuild
'';
@@ -63,76 +118,52 @@ stdenvNoCC.mkDerivation (finalAttrs: {
installPhase = ''
runHook preInstall
- cd packages/opencode
- if [ ! -d dist ]; then
- echo "ERROR: dist directory missing after bundle step"
- exit 1
- fi
-
- mkdir -p $out/lib/opencode
- cp -r dist $out/lib/opencode/
- chmod -R u+w $out/lib/opencode/dist
-
- # Select bundled worker assets deterministically (sorted find output)
- worker_file=$(find "$out/lib/opencode/dist" -type f \( -path '*/tui/worker.*' -o -name 'worker.*' \) | sort | head -n1)
- parser_worker_file=$(find "$out/lib/opencode/dist" -type f -name 'parser.worker.*' | sort | head -n1)
- if [ -z "$worker_file" ]; then
- echo "ERROR: bundled worker not found"
- exit 1
- fi
-
- main_wasm=$(printf '%s\n' "$out"/lib/opencode/dist/tree-sitter-*.wasm | sort | head -n1)
- wasm_list=$(find "$out/lib/opencode/dist" -maxdepth 1 -name 'tree-sitter-*.wasm' -print)
- for patch_file in "$worker_file" "$parser_worker_file"; do
- [ -z "$patch_file" ] && continue
- [ ! -f "$patch_file" ] && continue
- if [ -n "$wasm_list" ] && grep -q 'tree-sitter' "$patch_file"; then
- # Rewrite wasm references to absolute store paths to avoid runtime resolve failures.
- bun --bun ${scripts + "/patch-wasm.ts"} "$patch_file" "$main_wasm" $wasm_list
- fi
- done
-
- mkdir -p $out/lib/opencode/node_modules
- cp -r ../../node_modules/.bun $out/lib/opencode/node_modules/
- mkdir -p $out/lib/opencode/node_modules/@opentui
-
- mkdir -p $out/bin
- makeWrapper ${bun}/bin/bun $out/bin/opencode \
- --add-flags "run" \
- --add-flags "$out/lib/opencode/dist/src/index.js" \
- --prefix PATH : ${lib.makeBinPath [ ripgrep ]} \
- --argv0 opencode
+ install -Dm755 dist/opencode-*/bin/opencode $out/bin/opencode
+ install -Dm644 schema.json $out/share/opencode/schema.json
+
+ wrapProgram $out/bin/opencode \
+ --prefix PATH : ${
+ lib.makeBinPath (
+ [
+ ripgrep
+ ]
+ # bun runs sysctl to detect if dunning on rosetta2
+ ++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl
+ )
+ }
runHook postInstall
'';
- postInstall = ''
- for pkg in $out/lib/opencode/node_modules/.bun/@opentui+core-* $out/lib/opencode/node_modules/.bun/@opentui+solid-* $out/lib/opencode/node_modules/.bun/@opentui+core@* $out/lib/opencode/node_modules/.bun/@opentui+solid@*; do
- if [ -d "$pkg" ]; then
- pkgName=$(basename "$pkg" | sed 's/@opentui+\([^@]*\)@.*/\1/')
- ln -sf ../.bun/$(basename "$pkg")/node_modules/@opentui/$pkgName \
- $out/lib/opencode/node_modules/@opentui/$pkgName
- fi
- done
+ postInstall = lib.optionalString (stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform) ''
+ # trick yargs into also generating zsh completions
+ installShellCompletion --cmd opencode \
+ --bash <($out/bin/opencode completion) \
+ --zsh <(SHELL=/bin/zsh $out/bin/opencode completion)
'';
- dontFixup = true;
+ nativeInstallCheckInputs = [
+ versionCheckHook
+ writableTmpDirAsHomeHook
+ ];
+ doInstallCheck = true;
+ versionCheckKeepEnvironment = [ "HOME" ];
+ versionCheckProgramArg = "--version";
+
+ passthru = {
+ jsonschema = "${placeholder "out"}/share/opencode/schema.json";
+ };
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/anomalyco/opencode";
+ description = "The open source coding agent";
+ homepage = "https://opencode.ai/";
license = lib.licenses.mit;
+ mainProgram = "opencode";
platforms = [
"aarch64-linux"
"x86_64-linux"
"aarch64-darwin"
"x86_64-darwin"
];
- mainProgram = "opencode";
};
})