Skip to content

Commit 543529f

Browse files
Alb-Oopencodeopencode-agent[bot]
authored
feat: nix support for the nix folks (anomalyco#3924)
Co-authored-by: opencode <[email protected]> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
1 parent a736da0 commit 543529f

14 files changed

Lines changed: 790 additions & 8 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dist
1313
.turbo
1414
**/.serena
1515
.serena/
16+
/result
1617
refs
1718
Session.vim
1819
opencode.json

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ curl -fsSL https://opencode.ai/install | bash
2828
npm i -g opencode-ai@latest # or bun/pnpm/yarn
2929
scoop bucket add extras; scoop install extras/opencode # Windows
3030
choco install opencode # Windows
31-
brew install opencode # macOS and Linux
31+
brew install opencode # macOS and Linux
3232
paru -S opencode-bin # Arch Linux
3333
mise use --pin -g ubi:sst/opencode # Any OS
34+
nix run nixpkgs#opencode # or github:sst/opencode for latest dev branch
3435
```
3536

3637
> [!TIP]

flake.lock

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
{
2+
description = "OpenCode development flake";
3+
4+
inputs = {
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
6+
};
7+
8+
outputs =
9+
{
10+
nixpkgs,
11+
...
12+
}:
13+
let
14+
systems = [
15+
"aarch64-linux"
16+
"x86_64-linux"
17+
"aarch64-darwin"
18+
"x86_64-darwin"
19+
];
20+
lib = nixpkgs.lib;
21+
forEachSystem = lib.genAttrs systems;
22+
pkgsFor = system: nixpkgs.legacyPackages.${system};
23+
packageJson = builtins.fromJSON (builtins.readFile ./packages/opencode/package.json);
24+
bunTarget = {
25+
"aarch64-linux" = "bun-linux-arm64";
26+
"x86_64-linux" = "bun-linux-x64";
27+
"aarch64-darwin" = "bun-darwin-arm64";
28+
"x86_64-darwin" = "bun-darwin-x64";
29+
};
30+
defaultNodeModules = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
31+
hashesFile = "${./nix}/hashes.json";
32+
hashesData =
33+
if builtins.pathExists hashesFile then builtins.fromJSON (builtins.readFile hashesFile) else { };
34+
nodeModulesHash = hashesData.nodeModules or defaultNodeModules;
35+
modelsDev = forEachSystem (
36+
system:
37+
let
38+
pkgs = pkgsFor system;
39+
in
40+
pkgs."models-dev"
41+
);
42+
in
43+
{
44+
devShells = forEachSystem (
45+
system:
46+
let
47+
pkgs = pkgsFor system;
48+
in
49+
{
50+
default = pkgs.mkShell {
51+
packages = with pkgs; [
52+
bun
53+
nodejs_20
54+
pkg-config
55+
openssl
56+
git
57+
];
58+
};
59+
}
60+
);
61+
62+
packages = forEachSystem (
63+
system:
64+
let
65+
pkgs = pkgsFor system;
66+
mkNodeModules = pkgs.callPackage ./nix/node-modules.nix {
67+
hash = nodeModulesHash;
68+
};
69+
mkPackage = pkgs.callPackage ./nix/opencode.nix { };
70+
in
71+
{
72+
default = mkPackage {
73+
version = packageJson.version;
74+
src = ./.;
75+
scripts = ./nix/scripts;
76+
target = bunTarget.${system};
77+
modelsDev = "${modelsDev.${system}}/dist/_api.json";
78+
mkNodeModules = mkNodeModules;
79+
};
80+
}
81+
);
82+
83+
apps = forEachSystem (
84+
system:
85+
let
86+
pkgs = pkgsFor system;
87+
in
88+
{
89+
opencode-dev = {
90+
type = "app";
91+
meta = {
92+
description = "Nix devshell shell for OpenCode";
93+
runtimeInputs = [ pkgs.bun ];
94+
};
95+
program = "${
96+
pkgs.writeShellApplication {
97+
name = "opencode-dev";
98+
text = ''
99+
exec bun run dev "$@"
100+
'';
101+
}
102+
}/bin/opencode-dev";
103+
};
104+
}
105+
);
106+
};
107+
}

nix/hashes.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"nodeModules": "sha256-srbGIRjvpqUF+jWq4GAx7sGAasq02dRySnxTjijJJT8="
3+
}

nix/node-modules.nix

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{ hash, lib, stdenvNoCC, bun, cacert, curl }:
2+
args:
3+
stdenvNoCC.mkDerivation {
4+
pname = "opencode-node_modules";
5+
version = args.version;
6+
src = args.src;
7+
8+
impureEnvVars =
9+
lib.fetchers.proxyImpureEnvVars
10+
++ [
11+
"GIT_PROXY_COMMAND"
12+
"SOCKS_SERVER"
13+
];
14+
15+
nativeBuildInputs = [ bun cacert curl ];
16+
17+
dontConfigure = true;
18+
19+
buildPhase = ''
20+
runHook preBuild
21+
export HOME=$(mktemp -d)
22+
export BUN_INSTALL_CACHE_DIR=$(mktemp -d)
23+
bun install \
24+
--cpu="*" \
25+
--os="*" \
26+
--frozen-lockfile \
27+
--ignore-scripts \
28+
--no-progress \
29+
--linker=isolated
30+
bun --bun ${args.canonicalizeScript}
31+
bun --bun ${args.normalizeBinsScript}
32+
runHook postBuild
33+
'';
34+
35+
installPhase = ''
36+
runHook preInstall
37+
mkdir -p $out
38+
while IFS= read -r dir; do
39+
rel="''${dir#./}"
40+
dest="$out/$rel"
41+
mkdir -p "$(dirname "$dest")"
42+
cp -R "$dir" "$dest"
43+
done < <(find . -type d -name node_modules -prune | sort)
44+
runHook postInstall
45+
'';
46+
47+
dontFixup = true;
48+
49+
outputHashAlgo = "sha256";
50+
outputHashMode = "recursive";
51+
outputHash = hash;
52+
}

nix/opencode.nix

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{ lib, stdenv, stdenvNoCC, bun, fzf, ripgrep, makeBinaryWrapper }:
2+
args:
3+
let
4+
scripts = args.scripts;
5+
mkModules =
6+
attrs:
7+
args.mkNodeModules (
8+
attrs
9+
// {
10+
canonicalizeScript = scripts + "/canonicalize-node-modules.ts";
11+
normalizeBinsScript = scripts + "/normalize-bun-binaries.ts";
12+
}
13+
);
14+
in
15+
stdenvNoCC.mkDerivation (finalAttrs: {
16+
pname = "opencode";
17+
version = args.version;
18+
19+
src = args.src;
20+
21+
node_modules = mkModules {
22+
version = finalAttrs.version;
23+
src = finalAttrs.src;
24+
};
25+
26+
nativeBuildInputs = [
27+
bun
28+
makeBinaryWrapper
29+
];
30+
31+
configurePhase = ''
32+
runHook preConfigure
33+
cp -R ${finalAttrs.node_modules}/. .
34+
runHook postConfigure
35+
'';
36+
37+
env.MODELS_DEV_API_JSON = args.modelsDev;
38+
env.OPENCODE_VERSION = args.version;
39+
env.OPENCODE_CHANNEL = "stable";
40+
41+
buildPhase = ''
42+
runHook preBuild
43+
44+
cp ${scripts + "/bun-build.ts"} bun-build.ts
45+
46+
substituteInPlace bun-build.ts \
47+
--replace '@VERSION@' "${finalAttrs.version}"
48+
49+
export BUN_COMPILE_TARGET=${args.target}
50+
bun --bun bun-build.ts
51+
52+
runHook postBuild
53+
'';
54+
55+
dontStrip = true;
56+
57+
installPhase = ''
58+
runHook preInstall
59+
60+
cd packages/opencode
61+
if [ ! -f opencode ]; then
62+
echo "ERROR: opencode binary not found in $(pwd)"
63+
ls -la
64+
exit 1
65+
fi
66+
if [ ! -f opencode-worker.js ]; then
67+
echo "ERROR: opencode worker bundle not found in $(pwd)"
68+
ls -la
69+
exit 1
70+
fi
71+
72+
install -Dm755 opencode $out/bin/opencode
73+
install -Dm644 opencode-worker.js $out/bin/opencode-worker.js
74+
if [ -f opencode-assets.manifest ]; then
75+
while IFS= read -r asset; do
76+
[ -z "$asset" ] && continue
77+
if [ ! -f "$asset" ]; then
78+
echo "ERROR: referenced asset \"$asset\" missing"
79+
exit 1
80+
fi
81+
install -Dm644 "$asset" "$out/bin/$(basename "$asset")"
82+
done < opencode-assets.manifest
83+
fi
84+
runHook postInstall
85+
'';
86+
87+
postFixup = ''
88+
wrapProgram "$out/bin/opencode" --prefix PATH : ${lib.makeBinPath [ fzf ripgrep ]}
89+
'';
90+
91+
meta = {
92+
description = "AI coding agent built for the terminal";
93+
longDescription = ''
94+
OpenCode is a terminal-based agent that can build anything.
95+
It combines a TypeScript/JavaScript core with a Go-based TUI
96+
to provide an interactive AI coding experience.
97+
'';
98+
homepage = "https://github.com/sst/opencode";
99+
license = lib.licenses.mit;
100+
platforms = [
101+
"aarch64-linux"
102+
"x86_64-linux"
103+
"aarch64-darwin"
104+
"x86_64-darwin"
105+
];
106+
mainProgram = "opencode";
107+
};
108+
})

0 commit comments

Comments
 (0)