diff --git a/AGENTS.md b/AGENTS.md index dc582d5..0aae51f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,4 +2,4 @@ Данные правила применяются ко всем агентам, работающим конкретно в этом репозитории. -1. **Полная перегенерация standalone-скриптов при запуске сетап-скрипта (Full regeneration of standalone scripts on setup run):** При каждом запуске `ai-setup.sh` все генерируемые скрипты в выбранном `BIN_DIR` (`~/bin`, если он уже есть в `PATH`, иначе `~/.local/bin`: `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`, `ai-gemini`, `ai-api-helpers.sh`, `ai-claude`, `claude-gpt-effort-proxy.py`) должны быть **полностью перезаписаны** актуальными версиями. Запрещено выполнять слияние (merge) старого и нового содержимого или дополнение (append). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией. +1. **Полная перегенерация standalone-скриптов при запуске сетап-скрипта (Full regeneration of standalone scripts on setup run):** При каждом запуске `ai-setup.sh` все генерируемые скрипты в выбранном `BIN_DIR` (`~/bin`, если он уже есть в `PATH`, иначе `~/.local/bin`: `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-gemini`, `ai-api-helpers.sh`, `ai-claude`, `claude-gpt-effort-proxy.py`) должны быть **полностью перезаписаны** актуальными версиями. Запрещено выполнять слияние (merge) старого и нового содержимого или дополнение (append). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией. diff --git a/EFFORT_MAPPING.md b/EFFORT_MAPPING.md index 917efad..5a309c9 100644 --- a/EFFORT_MAPPING.md +++ b/EFFORT_MAPPING.md @@ -3,7 +3,7 @@ ## Как это работает `/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code: -`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`. +`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`. Нативные лаунчеры `ai-gpt` (OpenAI Codex) и `ai-gemini` (Antigravity `agy`) не используют эту схему. У них свои настройки reasoning внутри соответствующего CLI. @@ -12,13 +12,13 @@ ## Таблица маппинга -| Claude Code `/effort` | Anthropic (`ai-claude`) | DeepSeek V4 (`ai-deepseek`) | Kimi K2.7/K2.6 (`ai-kimi`) | OpenRouter/GPT-5.5 (`ai-openrouter`) | -|:---:|:---:|:---:|:---:|:---:| -| `low` | нативно `low` | провайдер поднимает до `high` | thinking on | без локального маппинга | -| `medium` | нативно `medium` | провайдер поднимает до `high` | thinking on | без локального маппинга | -| `high` | нативно `high` | нативно `high` | thinking on | без локального маппинга | -| `xhigh` | нативно `xhigh` | провайдер поднимает до `max` | thinking on | без локального маппинга | -| `max` | нативно `max` | нативно `max` | thinking on | без локального маппинга | +| Claude Code `/effort` | Anthropic (`ai-claude`) | DeepSeek V4 (`ai-deepseek`) | Kimi K2.7/K2.6 (`ai-kimi`) | GLM 5.2 (`ai-glm`) | OpenRouter/GPT-5.5 (`ai-openrouter`) | +|:---:|:---:|:---:|:---:|:---:|:---:| +| `low` | нативно `low` | провайдер поднимает до `high` | thinking on | на стороне сервера | без локального маппинга | +| `medium` | нативно `medium` | провайдер поднимает до `high` | thinking on | на стороне сервера | без локального маппинга | +| `high` | нативно `high` | нативно `high` | thinking on | на стороне сервера | без локального маппинга | +| `xhigh` | нативно `xhigh` | провайдер поднимает до `max` | thinking on | на стороне сервера | без локального маппинга | +| `max` | нативно `max` | нативно `max` | thinking on | на стороне сервера | без локального маппинга | Для OpenRouter текущий лаунчер не делает локального преобразования effort и отправляет значение дальше через Claude Code/OpenRouter. Конкретная интерпретация зависит от выбранной @@ -59,6 +59,16 @@ on / off - Градаций глубины reasoning нет. - Дефолт `ai-kimi`: `high`. +### GLM 5.2 (Zhipu AI) + +```text +high / max +``` + +- Маппинг выполняется на стороне Zhipu AI API. +- Текущий `ai-glm` не делает локального преобразования effort. +- Дефолт `ai-glm`: `high`. + ### OpenRouter / GPT-5.5 Текущий `ai-openrouter` работает через Claude Code с `ANTHROPIC_BASE_URL=https://openrouter.ai/api` @@ -76,12 +86,13 @@ on / off | Anthropic | Не нужен | - | | DeepSeek V4 | DeepSeek API | На стороне сервера | | Kimi K2.7/K2.6 | Moonshot API | На стороне сервера | +| GLM 5.2 | Zhipu AI API | На стороне сервера | | OpenRouter/GPT-5.5 | Локального маппинга нет | `ai-openrouter` отправляет значение как есть | | Legacy GPT proxy | helper-маппинг `xhigh` -> `high` | `~/bin/claude-gpt-effort-proxy.py` или `~/.local/bin/claude-gpt-effort-proxy.py` | ## Persistence effort между сессиями -Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`) +Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`) запоминает свой уровень effort отдельно в `settings.json` лаунчера. `/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется. @@ -99,5 +110,5 @@ ai-deepseek # без флага - использовать ур ## Рекомендации - Для повседневной работы: `high` или `xhigh`. -- `max` effort имеет реальный эффект у Anthropic и DeepSeek; у Kimi это все тот же thinking on. -- `low`/`medium` у DeepSeek и Kimi фактически не снижают reasoning. +- `max` effort имеет реальный эффект у Anthropic и DeepSeek; у Kimi и GLM это всё тот же thinking on / маппинг на стороне сервера. +- `low`/`medium` у DeepSeek, Kimi и GLM фактически не снижают reasoning. diff --git a/QUICK_START.md b/QUICK_START.md index d040def..d5e3c9a 100644 --- a/QUICK_START.md +++ b/QUICK_START.md @@ -7,7 +7,7 @@ bash setup.sh ``` Спросит про VLESS-прокси (по умолчанию `Y`; если не нужен, ответь `n`), затем установит лаунчеры -`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`, `ai-gemini` +`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-gemini` в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи. После установки, если команды не видны: diff --git a/README.md b/README.md index 91c0844..7f75c74 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ home-configs/ tests/ ├── test_fixes.sh # юнит-тесты структуры ai-setup.sh └── test_network.sh # тесты маршрутизации -test_isolated.sh # проверка автоустановки ai-gpt и ai-kimi +test_isolated.sh # проверка автоустановки ai-gpt, ai-kimi и ai-glm test_sigint.sh # ручной тест поведения SIGINT ``` @@ -157,6 +157,7 @@ bash tests/test_network.sh # полные тесты - `ai-gpt` - нативный OpenAI Codex CLI - `ai-deepseek` - Claude Code через DeepSeek API - `ai-kimi` - Claude Code через официальный Kimi Code API (`api.kimi.com/coding`) +- `ai-glm` - Claude Code через Zhipu AI GLM 5.2 API (`api.z.ai/api/anthropic`) - `ai-openrouter` - Claude Code через OpenRouter (GPT-5.5, Grok, Qwen, MiniMax, Llama и др.) - `ai-gemini` - нативный Antigravity CLI `agy` - `ai-api-helpers.sh` - вспомогательные функции для лаунчеров @@ -226,6 +227,7 @@ android init - `~/.config/ai-setup/deepseek_key` - DeepSeek API key (права 600) - `~/.config/ai-setup/kimi_key` - Kimi API key (права 600) +- `~/.config/ai-setup/glm_key` - Zhipu AI (GLM) API key (права 600) - `~/.config/ai-setup/openrouter_key` - OpenRouter API key (права 600) - `~/.config/ai-setup/global_rules.md` - глобальные правила агентов - `~/.config/ai-setup/network_.conf` - сохранённые сетевые профили (`GATEWAY`, `DEV`, `LOCAL_DNS`, `AMNEZIA_SERVER`, `KILL_SWITCH_EXCEPTIONS`) @@ -233,7 +235,7 @@ android init ## Права запуска агентов - `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox` -- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`, `ai-gemini` используют `--dangerously-skip-permissions` +- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-gemini` используют `--dangerously-skip-permissions` Удобно для локального coding workflow, но это не sandbox для недоверенного кода. @@ -248,7 +250,7 @@ Surgical Changes, Goal-Driven Execution) плюс пользовательски ## Effort Mapping `EFFORT_MAPPING.md` - таблица effort-уровней (`low`/`medium`/`high`/`xhigh`/`max`) -для Claude Code лаунчеров (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-openrouter`). +для Claude Code лаунчеров (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`). Нативные `ai-gpt` и `ai-gemini` живут отдельно. `claude-gpt-effort-proxy.py` маппит `xhigh` -> `high` для совместимости со старым @@ -266,7 +268,7 @@ GPT/claude-code-proxy backend; текущие лаунчеры его напря ```bash bash tests/test_fixes.sh # структура ai-setup.sh и синтаксис bash -bash test_isolated.sh # автоустановка ai-gpt и ai-kimi через mock curl +bash test_isolated.sh # автоустановка ai-gpt, ai-kimi и ai-glm через mock curl bash tests/test_network.sh # маршрутизация (нужен активный ru-bypass) # test_sigint.sh # ручной диагностический тест SIGINT ``` diff --git a/scripts/ai-setup.sh b/scripts/ai-setup.sh index ba280f7..1d6b980 100755 --- a/scripts/ai-setup.sh +++ b/scripts/ai-setup.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # ============================================================ -# AI Setup - Claude / GPT-5.5 / Grok / Qwen / DeepSeek / Kimi / MiniMax / Llama / Gemini +# AI Setup - Claude / GPT-5.5 / Grok / Qwen / DeepSeek / Kimi / GLM / MiniMax / Llama / Gemini # Запуск: bash ai-setup.sh # ============================================================ @@ -1687,6 +1687,95 @@ done KIMIEOF chmod +x "$BIN_DIR/ai-kimi" +# === ai-glm === +cat > "$BIN_DIR/ai-glm" << 'GLMEOF' +#!/usr/bin/env bash +# ai-glm - запуск Claude Code через Zhipu AI GLM 5.2 (Anthropic-compatible API) +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/null || true + +key_file="$HOME/.config/ai-setup/glm_key" +api_key="" +reauth=0 + +[ -f "$key_file" ] && api_key=$(cat "$key_file") + +# Endpoint: international Z.AI по умолчанию, можно переопределить через GLM_BASE_URL. +glm_base_url="${GLM_BASE_URL:-https://api.z.ai/api/anthropic}" + +if [ -n "$api_key" ]; then + echo -n "Проверка сохранённого GLM ключа... " + _claude_test_api "$glm_base_url/v1/messages" "x-api-key: $api_key" "glm-5.2" + _handle_api_response "GLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Пополните баланс: https://z.ai/manage-apikey/apikey-list" + ret=$_API_RET + if [ $ret -eq 401 ]; then + rm -f "$key_file" + api_key="" + reauth=1 + elif [ $ret -eq 429 ]; then + echo -n "Продолжить всё равно? (запросы могут не проходить) [y/N] " + read -r _ans; case "${_ans:-N}" in [Yy]*) ;; *) exit 1 ;; esac + elif [ $ret -ne 0 ]; then + exit 1 + fi +fi + +if [ -z "$api_key" ] && [ "$reauth" -eq 1 ]; then + echo -n "Хотите ввести новый GLM ключ? [Y/n] " + read -r _ans; case "${_ans:-Y}" in [Yy]*) ;; *) exit 1 ;; esac +fi + +if [ -z "$api_key" ]; then + echo "Получить ключ: https://z.ai/manage-apikey/apikey-list" + read -r -p "Введите ваш Zhipu AI (GLM) API ключ: " api_key + [ -z "$api_key" ] && { echo "Выход."; exit 1; } + + echo -n "Проверяю ключ... " + _claude_test_api "$glm_base_url/v1/messages" "x-api-key: $api_key" "glm-5.2" + _handle_api_response "GLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Пополните баланс: https://z.ai/manage-apikey/apikey-list" + ret=$_API_RET + if [ $ret -eq 0 ] || [ $ret -eq 429 ]; then + mkdir -p "$(dirname "$key_file")" + echo "$api_key" > "$key_file" + chmod 600 "$key_file" + echo "Ключ сохранён." + if [ $ret -eq 429 ]; then + echo -n "Продолжить всё равно? (запросы могут не проходить) [y/N] " + read -r _ans; case "${_ans:-N}" in [Yy]*) ;; *) exit 1 ;; esac + fi + else + echo "Ключ НЕ сохранён." + exit 1 + fi +fi + +_PROMPT_FILE=$(mktemp /tmp/ai-sys-prompt.XXXXXX) +trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM +_build_ai_sys_prompt > "$_PROMPT_FILE" +export AI_LAUNCHER=glm +export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/glm" +# Пикер: Opus/Sonnet = GLM 5.2, Haiku = GLM 5.2[1m]. availableModels НЕ задаём +# (он схлопывает пикер). Claude Code навязывает 3 слота; незаданный показал бы +# чужой Claude, поэтому opus+sonnet = glm-5.2, haiku = glm-5.2[1m]. +_setup_isolated_config glm opus high '' +_apply_effort glm high +ANTHROPIC_BASE_URL="$glm_base_url" \ +ANTHROPIC_AUTH_TOKEN="$api_key" \ +ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.2 \ +ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="GLM 5.2" \ +ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="GLM 5.2 — флагман Zhipu AI" \ +ANTHROPIC_DEFAULT_SONNET_MODEL=glm-5.2 \ +ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="GLM 5.2" \ +ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="GLM 5.2 — флагман Zhipu AI" \ +ANTHROPIC_DEFAULT_HAIKU_MODEL='glm-5.2[1m]' \ +ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="GLM 5.2 [1M]" \ +ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="GLM 5.2 [1M] — расширенный контекст" \ +CLAUDE_CODE_SUBAGENT_MODEL=glm-5.2 \ +CLAUDE_CODE_DISABLE_1M_CONTEXT=1 \ +CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \ +claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@" +GLMEOF +chmod +x "$BIN_DIR/ai-glm" + # === ai-openrouter === cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF' #!/usr/bin/env bash @@ -1838,6 +1927,7 @@ if [ "$USE_VLESS" -eq 1 ]; then sed -i 's/^exec "\$codex_bin"/exec proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" "\$codex_bin"/' "$BIN_DIR/ai-gpt" sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-deepseek" sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-kimi" + sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-glm" sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-openrouter" sed -i 's/^\([[:space:]]*\)exec "\$agy_bin"/\1exec proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" "\$agy_bin"/' "$BIN_DIR/ai-gemini" sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-claude" @@ -1850,6 +1940,7 @@ fi source "$BIN_DIR/ai-api-helpers.sh" _setup_isolated_config deepseek opus high '' _setup_isolated_config kimi opus high '' +_setup_isolated_config glm opus high '' _setup_isolated_config openrouter "openai/gpt-5.5" high '' info "Удаляю старые версии скриптов (claude_*)..." @@ -1859,7 +1950,7 @@ rm -f "$BIN_DIR/claude_gpt" "$BIN_DIR/claude_deepseek" "$BIN_DIR/claude_kimi" "$ if [ "$BIN_DIR" != "$HOME/.local/bin" ]; then warn "BIN_DIR=$BIN_DIR — удаляю старые скрипты из ~/.local/bin/ ..." rm -f "$HOME/.local/bin/ai-gpt" "$HOME/.local/bin/ai-deepseek" "$HOME/.local/bin/ai-kimi" \ - "$HOME/.local/bin/ai-openrouter" "$HOME/.local/bin/ai-gemini" "$HOME/.local/bin/ai-claude" \ + "$HOME/.local/bin/ai-glm" "$HOME/.local/bin/ai-openrouter" "$HOME/.local/bin/ai-gemini" "$HOME/.local/bin/ai-claude" \ "$HOME/.local/bin/ai-api-helpers.sh" "$HOME/.local/bin/claude-gpt-effort-proxy.py" fi @@ -1877,6 +1968,7 @@ echo " На базе Claude Code:" echo -e " ${CYAN}ai-claude${NC} - Оригинальный Claude Code (Anthropic)" echo -e " ${CYAN}ai-deepseek${NC} - DeepSeek (через Claude Code, API ключ сохраняется)" echo -e " ${CYAN}ai-kimi${NC} - Kimi K2.7 Code (через Claude Code, API ключ сохраняется)" +echo -e " ${CYAN}ai-glm${NC} - GLM 5.2 (через Claude Code, Zhipu AI API)" echo -e " ${CYAN}ai-openrouter${NC} - OpenRouter (через Claude Code: GPT-5.5, Grok, Qwen, MiniMax, Llama и др.)" echo "" echo " Нативные CLI:" diff --git a/setup.sh b/setup.sh index ba47d11..7fdef21 100755 --- a/setup.sh +++ b/setup.sh @@ -33,7 +33,7 @@ else echo -e "${YEL}Шаги для новой машины (выполнить по порядку):${CLR}" echo "" echo -e " ${BLD}1) AI-инструменты${CLR}" - echo -e " ${GRY}Устанавливает ai-claude, ai-gpt, ai-deepseek, ai-gemini и др.${CLR}" + echo -e " ${GRY}Устанавливает ai-claude, ai-gpt, ai-deepseek, ai-kimi, ai-glm, ai-gemini и др.${CLR}" echo -e " ${GRY}Запрашивает API-ключи. Запускать один раз.${CLR}" echo "" echo -e " ${BLD}2) Сеть: ru-bypass + kill switch${CLR}" @@ -173,7 +173,7 @@ case "$choice" in echo "" echo -e "${BLD}AI инструменты:${CLR}" - for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-openrouter ai-gemini android; do + for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-openrouter ai-gemini android; do if command -v "$cmd" &>/dev/null; then echo -e " ${GRN}✓${CLR} $cmd" else @@ -184,7 +184,7 @@ case "$choice" in echo "" echo -e "${BLD}API ключи:${CLR}" cfg="$HOME/.config/ai-setup" - for f in deepseek_key kimi_key openrouter_key; do + for f in deepseek_key kimi_key glm_key openrouter_key; do name="${f/_key/}" if [ -s "$cfg/$f" ]; then echo -e " ${GRN}✓${CLR} $name" @@ -195,7 +195,7 @@ case "$choice" in echo "" echo -e "${BLD}API доступность:${CLR}" - for entry in "Anthropic:api.anthropic.com" "DeepSeek:api.deepseek.com" "OpenAI:api.openai.com" "Kimi:api.kimi.com" "OpenRouter:openrouter.ai"; do + for entry in "Anthropic:api.anthropic.com" "DeepSeek:api.deepseek.com" "OpenAI:api.openai.com" "Kimi:api.kimi.com" "GLM:api.z.ai" "OpenRouter:openrouter.ai"; do _name="${entry%%:*}" _host="${entry##*:}" _ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null) diff --git a/test_isolated.sh b/test_isolated.sh index 17aa771..5a7c708 100644 --- a/test_isolated.sh +++ b/test_isolated.sh @@ -16,11 +16,16 @@ awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' scripts/ai-setup.sh | \ sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash chmod +x "$BIN_DIR/ai-gpt" -# Извлекаем ai-kimi +# Извлекаем ai-kimi awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' scripts/ai-setup.sh | \ sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash chmod +x "$BIN_DIR/ai-kimi" +# Извлекаем ai-glm +awk '/^cat > "\$BIN_DIR\/ai-glm"/,/^GLMEOF/' scripts/ai-setup.sh | \ + sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash +chmod +x "$BIN_DIR/ai-glm" + echo "=== Test 1: ai-gpt calls codex install URL when missing ===" MOCK_LOG="$TMPDIR/mock_curl.log" @@ -62,5 +67,17 @@ else exit 1 fi +echo "" +echo "=== Test 3: ai-glm is a Claude Code launcher with Zhipu AI backend ===" + +if grep -q 'ANTHROPIC_BASE_URL' "$BIN_DIR/ai-glm" \ + && grep -q 'api.z.ai/api/anthropic' "$BIN_DIR/ai-glm" \ + && grep -q 'claude --dangerously-skip-permissions' "$BIN_DIR/ai-glm"; then + echo "[PASS] ai-glm запускает claude с официальным Zhipu AI API" +else + echo "[FAIL] ai-glm должен запускать claude с api.z.ai/api/anthropic" + exit 1 +fi + echo "" echo "=== All tests passed ===" diff --git a/tests/test_fixes.sh b/tests/test_fixes.sh index 025e815..f0df0da 100755 --- a/tests/test_fixes.sh +++ b/tests/test_fixes.sh @@ -14,6 +14,7 @@ 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") +GLM_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-glm"/,/^GLMEOF/' "$SCRIPT") GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT") HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT") @@ -66,6 +67,28 @@ test_kimi_no_artemox() { fi } +# ── ai-glm: launches claude with GLM backend ────────────────────────────── +test_glm_claude_launcher() { + if echo "$GLM_SECTION" | grep -q 'claude --dangerously-skip-permissions' \ + && echo "$GLM_SECTION" | grep -q 'ANTHROPIC_BASE_URL'; then + ok "ai-glm: launches claude with ANTHROPIC_BASE_URL set" + else + fail "ai-glm: must launch claude with ANTHROPIC_BASE_URL" + fi +} + +# ── ai-glm: uses official Zhipu AI API ──────────────────────────────────── +test_glm_official_api() { + if echo "$GLM_SECTION" | grep -q 'api.z.ai/api/anthropic' \ + && echo "$GLM_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.2' \ + && echo "$GLM_SECTION" | grep -q "ANTHROPIC_DEFAULT_HAIKU_MODEL='glm-5.2\[1m\]'" \ + && echo "$GLM_SECTION" | grep -q 'x-api-key'; then + ok "ai-glm: uses official Zhipu AI API (glm-5.2 opus/sonnet, glm-5.2[1m] haiku)" + else + fail "ai-glm: must use official Zhipu AI API with glm-5.2 and x-api-key" + fi +} + # ── ai-gemini: native launcher generation ───────────────────────────────── test_gemini_native_launcher() { if echo "$GEMINI_SECTION" | grep -q 'antigravity CLI (agy)' \ @@ -176,6 +199,8 @@ test_gpt_no_proxy test_kimi_claude_launcher test_kimi_official_api test_kimi_no_artemox +test_glm_claude_launcher +test_glm_official_api test_gemini_native_launcher test_global_rules_include_quality_guidelines test_native_rule_files_generated