Раньше все 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>
144 lines
6.5 KiB
Bash
Executable File
144 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# tests/test_fixes.sh - unit tests for code-review fixes in ai-setup.sh
|
|
# Run: bash tests/test_fixes.sh
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT="$(cd "$(dirname "$0")/.." && pwd)/scripts/ai-setup.sh"
|
|
GLOBAL_RULES_SOURCE="$(cd "$(dirname "$0")/.." && pwd)/home-configs/GLOBAL_RULES.md"
|
|
PASS=0; FAIL=0
|
|
|
|
ok() { echo "[PASS] $1"; PASS=$((PASS+1)); }
|
|
fail() { echo "[FAIL] $1"; FAIL=$((FAIL+1)); }
|
|
|
|
# Extract sections
|
|
GPT_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' "$SCRIPT")
|
|
KIMI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' "$SCRIPT")
|
|
GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT")
|
|
HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT")
|
|
|
|
# ── ai-gpt: auto-install codex ────────────────────────────────────────────
|
|
test_gpt_autoinstall() {
|
|
if echo "$GPT_SECTION" | grep -q 'curl -fsSL https://chatgpt.com/codex/install.sh'; then
|
|
ok "ai-gpt: auto-installs codex via official install script"
|
|
else
|
|
fail "ai-gpt: missing codex auto-install"
|
|
fi
|
|
}
|
|
|
|
# ── ai-gpt: no proxy logic (simplified launcher) ──────────────────────────
|
|
test_gpt_no_proxy() {
|
|
if echo "$GPT_SECTION" | grep -q 'ANTHROPIC_BASE_URL'; then
|
|
fail "ai-gpt: still contains proxy logic (ANTHROPIC_BASE_URL)"
|
|
else
|
|
ok "ai-gpt: proxy logic removed (no ANTHROPIC_BASE_URL)"
|
|
fi
|
|
}
|
|
|
|
# ── ai-kimi: launches claude with Kimi backend ────────────────────────────
|
|
test_kimi_claude_launcher() {
|
|
if echo "$KIMI_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
|
&& echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_BASE_URL'; then
|
|
ok "ai-kimi: launches claude with ANTHROPIC_BASE_URL set"
|
|
else
|
|
fail "ai-kimi: must launch claude with ANTHROPIC_BASE_URL"
|
|
fi
|
|
}
|
|
|
|
# ── ai-kimi: uses official Kimi API ──────────────────────────────────────
|
|
test_kimi_official_api() {
|
|
if echo "$KIMI_SECTION" | grep -q 'api.kimi.com/coding' \
|
|
&& echo "$KIMI_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL=kimi-k2.6' \
|
|
&& ! echo "$KIMI_SECTION" | grep -q 'artemox'; then
|
|
ok "ai-kimi: uses official Kimi API and model"
|
|
else
|
|
fail "ai-kimi: must use official Kimi API (api.kimi.com/coding) and model kimi-k2.6"
|
|
fi
|
|
}
|
|
|
|
# ── ai-kimi: no artemox or config.toml logic ─────────────────────────────
|
|
test_kimi_no_artemox() {
|
|
if echo "$KIMI_SECTION" | grep -q 'config.toml' || echo "$KIMI_SECTION" | grep -q 'artemox'; then
|
|
fail "ai-kimi: still contains Artemox or config.toml logic"
|
|
else
|
|
ok "ai-kimi: Artemox and config.toml logic removed"
|
|
fi
|
|
}
|
|
|
|
# ── ai-gemini: native launcher generation ─────────────────────────────────
|
|
test_gemini_native_launcher() {
|
|
if echo "$GEMINI_SECTION" | grep -q 'antigravity CLI (agy)' \
|
|
&& echo "$GEMINI_SECTION" | grep -q 'https://antigravity.google/cli/install.sh'; then
|
|
ok "ai-gemini: native agy launcher is generated"
|
|
else
|
|
fail "ai-gemini: missing native agy launcher generation"
|
|
fi
|
|
}
|
|
|
|
# ── global rules: Karpathy-style guidelines and native rule files ───────────
|
|
test_global_rules_include_quality_guidelines() {
|
|
karpathy_line=$(grep -n '^## 1\. Think Before Coding$' "$GLOBAL_RULES_SOURCE" | head -1 | cut -d: -f1)
|
|
global_line=$(grep -n '^# Global Rules for All AI Agents$' "$GLOBAL_RULES_SOURCE" | head -1 | cut -d: -f1)
|
|
if [ -n "$karpathy_line" ] \
|
|
&& [ -n "$global_line" ] \
|
|
&& [ "$karpathy_line" -lt "$global_line" ] \
|
|
&& grep -q 'Always reply in Russian' "$GLOBAL_RULES_SOURCE" \
|
|
&& grep -q 'Plain git diff visibility' "$GLOBAL_RULES_SOURCE" \
|
|
&& grep -q 'GLOBAL_RULES_SOURCE=' "$SCRIPT" \
|
|
&& grep -q 'cp "$GLOBAL_RULES_SOURCE" "$CONFIG_DIR/global_rules.md"' "$SCRIPT"; then
|
|
ok "global rules: source file includes English Karpathy guidelines before user rules"
|
|
else
|
|
fail "global rules: missing source file, English Karpathy guidelines, or user rules"
|
|
fi
|
|
}
|
|
|
|
test_native_rule_files_generated() {
|
|
if grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.codex/AGENTS.md"' "$SCRIPT" \
|
|
&& grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.kimi-code/AGENTS.md"' "$SCRIPT" \
|
|
&& grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.claude/CLAUDE.md"' "$SCRIPT" \
|
|
&& grep -q 'cp "$CONFIG_DIR/global_rules.md" "$HOME/.gemini/GEMINI.md"' "$SCRIPT" \
|
|
&& echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.codex/AGENTS.md"' \
|
|
&& echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.kimi-code/AGENTS.md"' \
|
|
&& echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.claude/CLAUDE.md"' \
|
|
&& echo "$HELPERS_SECTION" | grep -q 'echo "$global_rendered" > "$HOME/.gemini/GEMINI.md"' \
|
|
&& ! echo "$HELPERS_SECTION" | grep -q 'echo "$rendered" >'; then
|
|
ok "global rules: setup and launchers write native rule files from global_rules.md"
|
|
else
|
|
fail "global rules: setup and launchers must write native rule files from global_rules.md"
|
|
fi
|
|
}
|
|
|
|
# ── Fix 7: trap quotes $TMP correctly ────────────────────────────────────────
|
|
test_fix7_trap_tmp() {
|
|
if grep -q "trap 'rm -rf \"\$TMP\"' EXIT" "$SCRIPT"; then
|
|
ok "Fix7: trap uses single quotes with quoted \"\$TMP\""
|
|
else
|
|
fail "Fix7: trap still uses double quotes or \$TMP still unquoted at execution"
|
|
fi
|
|
}
|
|
|
|
# ── bash syntax of the whole script ─────────────────────────────────────────
|
|
test_script_syntax() {
|
|
if bash -n "$SCRIPT" 2>&1; then
|
|
ok "syntax: ai-setup.sh passes 'bash -n'"
|
|
else
|
|
fail "syntax: ai-setup.sh has syntax errors"
|
|
fi
|
|
}
|
|
|
|
# ── run all tests ─────────────────────────────────────────────────────────────
|
|
test_script_syntax
|
|
test_gpt_autoinstall
|
|
test_gpt_no_proxy
|
|
test_kimi_claude_launcher
|
|
test_kimi_official_api
|
|
test_kimi_no_artemox
|
|
test_gemini_native_launcher
|
|
test_global_rules_include_quality_guidelines
|
|
test_native_rule_files_generated
|
|
test_fix7_trap_tmp
|
|
|
|
echo ""
|
|
echo "Results: $PASS passed, $FAIL failed"
|
|
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|