Skip to content

fix(nix): repair three packaging defects on the v2 branch - #51891

Merged
rekram1-node merged 9 commits into
anomalyco:v2from
jerome-benoit:fix-nix-v2-packaging
Oct 2, 2026
Merged

rekram1-node merged 9 commits into
anomalyco:v2from
jerome-benoit:fix-nix-v2-packaging

Conversation

@jerome-benoit

@jerome-benoit jerome-benoit commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Issue for this PR

Closes #50408

Type of change

  • Bug fix

What does this PR do?

Three independent build breaks in the v2 nix packaging.

  1. nix/opencode.nix ran opencode completion, a subcommand v2 removed: the Effect CLI parses completion as the optional directory argument, exits 1 with empty stdout (ENOENT … chdir '<cwd>' -> 'completion'). Completions now come from the global --completions <shell> flag. This also installs fish completions for the first time — v2 only wired up bash and zsh.
  2. nix/electron.nix carried electron 42.10.1's release hashes while the desktop pins 44.4.5, so fetchurl could not resolve them. It now takes nixpkgs' prebuilt electron for the pinned major.
  3. nix/desktop.nix staged the CLI executable but not the npm manifest that copyCliToResources reads the version from, so the prebuild aborted. The manifest is now written next to the binary, through JSON.stringify, from OPENCODE_VERSION — the same variable the bundled binary prints for --version, so the two cannot drift.

opencode2 is a symlink to opencode and its name is a build-time define, so the alias files are the generated ones renamed with substitute --replace-fail rather than regenerated.

Trade-off in 2: a hash has to live somewhere, so this relocates electron's release hash into nixpkgs rather than removing it. The cost is the exact version: at this lock electron_44-bin is 44.3.0 against the 44.4.5 pin. That is a minor gap — same Chromium 152.0.7977.* branch, same Node 24, same process.versions.modules 149, and the bundle ships one native addon, node-pty's Node-API prebuild, which only the win32 WSL runtime loads — and both values are declared on the package as passthru.electronVersion and passthru.electronPin, while the build prints resolved-versus-pinned once. A major nixpkgs does not carry fails evaluation with that advice instead of a hash mismatch; a new major needs nix flake update.

This reuses the approach of #51406 (closed unmerged); #50409 and #50622 stay open and are not closed here.

How did you verify your code works?

x86_64-linux at c977050030. Both builds overrode nix/node_modules.nix's hash with sha256-gvpzGXJG5vQKLCUarV2aSwOg8hvU4Sy3PlJF89XDQkU=, as recorded by the consumed opencode-node_modules, because nix/hashes.json on v2 is stale (committed: sha256-7DgxTpKv6ITKTom0mhlJNPQfdEjtEHK5P8uyCr26HZw=; see #49063).

  • /nix/store/39k7j7078jf03lzqa6lijvrr0mmr7yy3-opencode-2.0.19+c977050030/bin/opencode --completions {bash,zsh,fish} gives 31479/22433/64280 bytes; all six installed files are non-empty, opencode2 appears nowhere in the three opencode files and 1:1 in the other three, and bash -n, zsh -n, fish -n pass.
  • /nix/store/d0zy23nddpzyffrlxdq2xk87xi1l5gqx-opencode-desktop-2.0.19+c977050030 references /nix/store/z3lbj3jajnnc41m7sz2zzdw6yi4xgkdi-electron-44.3.0 from cache.nixos.org, electron-builder packaged against it, and its opencode-cli.version reads 2.0.19+c977050030, which is what the binary's --version prints.
  • Evaluated, not built: aarch64-linux and aarch64-darwin. x86_64-darwin does not evaluate because nixpkgs 26.11 dropped it.

What this does not fix

The packaged application still reports its own version as 2.0.19 (from packages/desktop/package.json, unchanged) while the CLI it bundles reports 2.0.19+<rev>. The published build keeps those in sync with packages/desktop/scripts/prepare.ts; the Nix build cannot use it — @opencode/script is not installed there, since nix/node_modules.nix:56 excludes the root workspace — and giving the app a rev-suffixed version would push a +build suffix into CFBundleShortVersionString (app-builder-lib macPackager.js:397), which Apple does not accept. Aligning them therefore needs a decision outside this diff: either an explicit bundleShortVersion/buildVersion in the electron-builder config, or relaxing the strict-equality gate at packages/client/src/service-version.ts:7, which today makes a Nix install and a published install evict each other's background service.

The Nix build also packages with OPENCODE_CHANNEL=prod, so UPDATER_ENABLED (packages/desktop/src/main/constants.ts:8) is true and resources/app-update.yml points at the published feed: a package-manager install can be offered a published binary. That predates this PR; deciding whether Nix builds should self-update needs a change in the TypeScript gating.

