electron-builder.config.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { execFile } from "node:child_process"
  2. import path from "node:path"
  3. import { fileURLToPath } from "node:url"
  4. import { promisify } from "node:util"
  5. import type { Configuration } from "electron-builder"
  6. const execFileAsync = promisify(execFile)
  7. const packageDir = path.dirname(fileURLToPath(import.meta.url))
  8. const rootDir = path.resolve(packageDir, "../..")
  9. const signScript = path.join(rootDir, "script", "sign-windows.ps1")
  10. // The Electron 42 packaging update briefly installed Linux launchers/icons under
  11. // "kirincode-desktop". Keep that hidden desktop entry around so existing GNOME/KDE
  12. // pins still resolve after the canonical app id changes back to ai.kirincode.desktop.
  13. const legacyDesktopEntry = path.join(packageDir, "resources", "linux", "kirincode-desktop.desktop")
  14. const legacyDesktopEntryFpm = `${legacyDesktopEntry}=/usr/share/applications/kirincode-desktop.desktop`
  15. async function signWindows(configuration: { path: string }) {
  16. if (process.platform !== "win32") return
  17. if (process.env.GITHUB_ACTIONS !== "true") return
  18. await execFileAsync(
  19. "pwsh",
  20. ["-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", signScript, configuration.path],
  21. { cwd: rootDir },
  22. )
  23. }
  24. const channel = (() => {
  25. const raw = process.env.KIRINCODE_CHANNEL
  26. if (raw === "dev" || raw === "beta" || raw === "prod") return raw
  27. return "dev"
  28. })()
  29. const APP_IDS = {
  30. dev: "ai.kirincode.desktop.dev",
  31. beta: "ai.kirincode.desktop.beta",
  32. prod: "ai.kirincode.desktop",
  33. } as const
  34. const getBase = (appId: string): Configuration => ({
  35. artifactName: "kirincode-desktop-${os}-${arch}.${ext}",
  36. directories: {
  37. output: "dist",
  38. buildResources: "resources",
  39. },
  40. // Linux launchers are .desktop files, so this is the desktop file name,
  41. // not just the app id. For prod, app id "ai.kirincode.desktop" becomes
  42. // "ai.kirincode.desktop.desktop".
  43. // https://developer.gnome.org/documentation/guidelines/maintainer/integrating.html
  44. // https://www.electron.build/docs/linux/
  45. extraMetadata: {
  46. desktopName: `${appId}.desktop`,
  47. },
  48. files: ["out/**/*", "resources/**/*"],
  49. asar: true,
  50. asarUnpack: ["node_modules/@lydell/node-pty*/**"],
  51. extraResources: [
  52. {
  53. from: "native/",
  54. to: "native/",
  55. filter: ["index.js", "index.d.ts", "build/Release/mac_window.node", "swift-build/**"],
  56. },
  57. ],
  58. mac: {
  59. category: "public.app-category.developer-tools",
  60. icon: `resources/icons/icon.icns`,
  61. hardenedRuntime: true,
  62. gatekeeperAssess: false,
  63. entitlements: "resources/entitlements.plist",
  64. entitlementsInherit: "resources/entitlements.plist",
  65. notarize: true,
  66. target: ["dmg", "zip"],
  67. },
  68. dmg: {
  69. sign: true,
  70. },
  71. protocols: {
  72. name: "K",
  73. schemes: ["kirincode"],
  74. },
  75. win: {
  76. icon: `resources/icons/icon.ico`,
  77. signtoolOptions: {
  78. sign: signWindows,
  79. },
  80. target: ["nsis"],
  81. verifyUpdateCodeSignature: false,
  82. },
  83. nsis: {
  84. oneClick: false,
  85. perMachine: true,
  86. allowToChangeInstallationDirectory: true,
  87. installerIcon: `resources/icons/icon.ico`,
  88. installerHeaderIcon: `resources/icons/icon.ico`,
  89. },
  90. linux: {
  91. icon: `resources/icons`,
  92. category: "Development",
  93. executableName: appId,
  94. desktop: {
  95. entry: {
  96. // Match the installed .desktop file and hicolor icon basename so
  97. // Linux shells can associate the running Electron window with its launcher.
  98. StartupWMClass: appId,
  99. },
  100. },
  101. target: ["AppImage", "deb", "rpm"],
  102. },
  103. })
  104. function getConfig() {
  105. const appId = APP_IDS[channel]
  106. const base = getBase(appId)
  107. switch (channel) {
  108. case "dev": {
  109. return {
  110. ...base,
  111. appId,
  112. productName: "KirinCode Dev",
  113. rpm: { packageName: "kirincode-dev" },
  114. }
  115. }
  116. case "beta": {
  117. return {
  118. ...base,
  119. appId,
  120. productName: "KirinCode Beta",
  121. protocols: { name: "K Beta", schemes: ["kirincode"] },
  122. publish: { provider: "github", owner: "kirincode", repo: "kirincode-beta", channel: "latest" },
  123. rpm: { packageName: "kirincode-beta" },
  124. }
  125. }
  126. case "prod": {
  127. return {
  128. ...base,
  129. appId,
  130. productName: "K",
  131. protocols: { name: "K", schemes: ["kirincode"] },
  132. publish: { provider: "github", owner: "kirincode", repo: "kirincode", channel: "latest" },
  133. deb: { fpm: [legacyDesktopEntryFpm] },
  134. rpm: { packageName: "kirincode", fpm: [legacyDesktopEntryFpm] },
  135. }
  136. }
  137. }
  138. }
  139. export default getConfig()