#!/usr/bin/env bash # Multica fork CLI — installer (Linux / macOS / WSL). # # Installs the fork-built `multica` CLI (with agent-arka runtime support, Arka # SSO, Russian i18n) from arka/public releases. # # curl -fsSL https://git.arka-ai.ru/arka/public/raw/branch/main/multica/install.sh | bash # # Environment: # MULTICA_VERSION pin a release (e.g. 0.6.1-arka). Default: newest multica-v* on git.arka-ai.ru/arka/public # MULTICA_BIN_DIR install dir (default: /usr/local/bin, else ~/.local/bin) # NO_COLOR 1 to disable color output if [ -z "${BASH_VERSION:-}" ]; then echo "The Multica installer needs bash. Run:" >&2 echo " curl -fsSL https://git.arka-ai.ru/arka/public/raw/branch/main/multica/install.sh | bash" >&2 exit 1 fi set -euo pipefail PUBLIC_API="${MULTICA_PUBLIC_API:-https://git.arka-ai.ru/api/v1}" PUBLIC_DL="${MULTICA_PUBLIC_DL:-https://git.arka-ai.ru/arka/public/releases/download}" REPO="arka/public" TAG_PREFIX="multica-v" if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'; C_RED=$'\033[31m'; C_BOLD=$'\033[1m'; C_RESET=$'\033[0m' else C_GREEN=''; C_YELLOW=''; C_RED=''; C_BOLD=''; C_RESET='' fi info() { printf '%s\n' "$*"; } ok() { printf '%s✓%s %s\n' "$C_GREEN" "$C_RESET" "$*"; } warn() { printf '%s⚠%s %s\n' "$C_YELLOW" "$C_RESET" "$*"; } die() { printf '%s✗%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; exit 1; } _mc_tmp="" cleanup() { [[ -n "${_mc_tmp:-}" ]] && rm -rf "$_mc_tmp"; } trap cleanup EXIT detect_platform() { local os arch os=$(uname -s | tr '[:upper:]' '[:lower:]') arch=$(uname -m) case "$arch" in x86_64|amd64) arch="amd64" ;; aarch64|arm64) arch="arm64" ;; *) die "Unsupported architecture: $arch" ;; esac case "$os" in linux) PLATFORM="linux-${arch}" ;; darwin) PLATFORM="darwin-${arch}" ;; mingw*|msys*|cygwin*) die "This curl installer is for Linux/macOS/WSL. On Windows run the PowerShell installer instead:"$'\n'" irm https://git.arka-ai.ru/arka/public/raw/branch/main/multica/install.ps1 | iex" ;; *) die "Unsupported OS: $os" ;; esac } fetch_latest_version() { local json tags json=$(curl -fsSL "${PUBLIC_API}/repos/${REPO}/releases?limit=50") || die "Cannot list releases at ${PUBLIC_API}/repos/${REPO}/releases" tags=$(printf '%s' "$json" | grep -oE '"tag_name":[[:space:]]*"'"${TAG_PREFIX}"'[^"]+"' | sed 's/.*"'"${TAG_PREFIX}"'//;s/"$//' || true) if [[ -z "$tags" ]]; then die "No ${TAG_PREFIX}* releases on ${REPO} yet" fi printf '%s\n' "$tags" | head -n 1 } sha256_file() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}' elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}' else die "Need sha256sum or shasum" fi } ensure_path() { local bindir="$1" case ":$PATH:" in *":${bindir}:"*) return 0 ;; esac local line="export PATH=\"${bindir}:\$PATH\"" local rc for rc in "${HOME}/.zprofile" "${HOME}/.zshrc" "${HOME}/.bash_profile" "${HOME}/.bashrc" "${HOME}/.profile"; do [[ -f "$rc" ]] || continue if grep -Fqs "$bindir" "$rc"; then return 0 fi done if [[ -n "${SHELL:-}" && "${SHELL}" == *zsh* ]]; then rc="${HOME}/.zshrc" else rc="${HOME}/.bashrc" [[ -f "$rc" ]] || rc="${HOME}/.profile" fi printf '\n# Multica CLI\n%s\n' "$line" >>"$rc" warn "Added ${bindir} to PATH in ${rc} (open a new shell, or: source ${rc})" } main() { printf '%s\n' "${C_BOLD}Multica${C_RESET} — fork CLI installer (agent-arka support)" command -v curl >/dev/null 2>&1 || die "curl is required" command -v tar >/dev/null 2>&1 || die "tar is required" detect_platform local version if [[ -n "${MULTICA_VERSION:-}" ]]; then version="${MULTICA_VERSION#v}" version="${version#multica-v}" info "Using pinned version ${version}" else info "Resolving latest Multica release…" version=$(fetch_latest_version) info "Latest: ${version}" fi local asset="multica-cli-${version}-${PLATFORM}.tar.gz" local url="${PUBLIC_DL}/${TAG_PREFIX}${version}/${asset}" _mc_tmp=$(mktemp -d) info "Downloading ${url} ..." curl -fsSL "$url" -o "$_mc_tmp/multica.tar.gz" || die "Failed to download ${asset}" info "Verifying checksum …" local expected actual expected=$(curl -fsSL "${PUBLIC_DL}/${TAG_PREFIX}${version}/checksums.txt" | awk -v a="$asset" '$2==a {print $1; exit}' 2>/dev/null || true) actual=$(sha256_file "$_mc_tmp/multica.tar.gz") if [[ -n "$expected" ]]; then if [[ "$expected" != "$actual" ]]; then die "Checksum mismatch for ${asset}: expected ${expected}, got ${actual}" fi ok "Checksum verified" else warn "No checksum entry for ${asset}; skipping verification" fi tar -xzf "$_mc_tmp/multica.tar.gz" -C "$_mc_tmp" multica || die "Failed to extract multica" local bindir if [[ -n "${MULTICA_BIN_DIR:-}" ]]; then bindir="${MULTICA_BIN_DIR}" elif [[ -w /usr/local/bin ]]; then bindir="/usr/local/bin" elif command -v sudo >/dev/null 2>&1; then bindir="/usr/local/bin" else bindir="${HOME}/.local/bin" fi mkdir -p "$bindir" if [[ ! -w "$bindir" ]]; then sudo mv "$_mc_tmp/multica" "$bindir/multica" || die "Cannot write to ${bindir}" else mv "$_mc_tmp/multica" "$bindir/multica" fi chmod +x "$bindir/multica" ensure_path "$bindir" ok "Multica CLI ${version} installed to ${bindir}/multica" rm -rf "$_mc_tmp"; _mc_tmp="" printf '\n' printf ' Next — connect to your Multica server:\n' printf ' multica setup self-host\n' printf ' Or for this instance:\n' printf ' multica setup self-host --server-url https://plan.arka-ai.ru --app-url https://plan.arka-ai.ru\n' printf '\n' } main "$@"