refactor(agents): убраны настройки Claude из git и пакет codex

Claude: из репозитория удалены settings.local.json (разрешения не нужны
при autoapprove), statusline-command.sh и устаревший CLAUDE.md; линкуются
только skills. install.sh убирает артефакты прежних прогонов.

Codex: пакет удалён целиком, ~/.codex - обычный каталог. Персональные
мостики скиллов убраны; миграция раскрывает свёрнутый симлинк и переносит
рантайм-данные. Чищены chezmoi-скрипты.

install.sh: migrate_claude_stow_symlink обобщена в migrate_folded_symlink.
Тесты: 3 устаревших удалены, 3 добавлены; assert_not_exists ловит битые
симлинки.
This commit is contained in:
Dmitry Dementiev committed 2026-10-10 17:15:34 +02:00
1 parent 346b3bfc61
commit c3efe60a00
14 files changed
+122 -407

No files matched your search

+66 -63
View File
@@ -21,7 +21,8 @@ assert_file_contains() {
assert_not_exists() {
local path="$1"
[ ! -e "$path" ] || fail "Path should not exist: $path"
# -e не видит битые симлинки, поэтому проверяем и -L
[ ! -e "$path" ] && [ ! -L "$path" ] || fail "Path should not exist: $path"
}
setup_fixture() {
@@ -37,7 +38,7 @@ setup_fixture() {
# zed/.config/opencode и т.п.) весят гигабайты, переполняют /tmp и ломают
# stow конфликтами, поэтому в тестовое дерево не попадает.
git -C "$REPO_ROOT" ls-files -z --cached --others --exclude-standard -- \
install.sh bash tmux vim zed kitty wezterm vscode agents opencode codex gemini \
install.sh bash tmux vim zed kitty wezterm vscode agents opencode gemini \
claude proxy-client chatgpt scripts \
| tar -C "$REPO_ROOT" --null -T - -cf - \
| tar -xf - -C "$repo_root"
@@ -225,22 +226,71 @@ test_existing_wezterm_config_is_backed_up() {
assert_file_contains "$backup" 'require("wezterm")'
}
test_folded_package_runtime_files_are_not_backed_up() {
test_codex_runtime_dir_is_unmanaged() {
local fixture repo_root home_dir backup
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
home_dir="$fixture/home"
# ~/.codex — обычный каталог с рантайм-данными Codex; install.sh его не трогает.
mkdir -p "$home_dir/.codex"
printf '%s\n' '{}' > "$home_dir/.codex/auth.json"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >"$fixture/install.out"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >"$fixture/install2.out"
[ -d "$home_dir/.codex" ] || fail "Expected ~/.codex to stay a directory"
[ ! -L "$home_dir/.codex" ] || fail "~/.codex must not become a symlink"
backup="$(find "$repo_root" "$home_dir" -name '*.bak.*' -print -quit)"
[ -z "$backup" ] || fail "Codex runtime files must not be backed up: $backup"
assert_file_contains "$home_dir/.codex/auth.json" "{}"
}
test_migrates_folded_codex_symlink() {
local fixture repo_root home_dir legacy_dir
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
home_dir="$fixture/home"
mkdir -p "$home_dir"
# Старая схема: ~/.codex — симлинк на каталог внутри репозитория с рантайм-данными
legacy_dir="$fixture/legacy-repo-codex"
mkdir -p "$legacy_dir"
printf '%s\n' '{"token":"x"}' > "$legacy_dir/auth.json"
printf '%s\n' 'HTTPS_PROXY=http://hproxy.local' > "$legacy_dir/.env"
ln -s "$legacy_dir" "$home_dir/.codex"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >"$fixture/install.out"
# ~/.codex свёрнут в симлинк на пакет: файлы внутри — уже наши, не конфликт.
printf '%s\n' '{}' > "$home_dir/.codex/auth.json"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >"$fixture/install2.out"
[ -d "$home_dir/.codex" ] || fail "Expected ~/.codex to become a directory"
[ ! -L "$home_dir/.codex" ] || fail "Expected ~/.codex to stop being a symlink"
assert_file_contains "$home_dir/.codex/auth.json" '"token":"x"'
assert_file_contains "$home_dir/.codex/.env" "hproxy.local"
}
backup="$(find "$repo_root" "$home_dir" -name '*.bak.*' -print -quit)"
[ -z "$backup" ] || fail "Folded package contents must not be backed up: $backup"
assert_file_contains "$home_dir/.codex/auth.json" "{}"
test_claude_stale_artifacts_are_removed() {
local fixture repo_root home_dir
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
home_dir="$fixture/home"
mkdir -p "$home_dir/.claude"
# Артефакты прежнего установщика: симлинки на удалённые из репозитория файлы
# и наша копия statusline (узнаётся по строке-маркеру).
ln -s "$repo_root/claude/.claude/CLAUDE.md" "$home_dir/.claude/CLAUDE.md"
ln -s "$repo_root/claude/.claude/settings.local.json" "$home_dir/.claude/settings.local.json"
printf '#!/usr/bin/env bash\n# Статусная строка Claude Code. JSON приходит на stdin.\n' \
> "$home_dir/.claude/statusline-command.sh"
# Чужой файл с похожим именем трогать нельзя
printf 'echo mine\n' > "$home_dir/.claude/statusline-mine.sh"
chmod +x "$home_dir/.claude/statusline-command.sh"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >"$fixture/install.out"
assert_not_exists "$home_dir/.claude/CLAUDE.md"
assert_not_exists "$home_dir/.claude/settings.local.json"
assert_not_exists "$home_dir/.claude/statusline-command.sh"
assert_file_contains "$home_dir/.claude/statusline-mine.sh" "echo mine"
[ -L "$home_dir/.claude/skills" ] || fail "Expected skills symlink to be created"
}
test_migrates_legacy_zed_config_symlink() {
@@ -358,53 +408,7 @@ test_does_not_follow_unrelated_local_symlink() {
assert_not_exists "$unrelated_local/bin"
}
test_settings_local_is_symlinked_to_repo() {
local fixture repo_root home_dir
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
home_dir="$fixture/home"
mkdir -p "$home_dir"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >/tmp/test-install.out
[ -L "$home_dir/.claude/settings.local.json" ] || fail "Expected settings.local.json to be a symlink"
local target
target="$(readlink -f "$home_dir/.claude/settings.local.json")"
local expected
expected="$(readlink -f "$repo_root/claude/.claude/settings.local.json")"
[ "$target" = "$expected" ] || fail "settings.local.json points to $target, expected $expected"
}
test_settings_local_backup_on_existing_file() {
local fixture repo_root home_dir
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
home_dir="$fixture/home"
mkdir -p "$home_dir/.claude"
echo '{"model":"sonnet"}' > "$home_dir/.claude/settings.local.json"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >/tmp/test-install.out
[ -L "$home_dir/.claude/settings.local.json" ] || fail "Expected settings.local.json to become a symlink"
local backup
backup="$(find "$home_dir/.claude" -maxdepth 1 -name 'settings.local.json.bak.*' -print -quit)"
[ -n "$backup" ] || fail "Expected backup for existing settings.local.json"
assert_file_contains "$backup" '"model":"sonnet"'
}
test_settings_local_dir_is_skipped() {
local fixture repo_root home_dir
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
home_dir="$fixture/home"
mkdir -p "$home_dir/.claude/settings.local.json"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >/tmp/test-install.out
[ -d "$home_dir/.claude/settings.local.json" ] || fail "Expected directory to be preserved (not replaced)"
}
test_stow_migration_preserves_legacy_settings_local() {
test_stow_migration_preserves_legacy_files() {
local fixture repo_root home_dir stow_target
fixture="$(setup_fixture)"
repo_root="$fixture/repo"
@@ -414,14 +418,14 @@ test_stow_migration_preserves_legacy_settings_local() {
# Simulate old stow layout: ~/.claude → repo dir
stow_target="$repo_root/claude/.claude"
ln -s "$stow_target" "$home_dir/.claude"
# Put a legacy settings.local.json in the stow target (would have been gitignored before)
# Put a legacy local file in the stow target (раньше settings.local.json
# был git-tracked и пропускался; теперь это машинные данные — переносим)
echo '{"model":"opus"}' > "$stow_target/legacy-local.json"
run_install "$repo_root" "$home_dir" env WSL_DISTRO_NAME= INSTALL_INTERACTIVE_MODE=never >/tmp/test-install.out
[ -d "$home_dir/.claude" ] || fail "Expected ~/.claude to become a directory"
[ ! -L "$home_dir/.claude" ] || fail "Expected ~/.claude to stop being a symlink"
[ -L "$home_dir/.claude/settings.local.json" ] || fail "Expected settings.local.json symlink after migration"
# legacy-local.json should have been moved from stow dir to real ~/.claude
[ -f "$home_dir/.claude/legacy-local.json" ] || fail "Expected legacy file to be migrated"
}
@@ -643,15 +647,14 @@ main() {
test_foreign_kitty_config_symlink_is_backed_up
test_rerun_does_not_backup_managed_kitty_config
test_existing_wezterm_config_is_backed_up
test_folded_package_runtime_files_are_not_backed_up
test_codex_runtime_dir_is_unmanaged
test_migrates_folded_codex_symlink
test_claude_stale_artifacts_are_removed
test_migrates_legacy_zed_config_symlink
test_stops_legacy_migration_when_listing_fails
test_does_not_migrate_unrelated_config_symlink
test_does_not_follow_unrelated_local_symlink
test_settings_local_is_symlinked_to_repo
test_settings_local_backup_on_existing_file
test_settings_local_dir_is_skipped
test_stow_migration_preserves_legacy_settings_local
test_stow_migration_preserves_legacy_files
test_rerun_does_not_duplicate_bashrc_line
test_repairs_nested_skills_directory_bug
test_preserves_nonempty_skills_directory