build.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/usr/bin/env bun
  2. import { $ } from "bun"
  3. import { rm } from "fs/promises"
  4. import path from "path"
  5. import { Script } from "@opencode-ai/script"
  6. import { createSolidTransformPlugin } from "@opentui/solid/bun-plugin"
  7. import type { BunPlugin } from "bun"
  8. import pkg from "../package.json"
  9. import { modelsData } from "./generate"
  10. const dir = path.resolve(import.meta.dirname, "..")
  11. const binary = "opencode2"
  12. const outdir = path.resolve(
  13. dir,
  14. process.argv.find((arg) => arg.startsWith("--outdir="))?.slice("--outdir=".length) ?? "dist",
  15. )
  16. if (outdir === dir) throw new Error("--outdir must not be the package directory")
  17. process.chdir(dir)
  18. await rm(outdir, { recursive: true, force: true })
  19. const singleFlag = process.argv.includes("--single")
  20. const baselineFlag = process.argv.includes("--baseline")
  21. const skipInstall = process.argv.includes("--skip-install")
  22. const solidPlugin = createSolidTransformPlugin()
  23. const allTargets: {
  24. os: string
  25. arch: "arm64" | "x64"
  26. abi?: "musl"
  27. avx2?: false
  28. }[] = [
  29. { os: "linux", arch: "arm64" },
  30. { os: "linux", arch: "x64" },
  31. { os: "linux", arch: "x64", avx2: false },
  32. { os: "linux", arch: "arm64", abi: "musl" },
  33. { os: "linux", arch: "x64", abi: "musl" },
  34. { os: "linux", arch: "x64", abi: "musl", avx2: false },
  35. { os: "darwin", arch: "arm64" },
  36. { os: "darwin", arch: "x64" },
  37. { os: "darwin", arch: "x64", avx2: false },
  38. { os: "win32", arch: "arm64" },
  39. { os: "win32", arch: "x64" },
  40. { os: "win32", arch: "x64", avx2: false },
  41. ]
  42. const targets = singleFlag
  43. ? allTargets.filter((item) => {
  44. if (item.os !== process.platform || item.arch !== process.arch) return false
  45. if (item.avx2 === false) return baselineFlag
  46. return item.abi === undefined
  47. })
  48. : allTargets
  49. if (!skipInstall) await $`bun install --os="*" --cpu="*" @opentui/core@${pkg.dependencies["@opentui/core"]}`
  50. for (const item of targets) {
  51. const parcelWatcherPackage = `@parcel/watcher-${item.os}-${item.arch}${item.os === "linux" ? `-${item.abi ?? "glibc"}` : ""}`
  52. const parcelWatcherPlugin: BunPlugin = {
  53. name: "parcel-watcher-binding",
  54. setup(build) {
  55. build.onLoad({ filter: /filesystem\/watcher-binding\.ts$/ }, () => ({
  56. contents: `import binding from ${JSON.stringify(parcelWatcherPackage)}; export default () => binding`,
  57. loader: "js",
  58. }))
  59. },
  60. }
  61. const target = [
  62. binary,
  63. item.os === "win32" ? "windows" : item.os,
  64. item.arch,
  65. item.avx2 === false ? "baseline" : undefined,
  66. item.abi,
  67. ]
  68. .filter(Boolean)
  69. .join("-")
  70. const name = target.replace(binary, "cli")
  71. console.log(`building ${name}`)
  72. const result = await Bun.build({
  73. entrypoints: ["./src/index.ts"],
  74. tsconfig: "./tsconfig.json",
  75. plugins: [solidPlugin, parcelWatcherPlugin],
  76. external: ["node-gyp"],
  77. format: "esm",
  78. minify: true,
  79. sourcemap: "inline",
  80. splitting: true,
  81. compile: {
  82. autoloadBunfig: false,
  83. autoloadDotenv: false,
  84. autoloadTsconfig: true,
  85. autoloadPackageJson: true,
  86. target: target.replace(binary, "bun") as Bun.Build.CompileTarget,
  87. outfile: path.join(outdir, name, "bin", binary),
  88. execArgv: [`--user-agent=${binary}/${Script.version}`, "--use-system-ca", "--"],
  89. windows: {},
  90. },
  91. define: {
  92. OPENCODE_VERSION: `'${Script.version}'`,
  93. OPENCODE_CLI_NAME: `'${binary}'`,
  94. OPENCODE_MODELS_DEV: modelsData,
  95. OPENCODE_CHANNEL: `'${Script.channel}'`,
  96. OPENCODE_LIBC: item.os === "linux" ? `'${item.abi ?? "glibc"}'` : "undefined",
  97. // FFF_LIBC selects the fff native lib variant: "musl" or "gnu".
  98. FFF_LIBC: item.os === "linux" ? `'${item.abi ?? "gnu"}'` : "undefined",
  99. ...(item.os === "linux" ? { "process.env.OPENTUI_LIBC": JSON.stringify(item.abi ?? "glibc") } : {}),
  100. },
  101. })
  102. if (!result.success) {
  103. for (const log of result.logs) console.error(log)
  104. process.exit(1)
  105. }
  106. await Bun.write(
  107. path.join(outdir, name, "package.json"),
  108. JSON.stringify(
  109. {
  110. name: `@opencode-ai/${name}`,
  111. version: Script.version,
  112. license: "MIT",
  113. repository: { type: "git", url: "git+https://github.com/anomalyco/opencode.git" },
  114. os: [item.os],
  115. cpu: [item.arch],
  116. },
  117. null,
  118. 2,
  119. ),
  120. )
  121. }