postinstall.mjs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #!/usr/bin/env node
  2. import fs from "fs"
  3. import path from "path"
  4. import os from "os"
  5. import childProcess from "child_process"
  6. import { fileURLToPath } from "url"
  7. import { createRequire } from "module"
  8. const __dirname = path.dirname(fileURLToPath(import.meta.url))
  9. const require = createRequire(import.meta.url)
  10. // kilocode_change start - variant detection matching bin/kilo logic
  11. const platformMap = {
  12. darwin: "darwin",
  13. linux: "linux",
  14. win32: "windows",
  15. }
  16. const archMap = {
  17. x64: "x64",
  18. arm64: "arm64",
  19. arm: "arm",
  20. }
  21. function detectPlatformAndArch() {
  22. const platform = platformMap[os.platform()] || os.platform()
  23. const arch = archMap[os.arch()] || os.arch()
  24. return { platform, arch }
  25. }
  26. function supportsAvx2() {
  27. const { platform, arch } = detectPlatformAndArch()
  28. if (arch !== "x64") return false
  29. if (platform === "linux") {
  30. try {
  31. return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
  32. } catch {
  33. return false
  34. }
  35. }
  36. if (platform === "darwin") {
  37. try {
  38. const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
  39. encoding: "utf8",
  40. timeout: 1500,
  41. })
  42. if (result.status !== 0) return false
  43. return (result.stdout || "").trim() === "1"
  44. } catch {
  45. return false
  46. }
  47. }
  48. return false
  49. }
  50. function isMusl() {
  51. try {
  52. if (fs.existsSync("/etc/alpine-release")) return true
  53. } catch {
  54. // ignore
  55. }
  56. try {
  57. const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
  58. const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
  59. if (text.includes("musl")) return true
  60. } catch {
  61. // ignore
  62. }
  63. return false
  64. }
  65. function getPackageNames() {
  66. const { platform, arch } = detectPlatformAndArch()
  67. const base = `@kilocode/cli-${platform}-${arch}`
  68. const avx2 = supportsAvx2()
  69. const baseline = arch === "x64" && !avx2
  70. if (platform === "linux") {
  71. const musl = isMusl()
  72. if (musl) {
  73. if (arch === "x64") {
  74. if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
  75. return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
  76. }
  77. return [`${base}-musl`, base]
  78. }
  79. if (arch === "x64") {
  80. if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
  81. return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
  82. }
  83. return [base, `${base}-musl`]
  84. }
  85. if (arch === "x64") {
  86. if (baseline) return [`${base}-baseline`, base]
  87. return [base, `${base}-baseline`]
  88. }
  89. return [base]
  90. }
  91. function findBinary() {
  92. const { platform } = detectPlatformAndArch()
  93. const binaryName = platform === "windows" ? "kilo.exe" : "kilo"
  94. const names = getPackageNames()
  95. for (const packageName of names) {
  96. try {
  97. const packageJsonPath = require.resolve(`${packageName}/package.json`)
  98. const packageDir = path.dirname(packageJsonPath)
  99. const binaryPath = path.join(packageDir, "bin", binaryName)
  100. if (fs.existsSync(binaryPath)) {
  101. return { binaryPath, binaryName }
  102. }
  103. } catch {
  104. // package not installed, try next variant
  105. }
  106. }
  107. throw new Error(`Could not find any binary package. Tried: ${names.map((n) => `"${n}"`).join(", ")}`)
  108. }
  109. // kilocode_change end
  110. function main() {
  111. if (os.platform() === "win32") {
  112. // On Windows, the .exe is already included in the package and bin field points to it
  113. console.log("Windows detected: binary setup not needed (using packaged .exe)")
  114. return
  115. }
  116. const { binaryPath } = findBinary()
  117. const target = path.join(__dirname, "bin", ".kilo") // kilocode_change
  118. if (fs.existsSync(target)) fs.unlinkSync(target)
  119. try {
  120. fs.linkSync(binaryPath, target)
  121. } catch {
  122. fs.copyFileSync(binaryPath, target)
  123. }
  124. fs.chmodSync(target, 0o755)
  125. }
  126. try {
  127. main()
  128. } catch (error) {
  129. console.error("Failed to setup kilo binary:", error.message)
  130. process.exit(1)
  131. }