feat: добавить ai-glm - лаунчер Claude Code через Zhipu AI GLM 5.2

Новый лаунчер ai-glm запускает Claude Code через официальный Anthropic-совместимый
API Zhipu AI (api.z.ai). Модели: glm-5.2 (opus/sonnet), glm-5.2[1m] (haiku).
Обновлены документация, статус, тесты и EFFORT_MAPPING.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Виталий Никитенко
2026-06-19 06:41:41 +03:00
parent 463a3f0bc6
commit 83a7790235
8 changed files with 171 additions and 24 deletions

View File

@@ -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). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией.

View File

@@ -3,7 +3,7 @@
## Как это работает ## Как это работает
`/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code: `/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`) не используют Нативные лаунчеры `ai-gpt` (OpenAI Codex) и `ai-gemini` (Antigravity `agy`) не используют
эту схему. У них свои настройки reasoning внутри соответствующего CLI. эту схему. У них свои настройки 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`) | | 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 | без локального маппинга | | `low` | нативно `low` | провайдер поднимает до `high` | thinking on | на стороне сервера | без локального маппинга |
| `medium` | нативно `medium` | провайдер поднимает до `high` | thinking on | без локального маппинга | | `medium` | нативно `medium` | провайдер поднимает до `high` | thinking on | на стороне сервера | без локального маппинга |
| `high` | нативно `high` | нативно `high` | thinking on | без локального маппинга | | `high` | нативно `high` | нативно `high` | thinking on | на стороне сервера | без локального маппинга |
| `xhigh` | нативно `xhigh` | провайдер поднимает до `max` | thinking on | без локального маппинга | | `xhigh` | нативно `xhigh` | провайдер поднимает до `max` | thinking on | на стороне сервера | без локального маппинга |
| `max` | нативно `max` | нативно `max` | thinking on | без локального маппинга | | `max` | нативно `max` | нативно `max` | thinking on | на стороне сервера | без локального маппинга |
Для OpenRouter текущий лаунчер не делает локального преобразования effort и отправляет Для OpenRouter текущий лаунчер не делает локального преобразования effort и отправляет
значение дальше через Claude Code/OpenRouter. Конкретная интерпретация зависит от выбранной значение дальше через Claude Code/OpenRouter. Конкретная интерпретация зависит от выбранной
@@ -59,6 +59,16 @@ on / off
- Градаций глубины reasoning нет. - Градаций глубины reasoning нет.
- Дефолт `ai-kimi`: `high`. - Дефолт `ai-kimi`: `high`.
### GLM 5.2 (Zhipu AI)
```text
high / max
```
- Маппинг выполняется на стороне Zhipu AI API.
- Текущий `ai-glm` не делает локального преобразования effort.
- Дефолт `ai-glm`: `high`.
### OpenRouter / GPT-5.5 ### OpenRouter / GPT-5.5
Текущий `ai-openrouter` работает через Claude Code с `ANTHROPIC_BASE_URL=https://openrouter.ai/api` Текущий `ai-openrouter` работает через Claude Code с `ANTHROPIC_BASE_URL=https://openrouter.ai/api`
@@ -76,12 +86,13 @@ on / off
| Anthropic | Не нужен | - | | Anthropic | Не нужен | - |
| DeepSeek V4 | DeepSeek API | На стороне сервера | | DeepSeek V4 | DeepSeek API | На стороне сервера |
| Kimi K2.7/K2.6 | Moonshot API | На стороне сервера | | Kimi K2.7/K2.6 | Moonshot API | На стороне сервера |
| GLM 5.2 | Zhipu AI API | На стороне сервера |
| OpenRouter/GPT-5.5 | Локального маппинга нет | `ai-openrouter` отправляет значение как есть | | 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` | | Legacy GPT proxy | helper-маппинг `xhigh` -> `high` | `~/bin/claude-gpt-effort-proxy.py` или `~/.local/bin/claude-gpt-effort-proxy.py` |
## Persistence effort между сессиями ## 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 отдельно в `settings.json` лаунчера.
`/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется. `/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется.
@@ -99,5 +110,5 @@ ai-deepseek # без флага - использовать ур
## Рекомендации ## Рекомендации
- Для повседневной работы: `high` или `xhigh`. - Для повседневной работы: `high` или `xhigh`.
- `max` effort имеет реальный эффект у Anthropic и DeepSeek; у Kimi это все тот же thinking on. - `max` effort имеет реальный эффект у Anthropic и DeepSeek; у Kimi и GLM это всё тот же thinking on / маппинг на стороне сервера.
- `low`/`medium` у DeepSeek и Kimi фактически не снижают reasoning. - `low`/`medium` у DeepSeek, Kimi и GLM фактически не снижают reasoning.

View File

@@ -7,7 +7,7 @@ bash setup.sh
``` ```
Спросит про VLESS-прокси (по умолчанию `Y`; если не нужен, ответь `n`), затем установит лаунчеры Спросит про 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-ключи. в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
После установки, если команды не видны: После установки, если команды не видны:

View File

@@ -29,7 +29,7 @@ home-configs/
tests/ tests/
├── test_fixes.sh # юнит-тесты структуры ai-setup.sh ├── test_fixes.sh # юнит-тесты структуры ai-setup.sh
└── test_network.sh # тесты маршрутизации └── test_network.sh # тесты маршрутизации
test_isolated.sh # проверка автоустановки ai-gpt и ai-kimi test_isolated.sh # проверка автоустановки ai-gpt, ai-kimi и ai-glm
test_sigint.sh # ручной тест поведения SIGINT test_sigint.sh # ручной тест поведения SIGINT
``` ```
@@ -157,6 +157,7 @@ bash tests/test_network.sh # полные тесты
- `ai-gpt` - нативный OpenAI Codex CLI - `ai-gpt` - нативный OpenAI Codex CLI
- `ai-deepseek` - Claude Code через DeepSeek API - `ai-deepseek` - Claude Code через DeepSeek API
- `ai-kimi` - Claude Code через официальный Kimi Code API (`api.kimi.com/coding`) - `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-openrouter` - Claude Code через OpenRouter (GPT-5.5, Grok, Qwen, MiniMax, Llama и др.)
- `ai-gemini` - нативный Antigravity CLI `agy` - `ai-gemini` - нативный Antigravity CLI `agy`
- `ai-api-helpers.sh` - вспомогательные функции для лаунчеров - `ai-api-helpers.sh` - вспомогательные функции для лаунчеров
@@ -226,6 +227,7 @@ android init
- `~/.config/ai-setup/deepseek_key` - DeepSeek API key (права 600) - `~/.config/ai-setup/deepseek_key` - DeepSeek API key (права 600)
- `~/.config/ai-setup/kimi_key` - Kimi 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/openrouter_key` - OpenRouter API key (права 600)
- `~/.config/ai-setup/global_rules.md` - глобальные правила агентов - `~/.config/ai-setup/global_rules.md` - глобальные правила агентов
- `~/.config/ai-setup/network_<profile>.conf` - сохранённые сетевые профили (`GATEWAY`, `DEV`, `LOCAL_DNS`, `AMNEZIA_SERVER`, `KILL_SWITCH_EXCEPTIONS`) - `~/.config/ai-setup/network_<profile>.conf` - сохранённые сетевые профили (`GATEWAY`, `DEV`, `LOCAL_DNS`, `AMNEZIA_SERVER`, `KILL_SWITCH_EXCEPTIONS`)
@@ -233,7 +235,7 @@ android init
## Права запуска агентов ## Права запуска агентов
- `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox` - `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 для недоверенного кода. Удобно для локального coding workflow, но это не sandbox для недоверенного кода.
@@ -248,7 +250,7 @@ Surgical Changes, Goal-Driven Execution) плюс пользовательски
## Effort Mapping ## Effort Mapping
`EFFORT_MAPPING.md` - таблица effort-уровней (`low`/`medium`/`high`/`xhigh`/`max`) `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` живут отдельно. Нативные `ai-gpt` и `ai-gemini` живут отдельно.
`claude-gpt-effort-proxy.py` маппит `xhigh` -> `high` для совместимости со старым `claude-gpt-effort-proxy.py` маппит `xhigh` -> `high` для совместимости со старым
@@ -266,7 +268,7 @@ GPT/claude-code-proxy backend; текущие лаунчеры его напря
```bash ```bash
bash tests/test_fixes.sh # структура ai-setup.sh и синтаксис 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) bash tests/test_network.sh # маршрутизация (нужен активный ru-bypass)
# test_sigint.sh # ручной диагностический тест SIGINT # test_sigint.sh # ручной диагностический тест SIGINT
``` ```

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/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 # Запуск: bash ai-setup.sh
# ============================================================ # ============================================================
@@ -1687,6 +1687,95 @@ done
KIMIEOF KIMIEOF
chmod +x "$BIN_DIR/ai-kimi" 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 === # === ai-openrouter ===
cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF' cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF'
#!/usr/bin/env bash #!/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/^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-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-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/^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/^\([[: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" 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" source "$BIN_DIR/ai-api-helpers.sh"
_setup_isolated_config deepseek opus high '' _setup_isolated_config deepseek opus high ''
_setup_isolated_config kimi opus high '' _setup_isolated_config kimi opus high ''
_setup_isolated_config glm opus high ''
_setup_isolated_config openrouter "openai/gpt-5.5" high '' _setup_isolated_config openrouter "openai/gpt-5.5" high ''
info "Удаляю старые версии скриптов (claude_*)..." 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 if [ "$BIN_DIR" != "$HOME/.local/bin" ]; then
warn "BIN_DIR=$BIN_DIR — удаляю старые скрипты из ~/.local/bin/ ..." warn "BIN_DIR=$BIN_DIR — удаляю старые скрипты из ~/.local/bin/ ..."
rm -f "$HOME/.local/bin/ai-gpt" "$HOME/.local/bin/ai-deepseek" "$HOME/.local/bin/ai-kimi" \ 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" "$HOME/.local/bin/ai-api-helpers.sh" "$HOME/.local/bin/claude-gpt-effort-proxy.py"
fi fi
@@ -1877,6 +1968,7 @@ echo " На базе Claude Code:"
echo -e " ${CYAN}ai-claude${NC} - Оригинальный Claude Code (Anthropic)" echo -e " ${CYAN}ai-claude${NC} - Оригинальный Claude Code (Anthropic)"
echo -e " ${CYAN}ai-deepseek${NC} - DeepSeek (через Claude Code, API ключ сохраняется)" 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-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 -e " ${CYAN}ai-openrouter${NC} - OpenRouter (через Claude Code: GPT-5.5, Grok, Qwen, MiniMax, Llama и др.)"
echo "" echo ""
echo " Нативные CLI:" echo " Нативные CLI:"

View File

@@ -33,7 +33,7 @@ else
echo -e "${YEL}Шаги для новой машины (выполнить по порядку):${CLR}" echo -e "${YEL}Шаги для новой машины (выполнить по порядку):${CLR}"
echo "" echo ""
echo -e " ${BLD}1) AI-инструменты${CLR}" 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 -e " ${GRY}Запрашивает API-ключи. Запускать один раз.${CLR}"
echo "" echo ""
echo -e " ${BLD}2) Сеть: ru-bypass + kill switch${CLR}" echo -e " ${BLD}2) Сеть: ru-bypass + kill switch${CLR}"
@@ -173,7 +173,7 @@ case "$choice" in
echo "" echo ""
echo -e "${BLD}AI инструменты:${CLR}" 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 if command -v "$cmd" &>/dev/null; then
echo -e " ${GRN}${CLR} $cmd" echo -e " ${GRN}${CLR} $cmd"
else else
@@ -184,7 +184,7 @@ case "$choice" in
echo "" echo ""
echo -e "${BLD}API ключи:${CLR}" echo -e "${BLD}API ключи:${CLR}"
cfg="$HOME/.config/ai-setup" 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/}" name="${f/_key/}"
if [ -s "$cfg/$f" ]; then if [ -s "$cfg/$f" ]; then
echo -e " ${GRN}${CLR} $name" echo -e " ${GRN}${CLR} $name"
@@ -195,7 +195,7 @@ case "$choice" in
echo "" echo ""
echo -e "${BLD}API доступность:${CLR}" 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%%:*}" _name="${entry%%:*}"
_host="${entry##*:}" _host="${entry##*:}"
_ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null) _ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null)

View File

@@ -16,11 +16,16 @@ awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' scripts/ai-setup.sh | \
sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash
chmod +x "$BIN_DIR/ai-gpt" chmod +x "$BIN_DIR/ai-gpt"
# Извлекаем ai-kimi # Извлекаем ai-kimi
awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' scripts/ai-setup.sh | \ awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' scripts/ai-setup.sh | \
sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash sed "s|\\\$BIN_DIR|$BIN_DIR|g" | bash
chmod +x "$BIN_DIR/ai-kimi" 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 ===" echo "=== Test 1: ai-gpt calls codex install URL when missing ==="
MOCK_LOG="$TMPDIR/mock_curl.log" MOCK_LOG="$TMPDIR/mock_curl.log"
@@ -62,5 +67,17 @@ else
exit 1 exit 1
fi 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 ""
echo "=== All tests passed ===" echo "=== All tests passed ==="

View File

@@ -14,6 +14,7 @@ fail() { echo "[FAIL] $1"; FAIL=$((FAIL+1)); }
# Extract sections # Extract sections
GPT_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' "$SCRIPT") GPT_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gpt"/,/^GPTEOF/' "$SCRIPT")
KIMI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' "$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") GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT")
HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT") HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT")
@@ -66,6 +67,28 @@ test_kimi_no_artemox() {
fi 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 ───────────────────────────────── # ── ai-gemini: native launcher generation ─────────────────────────────────
test_gemini_native_launcher() { test_gemini_native_launcher() {
if echo "$GEMINI_SECTION" | grep -q 'antigravity CLI (agy)' \ if echo "$GEMINI_SECTION" | grep -q 'antigravity CLI (agy)' \
@@ -176,6 +199,8 @@ test_gpt_no_proxy
test_kimi_claude_launcher test_kimi_claude_launcher
test_kimi_official_api test_kimi_official_api
test_kimi_no_artemox test_kimi_no_artemox
test_glm_claude_launcher
test_glm_official_api
test_gemini_native_launcher test_gemini_native_launcher
test_global_rules_include_quality_guidelines test_global_rules_include_quality_guidelines
test_native_rule_files_generated test_native_rule_files_generated