feat: полная изоляция моделей между ai-* и гибридный persistence effort

Раньше все ai-* лаунчеры делили один ~/.claude и общий settings.json, из-за
чего кастомная модель (openai/gpt-5.5) из ai-openrouter протекала в пикер
ai-claude. Теперь каждый сторонний провайдер изолирован в своём
CLAUDE_CONFIG_DIR (~/.config/ai-setup/cfg/<launcher>) - свои settings.json и
.claude.json, ноль протечек. ai-claude остаётся на ~/.claude (нативный логин).

Пикеры /model приведены к требуемому виду:
- ai-deepseek: только DeepSeek V4 Pro (opus) и DeepSeek V4 Flash (haiku),
  дефолт Pro; через availableModels + ANTHROPIC_DEFAULT_*_MODEL_NAME
- ai-kimi: только Kimi K2.6 (opus)
- ai-claude: только нативные модели Claude
Общие skills и CLAUDE.md шарятся симлинком из ~/.claude.

Persistence effort - гибрид:
- low/medium/high/xhigh живут нативно в settings.json лаунчера, /effort
  внутри сессии работает свободно и уровень сохраняется
- max нельзя сохранить в settings.json (session-only), поэтому он
  восстанавливается через CLAUDE_CODE_EFFORT_LEVEL; в такой max-сессии
  /effort залочен (ограничение Claude Code), выход - AI_EFFORT=<lvl> ai-*
Текущий уровень ловит статусбар в ~/.cache/ai-setup/effort_<launcher>.

Удалён устаревший effort-save-hook (заменён нативным persistence + гибридом),
почищен из ~/.claude/settings.json и осиротевший кэш model_*.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 07:33:30 +03:00
parent 07983ea84e
commit f8465580e0
5 changed files with 166 additions and 121 deletions

View File

@@ -1,24 +0,0 @@
#!/usr/bin/env bash
# Сохраняет текущий effortLevel в кэш лаунчера при завершении сессии.
# /effort внутри Claude Code обновляет settings.json - мы читаем оттуда.
launcher="${AI_LAUNCHER:-}"
[ -z "$launcher" ] && exit 0
cat /dev/stdin > /dev/null 2>&1 # drain stdin (Claude Code передаёт JSON)
mkdir -p "$HOME/.cache/ai-setup"
python3 - "$HOME/.claude/settings.json" "$HOME/.cache/ai-setup" "$launcher" <<'PYEOF'
import json, os, sys
settings_path, cache_dir, launcher = sys.argv[1], sys.argv[2], sys.argv[3]
if not os.path.exists(settings_path):
sys.exit(0)
try:
d = json.load(open(settings_path))
except Exception:
sys.exit(0)
effort = d.get('effortLevel', '')
if effort:
open(os.path.join(cache_dir, f'effort_{launcher}'), 'w').write(effort)
model = d.get('model', '')
if model:
open(os.path.join(cache_dir, f'model_{launcher}'), 'w').write(model)
PYEOF
exit 0