- Patch prebuilt .node files (node-pty, @parcel/watcher) with
autoPatchelfHook so they can dlopen libstdc++. Without this, the
sidecar exits on startup because glibc does not consult electron's
DT_RUNPATH transitively for dlopened libraries, and the renderer
shows an empty window with no backend.
- Ignore unresolved libc.musl-* SONAMEs in the prebuilt .node files
so autoPatchelfHook accepts them on glibc systems. The musl-targeting
bindings are dead code at runtime on the host's libc anyway.
- Pass --config.asarUnpack='**/*.node' to electron-builder so every
prebuilt native binding lands on the filesystem (not embedded in
app.asar where dlopen cannot find them).
- Disable the auto-updater at source via postPatch. With the package
now correctly identifying as packaged, the updater would otherwise
try to download and run upstream binaries that aren't patched for
Nix.
- Generate a .desktop entry via makeDesktopItem. electron-builder
--dir skips the deb/AppImage/rpm stages that normally produce one,
so copyDesktopItems on its own was a no-op.
- Install icons into share/icons/hicolor/{30,32,44,64,71,89,107,128,
142,150,284,310}x*/apps/ mirroring upstream's deb layout, so desktop
environments find them. Previously a single bare PNG at
share/icons/opencode-desktop.png (not part of any icon theme path).
- Set ELECTRON_FORCE_IS_PACKAGED=1 in the wrapper. With
--inherit-argv0, Electron's app.isPackaged heuristic returns false,
which routes the app to the dev XDG dir and breaks the WM-class
match with StartupWMClass=OpenCode.
- On darwin, symlink Contents/MacOS/OpenCode into $out/bin and set
mainProgram accordingly so lib.getExe works on both platforms.
- Drop the unused opencode-cli sidecar copy; the bundled chunk hosts
its own server and never spawns the CLI.
Assisted-by: OpenCode:claude-opus-4-7
Co-authored-by: typedrat <alexis@typedr.at>