#!/usr/bin/env bash # Agent Arka — daemon + web dashboard installer (Linux / macOS / WSL). # # curl -fsSL https://git.arka-ai.ru/arka/public/raw/branch/main/agent-arka/install.sh | bash # # Environment: # AGENT_ARKA_VERSION pin a release (e.g. 2026.9.1). Default: newest agent-arka-v* on git.arka-ai.ru/arka/public # AGENT_ARKA_HOME data dir. Existing ~/.librefang is reused; else ~/.agent-arka # AGENT_ARKA_INSTALL_DIR binary dir (default: $AGENT_ARKA_HOME/bin) # AGENT_ARKA_AUTO_START 1/true/yes to run `agent-arka start` when :4545 is free (default: 1) # AGENT_ARKA_INIT 1 to run `agent-arka init --quick` when no config.toml exists (default: 1) # LIBREFANG_* names for the same keys still work. # Fail with a clear hint when piped into POSIX `sh` (dash) — this script needs # bash (pipefail, [[ ]], indirect expansion). `curl … | bash`, not `| sh`. if [ -z "${BASH_VERSION:-}" ]; then echo "Agent Arka installer needs bash. Run:" >&2 echo " curl -fsSL https://git.arka-ai.ru/arka/public/raw/branch/main/agent-arka/install.sh | bash" >&2 exit 1 fi set -euo pipefail PUBLIC_API="${AGENT_ARKA_PUBLIC_API:-https://git.arka-ai.ru/api/v1}" PUBLIC_DL="${AGENT_ARKA_PUBLIC_DL:-https://git.arka-ai.ru/arka/public/releases/download}" REPO="arka/public" TAG_PREFIX="agent-arka-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; } _aa_tmp="" cleanup() { [[ -n "${_aa_tmp:-}" ]] && rm -rf "$_aa_tmp"; } trap cleanup EXIT brand_env() { local suffix="$1" local new_name="AGENT_ARKA_${suffix}" local old_name="LIBREFANG_${suffix}" local value="${!new_name:-}" if [[ -n "${value// }" ]]; then printf '%s\n' "$value" return 0 fi value="${!old_name:-}" if [[ -n "${value// }" ]]; then printf '%s\n' "$value" return 0 fi return 1 } is_on() { case "${1:-}" in 1|true|TRUE|yes|YES|on|ON) return 0 ;; *) return 1 ;; esac } detect_platform() { local os arch os=$(uname -s | tr '[:upper:]' '[:lower:]') arch=$(uname -m) case "$arch" in x86_64|amd64) arch="x86_64" ;; aarch64|arm64) arch="aarch64" ;; *) 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/WSL. On Windows download Agent Arka_*_x64-setup.exe from https://git.arka-ai.ru/arka/public/releases/tag/agent-arka-v2026.9.1 (SmartScreen: More info → Run anyway). Or install WSL and re-run: wsl --install" ;; *) die "Unsupported OS: $os" ;; esac } resolve_home() { local override if override=$(brand_env HOME 2>/dev/null); then HOME_DIR="$override" return fi if [[ -d "${HOME}/.librefang" ]]; then HOME_DIR="${HOME}/.librefang" return fi HOME_DIR="${HOME}/.agent-arka" } port_in_use() { local port="$1" if command -v ss >/dev/null 2>&1; then ss -ltn 2>/dev/null | grep -qE ":${port}([[:space:]]|$)" return $? fi if command -v lsof >/dev/null 2>&1; then lsof -iTCP:"$port" -sTCP:LISTEN >/dev/null 2>&1 return $? fi (echo >/dev/tcp/127.0.0.1/"$port") >/dev/null 2>&1 } 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# Agent Arka\n%s\n' "$line" >>"$rc" warn "Added ${bindir} to PATH in ${rc} (open a new shell, or: source ${rc})" } # Normalize a CalVer "YYYY.M.D" into a single sortable integer (YYYYMMDD pads). ver_cmp_key() { printf '%s' "$1" | awk -F. '{ printf "%04d%02d%02d", $1, $2, $3 }' 2>/dev/null || printf '%s' 0 } # Installed version, or empty when there is no binary/detectable version. installed_version() { local bin="$1" out [[ -x "$bin" ]] || return 1 out=$("$bin" --version 2>/dev/null | head -n 1) || return 1 printf '%s\n' "$out" | grep -oE '[0-9]{4}\.[0-9]+(\.[0-9]+)?' | tail -n 1 } main() { printf '%s\n' "${C_BOLD}Agent Arka${C_RESET} — web dashboard installer" command -v curl >/dev/null 2>&1 || die "curl is required" command -v tar >/dev/null 2>&1 || die "tar is required" detect_platform resolve_home local bindir if bindir=$(brand_env INSTALL_DIR 2>/dev/null); then : else bindir="${HOME_DIR}/bin" fi mkdir -p "$bindir" "$HOME_DIR" local version if version=$(brand_env VERSION 2>/dev/null); then version="${version#v}" version="${version#agent-arka-v}" info "Using pinned version ${version}" else info "Resolving latest Agent Arka release…" version=$(fetch_latest_version) info "Latest: ${version}" fi # Update handling: detect an existing install and skip / stop / back it up. local existing existing=$(installed_version "${bindir}/agent-arka" 2>/dev/null || true) if [[ -n "$existing" ]]; then local ek tk ek=$(ver_cmp_key "$existing") tk=$(ver_cmp_key "$version") if [[ "$ek" == "$tk" ]]; then info "Already up to date: agent-arka ${existing} (target ${version})" ensure_path "$bindir" return 0 fi if [[ "$ek" -gt "$tk" ]]; then warn "Downgrading ${existing} -> ${version}" else info "Upgrading ${existing} -> ${version}" fi # Bring the running daemon down before replacing the binary. if AGENT_ARKA_HOME="${HOME_DIR}" LIBREFANG_HOME="${HOME_DIR}" "${bindir}/agent-arka" stop >/dev/null 2>&1; then ok "Stopped running agent-arka ${existing}" fi # Keep a rollback copy of the current binary. cp -f "${bindir}/agent-arka" "${bindir}/agent-arka.previous" 2>/dev/null || true fi local tag="${TAG_PREFIX}${version}" local asset="agent-arka-${version}-${PLATFORM}.tar.gz" local url="${PUBLIC_DL}/${tag}/${asset}" local sums_url="${PUBLIC_DL}/${tag}/SHA256SUMS" _aa_tmp=$(mktemp -d) info "Downloading ${asset}" if ! curl -fsSL --retry 3 -o "${_aa_tmp}/${asset}" "$url"; then die "No package for ${PLATFORM} in ${tag}. See https://git.arka-ai.ru/arka/public/releases" fi curl -fsSL -o "${_aa_tmp}/SHA256SUMS" "$sums_url" || die "Missing SHA256SUMS for ${tag}" local expected actual expected=$(grep -E "[[:space:]]${asset}\$" "${_aa_tmp}/SHA256SUMS" | awk '{print $1}' | head -n 1) [[ -n "$expected" ]] || die "SHA256SUMS has no entry for ${asset}" actual=$(sha256_file "${_aa_tmp}/${asset}") [[ "$expected" == "$actual" ]] || die "SHA256 mismatch for ${asset} (got ${actual}, want ${expected})" ok "Checksum ok" tar -xzf "${_aa_tmp}/${asset}" -C "$_aa_tmp" [[ -f "${_aa_tmp}/agent-arka" ]] || die "Archive did not contain agent-arka" chmod 755 "${_aa_tmp}/agent-arka" "${_aa_tmp}/agent-arka" --version >/dev/null || die "Downloaded binary failed to run on this host" cp -f "${_aa_tmp}/agent-arka" "${bindir}/agent-arka" ln -sfn agent-arka "${bindir}/librefang" ok "Installed ${bindir}/agent-arka ($("${bindir}/agent-arka" --version 2>/dev/null | head -n 1))" ensure_path "$bindir" export PATH="${bindir}:$PATH" local do_init do_start do_init=$(brand_env INIT 2>/dev/null || echo 1) do_start=$(brand_env AUTO_START 2>/dev/null || echo 1) if is_on "$do_init" && [[ ! -f "${HOME_DIR}/config.toml" ]]; then info "First run: agent-arka init --quick" AGENT_ARKA_HOME="${HOME_DIR}" LIBREFANG_HOME="${HOME_DIR}" "${bindir}/agent-arka" init --quick || warn "init --quick failed; run: agent-arka init" fi if is_on "$do_start"; then if port_in_use 4545; then warn "Port 4545 is already in use — not starting a second daemon" else info "Starting daemon" AGENT_ARKA_HOME="${HOME_DIR}" LIBREFANG_HOME="${HOME_DIR}" "${bindir}/agent-arka" start || warn "agent-arka start failed" fi fi printf '\n' ok "Open the web UI: ${C_BOLD}http://127.0.0.1:4545${C_RESET}" info "Sign in with Arka AI (account at https://arka-ai.ru)." info "For models, put ARKA_API_KEY in ${HOME_DIR}/secrets.env (create a key at https://arka-ai.ru)." info "Docs: https://git.arka-ai.ru/arka/public/src/branch/main/agent-arka" } if [[ "${AGENT_ARKA_INSTALLER_SOURCE_ONLY:-}" == 1 ]]; then return 0 2>/dev/null || true fi main "$@"