refactor(claude): settings.json отдан Claude Code, базовые настройки в settings.local.json

- Зачем:
  - Claude Code перезаписывает settings.json при каждом «always allow», что создавало
    конфликт с managed-копией из dotfiles при повторном запуске install.sh.
- Что:
  - settings.json удалён из репозитория, Claude Code владеет им полностью.
  - создан settings.local.json (базовые permissions + statusLine), деплоится через симлинк.
  - install.sh: копирование + шаблон заменены на ln -sf с бэкапом и guard для edge cases.
  - check.sh: проверка обновлена под симлинк вместо «файл + chmod 444».
  - тесты: старый тест копирования заменён на 4 новых (симлинк, бэкап, директория, stow-миграция).
- Проверка:
  - bash tests/test_install.sh (15 тестов).
  - bash agents/.agents/skills/dotfiles-check/check.sh.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ddadminandClaude Opus 4.6 committed 2026-03-31 10:28:41 +03:00
1 parent bdccd889fe
commit 9341853479
6 files changed
+117 -69

No files matched your search

+21 -30
View File
@@ -160,7 +160,7 @@ migrate_claude_stow_symlink() {
local base
base=$(basename "$item")
# git-tracked файлы остаются в репозитории
case "$base" in .gitignore|settings.json|skills) continue ;; esac
case "$base" in .gitignore|settings.local.json|skills) continue ;; esac
mv "$item" "$HOME/.claude/" 2>/dev/null || true
done
info "Рантайм-данные перенесены в ~/.claude/"
@@ -271,8 +271,10 @@ if [ -f "$OPENCODE_JSON_SRC" ]; then
fi
# ── Claude Code ──────────────────────────────────────────────────────
# settings.json КОПИРУЕТСЯ (не линкуется), чтобы Claude Code не модифицировал
# файл в репозитории. Локальные настройки — в settings.local.json.
# settings.local.json ЛИНКУЕТСЯ из репозитория (базовые permissions + statusLine).
# Claude Code не модифицирует settings.local.json — только читает и мержит
# с settings.json, который Claude Code создаёт и обновляет самостоятельно.
# Машинно-специфичные настройки (model, effortLevel) — в settings.json.
migrate_claude_stow_symlink
mkdir -p "$HOME/.claude"
@@ -282,35 +284,24 @@ if [ -d "$SKILLS_SRC" ]; then
ensure_symlink "$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
chmod 444 "$CLAUDE_SETTINGS_SRC"
if "$GIT_BIN" -C "$DOTFILES_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
if ! "$GIT_BIN" -C "$DOTFILES_DIR" show "HEAD:claude/.claude/settings.json" > "$CLAUDE_SETTINGS_DST"; then
warn "Не удалось прочитать committed settings.json, копирую текущий файл из репозитория"
cp -f "$CLAUDE_SETTINGS_SRC" "$CLAUDE_SETTINGS_DST"
fi
# settings.local.json — базовые настройки из репозитория (симлинк)
CLAUDE_LOCAL_SRC="$DOTFILES_DIR/claude/.claude/settings.local.json"
CLAUDE_LOCAL_DST="$HOME/.claude/settings.local.json"
if [ -f "$CLAUDE_LOCAL_SRC" ]; then
if [ -L "$CLAUDE_LOCAL_DST" ]; then
ln -sfnT "$CLAUDE_LOCAL_SRC" "$CLAUDE_LOCAL_DST"
info "settings.local.json → репозиторий"
elif [ -f "$CLAUDE_LOCAL_DST" ]; then
backup_existing_path "$CLAUDE_LOCAL_DST" "settings.local.json"
ln -s "$CLAUDE_LOCAL_SRC" "$CLAUDE_LOCAL_DST"
info "settings.local.json → репозиторий"
info "Машинно-специфичные настройки (model, effortLevel) теперь задаются через Claude Code"
elif [ -d "$CLAUDE_LOCAL_DST" ] || [ -e "$CLAUDE_LOCAL_DST" ]; then
warn "$CLAUDE_LOCAL_DST уже существует (не файл и не симлинк), удалите вручную"
else
cp -f "$CLAUDE_SETTINGS_SRC" "$CLAUDE_SETTINGS_DST"
ln -s "$CLAUDE_LOCAL_SRC" "$CLAUDE_LOCAL_DST"
info "settings.local.json → репозиторий"
fi
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 ────────────────────────────────────────────────────