소스 검색

feat(nix): preliminary desktop app flake integration (#6135)

Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: rekram1-node <[email protected]>
Co-authored-by: Aiden Cline <[email protected]>
Jérôme Benoit 1 개월 전
부모
커밋
e00621cb17
3개의 변경된 파일190개의 추가작업 그리고 4개의 파일을 삭제
  1. 29 0
      .github/workflows/nix-desktop.yml
  2. 16 4
      flake.nix
  3. 145 0
      nix/desktop.nix

+ 29 - 0
.github/workflows/nix-desktop.yml

@@ -0,0 +1,29 @@
+name: nix desktop
+
+on:
+  pull_request:
+    branches: [dev]
+  workflow_dispatch:
+
+jobs:
+  build-desktop:
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - blacksmith-4vcpu-ubuntu-2404
+          - macos-latest
+    runs-on: ${{ matrix.os }}
+    timeout-minutes: 60
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Setup Nix
+        uses: DeterminateSystems/nix-installer-action@v21
+
+      - name: Build desktop via flake
+        run: |
+          set -euo pipefail
+          nix --version
+          nix build .#desktop -L

+ 16 - 4
flake.nix

@@ -66,10 +66,10 @@
           mkNodeModules = pkgs.callPackage ./nix/node-modules.nix {
             hash = nodeModulesHash;
           };
-          mkPackage = pkgs.callPackage ./nix/opencode.nix { };
-        in
-        {
-          default = mkPackage {
+          mkOpencode = pkgs.callPackage ./nix/opencode.nix { };
+          mkDesktop = pkgs.callPackage ./nix/desktop.nix { };
+
+          opencodePkg = mkOpencode {
             inherit (packageJson) version;
             src = ./.;
             scripts = ./nix/scripts;
@@ -77,6 +77,18 @@
             modelsDev = "${modelsDev.${system}}/dist/_api.json";
             inherit mkNodeModules;
           };
+
+          desktopPkg = mkDesktop {
+            inherit (packageJson) version;
+            src = ./.;
+            scripts = ./nix/scripts;
+            mkNodeModules = mkNodeModules;
+            opencode = opencodePkg;
+          };
+        in
+        {
+          default = opencodePkg;
+          desktop = desktopPkg;
         }
       );
 

+ 145 - 0
nix/desktop.nix

@@ -0,0 +1,145 @@
+{
+  lib,
+  stdenv,
+  rustPlatform,
+  bun,
+  pkg-config,
+  dbus ? null,
+  openssl,
+  glib ? null,
+  gtk3 ? null,
+  libsoup_3 ? null,
+  webkitgtk_4_1 ? null,
+  librsvg ? null,
+  libappindicator-gtk3 ? null,
+  cargo,
+  rustc,
+  makeBinaryWrapper,
+  nodejs,
+  jq,
+}:
+args:
+let
+  scripts = args.scripts;
+  mkModules =
+    attrs:
+    args.mkNodeModules (
+      attrs
+      // {
+        canonicalizeScript = scripts + "/canonicalize-node-modules.ts";
+        normalizeBinsScript = scripts + "/normalize-bun-binaries.ts";
+      }
+    );
+in
+rustPlatform.buildRustPackage rec {
+  pname = "opencode-desktop";
+  version = args.version;
+
+  src = args.src;
+
+  # We need to set the root for cargo, but we also need access to the whole repo.
+  postUnpack = ''
+    # Update sourceRoot to point to the tauri app
+    sourceRoot+=/packages/desktop/src-tauri
+  '';
+
+  cargoLock = {
+    lockFile = ../packages/desktop/src-tauri/Cargo.lock;
+    allowBuiltinFetchGit = true;
+  };
+
+  node_modules = mkModules {
+    version = version;
+    src = src;
+  };
+
+  nativeBuildInputs = [
+    pkg-config
+    bun
+    makeBinaryWrapper
+    cargo
+    rustc
+    nodejs
+    jq
+  ];
+
+  buildInputs = [
+    openssl
+  ]
+  ++ lib.optionals stdenv.isLinux [
+    dbus
+    glib
+    gtk3
+    libsoup_3
+    webkitgtk_4_1
+    librsvg
+    libappindicator-gtk3
+  ];
+
+  preBuild = ''
+    # Restore node_modules
+    pushd ../../..
+
+    # Copy node_modules from the fixed-output derivation
+    # We use cp -r --no-preserve=mode to ensure we can write to them if needed,
+    # though we usually just read.
+    cp -r ${node_modules}/node_modules .
+    cp -r ${node_modules}/packages .
+
+    # Ensure node_modules is writable so patchShebangs can update script headers
+    chmod -R u+w node_modules
+    # Ensure workspace packages are writable for tsgo incremental outputs (.tsbuildinfo)
+    chmod -R u+w packages
+    # Patch shebangs so scripts can run
+    patchShebangs node_modules
+
+    # Copy sidecar
+    mkdir -p packages/desktop/src-tauri/sidecars
+    targetTriple=${stdenv.hostPlatform.rust.rustcTarget}
+    cp ${args.opencode}/bin/opencode packages/desktop/src-tauri/sidecars/opencode-cli-$targetTriple
+
+    # Merge prod config into tauri.conf.json
+    if ! jq -s '.[0] * .[1]' \
+      packages/desktop/src-tauri/tauri.conf.json \
+      packages/desktop/src-tauri/tauri.prod.conf.json \
+      > packages/desktop/src-tauri/tauri.conf.json.tmp; then
+      echo "Error: failed to merge tauri.conf.json with tauri.prod.conf.json" >&2
+      exit 1
+    fi
+    mv packages/desktop/src-tauri/tauri.conf.json.tmp packages/desktop/src-tauri/tauri.conf.json
+
+    # Build the frontend
+    cd packages/desktop
+
+    # The 'build' script runs 'bun run typecheck && vite build'.
+    bun run build
+
+    popd
+  '';
+
+  # Tauri bundles the assets during the rust build phase (which happens after preBuild).
+  # It looks for them in the location specified in tauri.conf.json.
+
+  postInstall = lib.optionalString stdenv.isLinux ''
+    # Wrap the binary to ensure it finds the libraries
+    wrapProgram $out/bin/opencode-desktop \
+      --prefix LD_LIBRARY_PATH : ${
+        lib.makeLibraryPath [
+          gtk3
+          webkitgtk_4_1
+          librsvg
+          glib
+          libsoup_3
+        ]
+      }
+  '';
+
+  meta = with lib; {
+    description = "OpenCode Desktop App";
+    homepage = "https://opencode.ai";
+    license = licenses.mit;
+    maintainers = with maintainers; [ ];
+    mainProgram = "opencode-desktop";
+    platforms = platforms.linux ++ platforms.darwin;
+  };
+}