diff options
| author | Igor Soarez <igor@soarez.org> | 2026-09-17 19:45:23 +0100 |
|---|---|---|
| committer | Igor Soarez <igor@soarez.org> | 2026-09-17 19:45:23 +0100 |
| commit | 13cc065ec014b86369dfe4ad60d1a43fa06fd251 (patch) | |
| tree | 684690c61b7b59758c2aac132c65b81c86de0608 /extra/install-kimi.sh | |
dotfiles
Shell, editor and terminal configuration, the tools that go with them, and
szecret, an age-based secret manager whose store lives elsewhere.
History restarts here. What came before was not written to be read by
anyone else, and carried machine names, addresses and an encrypted secret
store; it is kept privately instead. What is left is meant to be safe on
any machine, including one whose owner is not me: see CLAUDE.md for the
rule it is written to.
Diffstat (limited to 'extra/install-kimi.sh')
| -rw-r--r-- | extra/install-kimi.sh | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/extra/install-kimi.sh b/extra/install-kimi.sh new file mode 100644 index 0000000..d1013ca --- /dev/null +++ b/extra/install-kimi.sh @@ -0,0 +1,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 "$@" |