nix/hashes.json on v2 is stale, so nix build from a clean checkout fails there with or without this PR (#49063). The electron and manifest fixes have no tracking issue. No nix CI check runs on this PR: nix-eval.yml triggers on dev only.

Screenshots / recordings

Not a UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

jerome-benoit added a commit to jerome-benoit/dotfiles that referenced this pull request Sep 28, 2026
OpenCode 2.x is the shipping line. The default branch still carries the 1.x
`opencode2` binary; v2 inverts that, installing `opencode` and symlinking
`opencode2` to it.

The input now follows the root nixpkgs instead of pinning opencode's own.
That drops an intermediate snapshot between releases and turns out to be
what makes the build work: the node_modules FOD hash is only served from
the binary cache for the derivation built from the root nixpkgs' bun, so
the old arrangement had to build it locally and hit a hash mismatch. See
the added note on #49063 for why that hash is not reproducible anyway.

v2 changed the process model, and both consumers needed porting:

- `oc()` used to scan for a free port and run `opencode --port`. v2 has no
  root-level `--port`; every client attaches to one background daemon, so
  the scan and the `OPENCODE_PORT` export are gone and the wrapper just
  runs the TUI in a per-project tmux session.
- opencode.nvim likewise lost `opencode --port`. The plugin finds the
  daemon through the state directory instead, so the terminal command is
  plain `opencode`. It also stopped managing a per-invocation server
  process, which is all lsof and procps were there for; curl stays, the
  event stream is SSE.

opencode-desktop moved to electron 44.x, which is no longer EOL, so the
permittedInsecurePackages entry and the `electron_41` re-instancing that
existed to keep the host nixpkgs config applied to it both go away.

Blocked on anomalyco/opencode#51891, which fixes three defects that make
the v2 packages unbuildable: completions are generated through a removed
subcommand, nix/electron.nix carries hashes for electron 42.10.1 while the
desktop pins 44.4.3, and the desktop never stages the CLI package manifest
its prebuild reads. No local workarounds are carried for those.

Refs anomalyco/opencode#50408
@jerome-benoit
jerome-benoit force-pushed the fix-nix-v2-packaging branch 3 times, most recently from fd912b2 to 870ad46 Compare September 28, 2026 16:31
`nix/opencode.nix` generates completions through `opencode completion`, which
v2 removed: the Effect CLI parses it as the optional `directory` argument, so
the TUI opens instead and `installShellCompletion` gets a zero-size file. It
now uses the global `--completions <shell>` flag, and renames the opencode2
copies because the command name is a build-time define. Fish ships now; `sh`
is a synonym for `bash`, so --bash already covers it.

`nix/electron.nix` carries the electron 42.10.1 hashes while
`packages/desktop/package.json` moved to 44.4.3, so the desktop's electron
fetchzip cannot resolve. Refreshed from the 44.4.3 SHASUMS256.txt; the
headers hash recomputed the same way the 42.10.1 one was, reproducing it as
a control.

`nix/desktop.nix` stages the CLI executable but not the manifest that
`packages/desktop/scripts/utils.ts` reads the version from, so
`scripts/prebuild.ts` aborts on a missing package.json.

Fixes anomalyco#50408
@jerome-benoit jerome-benoit changed the title fix(nix): make the v2 packages buildable fix(nix): repair three packaging defects on the v2 branch Sep 28, 2026
`nix/opencode.nix` generates completions through `opencode completion`, which
v2 removed: the Effect CLI parses it as the optional `directory` argument, so
the TUI opens instead and `installShellCompletion` gets a zero-size file. It
now uses the global `--completions <shell>` flag, and renames the opencode2
copies because the command name is a build-time define. Fish ships now; `sh`
is a synonym for `bash`, so --bash already covers it.

`nix/electron.nix` carries the electron 42.10.1 hashes while
`packages/desktop/package.json` has moved on twice, to 44.4.5, so the
desktop's electron fetchzip cannot resolve. Refreshed from the 44.4.5
SHASUMS256.txt. The headers entry is unchanged: the 44.4.5 and 44.4.3
archives differ but unpack to the same tree, so the recursive hash holds. It
was computed the same way the committed 42.10.1 one was, reproducing that
value first as a control.

`nix/desktop.nix` stages the CLI executable but not the manifest that
`packages/desktop/scripts/utils.ts` reads the version from, so
`scripts/prebuild.ts` aborts on a missing package.json.

Fixes anomalyco#50408
Test User and others added 3 commits September 29, 2026 18:41
The pinned version is read once in nix/desktop.nix and passed to
nix/electron.nix instead of being parsed in both files, the desktop derivation
declares the resolved and pinned versions in passthru, and the two comments
that asserted unverified facts now state the real constraints: installShellFiles
does support named pipes, so staging exists for substitute, which requires a
regular file, and --replace-fail is an unanchored global substitution.

Also repairs two latent defects in the files this PR touches: the
node_modules default pointed at ./node-modules.nix instead of ./node_modules.nix,
and stdenv.isLinux was deprecated.
The staged manifest was assembled with printf, so an unescaped value would have
produced a manifest the desktop cannot parse; it now goes through
JSON.stringify and reads the same variable the bundled binary prints for
--version, which makes the manifest and the executable unable to drift.

Also restates the node-pty remark: the addon is externalised and shipped on
every platform, and only the win32 WSL runtime loads it.
@rekram1-node
rekram1-node merged commit c079050 into anomalyco:v2 Oct 2, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants