From b6becd5e01a428fe0175e3ef05e9ef2a3b5302e7 Mon Sep 17 00:00:00 2001 From: Alexander Miroshnichenko Date: Sat, 26 Sep 2026 11:35:09 +0300 Subject: [PATCH] feat: bundle opencode plugin as open-code-review passthru + HM module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - packages/open-code-review/opencode-plugin.nix: builds the plugin TS file plus runtime node_modules from the plugin's package-lock.json into share/open-code-review/opencode (exposed as passthru.opencode-plugin, same source rev as the CLI so versions stay locked) - modules/open-code-review-hm.nix: homeManagerModules.default with programs.open-code-review.{enable,opencode.enable} — symlinks the plugin and node_modules into ~/.config/opencode/plugins/ and installs the CLI - flake.nix: expose homeManagerModules.default Note: upstream declares the plugin SDKs as devDependencies, so the lockfile install must not use --omit=dev. 🤖 Generated with Codebuff Co-Authored-By: Codebuff --- README.md | 35 +++++++ flake.nix | 4 + modules/open-code-review-hm.nix | 50 ++++++++++ packages/open-code-review/opencode-plugin.nix | 92 +++++++++++++++++++ packages/open-code-review/package.nix | 5 + 5 files changed, 186 insertions(+) create mode 100644 modules/open-code-review-hm.nix create mode 100644 packages/open-code-review/opencode-plugin.nix diff --git a/README.md b/README.md index 2dbd215..e4b6b09 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,41 @@ nftablesbuilder.eu (served with a self-signed certificate, hence the `curlOpts = "-k"` in the derivation); the source repository is missing the `settings` crate, which this overlay patches in. +### OpenCodeReview OpenCode Plugin (Home Manager) + +The `open-code-review` package bundles its OpenCode plugin (the plugin file +plus runtime `node_modules`) as `passthru.opencode-plugin`, built from the +same source revision as the CLI. A Home Manager module symlinks it into +`~/.config/opencode/plugins/` and puts the `ocr` CLI on PATH: + +```nix +inputs.millerson-nix-overlay.url = "git+https://git.millerson.name/alex/millerson-overlay.nix.git"; +inputs.home-manager.url = "github:nix-community/home-manager"; +``` + +```nix +# in your home-manager configuration +imports = [ millerson-nix-overlay.homeManagerModules.default ]; + +programs.open-code-review = { + enable = true; + opencode.enable = true; # symlink plugin into ~/.config/opencode +}; +``` + +Without Home Manager, symlink manually: + +```bash +plugin=$(nix build --print-out-paths \ + git+https://git.millerson.name/alex/millerson-overlay.nix.git#open-code-review.passthru.opencode-plugin) +mkdir -p ~/.config/opencode/plugins +ln -sf $plugin/share/open-code-review/opencode/open-code-review.ts ~/.config/opencode/plugins/ +ln -sfn $plugin/share/open-code-review/opencode/node_modules ~/.config/opencode/plugins/node_modules +``` + +Note: the `node_modules` symlink is shared across everything in the plugins +directory; other manually-installed plugins with conflicting npm dependencies +cannot coexist with it. ## Development diff --git a/flake.nix b/flake.nix index 9de7b8d..1882e1e 100644 --- a/flake.nix +++ b/flake.nix @@ -57,5 +57,9 @@ nixosModules.default = { nixpkgs.overlays = [ self.overlays.default ]; }; + + homeManagerModules.default = { + imports = [ ./modules/open-code-review-hm.nix ]; + }; }; } diff --git a/modules/open-code-review-hm.nix b/modules/open-code-review-hm.nix new file mode 100644 index 0000000..e93638f --- /dev/null +++ b/modules/open-code-review-hm.nix @@ -0,0 +1,50 @@ +# Home Manager module: installs the OpenCode plugin for OpenCodeReview. +# +# Creates symlinks under ~/.config/opencode/plugins/ for the plugin file and +# its runtime node_modules, and puts the matching `ocr` CLI on PATH. +# +# Note: the node_modules symlink is shared by everything in the plugins +# directory. Plugins installed by other means that need conflicting npm +# dependencies cannot coexist with this one. +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.programs.open-code-review; +in +{ + options.programs.open-code-review = { + enable = lib.mkEnableOption "OpenCodeReview AI code review CLI and its OpenCode plugin"; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.open-code-review; + defaultText = lib.literalExpression "pkgs.open-code-review"; + description = "The open-code-review package to use."; + }; + + opencode = { + enable = lib.mkEnableOption "symlink the bundled OpenCode plugin into ~/.config/opencode"; + }; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + home.packages = [ cfg.package ]; + } + (lib.mkIf cfg.opencode.enable { + # The plugin resolves its imports Node-style: node_modules next to the + # plugin file, or in any parent directory (via the file's realpath). + # Linking both the file and node_modules covers either resolution. + xdg.configFile."opencode/plugins/open-code-review.ts".source = + "${cfg.package.passthru.opencode-plugin}/share/open-code-review/opencode/open-code-review.ts"; + + xdg.configFile."opencode/plugins/node_modules".source = + "${cfg.package.passthru.opencode-plugin}/share/open-code-review/opencode/node_modules"; + }) + ]); +} diff --git a/packages/open-code-review/opencode-plugin.nix b/packages/open-code-review/opencode-plugin.nix new file mode 100644 index 0000000..ba854a6 --- /dev/null +++ b/packages/open-code-review/opencode-plugin.nix @@ -0,0 +1,92 @@ +# OpenCode plugin for OpenCodeReview, built from the same source revision as +# the CLI (see package.nix). Ships the plugin TypeScript file plus the runtime +# node_modules resolved from the plugin's package-lock.json, so OpenCode can +# import `@opencode-ai/plugin` (v1.x) and `@opencode/plugin` (v2.x) without a +# network install. +{ + lib, + stdenv, + nodejs, + fetchNpmDeps, + src, + version, +}: + +let + pluginDir = "plugins/open-code-review/opencode"; + + lockfileCopy = '' + cp ${pluginDir}/package-lock.json ./package-lock.json + chmod +w package-lock.json + ''; + + npmDeps = fetchNpmDeps { + name = "open-code-review-opencode-plugin-npm-deps"; + inherit src; + postPatch = lockfileCopy; + hash = "sha256-s5BO+JJJ9qZkKRTDmWyfBFVKB9GEeqObzyJ1lkORQo0="; + }; +in +stdenv.mkDerivation { + pname = "open-code-review-opencode-plugin"; + inherit version src; + + # The lockfile lives in plugins/open-code-review/opencode/, but fetchNpmDeps + # and npm ci expect it at the package root. + postPatch = lockfileCopy; + + # Exposed as an env var; used as the offline npm cache in installPhase. + inherit npmDeps; + + # No build steps needed: the plugin is a single .ts file that OpenCode's + # runtime transpiles on the fly; only node_modules is materialized. + dontBuild = true; + dontConfigure = true; + + nativeBuildInputs = [ nodejs ]; + + # OpenCode resolves plugin imports Node-style: node_modules next to the + # plugin file, or in any parent directory (resolved via the file's realpath). + # Install both the plugin file and node_modules so the plugin works whether + # users symlink the file only, the plugin dir, or point OpenCode at the + # store path directly. + installPhase = '' + runHook preInstall + + pushd ${pluginDir} + + # NOTE: upstream's package.json declares the plugin SDKs as + # devDependencies, so --omit=dev must NOT be used — it would install + # nothing. The full lockfile install is required. + npm ci \ + --ignore-scripts \ + --no-audit \ + --no-fund \ + --no-progress \ + --loglevel=error \ + --offline \ + --cache "$npmDeps" + + pluginOut=$out/share/open-code-review/opencode + mkdir -p "$pluginOut" + cp open-code-review.ts "$pluginOut/" + cp -r node_modules "$pluginOut/" + + popd + runHook postInstall + ''; + + passthru = { + # The plugin speaks the CLI's JSON protocol; use it with a matching CLI + # version (both are built from the same source revision here). + forCli = "open-code-review"; + }; + + meta = with lib; { + description = "OpenCode plugin exposing OpenCodeReview as native tools and slash commands"; + homepage = "https://github.com/alibaba/open-code-review"; + changelog = "https://github.com/alibaba/open-code-review/releases/tag/v${version}"; + license = licenses.asl20; + platforms = platforms.all; + }; +} diff --git a/packages/open-code-review/package.nix b/packages/open-code-review/package.nix index d6b094d..fed2db4 100644 --- a/packages/open-code-review/package.nix +++ b/packages/open-code-review/package.nix @@ -2,6 +2,7 @@ lib, buildGoModule, fetchFromGitHub, + callPackage, }: buildGoModule rec { @@ -33,6 +34,10 @@ buildGoModule rec { passthru = { category = "Code Review"; + # OpenCode plugin built from the same source revision as the CLI. + opencode-plugin = callPackage ./opencode-plugin.nix { + inherit src version; + }; updateScript = [ "nix-update" "--flake"