Ctrl K
ComunidadGuías…

install.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env bash
# any-console のバイナリ配布インストーラ。
#
# GitHub Releases から自分の OS/arch 向けの tarball を取得し、
# ~/.any-console へ展開する(Rust/cargo/Node/npm/Python venv の事前準備は不要。
# 実行時に git・tmux のみが必要)。
#
# 使い方:
#   curl -fsSL https://raw.githubusercontent.com/kt0319/any-console/main/install.sh | bash
#
# 冪等: 既存の ~/.any-console に対して再実行すると、data/・config.json・certs/
# には一切触れずバイナリ・スクリプト・agent_manifests のみを最新版へ差し替える
# (= アップデート導線もこのスクリプトの再実行に一本化している。
# `./any-console update` もバイナリ配布モードでは内部的にこのスクリプトを
# 再実行する)。サービスが既に登録済みなら(=更新シナリオ)反映のため
# 自動で再起動する。新規インストールでは対話が必要なサービス登録は行わず
# 案内のみ表示する(標準入力がパイプ占有される curl | bash 実行を想定)。
set -euo pipefail

REPO="kt0319/any-console"
INSTALL_DIR="${ANY_CONSOLE_INSTALL_DIR:-$HOME/.any-console}"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

info() { echo -e "${GREEN}$1${NC}"; }
warn() { echo -e "${YELLOW}$1${NC}"; }
error() { echo -e "${RED}Error: $1${NC}" >&2; exit 1; }

detect_target() {
  local os arch
  os="$(uname -s)"
  arch="$(uname -m)"
  case "$os" in
    Linux) os="unknown-linux-gnu" ;;
    Darwin) os="apple-darwin" ;;
    *) error "Unsupported OS: $os (any-console supports Linux and macOS)" ;;
  esac
  case "$arch" in
    x86_64|amd64) arch="x86_64" ;;
    aarch64|arm64) arch="aarch64" ;;
    *) error "Unsupported architecture: $arch" ;;
  esac
  echo "${arch}-${os}"
}

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || error "$1 is required but not found. Please install it first."
}

sha256_of_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
    error "Neither sha256sum nor shasum found — cannot verify checksum"
  fi
}

verify_checksum() {
  local file="$1" checksum_file="$2" expected actual
  expected="$(awk '{print $1}' "$checksum_file")"
  [ -n "$expected" ] || error "Checksum file is empty or malformed: $checksum_file"
  actual="$(sha256_of_file "$file")"
  if [ "$expected" != "$actual" ]; then
    error "Checksum mismatch for $(basename "$file"): expected $expected, got $actual"
  fi
  info "Checksum verified"
}

# 一時パスへコピーしてから rename する(同一ファイルシステム内の mv は
# atomic)。ダウンロード直後の展開物から INSTALL_DIR へ反映する際、コピー
# 途中でプロセスが落ちても INSTALL_DIR 側の既存ファイルが破損した状態で
# 中途半端に残らないようにするため。
atomic_install_file() {
  local src="$1" dest="$2" tmp
  tmp="${dest}.new.$$"
  cp "$src" "$tmp"
  mv "$tmp" "$dest"
}

atomic_install_dir() {
  local src="$1" dest="$2" tmp old
  tmp="${dest}.new.$$"
  rm -rf "$tmp"
  cp -R "$src" "$tmp"
  old="${dest}.old.$$"
  if [ -d "$dest" ]; then
    mv "$dest" "$old"
  fi
  mv "$tmp" "$dest"
  [ -d "$old" ] && rm -rf "$old"
  return 0
}

main() {
  require_cmd curl
  require_cmd tar

  local target
  target="$(detect_target)"
  info "Detected platform: $target"

  local tag
  if [ -n "${ANY_CONSOLE_VERSION:-}" ]; then
    tag="$ANY_CONSOLE_VERSION"
  else
    info "Looking up the latest release..."
    tag="$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" | grep -o '"tag_name": *"[^"]*"' | head -1 | cut -d'"' -f4)"
    [ -n "$tag" ] || error "Could not determine the latest release tag. Check https://github.com/$REPO/releases"
  fi

  local current_version=""
  [ -f "$INSTALL_DIR/VERSION" ] && current_version="$(cat "$INSTALL_DIR/VERSION")"
  if [ "$current_version" = "$tag" ] && [ "${ANY_CONSOLE_FORCE:-}" != "1" ]; then
    info "any-console is already up to date ($tag)"
    return
  fi
  info "Installing any-console $tag${current_version:+ (currently $current_version)}"

  local asset="any-console-${tag}-${target}.tar.gz"
  local url="https://github.com/$REPO/releases/download/$tag/$asset"
  local checksum_url="${url}.sha256"
  local tmp_dir
  tmp_dir="$(mktemp -d)"
  trap 'rm -rf "$tmp_dir"' EXIT

  info "Downloading $asset..."
  curl -fsSL -o "$tmp_dir/$asset" "$url" || error "Download failed: $url"
  info "Downloading checksum..."
  curl -fsSL -o "$tmp_dir/$asset.sha256" "$checksum_url" || error "Checksum download failed: $checksum_url"
  verify_checksum "$tmp_dir/$asset" "$tmp_dir/$asset.sha256"

  info "Extracting..."
  tar xzf "$tmp_dir/$asset" -C "$tmp_dir"
  local stage="$tmp_dir/any-console-${tag}-${target}"
  [ -d "$stage" ] || error "Unexpected archive layout (missing $stage)"

  mkdir -p "$INSTALL_DIR"
  # data/・config.json・certs/ には一切触れず、配布物のみを差し替える。
  atomic_install_file "$stage/any-console-server" "$INSTALL_DIR/any-console-server"
  atomic_install_file "$stage/any-console" "$INSTALL_DIR/any-console"
  atomic_install_file "$stage/VERSION" "$INSTALL_DIR/VERSION"
  atomic_install_dir "$stage/agent_manifests" "$INSTALL_DIR/agent_manifests"
  # scripts/(Claude Code hooks 用)は同梱を始めた版から入る。古い tarball
  # には無いため存在チェック付きで反映する。
  if [ -d "$stage/scripts" ]; then
    atomic_install_dir "$stage/scripts" "$INSTALL_DIR/scripts"
    chmod +x "$INSTALL_DIR/scripts/"*.sh
  fi
  chmod +x "$INSTALL_DIR/any-console-server" "$INSTALL_DIR/any-console"

  info "Installed to $INSTALL_DIR"

  echo ""
  info "Running non-interactive setup (dependency check, default bind)..."
  (cd "$INSTALL_DIR" && ./any-console setup --non-interactive)

  echo ""
  if (cd "$INSTALL_DIR" && ./any-console is-registered) 2>/dev/null; then
    info "Restarting the any-console service to apply the update..."
    if (cd "$INSTALL_DIR" && ./any-console restart); then
      info "=== Update complete ($tag) ==="
    else
      warn "Could not restart automatically — run: cd $INSTALL_DIR && ./any-console restart"
    fi
  else
    info "=== Install complete ($tag) ==="
    echo ""
    echo "Service registration (systemd/launchd) requires an interactive step."
    echo "To finish setup and start any-console as a background service, run:"
    echo ""
    echo "  cd $INSTALL_DIR && ./any-console setup"
  fi
  echo ""
  echo "To update later, just re-run this installer (or run './any-console update'):"
  echo ""
  echo "  curl -fsSL https://raw.githubusercontent.com/$REPO/main/install.sh | bash"
}

main "$@"