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:
1 parent
346b3bfc61
commit
c3efe60a00
14 files changed
+122
-407
No files matched your search
@@ -30,19 +30,6 @@ if ((Test-Path "claude") -and -not (Test-Path "dot_claude")) {
|
|||||||
Write-Host " [OK] claude -> dot_claude"
|
Write-Host " [OK] claude -> dot_claude"
|
||||||
}
|
}
|
||||||
|
|
||||||
# codex → dot_codex (будет ~/.codex)
|
|
||||||
if ((Test-Path "codex") -and -not (Test-Path "dot_codex")) {
|
|
||||||
Rename-Item "codex" "dot_codex"
|
|
||||||
# Перемещаем содержимое .codex в корень и удаляем файлы skills
|
|
||||||
if (Test-Path "dot_codex/.codex") {
|
|
||||||
Move-Item "dot_codex/.codex/*" "dot_codex/" -ErrorAction SilentlyContinue
|
|
||||||
Remove-Item "dot_codex/.codex" -Recurse -Force -ErrorAction SilentlyContinue
|
|
||||||
}
|
|
||||||
# Удаляем старые файлы skills (будут созданы как симлинки)
|
|
||||||
Remove-Item "dot_codex/skills" -Recurse -Force -ErrorAction SilentlyContinue
|
|
||||||
Write-Host " [OK] codex -> dot_codex"
|
|
||||||
}
|
|
||||||
|
|
||||||
# vim/.vimrc → dot_vimrc (будет ~/.vimrc)
|
# vim/.vimrc → dot_vimrc (будет ~/.vimrc)
|
||||||
if ((Test-Path "vim/.vimrc") -and -not (Test-Path "dot_vimrc")) {
|
if ((Test-Path "vim/.vimrc") -and -not (Test-Path "dot_vimrc")) {
|
||||||
Move-Item "vim/.vimrc" "dot_vimrc"
|
Move-Item "vim/.vimrc" "dot_vimrc"
|
||||||
|
|||||||
@@ -30,14 +30,6 @@ if (Test-Path "$env:USERPROFILE\.claude\skills") {
|
|||||||
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.claude\skills" -Target $skillsSource
|
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.claude\skills" -Target $skillsSource
|
||||||
Write-Host "Created: ~/.claude/skills -> ~/.agents/skills"
|
Write-Host "Created: ~/.claude/skills -> ~/.agents/skills"
|
||||||
|
|
||||||
# Codex
|
|
||||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex\skills" | Out-Null
|
|
||||||
if (Test-Path "$env:USERPROFILE\.codex\skills\conventional-commits") {
|
|
||||||
Remove-Item "$env:USERPROFILE\.codex\skills\conventional-commits" -Force
|
|
||||||
}
|
|
||||||
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.codex\skills\conventional-commits" -Target "$skillsSource\conventional-commits"
|
|
||||||
Write-Host "Created: ~/.codex/skills/conventional-commits -> ~/.agents/skills/conventional-commits"
|
|
||||||
|
|
||||||
# Opencode
|
# Opencode
|
||||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode" | Out-Null
|
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode" | Out-Null
|
||||||
if (Test-Path "$env:USERPROFILE\.config\opencode\skills") {
|
if (Test-Path "$env:USERPROFILE\.config\opencode\skills") {
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ opencode/.config/opencode/package.json
|
|||||||
opencode/.config/opencode/node_modules/
|
opencode/.config/opencode/node_modules/
|
||||||
opencode/.config/opencode/bun.lock
|
opencode/.config/opencode/bun.lock
|
||||||
|
|
||||||
# Codex local files
|
|
||||||
codex/.codex/
|
|
||||||
!codex/.codex/skills/
|
|
||||||
|
|
||||||
# Gemini local files
|
# Gemini local files
|
||||||
gemini/.gemini/
|
gemini/.gemini/
|
||||||
!gemini/.gemini/policies/
|
!gemini/.gemini/policies/
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ This repository contains personal dotfiles and configurations for a highly produ
|
|||||||
* **Gemini CLI:** Configured via `gemini/.gemini/`.
|
* **Gemini CLI:** Configured via `gemini/.gemini/`.
|
||||||
* **Policies:** `readonly-commands.toml` allows critical commands like `git status`, `git diff`, and `git add` to run without confirmation.
|
* **Policies:** `readonly-commands.toml` allows critical commands like `git status`, `git diff`, and `git add` to run without confirmation.
|
||||||
* **Opencode:** MCP-based assistant configuration (`opencode.json`) with support for documentation, search, and web-reading.
|
* **Opencode:** MCP-based assistant configuration (`opencode.json`) with support for documentation, search, and web-reading.
|
||||||
* **Skill Bridges:** Symlinks are used to share skills across Claude, Codex, and Opencode.
|
* **Skill Bridges:** Symlinks are used to share skills across Claude and Opencode.
|
||||||
|
|
||||||
## 🚀 Usage & Maintenance
|
## 🚀 Usage & Maintenance
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ Chezmoi использует отдельный source dir `chezmoi/` внутр
|
|||||||
| `vscode` | `server-env-setup` для VS Code Server в WSL: секреты + авто-прокси |
|
| `vscode` | `server-env-setup` для VS Code Server в WSL: секреты + авто-прокси |
|
||||||
| `chatgpt` | Отдельный ярлык `ChatGPT Proxy` с запретом прямого запуска при ошибке |
|
| `chatgpt` | Отдельный ярлык `ChatGPT Proxy` с запретом прямого запуска при ошибке |
|
||||||
|
|
||||||
`install.sh` дополнительно настраивает opencode (симлинки, MCP-конфиг), claude (симлинкает `settings.local.json` из репозитория) и подключает bash_custom.
|
`install.sh` дополнительно настраивает opencode (симлинки, MCP-конфиг), claude (симлинк `~/.claude/skills` на общие скиллы) и подключает bash_custom.
|
||||||
|
|
||||||
### Windows (chezmoi)
|
### Windows (chezmoi)
|
||||||
|
|
||||||
@@ -76,9 +76,9 @@ Chezmoi использует отдельный source dir `chezmoi/` внутр
|
|||||||
| Инструмент | Что настраивается |
|
| Инструмент | Что настраивается |
|
||||||
|------------|-------------------|
|
|------------|-------------------|
|
||||||
| **Agents** | Каноничное хранилище скиллов: `~/.agents/skills/<name>/SKILL.md` |
|
| **Agents** | Каноничное хранилище скиллов: `~/.agents/skills/<name>/SKILL.md` |
|
||||||
| **Claude** | `~/.claude/skills` -> симлинк на agents; `settings.local.json` -> симлинк на репозиторий (базовые permissions + statusLine); `statusline-command.sh` -> копия из репозитория; `settings.json` - управляется Claude Code |
|
| **Claude** | `~/.claude/skills` -> симлинк на agents; настройки (`settings.json`, `settings.local.json`) - управляются Claude Code на машине |
|
||||||
| **[Opencode](https://github.com/anomalyco/opencode)** | MCP-серверы (context7, web-reader, playwright и др.), `~/.config/opencode/skills` -> симлинк на agents |
|
| **[Opencode](https://github.com/anomalyco/opencode)** | MCP-серверы (context7, web-reader, playwright и др.), `~/.config/opencode/skills` -> симлинк на agents |
|
||||||
| **Codex** | `~/.codex/skills/` -> симлинки на agents |
|
| **Codex** | `~/.codex` - обычный каталог, управляется Codex; скиллы - из общего хранилища agents |
|
||||||
| **Gemini** | Политики для CLI: pre-approved readonly команды |
|
| **Gemini** | Политики для CLI: pre-approved readonly команды |
|
||||||
|
|
||||||
## Настройка
|
## Настройка
|
||||||
@@ -221,5 +221,5 @@ stow проще и покрывает весь Linux/WSL workflow. chezmoi ну
|
|||||||
**Почему Windows PowerShell 5.1 не трогается?**
|
**Почему Windows PowerShell 5.1 не трогается?**
|
||||||
Если форсировать UTF-8 и менять профиль PS 5.1, можно сломать старые скрипты, `.bat`/`.cmd` и консольные утилиты. PS 7 - основной shell, PS 5.1 - режим совместимости.
|
Если форсировать UTF-8 и менять профиль PS 5.1, можно сломать старые скрипты, `.bat`/`.cmd` и консольные утилиты. PS 7 - основной shell, PS 5.1 - режим совместимости.
|
||||||
|
|
||||||
**Почему Claude `settings.local.json` - симлинк, а `settings.json` - нет?**
|
**Почему у Claude в репозитории нет настроек?**
|
||||||
Claude Code перезаписывает `settings.json` при каждом "always allow" - этот файл принадлежит Claude Code. Базовые permissions и statusLine живут в `settings.local.json`, который Claude Code только читает и мержит с `settings.json`. Симлинк из `~/.claude/settings.local.json` на файл в репозитории безопасен. Машинно-специфичные настройки (`model`, `effortLevel`) - в `settings.json`, управляются через Claude Code.
|
Все настройки Claude Code (`settings.json`, `settings.local.json`) принадлежат самому Claude Code: он перезаписывает их при каждом "always allow" и при смене модели. Список разрешений не ведём вручную - работаем с autoapprove. Из репозитория линкуются только скиллы. Машинно-специфичные настройки (`model`, `effortLevel`) - в `settings.json`, управляются через Claude Code.
|
||||||
@@ -2,6 +2,3 @@
|
|||||||
*
|
*
|
||||||
!skills
|
!skills
|
||||||
!.gitignore
|
!.gitignore
|
||||||
!settings.local.json
|
|
||||||
!statusline-command.sh
|
|
||||||
!CLAUDE.md
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Глобальный словарь рабочего процесса
|
|
||||||
|
|
||||||
Термины владельца, общие для всех проектов на этой машине.
|
|
||||||
|
|
||||||
## Ревью по температуре
|
|
||||||
|
|
||||||
Ось — сколько авторского контекста несёт ревьюер:
|
|
||||||
|
|
||||||
- **Горячее ревью** — автор сам перечитывает свой артефакт глазами читателя,
|
|
||||||
не автора. Контекст полный, дёшево. Текстовые огрехи правит по месту молча;
|
|
||||||
находку уровня решений (противоречие, дыра в охвате) предъявляет владельцу,
|
|
||||||
не исправляя и не замалчивая.
|
|
||||||
- **Тёплое ревью** — другой агент, получивший бриф. Контекст частичный: знает
|
|
||||||
замысел, но не варился в нём.
|
|
||||||
- **Холодное ревью** — свежая сессия или субагент без общего контекста.
|
|
||||||
Независимо, дороже всех.
|
|
||||||
|
|
||||||
Просьба «перечитай свежим взглядом» двусмысленна — уточни температуру;
|
|
||||||
по умолчанию имеется в виду горячее.
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
{
|
|
||||||
"permissions": {
|
|
||||||
"allow": [
|
|
||||||
"Bash(cat *)",
|
|
||||||
"Bash(ls)",
|
|
||||||
"Bash(ls *)",
|
|
||||||
"Bash(wc *)",
|
|
||||||
"Bash(head *)",
|
|
||||||
"Bash(tail *)",
|
|
||||||
"Bash(find *)",
|
|
||||||
"Bash(tree)",
|
|
||||||
"Bash(tree *)",
|
|
||||||
"Bash(file *)",
|
|
||||||
"Bash(stat *)",
|
|
||||||
"Bash(diff *)",
|
|
||||||
"Bash(realpath *)",
|
|
||||||
"Bash(readlink *)",
|
|
||||||
"Bash(basename *)",
|
|
||||||
"Bash(dirname *)",
|
|
||||||
"Bash(sort *)",
|
|
||||||
"Bash(uniq *)",
|
|
||||||
"Bash(cut *)",
|
|
||||||
"Bash(awk *)",
|
|
||||||
"Bash(sed *)",
|
|
||||||
"Bash(grep *)",
|
|
||||||
"Bash(rg *)",
|
|
||||||
"Bash(jq *)",
|
|
||||||
"Bash(yq *)",
|
|
||||||
"Bash(tr *)",
|
|
||||||
"Bash(echo *)",
|
|
||||||
"Bash(printf *)",
|
|
||||||
"Bash(which *)",
|
|
||||||
"Bash(type *)",
|
|
||||||
"Bash(command -v *)",
|
|
||||||
"Bash(env)",
|
|
||||||
"Bash(env *)",
|
|
||||||
"Bash(printenv)",
|
|
||||||
"Bash(printenv *)",
|
|
||||||
"Bash(pwd)",
|
|
||||||
"Bash(uname *)",
|
|
||||||
"Bash(whoami)",
|
|
||||||
"Bash(id)",
|
|
||||||
"Bash(date)",
|
|
||||||
"Bash(date *)",
|
|
||||||
"Bash(hostname)",
|
|
||||||
"Bash(git log*)",
|
|
||||||
"Bash(git diff*)",
|
|
||||||
"Bash(git status*)",
|
|
||||||
"Bash(git show*)",
|
|
||||||
"Bash(git branch*)",
|
|
||||||
"Bash(git remote -v*)",
|
|
||||||
"Bash(git remote show*)",
|
|
||||||
"Bash(git tag*)",
|
|
||||||
"Bash(git stash list*)",
|
|
||||||
"Bash(git rev-parse*)",
|
|
||||||
"Bash(git ls-files*)",
|
|
||||||
"Bash(git blame*)",
|
|
||||||
"Bash(git shortlog*)",
|
|
||||||
"Bash(git config --get*)",
|
|
||||||
"Bash(git config --list*)",
|
|
||||||
"Bash(git fetch*)",
|
|
||||||
"Bash(git add*)",
|
|
||||||
"Bash(docker ps*)",
|
|
||||||
"Bash(docker logs*)",
|
|
||||||
"Bash(docker inspect*)",
|
|
||||||
"Bash(docker images*)",
|
|
||||||
"Bash(docker stats*)",
|
|
||||||
"Bash(docker info*)",
|
|
||||||
"Bash(docker version*)",
|
|
||||||
"Bash(docker compose ps*)",
|
|
||||||
"Bash(docker compose logs*)",
|
|
||||||
"Bash(docker compose:*)",
|
|
||||||
"Bash(docker restart:*)",
|
|
||||||
"Bash(docker exec:*)",
|
|
||||||
"Bash(docker run:*)",
|
|
||||||
"Bash(docker stop:*)",
|
|
||||||
"Bash(docker rm:*)",
|
|
||||||
"Bash(curl *)",
|
|
||||||
"Bash(wget *)",
|
|
||||||
"Bash(mkdir *)",
|
|
||||||
"Bash(cp *)",
|
|
||||||
"Bash(mv *)",
|
|
||||||
"Bash(touch *)",
|
|
||||||
"Bash(chmod *)",
|
|
||||||
"Bash(ln *)",
|
|
||||||
"Bash(npm *)",
|
|
||||||
"Bash(npx *)",
|
|
||||||
"Bash(yarn *)",
|
|
||||||
"Bash(pnpm *)",
|
|
||||||
"Bash(bun *)",
|
|
||||||
"Bash(go *)",
|
|
||||||
"Bash(cargo *)",
|
|
||||||
"Bash(make *)",
|
|
||||||
"Bash(python *)",
|
|
||||||
"Bash(python3 *)",
|
|
||||||
"Bash(pip *)",
|
|
||||||
"Bash(pip3 *)",
|
|
||||||
"Bash(pytest *)",
|
|
||||||
"Bash(node *)",
|
|
||||||
"Bash(deno *)",
|
|
||||||
"Bash(stow *)",
|
|
||||||
"Bash(gh api:*)",
|
|
||||||
"Bash(gh search:*)",
|
|
||||||
"Bash(gh issue:*)",
|
|
||||||
"Bash(gh repo:*)",
|
|
||||||
"Bash(codex *)",
|
|
||||||
"Bash(timeout 600 codex exec *)",
|
|
||||||
"Bash(rm -f /tmp/claude-plan-*)",
|
|
||||||
"Bash(rm -f /tmp/codex-*)",
|
|
||||||
"WebSearch",
|
|
||||||
"mcp__claude_ai_Context7__resolve-library-id",
|
|
||||||
"Write(/tmp/claude-plan-*)",
|
|
||||||
"Write(/tmp/codex-*)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"statusLine": {
|
|
||||||
"type": "command",
|
|
||||||
"command": "bash ~/.claude/statusline-command.sh"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Статусная строка Claude Code. JSON приходит на stdin.
|
|
||||||
#
|
|
||||||
# user@host:.../dir (branch) | Model Name (NM context) ctx:N% | 5h:N% 7d:N%
|
|
||||||
#
|
|
||||||
# Работает в Linux и в Git Bash на Windows: без `hostname -s`, jq не обязателен.
|
|
||||||
|
|
||||||
# Порог, после которого путь сокращается до .../<последний каталог>
|
|
||||||
MAX_PATH_LEN="${STATUSLINE_MAX_PATH_LEN:-28}"
|
|
||||||
|
|
||||||
input="$(cat)"
|
|
||||||
|
|
||||||
# ── Разбор JSON ───────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
# Числовое поле $2 внутри объекта $1 (резервный разбор, без jq).
|
|
||||||
json_num() {
|
|
||||||
printf '%s' "$input" \
|
|
||||||
| tr -d ' \t\n\r' \
|
|
||||||
| grep -o "\"$1\":{[^}]*}" \
|
|
||||||
| grep -o "\"$2\":[0-9.eE+-]*" \
|
|
||||||
| head -1 \
|
|
||||||
| cut -d: -f2
|
|
||||||
}
|
|
||||||
|
|
||||||
# Строковое поле $2 внутри объекта $1 (резервный разбор, без jq).
|
|
||||||
json_str() {
|
|
||||||
printf '%s' "$input" \
|
|
||||||
| tr -d '\n\r' \
|
|
||||||
| grep -o "\"$1\"[[:space:]]*:[[:space:]]*{[^}]*}" \
|
|
||||||
| grep -o "\"$2\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" \
|
|
||||||
| head -1 \
|
|
||||||
| sed 's/.*"[[:space:]]*:[[:space:]]*"//; s/"$//'
|
|
||||||
}
|
|
||||||
|
|
||||||
if command -v jq >/dev/null 2>&1; then
|
|
||||||
IFS=$'\t' read -r cwd display_name ctx_pct rate5h rate7d <<EOF
|
|
||||||
$(printf '%s' "$input" | jq -r '
|
|
||||||
def num: if type == "number" then tostring else "" end;
|
|
||||||
[ (.workspace.current_dir // ""),
|
|
||||||
(.model.display_name // ""),
|
|
||||||
(.context_window.used_percentage | num),
|
|
||||||
(.rate_limits.five_hour.used_percentage | num),
|
|
||||||
(.rate_limits.seven_day.used_percentage | num)
|
|
||||||
] | @tsv' 2>/dev/null)
|
|
||||||
EOF
|
|
||||||
else
|
|
||||||
cwd="$(json_str workspace current_dir)"
|
|
||||||
display_name="$(json_str model display_name)"
|
|
||||||
ctx_pct="$(json_num context_window used_percentage)"
|
|
||||||
rate5h="$(json_num five_hour used_percentage)"
|
|
||||||
rate7d="$(json_num seven_day used_percentage)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Проценты в JSON дробные — округляем до целых.
|
|
||||||
round_pct() {
|
|
||||||
case "$1" in
|
|
||||||
''|null) return 0 ;;
|
|
||||||
esac
|
|
||||||
awk -v v="$1" 'BEGIN { printf "%d", (v < 0 ? -int(-v + 0.5) : int(v + 0.5)) }' 2>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx_pct="$(round_pct "$ctx_pct")"
|
|
||||||
rate5h="$(round_pct "$rate5h")"
|
|
||||||
rate7d="$(round_pct "$rate7d")"
|
|
||||||
|
|
||||||
# ── Путь ──────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
# В Git Bash current_dir может прийти с обратными слэшами.
|
|
||||||
path="${cwd//\\//}"
|
|
||||||
home="${HOME//\\//}"
|
|
||||||
|
|
||||||
if [ -n "$home" ]; then
|
|
||||||
if [ "$path" = "$home" ]; then
|
|
||||||
path="~"
|
|
||||||
else
|
|
||||||
case "$path" in
|
|
||||||
"$home"/*) path="~${path#"$home"}" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${#path}" -gt "$MAX_PATH_LEN" ]; then
|
|
||||||
path=".../${path##*/}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Остальные секции ──────────────────────────────────────────────────
|
|
||||||
|
|
||||||
branch=""
|
|
||||||
if [ -n "$cwd" ]; then
|
|
||||||
branch="$(git -C "$cwd" rev-parse --abbrev-ref HEAD 2>/dev/null)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Размер контекста уже внутри display_name, убираем только префикс «Claude ».
|
|
||||||
model="${display_name#Claude }"
|
|
||||||
|
|
||||||
user="${USER:-${USERNAME:-$(id -un 2>/dev/null)}}"
|
|
||||||
host="${HOSTNAME:-$(hostname 2>/dev/null)}"
|
|
||||||
host="${host%%.*}"
|
|
||||||
|
|
||||||
GREEN=$'\033[32m'
|
|
||||||
YELLOW=$'\033[33m'
|
|
||||||
PURPLE=$'\033[35m'
|
|
||||||
CYAN=$'\033[36m'
|
|
||||||
RESET=$'\033[0m'
|
|
||||||
|
|
||||||
out="${GREEN}${user}@${host}${RESET}:${YELLOW}${path}${RESET}"
|
|
||||||
[ -n "$branch" ] && out="${out} ${PURPLE}(${branch})${RESET}"
|
|
||||||
out="${out} | ${CYAN}${model}${RESET}"
|
|
||||||
[ -n "$ctx_pct" ] && out="${out} ctx:${ctx_pct}%"
|
|
||||||
|
|
||||||
rates=""
|
|
||||||
[ -n "$rate5h" ] && rates="${rates} 5h:${rate5h}%"
|
|
||||||
[ -n "$rate7d" ] && rates="${rates} 7d:${rate7d}%"
|
|
||||||
[ -n "$rates" ] && out="${out} |${rates}"
|
|
||||||
|
|
||||||
printf '%s\n' "$out"
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
# Claude Code управляется вручную через install.sh (копирование, не симлинк).
|
# Claude Code управляется вручную через install.sh (точечные симлинки).
|
||||||
# Этот файл не даёт stow случайно создать симлинк ~/.claude.
|
# Этот файл не даёт stow случайно создать симлинк ~/.claude.
|
||||||
\.claude
|
\.claude
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../agents/.agents/skills/conventional-commits
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../agents/.agents/skills/coordinator-loop
|
|
||||||
+49
-52
@@ -144,28 +144,36 @@ wsl_conf_has_boot_command() {
|
|||||||
' "$1" 2>/dev/null
|
' "$1" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Миграция: если ~/.claude — stow-симлинк, раскрыть в директорию.
|
# Миграция: если $1 — stow-симлинк (пакет был свёрнут в репозиторий),
|
||||||
migrate_claude_stow_symlink() {
|
# раскрыть в настоящий каталог и перенести содержимое. Остальные аргументы —
|
||||||
[ -L "$HOME/.claude" ] || return 0
|
# имена git-tracked файлов, которые остаются в репозитории.
|
||||||
|
migrate_folded_symlink() {
|
||||||
|
local link="$1"
|
||||||
|
shift
|
||||||
|
[ -L "$link" ] || return 0
|
||||||
|
|
||||||
info "Миграция: ~/.claude — симлинк, преобразую в директорию..."
|
info "Миграция: $link — симлинк, преобразую в директорию..."
|
||||||
local stow_dir
|
local stow_dir
|
||||||
stow_dir="$(readlink -f "$HOME/.claude" 2>/dev/null || true)"
|
stow_dir="$(readlink -f "$link" 2>/dev/null || true)"
|
||||||
rm "$HOME/.claude"
|
rm "$link"
|
||||||
mkdir -p "$HOME/.claude"
|
mkdir -p "$link"
|
||||||
|
|
||||||
if [ -n "$stow_dir" ] && [ -d "$stow_dir" ]; then
|
if [ -n "$stow_dir" ] && [ -d "$stow_dir" ]; then
|
||||||
for item in "$stow_dir"/* "$stow_dir"/.[!.]*; do
|
for item in "$stow_dir"/* "$stow_dir"/.[!.]*; do
|
||||||
[ -e "$item" ] || continue
|
[ -e "$item" ] || [ -L "$item" ] || continue
|
||||||
local base
|
local base skip s
|
||||||
base=$(basename "$item")
|
base=$(basename "$item")
|
||||||
# git-tracked файлы остаются в репозитории
|
# git-tracked файлы остаются в репозитории
|
||||||
case "$base" in .gitignore|settings.local.json|skills) continue ;; esac
|
skip=""
|
||||||
mv "$item" "$HOME/.claude/" 2>/dev/null || true
|
for s in "$@"; do
|
||||||
|
[ "$base" = "$s" ] && skip=1
|
||||||
|
done
|
||||||
|
[ -n "$skip" ] && continue
|
||||||
|
mv "$item" "$link/" 2>/dev/null || true
|
||||||
done
|
done
|
||||||
info "Рантайм-данные перенесены в ~/.claude/"
|
info "Рантайм-данные перенесены в $link/"
|
||||||
else
|
else
|
||||||
warn "Не удалось прочитать источник старого симлинка ~/.claude, продолжаю без миграции данных"
|
warn "Не удалось прочитать источник старого симлинка $link, продолжаю без миграции данных"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +186,7 @@ migrate_claude_stow_symlink() {
|
|||||||
#
|
#
|
||||||
# Обход повторяет логику stow, а не перебирает файлы подряд: если каталога в
|
# Обход повторяет логику stow, а не перебирает файлы подряд: если каталога в
|
||||||
# HOME нет, конфликта быть не может и всё поддерево пропускается. Это заодно
|
# HOME нет, конфликта быть не может и всё поддерево пропускается. Это заодно
|
||||||
# отсекает свёрнутые пакеты (~/.codex, ~/.vscode-server) с их гигабайтами
|
# отсекает свёрнутые пакеты (~/.vscode-server) с их гигабайтами
|
||||||
# рантайм-данных.
|
# рантайм-данных.
|
||||||
backup_conflicting_stow_targets() {
|
backup_conflicting_stow_targets() {
|
||||||
local pkg=""
|
local pkg=""
|
||||||
@@ -370,7 +378,7 @@ if ! command -v "$STOW_BIN" &>/dev/null; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PACKAGES=(bash tmux vim wezterm kitty vscode agents codex gemini proxy-client chatgpt)
|
PACKAGES=(bash tmux vim wezterm kitty vscode agents gemini proxy-client chatgpt)
|
||||||
AVAILABLE_PACKAGES=()
|
AVAILABLE_PACKAGES=()
|
||||||
|
|
||||||
info "Применяю stow пакеты..."
|
info "Применяю stow пакеты..."
|
||||||
@@ -445,52 +453,41 @@ if [ -f "$OPENCODE_JSON_SRC" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ── Claude Code ──────────────────────────────────────────────────────
|
# ── Claude Code ──────────────────────────────────────────────────────
|
||||||
# settings.local.json ЛИНКУЕТСЯ из репозитория (базовые permissions + statusLine).
|
# Из репозитория линкуются только skills. Настройки (settings.json,
|
||||||
# Claude Code не модифицирует settings.local.json — только читает и мержит
|
# settings.local.json) принадлежат Claude Code и живут только на машине.
|
||||||
# с settings.json, который Claude Code создаёт и обновляет самостоятельно.
|
|
||||||
# Машинно-специфичные настройки (model, effortLevel) — в settings.json.
|
|
||||||
|
|
||||||
migrate_claude_stow_symlink
|
migrate_folded_symlink "$HOME/.claude" .gitignore skills
|
||||||
mkdir -p "$HOME/.claude"
|
mkdir -p "$HOME/.claude"
|
||||||
|
|
||||||
|
# Уборка артефактов прежних версий установщика: битые симлинки на удалённые
|
||||||
|
# из репозитория файлы и забытая копия statusline (наша — по строке-маркеру).
|
||||||
|
for stale in CLAUDE.md settings.local.json; do
|
||||||
|
stale_path="$HOME/.claude/$stale"
|
||||||
|
if [ -L "$stale_path" ]; then
|
||||||
|
case "$(readlink "$stale_path" 2>/dev/null || true)" in
|
||||||
|
"$DOTFILES_DIR"/*)
|
||||||
|
rm "$stale_path"
|
||||||
|
info "Удалён устаревший симлинк ~/.claude/$stale"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -f "$HOME/.claude/statusline-command.sh" ] && [ ! -L "$HOME/.claude/statusline-command.sh" ] \
|
||||||
|
&& grep -q "Статусная строка Claude Code" "$HOME/.claude/statusline-command.sh" 2>/dev/null; then
|
||||||
|
rm "$HOME/.claude/statusline-command.sh"
|
||||||
|
info "Удалена устаревшая копия ~/.claude/statusline-command.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
# Skills (симлинк)
|
# Skills (симлинк)
|
||||||
if [ -d "$SKILLS_SRC" ]; then
|
if [ -d "$SKILLS_SRC" ]; then
|
||||||
ensure_symlink "$SKILLS_SRC" "$HOME/.claude/skills"
|
ensure_symlink "$SKILLS_SRC" "$HOME/.claude/skills"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Глобальный CLAUDE.md — словарь рабочего процесса (симлинк)
|
# ── Codex ────────────────────────────────────────────────────────────
|
||||||
CLAUDE_MD_SRC="$DOTFILES_DIR/claude/.claude/CLAUDE.md"
|
# Пакета в репозитории нет: ~/.codex — обычный каталог, его заполняет Codex.
|
||||||
if [ -f "$CLAUDE_MD_SRC" ]; then
|
# Миграция раскрывает старый свёрнутый симлинк и переносит рантайм-данные.
|
||||||
ensure_symlink "$CLAUDE_MD_SRC" "$HOME/.claude/CLAUDE.md"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# settings.local.json — базовые настройки из репозитория (симлинк)
|
migrate_folded_symlink "$HOME/.codex" .gitkeep
|
||||||
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
|
|
||||||
ln -s "$CLAUDE_LOCAL_SRC" "$CLAUDE_LOCAL_DST"
|
|
||||||
info "settings.local.json → репозиторий"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# statusline-command.sh — копия из репозитория (на Windows симлинки ненадёжны)
|
|
||||||
CLAUDE_STATUSLINE_SRC="$DOTFILES_DIR/claude/.claude/statusline-command.sh"
|
|
||||||
CLAUDE_STATUSLINE_DST="$HOME/.claude/statusline-command.sh"
|
|
||||||
if [ -f "$CLAUDE_STATUSLINE_SRC" ]; then
|
|
||||||
install -m 755 "$CLAUDE_STATUSLINE_SRC" "$CLAUDE_STATUSLINE_DST"
|
|
||||||
info "statusline-command.sh скопирован в ~/.claude/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ── Bash: .bashrc ────────────────────────────────────────────────────
|
# ── Bash: .bashrc ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
+66
-63
@@ -21,7 +21,8 @@ assert_file_contains() {
|
|||||||
|
|
||||||
assert_not_exists() {
|
assert_not_exists() {
|
||||||
local path="$1"
|
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() {
|
setup_fixture() {
|
||||||
@@ -37,7 +38,7 @@ setup_fixture() {
|
|||||||
# zed/.config/opencode и т.п.) весят гигабайты, переполняют /tmp и ломают
|
# zed/.config/opencode и т.п.) весят гигабайты, переполняют /tmp и ломают
|
||||||
# stow конфликтами, поэтому в тестовое дерево не попадает.
|
# stow конфликтами, поэтому в тестовое дерево не попадает.
|
||||||
git -C "$REPO_ROOT" ls-files -z --cached --others --exclude-standard -- \
|
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 \
|
claude proxy-client chatgpt scripts \
|
||||||
| tar -C "$REPO_ROOT" --null -T - -cf - \
|
| tar -C "$REPO_ROOT" --null -T - -cf - \
|
||||||
| tar -xf - -C "$repo_root"
|
| tar -xf - -C "$repo_root"
|
||||||
@@ -225,22 +226,71 @@ test_existing_wezterm_config_is_backed_up() {
|
|||||||
assert_file_contains "$backup" 'require("wezterm")'
|
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
|
local fixture repo_root home_dir backup
|
||||||
fixture="$(setup_fixture)"
|
fixture="$(setup_fixture)"
|
||||||
repo_root="$fixture/repo"
|
repo_root="$fixture/repo"
|
||||||
home_dir="$fixture/home"
|
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"
|
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"
|
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)"
|
test_claude_stale_artifacts_are_removed() {
|
||||||
[ -z "$backup" ] || fail "Folded package contents must not be backed up: $backup"
|
local fixture repo_root home_dir
|
||||||
assert_file_contains "$home_dir/.codex/auth.json" "{}"
|
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() {
|
test_migrates_legacy_zed_config_symlink() {
|
||||||
@@ -358,53 +408,7 @@ test_does_not_follow_unrelated_local_symlink() {
|
|||||||
assert_not_exists "$unrelated_local/bin"
|
assert_not_exists "$unrelated_local/bin"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_settings_local_is_symlinked_to_repo() {
|
test_stow_migration_preserves_legacy_files() {
|
||||||
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() {
|
|
||||||
local fixture repo_root home_dir stow_target
|
local fixture repo_root home_dir stow_target
|
||||||
fixture="$(setup_fixture)"
|
fixture="$(setup_fixture)"
|
||||||
repo_root="$fixture/repo"
|
repo_root="$fixture/repo"
|
||||||
@@ -414,14 +418,14 @@ test_stow_migration_preserves_legacy_settings_local() {
|
|||||||
# Simulate old stow layout: ~/.claude → repo dir
|
# Simulate old stow layout: ~/.claude → repo dir
|
||||||
stow_target="$repo_root/claude/.claude"
|
stow_target="$repo_root/claude/.claude"
|
||||||
ln -s "$stow_target" "$home_dir/.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"
|
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
|
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"
|
[ -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" ] || 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
|
# 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"
|
[ -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_foreign_kitty_config_symlink_is_backed_up
|
||||||
test_rerun_does_not_backup_managed_kitty_config
|
test_rerun_does_not_backup_managed_kitty_config
|
||||||
test_existing_wezterm_config_is_backed_up
|
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_migrates_legacy_zed_config_symlink
|
||||||
test_stops_legacy_migration_when_listing_fails
|
test_stops_legacy_migration_when_listing_fails
|
||||||
test_does_not_migrate_unrelated_config_symlink
|
test_does_not_migrate_unrelated_config_symlink
|
||||||
test_does_not_follow_unrelated_local_symlink
|
test_does_not_follow_unrelated_local_symlink
|
||||||
test_settings_local_is_symlinked_to_repo
|
test_stow_migration_preserves_legacy_files
|
||||||
test_settings_local_backup_on_existing_file
|
|
||||||
test_settings_local_dir_is_skipped
|
|
||||||
test_stow_migration_preserves_legacy_settings_local
|
|
||||||
test_rerun_does_not_duplicate_bashrc_line
|
test_rerun_does_not_duplicate_bashrc_line
|
||||||
test_repairs_nested_skills_directory_bug
|
test_repairs_nested_skills_directory_bug
|
||||||
test_preserves_nonempty_skills_directory
|
test_preserves_nonempty_skills_directory
|
||||||
|
|||||||
Reference in new issue
Block a user