kilo 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!/usr/bin/env node
  2. const childProcess = require("child_process")
  3. const fs = require("fs")
  4. const path = require("path")
  5. const os = require("os")
  6. function run(target) {
  7. const result = childProcess.spawnSync(target, process.argv.slice(2), {
  8. stdio: "inherit",
  9. })
  10. if (result.error) {
  11. console.error(result.error.message)
  12. process.exit(1)
  13. }
  14. const code = typeof result.status === "number" ? result.status : 0
  15. process.exit(code)
  16. }
  17. const envPath = process.env.KILO_BIN_PATH
  18. if (envPath) {
  19. run(envPath)
  20. }
  21. const scriptPath = fs.realpathSync(__filename)
  22. const scriptDir = path.dirname(scriptPath)
  23. // kilocode_change start - fall through to findBinary() if cached binary fails
  24. const cached = path.join(scriptDir, ".kilo")
  25. if (fs.existsSync(cached)) {
  26. const result = childProcess.spawnSync(cached, process.argv.slice(2), {
  27. stdio: "inherit",
  28. })
  29. if (!result.error) {
  30. const code = typeof result.status === "number" ? result.status : 0
  31. process.exit(code)
  32. }
  33. // cached binary failed (e.g. wrong platform/arch, missing dynamic linker),
  34. // fall through to findBinary() which has better variant detection
  35. }
  36. // kilocode_change end
  37. const platformMap = {
  38. darwin: "darwin",
  39. linux: "linux",
  40. win32: "windows",
  41. }
  42. const archMap = {
  43. x64: "x64",
  44. arm64: "arm64",
  45. arm: "arm",
  46. }
  47. let platform = platformMap[os.platform()]
  48. if (!platform) {
  49. platform = os.platform()
  50. }
  51. let arch = archMap[os.arch()]
  52. if (!arch) {
  53. arch = os.arch()
  54. }
  55. const base = "@kilocode/cli-" + platform + "-" + arch
  56. const binary = platform === "windows" ? "kilo.exe" : "kilo"
  57. function supportsAvx2() {
  58. if (arch !== "x64") return false
  59. if (platform === "linux") {
  60. try {
  61. return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
  62. } catch {
  63. return false
  64. }
  65. }
  66. if (platform === "darwin") {
  67. try {
  68. const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
  69. encoding: "utf8",
  70. timeout: 1500,
  71. })
  72. if (result.status !== 0) return false
  73. return (result.stdout || "").trim() === "1"
  74. } catch {
  75. return false
  76. }
  77. }
  78. if (platform === "windows") {
  79. const cmd =
  80. '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
  81. for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
  82. try {
  83. const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
  84. encoding: "utf8",
  85. timeout: 3000,
  86. windowsHide: true,
  87. })
  88. if (result.status !== 0) continue
  89. const out = (result.stdout || "").trim().toLowerCase()
  90. if (out === "true" || out === "1") return true
  91. if (out === "false" || out === "0") return false
  92. } catch {
  93. continue
  94. }
  95. }
  96. return false
  97. }
  98. return false
  99. }
  100. const names = (() => {
  101. const avx2 = supportsAvx2()
  102. const baseline = arch === "x64" && !avx2
  103. if (platform === "linux") {
  104. const musl = (() => {
  105. try {
  106. if (fs.existsSync("/etc/alpine-release")) return true
  107. } catch {
  108. // ignore
  109. }
  110. try {
  111. const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
  112. const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
  113. if (text.includes("musl")) return true
  114. } catch {
  115. // ignore
  116. }
  117. return false
  118. })()
  119. if (musl) {
  120. if (arch === "x64") {
  121. if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
  122. return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
  123. }
  124. return [`${base}-musl`, base]
  125. }
  126. if (arch === "x64") {
  127. if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
  128. return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
  129. }
  130. return [base, `${base}-musl`]
  131. }
  132. if (arch === "x64") {
  133. if (baseline) return [`${base}-baseline`, base]
  134. return [base, `${base}-baseline`]
  135. }
  136. return [base]
  137. })()
  138. function findBinary(startDir) {
  139. let current = startDir
  140. for (;;) {
  141. const modules = path.join(current, "node_modules")
  142. if (fs.existsSync(modules)) {
  143. for (const name of names) {
  144. const candidate = path.join(modules, name, "bin", binary)
  145. if (fs.existsSync(candidate)) return candidate
  146. }
  147. }
  148. const parent = path.dirname(current)
  149. if (parent === current) {
  150. return
  151. }
  152. current = parent
  153. }
  154. }
  155. const resolved = findBinary(scriptDir)
  156. if (!resolved) {
  157. console.error(
  158. "It seems that your package manager failed to install the right version of the Kilo CLI for your platform. You can try manually installing " +
  159. names.map((n) => `\"${n}\"`).join(" or ") +
  160. " package",
  161. )
  162. process.exit(1)
  163. }
  164. run(resolved)