mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 19:11:03 +08:00
b51b9eb677
Update all github.com/Kilo-Org/kilo references to github.com/Kilo-Org/kilocode across package.json files, documentation, scripts, and configuration files. This reflects the repository rename from kilo to kilocode.
472 lines
14 KiB
Bash
Executable File
472 lines
14 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
APP=kilo # kilocode_change
|
|
|
|
MUTED='\033[0;2m'
|
|
RED='\033[0;31m'
|
|
ORANGE='\033[38;5;214m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# kilocode_change start - usage text
|
|
usage() {
|
|
cat <<EOF
|
|
Kilo Code Installer
|
|
|
|
Usage: install [options]
|
|
|
|
Options:
|
|
-h, --help Display this help message
|
|
-v, --version <version> Install a specific version (e.g., 1.0.180)
|
|
-b, --binary <path> Install from a local binary instead of downloading
|
|
--no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.)
|
|
|
|
Examples:
|
|
curl -fsSL https://kilo.ai/cli/install | bash
|
|
curl -fsSL https://kilo.ai/cli/install | bash -s -- --version 1.0.180
|
|
./install --binary /path/to/kilo
|
|
EOF
|
|
}
|
|
# kilocode_change end
|
|
|
|
requested_version=${VERSION:-}
|
|
no_modify_path=false
|
|
binary_path=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
-v|--version)
|
|
if [[ -n "${2:-}" ]]; then
|
|
requested_version="$2"
|
|
shift 2
|
|
else
|
|
echo -e "${RED}Error: --version requires a version argument${NC}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
-b|--binary)
|
|
if [[ -n "${2:-}" ]]; then
|
|
binary_path="$2"
|
|
shift 2
|
|
else
|
|
echo -e "${RED}Error: --binary requires a path argument${NC}"
|
|
exit 1
|
|
fi
|
|
;;
|
|
--no-modify-path)
|
|
no_modify_path=true
|
|
shift
|
|
;;
|
|
*)
|
|
echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
INSTALL_DIR=$HOME/.kilo/bin # kilocode_change
|
|
mkdir -p "$INSTALL_DIR"
|
|
|
|
# If --binary is provided, skip all download/detection logic
|
|
if [ -n "$binary_path" ]; then
|
|
if [ ! -f "$binary_path" ]; then
|
|
echo -e "${RED}Error: Binary not found at ${binary_path}${NC}"
|
|
exit 1
|
|
fi
|
|
specific_version="local"
|
|
else
|
|
raw_os=$(uname -s)
|
|
os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]')
|
|
case "$raw_os" in
|
|
Darwin*) os="darwin" ;;
|
|
Linux*) os="linux" ;;
|
|
MINGW*|MSYS*|CYGWIN*) os="windows" ;;
|
|
esac
|
|
|
|
arch=$(uname -m)
|
|
if [[ "$arch" == "aarch64" ]]; then
|
|
arch="arm64"
|
|
fi
|
|
if [[ "$arch" == "x86_64" ]]; then
|
|
arch="x64"
|
|
fi
|
|
|
|
if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then
|
|
rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)
|
|
if [ "$rosetta_flag" = "1" ]; then
|
|
arch="arm64"
|
|
fi
|
|
fi
|
|
|
|
combo="$os-$arch"
|
|
case "$combo" in
|
|
linux-x64|linux-arm64|darwin-x64|darwin-arm64|windows-x64)
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
archive_ext=".zip"
|
|
if [ "$os" = "linux" ]; then
|
|
archive_ext=".tar.gz"
|
|
fi
|
|
|
|
is_musl=false
|
|
if [ "$os" = "linux" ]; then
|
|
if [ -f /etc/alpine-release ]; then
|
|
is_musl=true
|
|
fi
|
|
|
|
if command -v ldd >/dev/null 2>&1; then
|
|
if ldd --version 2>&1 | grep -qi musl; then
|
|
is_musl=true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
needs_baseline=false
|
|
if [ "$arch" = "x64" ]; then
|
|
if [ "$os" = "linux" ]; then
|
|
if ! grep -qwi avx2 /proc/cpuinfo 2>/dev/null; then
|
|
needs_baseline=true
|
|
fi
|
|
fi
|
|
|
|
if [ "$os" = "darwin" ]; then
|
|
avx2=$(sysctl -n hw.optional.avx2_0 2>/dev/null || echo 0)
|
|
if [ "$avx2" != "1" ]; then
|
|
needs_baseline=true
|
|
fi
|
|
fi
|
|
|
|
if [ "$os" = "windows" ]; then
|
|
ps="(Add-Type -MemberDefinition \"[DllImport(\"\"kernel32.dll\"\")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);\" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)"
|
|
out=""
|
|
if command -v powershell.exe >/dev/null 2>&1; then
|
|
out=$(powershell.exe -NoProfile -NonInteractive -Command "$ps" 2>/dev/null || true)
|
|
elif command -v pwsh >/dev/null 2>&1; then
|
|
out=$(pwsh -NoProfile -NonInteractive -Command "$ps" 2>/dev/null || true)
|
|
fi
|
|
out=$(echo "$out" | tr -d '\r' | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')
|
|
if [ "$out" != "true" ] && [ "$out" != "1" ]; then
|
|
needs_baseline=true
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
target="$os-$arch"
|
|
if [ "$needs_baseline" = "true" ]; then
|
|
target="$target-baseline"
|
|
fi
|
|
if [ "$is_musl" = "true" ]; then
|
|
target="$target-musl"
|
|
fi
|
|
|
|
filename="$APP-$target$archive_ext"
|
|
|
|
|
|
if [ "$os" = "linux" ]; then
|
|
if ! command -v tar >/dev/null 2>&1; then
|
|
echo -e "${RED}Error: 'tar' is required but not installed.${NC}"
|
|
exit 1
|
|
fi
|
|
else
|
|
if ! command -v unzip >/dev/null 2>&1; then
|
|
echo -e "${RED}Error: 'unzip' is required but not installed.${NC}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$requested_version" ]; then
|
|
url="https://github.com/Kilo-Org/kilocode/releases/latest/download/$filename"
|
|
specific_version=$(curl -s https://api.github.com/repos/Kilo-Org/kilo/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
|
|
|
|
if [[ $? -ne 0 || -z "$specific_version" ]]; then
|
|
echo -e "${RED}Failed to fetch version information${NC}"
|
|
exit 1
|
|
fi
|
|
else
|
|
# Strip leading 'v' if present
|
|
requested_version="${requested_version#v}"
|
|
url="https://github.com/Kilo-Org/kilocode/releases/download/v${requested_version}/$filename"
|
|
specific_version=$requested_version
|
|
|
|
# Verify the release exists before downloading
|
|
http_status=$(curl -sI -o /dev/null -w "%{http_code}" "https://github.com/Kilo-Org/kilocode/releases/tag/v${requested_version}")
|
|
if [ "$http_status" = "404" ]; then
|
|
echo -e "${RED}Error: Release v${requested_version} not found${NC}"
|
|
echo -e "${MUTED}Available releases: https://github.com/Kilo-Org/kilocode/releases${NC}"
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
print_message() {
|
|
local level=$1
|
|
local message=$2
|
|
local color=""
|
|
|
|
case $level in
|
|
info) color="${NC}" ;;
|
|
warning) color="${NC}" ;;
|
|
error) color="${RED}" ;;
|
|
esac
|
|
|
|
echo -e "${color}${message}${NC}"
|
|
}
|
|
|
|
# kilocode_change start
|
|
check_version() {
|
|
if command -v kilo >/dev/null 2>&1; then
|
|
kilo_path=$(which kilo)
|
|
|
|
## Check the installed version
|
|
installed_version=$(kilo --version 2>/dev/null || echo "")
|
|
|
|
if [[ "$installed_version" != "$specific_version" ]]; then
|
|
print_message info "${MUTED}Installed version: ${NC}$installed_version."
|
|
else
|
|
print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed"
|
|
exit 0
|
|
fi
|
|
fi
|
|
}
|
|
# kilocode_change end
|
|
|
|
unbuffered_sed() {
|
|
if echo | sed -u -e "" >/dev/null 2>&1; then
|
|
sed -nu "$@"
|
|
elif echo | sed -l -e "" >/dev/null 2>&1; then
|
|
sed -nl "$@"
|
|
else
|
|
local pad="$(printf "\n%512s" "")"
|
|
sed -ne "s/$/\\${pad}/" "$@"
|
|
fi
|
|
}
|
|
|
|
print_progress() {
|
|
local bytes="$1"
|
|
local length="$2"
|
|
[ "$length" -gt 0 ] || return 0
|
|
|
|
local width=50
|
|
local percent=$(( bytes * 100 / length ))
|
|
[ "$percent" -gt 100 ] && percent=100
|
|
local on=$(( percent * width / 100 ))
|
|
local off=$(( width - on ))
|
|
|
|
local filled=$(printf "%*s" "$on" "")
|
|
filled=${filled// /■}
|
|
local empty=$(printf "%*s" "$off" "")
|
|
empty=${empty// /・}
|
|
|
|
printf "\r${ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4
|
|
}
|
|
|
|
download_with_progress() {
|
|
local url="$1"
|
|
local output="$2"
|
|
|
|
if [ -t 2 ]; then
|
|
exec 4>&2
|
|
else
|
|
exec 4>/dev/null
|
|
fi
|
|
|
|
local tmp_dir=${TMPDIR:-/tmp}
|
|
local basename="${tmp_dir}/kilo_install_$$" # kilocode_change
|
|
local tracefile="${basename}.trace"
|
|
|
|
rm -f "$tracefile"
|
|
mkfifo "$tracefile"
|
|
|
|
# Hide cursor
|
|
printf "\033[?25l" >&4
|
|
|
|
trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN
|
|
|
|
(
|
|
curl --trace-ascii "$tracefile" -fsL -o "$output" "$url" # kilocode_change
|
|
) &
|
|
local curl_pid=$!
|
|
|
|
unbuffered_sed \
|
|
-e 'y/ACDEGHLNORTV/acdeghlnortv/' \
|
|
-e '/^0000: content-length:/p' \
|
|
-e '/^<= recv data/p' \
|
|
"$tracefile" | \
|
|
{
|
|
local length=0
|
|
local bytes=0
|
|
|
|
while IFS=" " read -r -a line; do
|
|
[ "${#line[@]}" -lt 2 ] && continue
|
|
local tag="${line[0]} ${line[1]}"
|
|
|
|
if [ "$tag" = "0000: content-length:" ]; then
|
|
length="${line[2]}"
|
|
length=$(echo "$length" | tr -d '\r')
|
|
bytes=0
|
|
elif [ "$tag" = "<= recv" ]; then
|
|
local size="${line[3]}"
|
|
bytes=$(( bytes + size ))
|
|
if [ "$length" -gt 0 ]; then
|
|
print_progress "$bytes" "$length"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
wait $curl_pid
|
|
local ret=$?
|
|
echo "" >&4
|
|
return $ret
|
|
}
|
|
|
|
download_and_install() {
|
|
# kilocode_change start
|
|
print_message info "\n${MUTED}Installing ${NC}Kilo Code ${MUTED}version: ${NC}$specific_version"
|
|
local tmp_dir="${TMPDIR:-/tmp}/kilo_install_$$"
|
|
# kilocode_change end
|
|
mkdir -p "$tmp_dir"
|
|
|
|
if [[ "$os" == "windows" ]] || ! [ -t 2 ] || ! download_with_progress "$url" "$tmp_dir/$filename"; then
|
|
# Fallback to standard curl on Windows, non-TTY environments, or if custom progress fails
|
|
curl -f# -L -o "$tmp_dir/$filename" "$url" # kilocode_change
|
|
fi
|
|
|
|
if [ "$os" = "linux" ]; then
|
|
tar -xzf "$tmp_dir/$filename" -C "$tmp_dir"
|
|
else
|
|
unzip -q "$tmp_dir/$filename" -d "$tmp_dir"
|
|
fi
|
|
|
|
# kilocode_change start
|
|
mv "$tmp_dir/kilo" "$INSTALL_DIR"
|
|
chmod 755 "${INSTALL_DIR}/kilo"
|
|
# kilocode_change end
|
|
rm -rf "$tmp_dir"
|
|
}
|
|
|
|
install_from_binary() {
|
|
# kilocode_change start
|
|
print_message info "\n${MUTED}Installing ${NC}Kilo Code ${MUTED}from: ${NC}$binary_path"
|
|
cp "$binary_path" "${INSTALL_DIR}/kilo"
|
|
chmod 755 "${INSTALL_DIR}/kilo"
|
|
# kilocode_change end
|
|
}
|
|
|
|
if [ -n "$binary_path" ]; then
|
|
install_from_binary
|
|
else
|
|
check_version
|
|
download_and_install
|
|
fi
|
|
|
|
|
|
add_to_path() {
|
|
local config_file=$1
|
|
local command=$2
|
|
|
|
if grep -Fxq "$command" "$config_file"; then
|
|
print_message info "Command already exists in $config_file, skipping write."
|
|
elif [[ -w $config_file ]]; then
|
|
echo -e "\n# kilo" >> "$config_file" # kilocode_change
|
|
echo "$command" >> "$config_file"
|
|
print_message info "${MUTED}Successfully added ${NC}kilo ${MUTED}to \$PATH in ${NC}$config_file" # kilocode_change
|
|
else
|
|
print_message warning "Manually add the directory to $config_file (or similar):"
|
|
print_message info " $command"
|
|
fi
|
|
}
|
|
|
|
XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
|
|
|
|
current_shell=$(basename "$SHELL")
|
|
case $current_shell in
|
|
fish)
|
|
config_files="$HOME/.config/fish/config.fish"
|
|
;;
|
|
zsh)
|
|
config_files="${ZDOTDIR:-$HOME}/.zshrc ${ZDOTDIR:-$HOME}/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv"
|
|
;;
|
|
bash)
|
|
config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
|
|
;;
|
|
ash)
|
|
config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
|
|
;;
|
|
sh)
|
|
config_files="$HOME/.ashrc $HOME/.profile /etc/profile"
|
|
;;
|
|
*)
|
|
# Default case if none of the above matches
|
|
config_files="$HOME/.bashrc $HOME/.bash_profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile"
|
|
;;
|
|
esac
|
|
|
|
if [[ "$no_modify_path" != "true" ]]; then
|
|
config_file=""
|
|
for file in $config_files; do
|
|
if [[ -f $file ]]; then
|
|
config_file=$file
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ -z $config_file ]]; then
|
|
print_message warning "No config file found for $current_shell. You may need to manually add to PATH:"
|
|
print_message info " export PATH=$INSTALL_DIR:\$PATH"
|
|
elif [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then
|
|
case $current_shell in
|
|
fish)
|
|
add_to_path "$config_file" "fish_add_path $INSTALL_DIR"
|
|
;;
|
|
zsh)
|
|
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
|
|
;;
|
|
bash)
|
|
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
|
|
;;
|
|
ash)
|
|
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
|
|
;;
|
|
sh)
|
|
add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH"
|
|
;;
|
|
*)
|
|
export PATH=$INSTALL_DIR:$PATH
|
|
print_message warning "Manually add the directory to $config_file (or similar):"
|
|
print_message info " export PATH=$INSTALL_DIR:\$PATH"
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
|
|
if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then
|
|
echo "$INSTALL_DIR" >> $GITHUB_PATH
|
|
print_message info "Added $INSTALL_DIR to \$GITHUB_PATH"
|
|
fi
|
|
|
|
# kilocode_change start
|
|
echo -e ""
|
|
echo -e "██ ▄█▀ ██ ██ ▄████▄ ▄█████ ██ ██ "
|
|
echo -e "████ ██ ██ ██ ██ ██ ██ ██ "
|
|
echo -e "██ ▀█▄ ██ ██████ ▀████▀ ▀█████ ██████ ██ "
|
|
echo -e ""
|
|
echo -e ""
|
|
echo -e "${MUTED}Kilo includes free models so you can start immediately:${NC}"
|
|
echo -e ""
|
|
echo -e "cd <project> ${MUTED}# Open directory${NC}"
|
|
echo -e "kilo ${MUTED}# Run Kilo${NC}"
|
|
echo -e ""
|
|
echo -e "${MUTED}For more information visit ${NC}https://kilo.ai/docs"
|
|
echo -e ""
|
|
echo -e ""
|
|
# kilocode_change end
|