diff --git a/README.md b/README.md index 6ee7396..0c9851e 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,6 @@ source ~/.bashrc ### Доступные команды запуска -* `claude_anthropic`: Оригинальный Claude (через API Anthropic). * `claude_gpt`: Доступ к GPT-5.5 (требует авторизации через `claude-code-proxy`). * `claude_deepseek`: Доступ к DeepSeek (требуется API ключ). * `claude_kimi`: Доступ к Kimi K2.6 от Moonshot AI (требуется API ключ). diff --git a/claude_setup.sh b/claude_setup.sh index 73d95f6..f5b1ad0 100755 --- a/claude_setup.sh +++ b/claude_setup.sh @@ -252,159 +252,6 @@ _claude_offer_reauth() { esac } -# ── claude_anthropic ────────────────────────────────────────── -claude_anthropic() { - unset ANTHROPIC_BASE_URL ANTHROPIC_AUTH_TOKEN - unset CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC - - local _token="" _method="" - - # Извлекаем OAuth-токен из credentials - _token=$(python3 -c " -import json, os -try: - with open(os.path.expanduser('~/.claude/.credentials.json')) as f: - d = json.load(f) - print(d.get('claudeAiOauth', {}).get('accessToken', '')) -except: pass -" 2>/dev/null) - - if [ -n "$_token" ]; then - _method="oauth" - elif [ -n "${ANTHROPIC_API_KEY:-}" ]; then - _token="$ANTHROPIC_API_KEY" - _method="apikey" - fi - - # ── Pre-launch auth validation ── - if [ "$_method" = "oauth" ]; then - # OAuth-токен предназначен для внутренней авторизации Claude Code, а не для прямых API-вызовов. - # Claude Code сам обрабатывает OAuth — прямой тест API с Bearer-токеном некорректен и даёт ложные 429. - : # пропускаем проверку, Claude Code обработает авторизацию самостоятельно - elif [ -n "$_token" ]; then - echo -n "Проверка авторизации Anthropic... " - _claude_test_api "https://api.anthropic.com/v1/messages" "x-api-key: $_token" - - local _emsg - case "$_CLAUDE_TEST_CODE" in - 200) - echo -e "\033[0;32mOK\033[0m" - ;; - 401) - _emsg=$(_claude_extract_error "$_CLAUDE_TEST_BODY") - echo -e "\033[0;31mОШИБКА: Недействительная авторизация (HTTP 401)\033[0m" - [ -n "$_emsg" ] && echo " $_emsg" - echo "" - echo "API-ключ недействителен." - echo " export ANTHROPIC_API_KEY=sk-ant-..." - echo "" - read -r -p "Ввести новый ключ сейчас? [y/N] " _ans - case "${_ans:-N}" in - [Yy]*) - read -r -p "Введите ключ: " _token - [ -z "$_token" ] && { echo "Ключ не введён."; return 1; } - echo -n "Проверяю новый ключ... " - _claude_test_api "https://api.anthropic.com/v1/messages" "x-api-key: $_token" - case "$_CLAUDE_TEST_CODE" in - 200) echo -e "\033[0;32mOK\033[0m"; ANTHROPIC_API_KEY="$_token" ;; - *) echo -e "\033[0;31mОШИБКА (HTTP $_CLAUDE_TEST_CODE)\033[0m"; return 1 ;; - esac - ;; - *) return 1 ;; - esac - ;; - 403) - _emsg=$(_claude_extract_error "$_CLAUDE_TEST_BODY") - echo "" - echo -e "\033[0;33m[ПРЕДУПРЕЖДЕНИЕ]\033[0m Доступ запрещён (HTTP 403) — возможно, подписка не позволяет." - [ -n "$_emsg" ] && echo " $_emsg" - echo "" - echo -n "Продолжить всё равно? (запросы могут не работать) [y/N] " - local _ans; read -r _ans - case "${_ans:-N}" in [Yy]*) ;; *) return 1 ;; esac - ;; - 429) - _emsg=$(_claude_extract_error "$_CLAUDE_TEST_BODY") - echo "" - echo -e "\033[0;33m[ЛИМИТ]\033[0m Лимит запросов исчерпан или пустой баланс (HTTP 429)." - [ -n "$_emsg" ] && echo " $_emsg" - echo "" - echo "Варианты:" - echo " [C] Продолжить всё равно (может не работать)" - echo " [Q] Выйти" - echo -n "Выберите [C/q]: " - local _ans; read -r _ans - case "${_ans:-C}" in - [Cc]) ;; # продолжаем - *) return 1 ;; - esac - ;; - 000) - echo "" - echo -e "\033[0;33m[СЕТЬ]\033[0m Не удалось проверить авторизацию (нет сети?). Продолжаю..." - ;; - *) - _emsg=$(_claude_extract_error "$_CLAUDE_TEST_BODY") - echo "" - echo -e "\033[0;31m[ОШИБКА]\033[0m API вернул HTTP $_CLAUDE_TEST_CODE" - [ -n "$_emsg" ] && echo " $_emsg" - echo "" - echo -n "Продолжить всё равно? [y/N] " - local _ans; read -r _ans - case "${_ans:-N}" in [Yy]*) ;; *) return 1 ;; esac - ;; - esac - else - # Нет ни OAuth, ни API-ключа — предлагаем выбор - echo "" - echo -e "\033[1;33mАнтропная авторизация не найдена.\033[0m" - echo "" - echo "Варианты:" - echo " [L] Залогиниться через браузер (OAuth)" - echo " [K] Ввести API-ключ вручную" - echo " [Q] Выйти" - echo -n "Выберите [L/k/q]: " - local _ans; read -r _ans - case "${_ans:-L}" in - [Ll]) - echo "" - echo "Запускаю Claude Code — войдите в аккаунт Anthropic в интерфейсе..." - # claude auth login + claude "$@" вызывали двойной auth flow (v2.x запускает - # полный TUI внутри auth login). Запускаем claude напрямую: он сам откроет - # браузер и попросит выбрать тип аккаунта в одном взаимодействии. - ANTHROPIC_MODEL=claude-sonnet-4-6 \ - ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-8 \ - ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6 \ - ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-haiku-4-5-20251001 \ - CLAUDE_CODE_SUBAGENT_MODEL=claude-haiku-4-5-20251001 \ - claude "$@" - return "$?" - ;; - [Kk]) - echo "" - read -r -p "Введите Anthropic API ключ (sk-ant-...): " _token - [ -z "$_token" ] && { echo "Ключ не введён."; return 1; } - _method="apikey" - echo -n "Проверяю ключ... " - _claude_test_api "https://api.anthropic.com/v1/messages" "x-api-key: $_token" - case "$_CLAUDE_TEST_CODE" in - 200) echo -e "\033[0;32mOK\033[0m"; export ANTHROPIC_API_KEY="$_token" ;; - *) echo -e "\033[0;31mОШИБКА (HTTP $_CLAUDE_TEST_CODE)\033[0m"; return 1 ;; - esac - ;; - *) echo "Отменено."; return 1 ;; - esac - fi - - # Явно задаём модели Anthropic, чтобы не подхватился deepseek-chat из settings.json - ANTHROPIC_MODEL=claude-sonnet-4-6 \ - ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-4-8 \ - ANTHROPIC_DEFAULT_SONNET_MODEL=claude-sonnet-4-6 \ - ANTHROPIC_DEFAULT_HAIKU_MODEL=claude-haiku-4-5-20251001 \ - CLAUDE_CODE_SUBAGENT_MODEL=claude-haiku-4-5-20251001 \ - claude "$@" -} - # ── claude_gpt ──────────────────────────────────────────────── claude_gpt() { local proxy_bin="$HOME/.local/bin/claude-code-proxy" @@ -534,7 +381,7 @@ claude_gpt() { esac # Сохраняем Anthropic credentials перед запуском — команда /logout внутри Claude Code - # удаляет их, хотя в режиме GPT они не нужны, но потом сломают claude_anthropic + # удаляет их, хотя в режиме GPT они не нужны, но потом сломают оригинальный claude local _creds_file="$HOME/.claude/.credentials.json" local _creds_backup="" [ -f "$_creds_file" ] && _creds_backup=$(cat "$_creds_file") @@ -1031,7 +878,6 @@ echo -e "${GREEN} Установка завершена!${NC}" echo -e "${GREEN}════════════════════════════════════════════════════${NC}" echo "" echo "Доступные команды:" -echo -e " ${CYAN}claude_anthropic${NC} — оригинальный Claude (Anthropic API)" echo -e " ${CYAN}claude_gpt${NC} — GPT-5.5 (ChatGPT Plus/Pro, браузерная авторизация)" echo -e " ${CYAN}claude_deepseek${NC} — DeepSeek (API ключ сохраняется)" echo -e " ${CYAN}claude_kimi${NC} — Kimi K2.6 (Moonshot AI, API ключ сохраняется)" diff --git a/tests/test_fixes.sh b/tests/test_fixes.sh index 100db9d..d2be17e 100755 --- a/tests/test_fixes.sh +++ b/tests/test_fixes.sh @@ -109,229 +109,3 @@ test_fix5_gemini_revalidate() { fi } -# ── Fix 6: prompt [C/q] matches default C in 429 handler ───────────────────── -test_fix6_prompt_default() { - # The prompt should now show [C/q] (capital C = default) matching case "${_ans:-C}" - if grep -q '\[C/q\]' "$SCRIPT"; then - ok "Fix6: prompt shows [C/q] — capital C signals default=continue" - else - fail "Fix6: prompt still shows [c/Q] (misleading) or was changed incorrectly" - fi - - # Confirm the default in case is still C - local anthropic_section - anthropic_section=$(awk '/^claude_anthropic\(\)/,/^}/' "$SCRIPT") - if echo "$anthropic_section" | grep -q '${_ans:-C}'; then - ok "Fix6: default in case is still C (continue on Enter)" - else - fail "Fix6: default in case changed unexpectedly" - fi -} - -# ── Fix 7: trap quotes $TMP correctly ──────────────────────────────────────── -test_fix7_trap_tmp() { - # Should be single-quoted trap so $TMP expands at execution, not definition - 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 - - # Old bad form should be gone - if grep -q 'trap "rm -rf \$TMP" EXIT' "$SCRIPT"; then - fail "Fix7: old unquoted trap form still present" - else - ok "Fix7: old unquoted trap form removed" - fi -} - -# ── _claude_test_api function isolation ────────────────────────────────────── -test_globals_set_by_test_api() { - _source_functions - - # Mock curl to return a fake 200 response - curl() { - echo '{"id":"msg_test"}' - echo "200" - } - export -f curl - - _CLAUDE_TEST_CODE="" - _CLAUDE_TEST_BODY="" - _claude_test_api "http://fake.api/v1/messages" "x-api-key: testkey" "test-model" - - if [ "$_CLAUDE_TEST_CODE" = "200" ]; then - ok "test_api: _CLAUDE_TEST_CODE set to 200" - else - fail "test_api: _CLAUDE_TEST_CODE='$_CLAUDE_TEST_CODE' expected '200'" - fi - - if echo "$_CLAUDE_TEST_BODY" | grep -q '"id"'; then - ok "test_api: _CLAUDE_TEST_BODY contains response body" - else - fail "test_api: _CLAUDE_TEST_BODY='$_CLAUDE_TEST_BODY' missing body" - fi - - unset -f curl -} - -test_globals_set_on_curl_fail() { - _source_functions - - # curl fails → fallback "000" - curl() { return 1; } - export -f curl - - _CLAUDE_TEST_CODE="" - _claude_test_api "http://unreachable/" "x-api-key: k" "m" - - if [ "$_CLAUDE_TEST_CODE" = "000" ]; then - ok "test_api: _CLAUDE_TEST_CODE=000 on curl failure" - else - fail "test_api: expected 000 on curl failure, got '$_CLAUDE_TEST_CODE'" - fi - - unset -f curl -} - -# ── _claude_extract_error ──────────────────────────────────────────────────── -test_extract_error_message() { - _source_functions - - local body='{"type":"error","error":{"type":"authentication_error","message":"Invalid API key"}}' - local result - result=$(_claude_extract_error "$body") - - if [ "$result" = "Invalid API key" ]; then - ok "extract_error: extracts error.message from JSON" - else - fail "extract_error: expected 'Invalid API key', got '$result'" - fi -} - -test_extract_error_empty_body() { - _source_functions - - local result - result=$(_claude_extract_error "not json at all") - - if [ -z "$result" ]; then - ok "extract_error: returns empty string on non-JSON input" - else - fail "extract_error: unexpected output '$result' on bad input" - fi -} - -# ── _claude_offer_reauth ───────────────────────────────────────────────────── -test_offer_reauth_yes() { - _source_functions - - # Simulate user typing "Y" - local result - result=$(echo "Y" | ( - _claude_offer_reauth "TestProvider" - echo "retcode:$?" - )) - - if echo "$result" | grep -q "retcode:0"; then - ok "offer_reauth: returns 0 on 'Y'" - else - fail "offer_reauth: expected retcode 0 on Y, got: $result" - fi -} - -test_offer_reauth_no() { - _source_functions - - local result - result=$(echo "n" | ( - _claude_offer_reauth "TestProvider" - echo "retcode:$?" - )) - - if echo "$result" | grep -q "retcode:1"; then - ok "offer_reauth: returns 1 on 'n'" - else - fail "offer_reauth: expected retcode 1 on n, got: $result" - fi -} - -test_offer_reauth_enter_defaults_yes() { - _source_functions - - local result - result=$(echo "" | ( - _claude_offer_reauth "TestProvider" - echo "retcode:$?" - )) - - if echo "$result" | grep -q "retcode:0"; then - ok "offer_reauth: Enter (empty) defaults to Yes (retcode 0)" - else - fail "offer_reauth: Enter should default to Yes, got: $result" - fi -} - -# ── Fix8: no double login — [L] branch calls claude directly, not auth login ─ -test_fix8_no_double_login() { - # [L] branch must NOT call "claude auth login"; must call claude directly and return. - - # Find the line number of [Ll]) - local ll_line - ll_line=$(grep -n '^\s*\[Ll\])' "$SCRIPT" | head -1 | cut -d: -f1) - - # Extract the next 20 lines starting at [Ll]) — enough to cover the whole arm - local ll_branch - ll_branch=$(awk "NR>=$ll_line && NR<=$((ll_line+20))" "$SCRIPT") - - # Check for actual invocation (not just a comment mentioning the command) - if echo "$ll_branch" | grep -v '^\s*#' | grep -q 'claude auth login'; then - fail "Fix8: [L] branch still calls 'claude auth login' — double login present" - else - ok "Fix8: [L] branch does NOT call 'claude auth login' (only mentions it in a comment)" - fi - - if echo "$ll_branch" | grep -qF 'return "$?"'; then - ok "Fix8: [L] branch returns after launching claude (no fallthrough to outer call)" - else - fail "Fix8: [L] branch missing 'return \"\$?\"' — outer claude call still reached" - fi - - if echo "$ll_branch" | grep -q 'ANTHROPIC_MODEL='; then - ok "Fix8: [L] branch sets model env vars before launching claude" - else - fail "Fix8: [L] branch missing model env vars" - fi -} - -# ── bash syntax of the whole script ───────────────────────────────────────── -test_script_syntax() { - if bash -n "$SCRIPT" 2>&1; then - ok "syntax: claude_setup.sh passes 'bash -n'" - else - fail "syntax: claude_setup.sh has syntax errors" - fi -} - -# ── run all tests ───────────────────────────────────────────────────────────── -test_script_syntax -test_fix8_no_double_login -test_fix1_export_api_key -test_fix2_trap_return -test_fix3_readiness_loop -test_fix3b_exit7_logic -test_fix4_gpt_revalidate -test_fix5_gemini_revalidate -test_fix6_prompt_default -test_fix7_trap_tmp -test_globals_set_by_test_api -test_globals_set_on_curl_fail -test_extract_error_message -test_extract_error_empty_body -test_offer_reauth_yes -test_offer_reauth_no -test_offer_reauth_enter_defaults_yes - -echo "" -echo "Results: $PASS passed, $FAIL failed" -[ "$FAIL" -eq 0 ] && exit 0 || exit 1