blob: d1013ca9c73c8794d46632af1d84065c93215118 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
#!/usr/bin/env bash
#
# kimi-code installer for macOS and Linux.
#
# Usage:
# curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash
# KIMI_VERSION=0.5.0 curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash
# KIMI_INSTALL_DIR=/usr/local curl -fsSL https://code.kimi.com/kimi-code/install.sh | sudo -E bash
#
# Optional env:
# KIMI_VERSION Explicit version; if unset, fetch from https://code.kimi.com/kimi-code/latest
# KIMI_INSTALL_DIR Installation directory, default $HOME/.kimi-code
set -euo pipefail
KIMI_DOWNLOAD_BASE="https://code.kimi.com/kimi-code"
KIMI_VERSION="${KIMI_VERSION:-}"
KIMI_INSTALL_DIR="${KIMI_INSTALL_DIR:-$HOME/.local/bin}"
# ---------- helpers ----------
_have() { command -v "$1" >/dev/null 2>&1; }
_log() {
if [ -t 1 ]; then
printf '\033[1;36m==>\033[0m %s\n' "$*"
else
printf '==> %s\n' "$*"
fi
}
_err() {
printf 'error: %s\n' "$*" >&2
exit 1
}
_detect_target() {
local os arch
case "$(uname -s)" in
Darwin) os="darwin" ;;
Linux) os="linux" ;;
MINGW*|MSYS*|CYGWIN*)
_err "Windows is not supported by install.sh — use install.ps1 (PowerShell)"
;;
*) _err "unsupported OS: $(uname -s)" ;;
esac
case "$(uname -m)" in
x86_64|amd64) arch="x64" ;;
arm64|aarch64) arch="arm64" ;;
*) _err "unsupported architecture: $(uname -m)" ;;
esac
# Rosetta 2: when running under an x64 shell on an ARM Mac, switch back to the native arm64 binary
if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then
if [ "$(sysctl -n sysctl.proc_translated 2>/dev/null)" = "1" ]; then
arch="arm64"
fi
fi
# musl detection (Alpine, etc.) — we currently only ship glibc binaries, so failing early is better than a runtime dlopen error
if [ "$os" = "linux" ]; then
if [ -f "/lib/libc.musl-x86_64.so.1" ] || \
[ -f "/lib/libc.musl-aarch64.so.1" ] || \
ldd /bin/ls 2>&1 | grep -q musl; then
_err "Alpine / musl Linux is not currently supported. Use Node.js + 'npm install -g @moonshot-ai/kimi-code' instead."
fi
fi
echo "${os}-${arch}"
}
_download() {
local url="$1" dest="${2:-}"
if _have curl; then
if [ -n "$dest" ]; then
if [ -t 1 ]; then
curl --fail --location --progress-bar -o "$dest" "$url"
else
curl --fail --location --silent -o "$dest" "$url"
fi
else
curl --fail --location --silent "$url"
fi
elif _have wget; then
if [ -n "$dest" ]; then
wget -q -O "$dest" "$url"
else
wget -q -O - "$url"
fi
else
_err "curl or wget is required"
fi
}
# Prefer jq; otherwise parse a single manifest field using pure bash regex
_manifest_field() {
local manifest_json="$1" target="$2" field="$3"
if _have jq; then
printf '%s' "$manifest_json" | jq -er ".platforms[\"$target\"].$field // empty"
else
local one_line
one_line="$(printf '%s' "$manifest_json" | tr -d '\n\r\t' | sed 's/ \+/ /g')"
if [[ $one_line =~ \"$target\"[^}]*\"$field\"[[:space:]]*:[[:space:]]*\"([^\"]+)\" ]]; then
printf '%s' "${BASH_REMATCH[1]}"
fi
fi
}
_sha256_check() {
local file="$1" expected="$2"
local actual
if _have shasum; then
actual="$(shasum -a 256 "$file" | cut -d' ' -f1)"
elif _have sha256sum; then
actual="$(sha256sum "$file" | cut -d' ' -f1)"
else
_err "shasum or sha256sum required to verify download"
fi
if [ "$actual" != "$expected" ]; then
_err "checksum mismatch: expected $expected, got $actual"
fi
}
# ---------- main ----------
TMPDIR_INSTALL=""
_cleanup() {
if [ -n "$TMPDIR_INSTALL" ] && [ -d "$TMPDIR_INSTALL" ]; then
rm -rf "$TMPDIR_INSTALL"
fi
}
trap _cleanup EXIT
main() {
local target version manifest_url manifest filename checksum binary_url tmpdir
target="$(_detect_target)"
_log "Detected target: $target"
# 1. Resolve version
if [ -n "$KIMI_VERSION" ]; then
version="$KIMI_VERSION"
_log "Using pinned version $version"
else
_log "Resolving latest version from ${KIMI_DOWNLOAD_BASE}/latest"
version="$(_download "${KIMI_DOWNLOAD_BASE}/latest" | tr -d '[:space:]')"
[ -n "$version" ] || _err "could not resolve latest version"
_log "Latest version: $version"
fi
# 2. Fetch manifest
manifest_url="${KIMI_DOWNLOAD_BASE}/${version}/manifest.json"
_log "Fetching manifest ${manifest_url}"
manifest="$(_download "$manifest_url")"
[ -n "$manifest" ] || _err "manifest is empty or unreachable: $manifest_url"
# 3. Find current platform entry
filename="$(_manifest_field "$manifest" "$target" "filename")"
checksum="$(_manifest_field "$manifest" "$target" "checksum")"
[ -n "$filename" ] || _err "platform $target not found in manifest"
[[ "$checksum" =~ ^[a-f0-9]{64}$ ]] || _err "invalid checksum for $target: $checksum"
# 4. Download binary
TMPDIR_INSTALL="$(mktemp -d 2>/dev/null || mktemp -d -t kimi-install)"
tmpdir="$TMPDIR_INSTALL"
binary_url="${KIMI_DOWNLOAD_BASE}/${version}/${filename}"
_log "Downloading ${binary_url}"
_download "$binary_url" "${tmpdir}/${filename}"
# 5. Verify checksum
_log "Verifying checksum"
_sha256_check "${tmpdir}/${filename}" "$checksum"
# 6. Install
chmod +x "${tmpdir}/${filename}"
mkdir -p "${KIMI_INSTALL_DIR}"
install -m 0755 "${tmpdir}/${filename}" "${KIMI_INSTALL_DIR}/kimi"
_log "Installed to ${KIMI_INSTALL_DIR}/kimi"
_log "Done. Run: kimi --version"
}
main "$@"
|