#!/usr/bin/env bash set -euo pipefail DOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)" # --- Цвета --- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' info() { echo -e "${GREEN}[+]${NC} $*"; } warn() { echo -e "${YELLOW}[!]${NC} $*"; } error() { echo -e "${RED}[✗]${NC} $*"; } # --- Проверка stow --- if ! command -v stow &>/dev/null; then error "stow не найден. Установите: sudo apt install stow" exit 1 fi # --- Stow пакеты --- PACKAGES=(bash tmux vim zed vscode agents opencode codex gemini) info "Применяю stow пакеты..." cd "$DOTFILES_DIR" for pkg in "${PACKAGES[@]}"; do if [ -d "$pkg" ]; then stow -v --restow "$pkg" 2>&1 | sed "s/^/ /" else warn "Пакет $pkg не найден, пропускаю" fi done # --- Claude Code: установка без stow --- # settings.json КОПИРУЕТСЯ (не линкуется), чтобы Claude Code не модифицировал # файл в репозитории. Локальные настройки — в settings.local.json. # Миграция: если ~/.claude — stow-симлинк, раскрываем в реальную директорию if [ -L "$HOME/.claude" ]; then info "Миграция: ~/.claude — симлинк, преобразую в директорию..." CLAUDE_STOW_DIR=$(readlink -f "$HOME/.claude") rm "$HOME/.claude" mkdir -p "$HOME/.claude" # Переносим рантайм-данные из stow-директории for item in "$CLAUDE_STOW_DIR"/* "$CLAUDE_STOW_DIR"/.[!.]*; do [ -e "$item" ] || continue base=$(basename "$item") # Пропускаем git-tracked файлы — они останутся в репозитории case "$base" in .gitignore|settings.json|skills) continue ;; esac mv "$item" "$HOME/.claude/" 2>/dev/null || true done info "Рантайм-данные перенесены в ~/.claude/" fi mkdir -p "$HOME/.claude" # Skills (симлинк) SKILLS_SRC="$DOTFILES_DIR/agents/.agents/skills" if [ -d "$SKILLS_SRC" ]; then ln -sfn "$SKILLS_SRC" "$HOME/.claude/skills" fi # settings.json — копия из репозитория (не симлинк!) CLAUDE_SETTINGS_SRC="$DOTFILES_DIR/claude/.claude/settings.json" CLAUDE_SETTINGS_DST="$HOME/.claude/settings.json" if [ -f "$CLAUDE_SETTINGS_SRC" ]; then # Если settings.json в репо был изменён (например, Claude Code писал через симлинк) — сбрасываем if cd "$DOTFILES_DIR" && ! git diff --quiet claude/.claude/settings.json 2>/dev/null; then warn "claude/.claude/settings.json имеет локальные изменения — сбрасываю" git checkout claude/.claude/settings.json fi # Защищаем оригинал в репозитории chmod 444 "$CLAUDE_SETTINGS_SRC" # Копируем в ~/.claude/ (перезаписывает при повторном запуске) cp -f "$CLAUDE_SETTINGS_SRC" "$CLAUDE_SETTINGS_DST" chmod 644 "$CLAUDE_SETTINGS_DST" info "settings.json скопирован (оригинал защищён chmod 444)" fi # settings.local.json — локальные переопределения (не в git) CLAUDE_LOCAL="$HOME/.claude/settings.local.json" if [ ! -f "$CLAUDE_LOCAL" ]; then info "Создаю $CLAUDE_LOCAL (локальные настройки Claude)..." cat > "$CLAUDE_LOCAL" <<'EOF' { "model": "opus", "effortLevel": "high" } EOF else warn "$CLAUDE_LOCAL уже существует, пропускаю" fi # --- Bash: подключение в .bashrc --- BASHRC="$HOME/.bashrc" BASHRC_LINE='[ -f ~/.bash_custom ] && source ~/.bash_custom' if grep -q 'bash_custom' "$BASHRC" 2>/dev/null; then warn "~/.bashrc уже содержит bash_custom, пропускаю" else echo "" >> "$BASHRC" echo "# dotfiles" >> "$BASHRC" echo "$BASHRC_LINE" >> "$BASHRC" info "Добавлено в ~/.bashrc: $BASHRC_LINE" fi # --- WSL: hproxy.local (автоматический резолв при старте) --- if [ -n "${WSL_DISTRO_NAME:-}" ]; then HPROXY_SCRIPT="$DOTFILES_DIR/scripts/setup-hproxy.sh" if grep -q "hproxy.local" /etc/wsl.conf 2>/dev/null; then warn "/etc/wsl.conf уже содержит hproxy.local, пропускаю" else echo "" info "Обнаружен WSL. Скрипт $HPROXY_SCRIPT может автоматически" info "прописывать hproxy.local в /etc/hosts при каждом старте WSL (NAT mode)." echo -ne "${YELLOW}[?]${NC} Добавить boot command в /etc/wsl.conf? [y/N] " read -r answer if [[ "$answer" =~ ^[Yy]$ ]]; then # Добавляем [boot] секцию, если её нет if ! grep -q '^\[boot\]' /etc/wsl.conf 2>/dev/null; then printf '\n[boot]\n' | sudo tee -a /etc/wsl.conf > /dev/null fi sudo sed -i "/^\[boot\]/a command = \"$HPROXY_SCRIPT\"" /etc/wsl.conf info "Добавлено в /etc/wsl.conf. Перезапустите WSL: wsl --shutdown" else warn "Пропущено. Можно настроить вручную — см. README.md" fi fi fi info "Готово!"