feat: полная поддержка macOS (Darwin arm64/x86_64)

- ai-setup.sh: brew shellenv + brew-ветки для jq/Node; npm-prefix теперь после установки Node
- ai-setup.sh: install_proxy использует OS_TAG/ARCH_TAG (качает darwin-arm64/amd64)
- ai-setup.sh: afplay в 5 звуковых блоках, портабельный sed -i (BSD), touch ~/.zshrc
- setup.sh: скрытие сетевых пунктов (2/3/4/6) на macOS + адаптация Статуса

Устраняет на маке: npm not found, «не удалось определить пакетный менеджер»,
«неизвестная архитектура: arm64». Сетевые скрипты (ru-bypass/ks-*) оставлены Linux-only.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Виталий Никитенко
2026-07-01 09:12:06 +03:00
parent 9e64088e46
commit 0f88f1e07a
2 changed files with 130 additions and 49 deletions

View File

@@ -17,6 +17,29 @@ PROXY_BIN="$BIN_DIR/claude-code-proxy"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
GLOBAL_RULES_SOURCE="$SCRIPT_DIR/home-configs/GLOBAL_RULES.md"
# ── 0. Определение ОС и архитектуры (глобально) ─────────────
# bash 3.2 на macOS: lowercasing через case, не через ${var,,}
OS_KERNEL="$(uname -s)" # Linux | Darwin | ...
OS_TAG=""
ARCH_TAG=""
case "$OS_KERNEL" in
Linux) OS_TAG="linux" ;;
Darwin) OS_TAG="darwin" ;;
*) OS_TAG="" ;;
esac
case "$(uname -m)" in
x86_64) ARCH_TAG="amd64" ;;
arm64|aarch64) ARCH_TAG="arm64" ;;
*) ARCH_TAG="" ;;
esac
# Портабельный sed -i: BSD (macOS) требует суффикс, GNU — нет
if [ "$OS_KERNEL" = "Darwin" ]; then
SED_INPLACE=(-i '')
else
SED_INPLACE=(-i)
fi
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}[OK]${NC} $*"; }
@@ -30,6 +53,20 @@ if [ "$EUID" -eq 0 ]; then
exit 1
fi
# ── Homebrew shellenv (macOS) ───────────────────────────────
# brew может быть установлен, но не в PATH текущего шелла (особенно
# после свежей установки). Подключаем shellenv, чтобы node/npm/jq
# стали видны через command -v в этой же сессии.
if [ "$OS_KERNEL" = "Darwin" ]; then
for _brew_prefix in /opt/homebrew /usr/local "$HOME/.homebrew"; do
if [ -x "$_brew_prefix/bin/brew" ]; then
eval "$("$_brew_prefix/bin/brew" shellenv)"
break
fi
done
unset _brew_prefix
fi
info "Проверяю зависимости (python3)..."
if ! command -v python3 &>/dev/null; then
err "Python 3 не установлен, но он требуется для работы скрипта."
@@ -38,8 +75,10 @@ success "Python 3 найден"
info "Проверяю зависимости (jq)..."
if ! command -v jq &>/dev/null; then
info "Устанавливаю jq (нужен sudo)..."
if command -v apt-get &>/dev/null; then
info "Устанавливаю jq..."
if command -v brew &>/dev/null; then
brew install jq
elif command -v apt-get &>/dev/null; then
sudo apt-get install -y jq
elif command -v dnf &>/dev/null; then
sudo dnf install -y jq
@@ -53,25 +92,19 @@ else
warn "jq не найден. statusline-command.sh и некоторые функции могут не работать."
fi
# ── 1. npm prefix в домашнюю папку ──────────────────────────
info "Настраиваю npm prefix..."
mkdir -p "$NPM_GLOBAL"
npm config set prefix "$NPM_GLOBAL"
success "npm prefix -> $NPM_GLOBAL"
export PATH="$NPM_GLOBAL/bin:$BIN_DIR:$PATH"
# ── 2. Node.js ───────────────────────────────────────────────
# ── 1. Node.js ───────────────────────────────────────────────
info "Проверяю Node.js..."
if ! command -v node &>/dev/null; then
info опытка установки Node.js (нужен sudo)..."
if command -v apt-get &>/dev/null; then
info ытаюсь установить Node.js..."
if command -v brew &>/dev/null; then
brew install node
elif command -v apt-get &>/dev/null; then
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
elif command -v dnf &>/dev/null; then
sudo dnf install -y nodejs
else
warn "Не удалось определить пакетный менеджер. Установите Node.js вручную."
warn "Не удалось определить пакетный менеджер. Установите Homebrew (https://brew.sh) или Node.js вручную."
fi
fi
if command -v node &>/dev/null; then
@@ -80,6 +113,19 @@ else
warn "Node.js не найден. Некоторые функции могут не работать."
fi
# ── 2. npm prefix в домашнюю папку ──────────────────────────
# После установки Node, чтобы npm гарантированно был доступен.
info "Настраиваю npm prefix..."
mkdir -p "$NPM_GLOBAL"
if command -v npm &>/dev/null; then
npm config set prefix "$NPM_GLOBAL"
success "npm prefix -> $NPM_GLOBAL"
else
warn "npm не найден — пропускаю настройку prefix (установите Node.js)."
fi
export PATH="$NPM_GLOBAL/bin:$BIN_DIR:$PATH"
# ── 3. Claude Code ───────────────────────────────────────────
info "Проверяю Claude Code..."
if ! command -v claude &>/dev/null; then
@@ -99,12 +145,9 @@ mkdir -p "$BIN_DIR"
install_proxy() {
info "Устанавливаю claude-code-proxy..."
ARCH=$(uname -m)
case "$ARCH" in
x86_64) ARCH_TAG="amd64" ;;
aarch64) ARCH_TAG="arm64" ;;
*) err "Неизвестная архитектура: $ARCH" ;;
esac
if [ -z "$OS_TAG" ] || [ -z "$ARCH_TAG" ]; then
err "Неизвестная платформа: kernel=$OS_KERNEL arch=$ARCH_TAG"
fi
LATEST=$(curl -fsSL "https://api.github.com/repos/raine/claude-code-proxy/releases/latest" \
| grep '"tag_name"' | sed 's/.*"tag_name": *"\(.*\)".*/\1/')
@@ -112,7 +155,7 @@ install_proxy() {
TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT
URL="https://github.com/raine/claude-code-proxy/releases/download/${LATEST}/claude-code-proxy-linux-${ARCH_TAG}.tar.gz"
URL="https://github.com/raine/claude-code-proxy/releases/download/${LATEST}/claude-code-proxy-${OS_TAG}-${ARCH_TAG}.tar.gz"
info "Скачиваю $URL"
curl -fsSL "$URL" -o "$TMP/proxy.tar.gz" || err "Не удалось скачать claude-code-proxy"
tar -xzf "$TMP/proxy.tar.gz" -C "$TMP"
@@ -590,7 +633,11 @@ PATHEOF
fi
}
add_path_to_rc "$HOME/.bashrc"
[ -f "$HOME/.zshrc" ] && add_path_to_rc "$HOME/.zshrc"
# На macOS дефолтный шелл — zsh, но ~/.zshrc может не существовать.
# Гарантируем наличие файла, иначе PATH не добавится и лаунчеры будут
# недоступны без ручного `exec`.
[ -f "$HOME/.zshrc" ] || touch "$HOME/.zshrc"
add_path_to_rc "$HOME/.zshrc"
# ── 8. Генерация Standalone скриптов ────────────────────────
@@ -983,6 +1030,7 @@ PYEOF
#!/usr/bin/env bash
# Minimal task-completion sound fallback
(
afplay /System/Library/Sounds/Glass.aiff 2>/dev/null ||
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
@@ -1074,6 +1122,7 @@ _setup_codex_sound_hooks() {
#!/usr/bin/env bash
# Minimal Codex turn-completion sound.
(
afplay /System/Library/Sounds/Glass.aiff 2>/dev/null ||
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
@@ -1084,6 +1133,7 @@ SOUNDEOF
#!/usr/bin/env bash
# Minimal Codex context auto-compact warning sound.
(
afplay /System/Library/Sounds/Basso.aiff 2>/dev/null ||
paplay /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null
@@ -1746,6 +1796,7 @@ source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/
"$agy_bin" --dangerously-skip-permissions "$@"
agy_exit=$?
(
afplay /System/Library/Sounds/Glass.aiff 2>/dev/null ||
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
@@ -1754,7 +1805,7 @@ exit $agy_exit
GEMINIEOF
chmod +x "$BIN_DIR/ai-gemini"
# Подменяем путь к agy, если BIN_DIR отличается от ~/.local/bin
[ "$BIN_DIR" != "$HOME/.local/bin" ] && sed -i "s|\$HOME/\.local/bin|\$HOME/${BIN_DIR#$HOME/}|g" "$BIN_DIR/ai-gemini"
[ "$BIN_DIR" != "$HOME/.local/bin" ] && sed "${SED_INPLACE[@]}" "s|\$HOME/\.local/bin|\$HOME/${BIN_DIR#$HOME/}|g" "$BIN_DIR/ai-gemini"
# === ai-cursor ===
cat > "$BIN_DIR/ai-cursor" << 'CURSOREOF'
@@ -1790,6 +1841,7 @@ _build_ai_sys_prompt > /dev/null
"$cursor_bin" --force "$@"
cursor_exit=$?
(
afplay /System/Library/Sounds/Glass.aiff 2>/dev/null ||
paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
pw-play --volume=1 /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null ||
aplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null
@@ -1798,7 +1850,7 @@ exit $cursor_exit
CURSOREOF
chmod +x "$BIN_DIR/ai-cursor"
# Подменяем путь к agent, если BIN_DIR отличается от ~/.local/bin
[ "$BIN_DIR" != "$HOME/.local/bin" ] && sed -i "s|\$HOME/\.local/bin|\$HOME/${BIN_DIR#$HOME/}|g" "$BIN_DIR/ai-cursor"
[ "$BIN_DIR" != "$HOME/.local/bin" ] && sed "${SED_INPLACE[@]}" "s|\$HOME/\.local/bin|\$HOME/${BIN_DIR#$HOME/}|g" "$BIN_DIR/ai-cursor"
# === ai-claude ===
cat > "$BIN_DIR/ai-claude" << 'CLAUDEEOF'