desktop.nix 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. {
  2. lib,
  3. stdenv,
  4. rustPlatform,
  5. bun,
  6. pkg-config,
  7. dbus ? null,
  8. openssl,
  9. glib ? null,
  10. gtk3 ? null,
  11. libsoup_3 ? null,
  12. webkitgtk_4_1 ? null,
  13. librsvg ? null,
  14. libappindicator-gtk3 ? null,
  15. cargo,
  16. rustc,
  17. makeBinaryWrapper,
  18. copyDesktopItems,
  19. makeDesktopItem,
  20. nodejs,
  21. jq,
  22. }:
  23. args:
  24. let
  25. scripts = args.scripts;
  26. mkModules =
  27. attrs:
  28. args.mkNodeModules (
  29. attrs
  30. // {
  31. canonicalizeScript = scripts + "/canonicalize-node-modules.ts";
  32. normalizeBinsScript = scripts + "/normalize-bun-binaries.ts";
  33. }
  34. );
  35. in
  36. rustPlatform.buildRustPackage rec {
  37. pname = "opencode-desktop";
  38. version = args.version;
  39. src = args.src;
  40. # We need to set the root for cargo, but we also need access to the whole repo.
  41. postUnpack = ''
  42. # Update sourceRoot to point to the tauri app
  43. sourceRoot+=/packages/desktop/src-tauri
  44. '';
  45. cargoLock = {
  46. lockFile = ../packages/desktop/src-tauri/Cargo.lock;
  47. allowBuiltinFetchGit = true;
  48. };
  49. node_modules = mkModules {
  50. version = version;
  51. src = src;
  52. };
  53. nativeBuildInputs = [
  54. pkg-config
  55. bun
  56. makeBinaryWrapper
  57. copyDesktopItems
  58. cargo
  59. rustc
  60. nodejs
  61. jq
  62. ];
  63. # based on packages/desktop/src-tauri/release/appstream.metainfo.xml
  64. desktopItems = lib.optionals stdenv.isLinux [
  65. (makeDesktopItem {
  66. name = "ai.opencode.opencode";
  67. desktopName = "OpenCode";
  68. comment = "Open source AI coding agent";
  69. exec = "opencode-desktop";
  70. icon = "opencode";
  71. terminal = false;
  72. type = "Application";
  73. categories = [ "Development" "IDE" ];
  74. startupWMClass = "opencode";
  75. })
  76. ];
  77. buildInputs = [
  78. openssl
  79. ]
  80. ++ lib.optionals stdenv.isLinux [
  81. dbus
  82. glib
  83. gtk3
  84. libsoup_3
  85. webkitgtk_4_1
  86. librsvg
  87. libappindicator-gtk3
  88. ];
  89. preBuild = ''
  90. # Restore node_modules
  91. pushd ../../..
  92. # Copy node_modules from the fixed-output derivation
  93. # We use cp -r --no-preserve=mode to ensure we can write to them if needed,
  94. # though we usually just read.
  95. cp -r ${node_modules}/node_modules .
  96. cp -r ${node_modules}/packages .
  97. # Ensure node_modules is writable so patchShebangs can update script headers
  98. chmod -R u+w node_modules
  99. # Ensure workspace packages are writable for tsgo incremental outputs (.tsbuildinfo)
  100. chmod -R u+w packages
  101. # Patch shebangs so scripts can run
  102. patchShebangs node_modules
  103. # Copy sidecar
  104. mkdir -p packages/desktop/src-tauri/sidecars
  105. targetTriple=${stdenv.hostPlatform.rust.rustcTarget}
  106. cp ${args.opencode}/bin/opencode packages/desktop/src-tauri/sidecars/opencode-cli-$targetTriple
  107. # Merge prod config into tauri.conf.json
  108. if ! jq -s '.[0] * .[1]' \
  109. packages/desktop/src-tauri/tauri.conf.json \
  110. packages/desktop/src-tauri/tauri.prod.conf.json \
  111. > packages/desktop/src-tauri/tauri.conf.json.tmp; then
  112. echo "Error: failed to merge tauri.conf.json with tauri.prod.conf.json" >&2
  113. exit 1
  114. fi
  115. mv packages/desktop/src-tauri/tauri.conf.json.tmp packages/desktop/src-tauri/tauri.conf.json
  116. # Build the frontend
  117. cd packages/desktop
  118. # The 'build' script runs 'bun run typecheck && vite build'.
  119. bun run build
  120. popd
  121. '';
  122. # Tauri bundles the assets during the rust build phase (which happens after preBuild).
  123. # It looks for them in the location specified in tauri.conf.json.
  124. postInstall = lib.optionalString stdenv.isLinux ''
  125. # Install icon
  126. mkdir -p $out/share/icons/hicolor/128x128/apps
  127. cp ../../../packages/desktop/src-tauri/icons/prod/128x128.png $out/share/icons/hicolor/128x128/apps/opencode.png
  128. # Wrap the binary to ensure it finds the libraries
  129. wrapProgram $out/bin/opencode-desktop \
  130. --prefix LD_LIBRARY_PATH : ${
  131. lib.makeLibraryPath [
  132. gtk3
  133. webkitgtk_4_1
  134. librsvg
  135. glib
  136. libsoup_3
  137. ]
  138. }
  139. '';
  140. meta = with lib; {
  141. description = "OpenCode Desktop App";
  142. homepage = "https://opencode.ai";
  143. license = licenses.mit;
  144. maintainers = with maintainers; [ ];
  145. mainProgram = "opencode-desktop";
  146. platforms = platforms.linux ++ platforms.darwin;
  147. };
  148. }