feat: добавить ai-opencode лаунчер (OpenCode Go + routatic-proxy)
- Новый лаунчер ai-opencode с routatic-proxy на 127.0.0.1:3456 - Автоустановка routatic-proxy под linux/darwin amd64/arm64 - Модели: deepseek-v4-pro (opus/sonnet), kimi-k2.6 (haiku) - AI_RESET_KEY, OPENCODE_GO_API_KEY env fallback, управление opencode_key - Документация: EFFORT_MAPPING.md, QUICK_START.md, README.md - Статус-проверка в setup.sh: ai-opencode, opencode_key, opencode.ai - Тесты: 4 новых теста для ai-opencode в test_fixes.sh Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
## Как это работает
|
## Как это работает
|
||||||
|
|
||||||
`/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code:
|
`/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code:
|
||||||
`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`.
|
`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`.
|
||||||
|
|
||||||
Нативные лаунчеры `ai-gpt` (OpenAI Codex) и `ai-gemini` (Antigravity `agy`) не используют
|
Нативные лаунчеры `ai-gpt` (OpenAI Codex) и `ai-gemini` (Antigravity `agy`) не используют
|
||||||
эту схему. У них свои настройки reasoning внутри соответствующего CLI.
|
эту схему. У них свои настройки reasoning внутри соответствующего CLI.
|
||||||
@@ -12,18 +12,23 @@
|
|||||||
|
|
||||||
## Таблица маппинга
|
## Таблица маппинга
|
||||||
|
|
||||||
| 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`) |
|
| 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`) | OpenCode Go (`ai-opencode`) |
|
||||||
|:---:|:---:|:---:|:---:|:---:|:---:|
|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|
||||||
| `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. Конкретная интерпретация зависит от выбранной
|
||||||
модели и backend-а OpenRouter.
|
модели и backend-а OpenRouter.
|
||||||
|
|
||||||
|
Для OpenCode Go лаунчер работает через `routatic-proxy`, который транслирует Anthropic-запросы
|
||||||
|
в OpenAI/Gemini-формат для OpenCode Go API. Локального маппинга effort нет — thinking budget
|
||||||
|
не транслируется напрямую в OpenCode Go бекенд. Прокси и бекенд-модели выполняют reasoning
|
||||||
|
на своей стороне независимо от уровня effort.
|
||||||
|
|
||||||
## Нативные уровни каждого провайдера
|
## Нативные уровни каждого провайдера
|
||||||
|
|
||||||
### Anthropic (Claude)
|
### Anthropic (Claude)
|
||||||
@@ -75,6 +80,13 @@ high / max
|
|||||||
и не вызывает локальный effort proxy. Поэтому `low`/`medium`/`high`/`xhigh`/`max` не
|
и не вызывает локальный effort proxy. Поэтому `low`/`medium`/`high`/`xhigh`/`max` не
|
||||||
преобразуются в shell-лаунчере.
|
преобразуются в shell-лаунчере.
|
||||||
|
|
||||||
|
### OpenCode Go (routatic-proxy)
|
||||||
|
|
||||||
|
Текущий `ai-opencode` работает через Claude Code с локальным `routatic-proxy`
|
||||||
|
(`ANTHROPIC_BASE_URL=http://127.0.0.1:3456`), который транслирует запросы в OpenCode Go API.
|
||||||
|
Effort не преобразуется локально — thinking budget не имеет прямого эффекта на OpenCode Go бекенд.
|
||||||
|
Дефолт `ai-opencode`: `high`.
|
||||||
|
|
||||||
`claude-gpt-effort-proxy.py` все еще генерируется как совместимый helper для старого
|
`claude-gpt-effort-proxy.py` все еще генерируется как совместимый helper для старого
|
||||||
`claude-code-proxy` backend-а. Если использовать его вручную, он маппит только
|
`claude-code-proxy` backend-а. Если использовать его вручную, он маппит только
|
||||||
`xhigh` -> `high`, потому что `claude-code-proxy` принимает `low`, `medium`, `high`, `max`.
|
`xhigh` -> `high`, потому что `claude-code-proxy` принимает `low`, `medium`, `high`, `max`.
|
||||||
@@ -88,11 +100,12 @@ high / max
|
|||||||
| Kimi K2.7/K2.6 | Moonshot API | На стороне сервера |
|
| Kimi K2.7/K2.6 | Moonshot API | На стороне сервера |
|
||||||
| GLM 5.2 | Zhipu AI API | На стороне сервера |
|
| GLM 5.2 | Zhipu AI API | На стороне сервера |
|
||||||
| OpenRouter/GPT-5.5 | Локального маппинга нет | `ai-openrouter` отправляет значение как есть |
|
| OpenRouter/GPT-5.5 | Локального маппинга нет | `ai-openrouter` отправляет значение как есть |
|
||||||
|
| OpenCode Go | Локального маппинга нет | `ai-opencode` отправляет значение через routatic-proxy |
|
||||||
| 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-glm`, `ai-openrouter`)
|
Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`)
|
||||||
запоминает свой уровень effort отдельно в `settings.json` лаунчера.
|
запоминает свой уровень effort отдельно в `settings.json` лаунчера.
|
||||||
|
|
||||||
`/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется.
|
`/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ bash setup.sh
|
|||||||
```
|
```
|
||||||
|
|
||||||
Спросит про VLESS-прокси (по умолчанию `Y`; если не нужен, ответь `n`), затем установит лаунчеры
|
Спросит про VLESS-прокси (по умолчанию `Y`; если не нужен, ответь `n`), затем установит лаунчеры
|
||||||
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-gemini`
|
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`, `ai-gemini`
|
||||||
в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
|
в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
|
||||||
|
|
||||||
После установки, если команды не видны:
|
После установки, если команды не видны:
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ bash tests/test_network.sh # полные тесты
|
|||||||
- `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-glm` - Claude Code через Zhipu AI GLM 5.2 API (`api.z.ai/api/anthropic`)
|
||||||
- `ai-openrouter` - Claude Code через OpenRouter (GPT-5.5, Grok, Qwen, GLM 5.2 и др.)
|
- `ai-openrouter` - Claude Code через OpenRouter (GPT-5.5, Grok, Qwen, GLM 5.2 и др.)
|
||||||
|
- `ai-opencode` - Claude Code через OpenCode Go + routatic-proxy (DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)
|
||||||
- `ai-gemini` - нативный Antigravity CLI `agy`
|
- `ai-gemini` - нативный Antigravity CLI `agy`
|
||||||
- `ai-api-helpers.sh` - вспомогательные функции для лаунчеров
|
- `ai-api-helpers.sh` - вспомогательные функции для лаунчеров
|
||||||
- `claude-gpt-effort-proxy.py` - совместимый helper для старого GPT/claude-code-proxy backend
|
- `claude-gpt-effort-proxy.py` - совместимый helper для старого GPT/claude-code-proxy backend
|
||||||
@@ -229,13 +230,14 @@ android init
|
|||||||
- `~/.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/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/opencode_key` - OpenCode Go 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`)
|
||||||
|
|
||||||
## Права запуска агентов
|
## Права запуска агентов
|
||||||
|
|
||||||
- `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox`
|
- `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox`
|
||||||
- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-gemini` используют `--dangerously-skip-permissions`
|
- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions`
|
||||||
|
|
||||||
Удобно для локального coding workflow, но это не sandbox для недоверенного кода.
|
Удобно для локального coding workflow, но это не sandbox для недоверенного кода.
|
||||||
|
|
||||||
@@ -250,7 +252,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-glm`, `ai-openrouter`).
|
для Claude Code лаунчеров (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`).
|
||||||
Нативные `ai-gpt` и `ai-gemini` живут отдельно.
|
Нативные `ai-gpt` и `ai-gemini` живут отдельно.
|
||||||
|
|
||||||
`claude-gpt-effort-proxy.py` маппит `xhigh` -> `high` для совместимости со старым
|
`claude-gpt-effort-proxy.py` маппит `xhigh` -> `high` для совместимости со старым
|
||||||
|
|||||||
@@ -685,6 +685,54 @@ else
|
|||||||
info "Android CLI не найден в PATH, пропускаю android init"
|
info "Android CLI не найден в PATH, пропускаю android init"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ── 5. routatic-proxy (OpenCode Go → Claude Code) ──────────
|
||||||
|
info "Проверяю routatic-proxy..."
|
||||||
|
ROUTATIC_BIN="$HOME/.local/bin/routatic-proxy"
|
||||||
|
[ ! -f "$ROUTATIC_BIN" ] && ROUTATIC_BIN="$(command -v routatic-proxy 2>/dev/null || true)"
|
||||||
|
|
||||||
|
if [ -z "$ROUTATIC_BIN" ] || [ ! -f "$ROUTATIC_BIN" ]; then
|
||||||
|
info "Устанавливаю routatic-proxy..."
|
||||||
|
_uname_s=$(uname -s)
|
||||||
|
_uname_m=$(uname -m)
|
||||||
|
ROUTATIC_PLATFORM=""
|
||||||
|
case "${_uname_s}-${_uname_m}" in
|
||||||
|
Linux-x86_64) ROUTATIC_PLATFORM="linux-amd64" ;;
|
||||||
|
Linux-aarch64) ROUTATIC_PLATFORM="linux-arm64" ;;
|
||||||
|
Linux-arm64) ROUTATIC_PLATFORM="linux-arm64" ;;
|
||||||
|
Darwin-x86_64) ROUTATIC_PLATFORM="darwin-amd64" ;;
|
||||||
|
Darwin-arm64) ROUTATIC_PLATFORM="darwin-arm64" ;;
|
||||||
|
Darwin-aarch64) ROUTATIC_PLATFORM="darwin-arm64" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -n "$ROUTATIC_PLATFORM" ]; then
|
||||||
|
ROUTATIC_URL="https://github.com/routatic/proxy/releases/latest/download/routatic-proxy_${ROUTATIC_PLATFORM}"
|
||||||
|
if curl -fsSL "$ROUTATIC_URL" -o "$HOME/.local/bin/routatic-proxy"; then
|
||||||
|
chmod +x "$HOME/.local/bin/routatic-proxy"
|
||||||
|
success "routatic-proxy установлен"
|
||||||
|
else
|
||||||
|
warn "Не удалось скачать routatic-proxy с GitHub"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Неизвестная платформа ${_uname_s} ${_uname_m}. Пропускаю routatic-proxy."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
success "routatic-proxy уже установлен"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Symlink в BIN_DIR если используется ~/bin вместо ~/.local/bin
|
||||||
|
if [ "$BIN_DIR" != "$HOME/.local/bin" ] && [ -f "$HOME/.local/bin/routatic-proxy" ] && [ ! -f "$BIN_DIR/routatic-proxy" ]; then
|
||||||
|
ln -sf "$HOME/.local/bin/routatic-proxy" "$BIN_DIR/routatic-proxy"
|
||||||
|
success "routatic-proxy symlink -> $BIN_DIR/routatic-proxy"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Инициализируем конфиг routatic-proxy
|
||||||
|
if command -v routatic-proxy &>/dev/null; then
|
||||||
|
if [ ! -f "$HOME/.config/routatic-proxy/config.json" ]; then
|
||||||
|
routatic-proxy init 2>/dev/null || true
|
||||||
|
success "routatic-proxy config инициализирован"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ── 6. Папка для конфигов ────────────────────────────────────
|
# ── 6. Папка для конфигов ────────────────────────────────────
|
||||||
mkdir -p "$CONFIG_DIR"
|
mkdir -p "$CONFIG_DIR"
|
||||||
|
|
||||||
@@ -2145,6 +2193,85 @@ claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
|||||||
CLAUDEEOF
|
CLAUDEEOF
|
||||||
chmod +x "$BIN_DIR/ai-claude"
|
chmod +x "$BIN_DIR/ai-claude"
|
||||||
|
|
||||||
|
# === ai-opencode ===
|
||||||
|
cat > "$BIN_DIR/ai-opencode" << 'OPENCODEEOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/null || true
|
||||||
|
|
||||||
|
key_file="$HOME/.config/ai-setup/opencode_key"
|
||||||
|
api_key=""
|
||||||
|
|
||||||
|
# Принудительный сброс сохранённого ключа через AI_RESET_KEY=1
|
||||||
|
if [ "${AI_RESET_KEY:-0}" == "1" ] && [ -f "$key_file" ]; then
|
||||||
|
rm -f "$key_file"
|
||||||
|
api_key=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -f "$key_file" ] && api_key=$(cat "$key_file")
|
||||||
|
|
||||||
|
# Приоритет: env var → файл → ввод
|
||||||
|
if [ -z "$api_key" ] && [ -n "$OPENCODE_GO_API_KEY" ]; then
|
||||||
|
api_key="$OPENCODE_GO_API_KEY"
|
||||||
|
mkdir -p "$(dirname "$key_file")"
|
||||||
|
printf '%s' "$api_key" > "$key_file"
|
||||||
|
chmod 600 "$key_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$api_key" ]; then
|
||||||
|
echo "Получить ключ: https://opencode.ai/en/go"
|
||||||
|
read -r -p "Введи OpenCode Go ключ (sk-opencode-...): " api_key
|
||||||
|
[ -z "$api_key" ] && { echo "Выход."; exit 1; }
|
||||||
|
mkdir -p "$(dirname "$key_file")"
|
||||||
|
printf '%s' "$api_key" > "$key_file"
|
||||||
|
chmod 600 "$key_file"
|
||||||
|
echo "Ключ сохранён."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- routatic-proxy ---
|
||||||
|
export ROUTATIC_PROXY_API_KEY="$api_key"
|
||||||
|
|
||||||
|
# Запускаем прокси в фоне, если ещё не запущен
|
||||||
|
if ! routatic-proxy status &>/dev/null; then
|
||||||
|
echo -n "Запускаю routatic-proxy... "
|
||||||
|
routatic-proxy serve -b 2>/dev/null
|
||||||
|
sleep 1
|
||||||
|
if routatic-proxy status &>/dev/null; then
|
||||||
|
echo "готово"
|
||||||
|
else
|
||||||
|
echo "НЕ УДАЛОСЬ"
|
||||||
|
echo "Проверь: routatic-proxy serve"
|
||||||
|
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=opencode
|
||||||
|
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/opencode"
|
||||||
|
# Модели OpenCode Go через routatic-proxy.
|
||||||
|
# deepseek-v4-pro — основной для сложных задач (opus/sonnet),
|
||||||
|
# kimi-k2.6 — быстрый (haiku), рекомендован routatic-proxy как дефолт.
|
||||||
|
_setup_isolated_config opencode deepseek-v4-pro high ''
|
||||||
|
_apply_effort opencode high
|
||||||
|
ANTHROPIC_BASE_URL="http://127.0.0.1:3456" \
|
||||||
|
ANTHROPIC_AUTH_TOKEN="unused" \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL="deepseek-v4-pro" \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="DeepSeek V4 Pro (Go)" \
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="DeepSeek V4 Pro через OpenCode Go" \
|
||||||
|
ANTHROPIC_DEFAULT_SONNET_MODEL="deepseek-v4-pro" \
|
||||||
|
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="DeepSeek V4 Pro (Go)" \
|
||||||
|
ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="DeepSeek V4 Pro через OpenCode Go" \
|
||||||
|
ANTHROPIC_DEFAULT_HAIKU_MODEL="kimi-k2.6" \
|
||||||
|
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="Kimi K2.6 (Go)" \
|
||||||
|
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="Kimi K2.6 через OpenCode Go" \
|
||||||
|
CLAUDE_CODE_SUBAGENT_MODEL="kimi-k2.6" \
|
||||||
|
CLAUDE_CODE_DISABLE_1M_CONTEXT=1 \
|
||||||
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
||||||
|
claude --dangerously-skip-permissions --system-prompt-file "$_PROMPT_FILE" "$@"
|
||||||
|
OPENCODEEOF
|
||||||
|
chmod +x "$BIN_DIR/ai-opencode"
|
||||||
|
|
||||||
# ── 8.5. Proxychains инъекция (только в режиме vless) ────────
|
# ── 8.5. Proxychains инъекция (только в режиме vless) ────────
|
||||||
if [ "$USE_VLESS" -eq 1 ]; then
|
if [ "$USE_VLESS" -eq 1 ]; then
|
||||||
info "Включаю proxychains4 в ai-лаунчеры..."
|
info "Включаю proxychains4 в ai-лаунчеры..."
|
||||||
@@ -2155,6 +2282,7 @@ if [ "$USE_VLESS" -eq 1 ]; then
|
|||||||
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:]]*\)"\$agy_bin" --dangerously-skip-permissions "\$@"|\1proxychains4 -f "\$HOME/.proxychains-xray.conf" "\$agy_bin" --dangerously-skip-permissions "\$@"|' "$BIN_DIR/ai-gemini"
|
sed -i 's|^\([[:space:]]*\)"\$agy_bin" --dangerously-skip-permissions "\$@"|\1proxychains4 -f "\$HOME/.proxychains-xray.conf" "\$agy_bin" --dangerously-skip-permissions "\$@"|' "$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"
|
||||||
|
sed -i 's/^claude --dangerously-skip-permissions/proxychains4 -f "\$HOME\/\.proxychains-xray\.conf" claude --dangerously-skip-permissions/' "$BIN_DIR/ai-opencode"
|
||||||
success "proxychains4 интегрирован"
|
success "proxychains4 интегрирован"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -2166,6 +2294,7 @@ _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 glm opus high ''
|
||||||
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
||||||
|
_setup_isolated_config opencode deepseek-v4-pro high ''
|
||||||
|
|
||||||
info "Удаляю старые версии скриптов (claude_*)..."
|
info "Удаляю старые версии скриптов (claude_*)..."
|
||||||
rm -f "$BIN_DIR/claude_gpt" "$BIN_DIR/claude_deepseek" "$BIN_DIR/claude_kimi" "$BIN_DIR/claude_gemini" "$BIN_DIR/claude_api_helpers.sh"
|
rm -f "$BIN_DIR/claude_gpt" "$BIN_DIR/claude_deepseek" "$BIN_DIR/claude_kimi" "$BIN_DIR/claude_gemini" "$BIN_DIR/claude_api_helpers.sh"
|
||||||
@@ -2175,6 +2304,7 @@ 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-glm" "$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-opencode" \
|
||||||
"$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
|
||||||
|
|
||||||
@@ -2194,6 +2324,7 @@ echo -e " ${CYAN}ai-deepseek${NC} - DeepSeek (через Claude Code,
|
|||||||
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-glm${NC} - GLM 5.2 (через Claude Code, Zhipu AI API)"
|
||||||
echo -e " ${CYAN}ai-openrouter${NC} - OpenRouter (через Claude Code: GPT-5.5, Grok, Qwen, GLM 5.2 и др.)"
|
echo -e " ${CYAN}ai-openrouter${NC} - OpenRouter (через Claude Code: GPT-5.5, Grok, Qwen, GLM 5.2 и др.)"
|
||||||
|
echo -e " ${CYAN}ai-opencode${NC} - OpenCode Go (через Claude Code + routatic-proxy: DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)"
|
||||||
echo ""
|
echo ""
|
||||||
echo " Нативные CLI:"
|
echo " Нативные CLI:"
|
||||||
echo -e " ${CYAN}ai-gpt${NC} - OpenAI Codex (нативный CLI, автоустановка)"
|
echo -e " ${CYAN}ai-gpt${NC} - OpenAI Codex (нативный CLI, автоустановка)"
|
||||||
|
|||||||
6
setup.sh
6
setup.sh
@@ -177,7 +177,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-glm ai-openrouter ai-gemini android; do
|
for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-openrouter ai-opencode 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
|
||||||
@@ -188,7 +188,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 glm_key openrouter_key; do
|
for f in deepseek_key kimi_key glm_key openrouter_key opencode_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"
|
||||||
@@ -199,7 +199,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" "GLM:api.z.ai" "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" "OpenCode:opencode.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)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ 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")
|
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")
|
||||||
|
OPENCODE_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-opencode"/,/^OPENCODEEOF/' "$SCRIPT")
|
||||||
HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT")
|
HELPERS_SECTION=$(awk '/^cat > "\$HELPERS_FILE"/,/^HELPEREOF/' "$SCRIPT")
|
||||||
|
|
||||||
# ── ai-gpt: auto-install codex ────────────────────────────────────────────
|
# ── ai-gpt: auto-install codex ────────────────────────────────────────────
|
||||||
@@ -192,6 +193,49 @@ test_android_skill_exists() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── ai-opencode: launches claude with routatic-proxy backend ──────────────────
|
||||||
|
test_opencode_claude_launcher() {
|
||||||
|
if echo "$OPENCODE_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q 'ANTHROPIC_BASE_URL'; then
|
||||||
|
ok "ai-opencode: launches claude with ANTHROPIC_BASE_URL set"
|
||||||
|
else
|
||||||
|
fail "ai-opencode: must launch claude with ANTHROPIC_BASE_URL"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── ai-opencode: uses routatic-proxy (local proxy) ─────────────────────────────
|
||||||
|
test_opencode_routatic_proxy() {
|
||||||
|
if echo "$OPENCODE_SECTION" | grep -q 'routatic-proxy' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q '127.0.0.1:3456' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q 'ROUTATIC_PROXY_API_KEY'; then
|
||||||
|
ok "ai-opencode: uses routatic-proxy on 127.0.0.1:3456"
|
||||||
|
else
|
||||||
|
fail "ai-opencode: must use routatic-proxy with local proxy and API key env"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── ai-opencode: manages opencode_key ──────────────────────────────────────────
|
||||||
|
test_opencode_key_management() {
|
||||||
|
if echo "$OPENCODE_SECTION" | grep -q 'opencode_key' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q 'AI_RESET_KEY' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q 'OPENCODE_GO_API_KEY'; then
|
||||||
|
ok "ai-opencode: opencode_key with AI_RESET_KEY and OPENCODE_GO_API_KEY env fallback"
|
||||||
|
else
|
||||||
|
fail "ai-opencode: must manage opencode_key with reset and env fallback"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── ai-opencode: correct default models ────────────────────────────────────────
|
||||||
|
test_opencode_models() {
|
||||||
|
if echo "$OPENCODE_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL="deepseek-v4-pro"' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q 'ANTHROPIC_DEFAULT_HAIKU_MODEL="kimi-k2.6"' \
|
||||||
|
&& echo "$OPENCODE_SECTION" | grep -q 'CLAUDE_CODE_DISABLE_1M_CONTEXT=1'; then
|
||||||
|
ok "ai-opencode: correct default models (deepseek-v4-pro opus, kimi-k2.6 haiku)"
|
||||||
|
else
|
||||||
|
fail "ai-opencode: must have deepseek-v4-pro opus and kimi-k2.6 haiku"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ── run all tests ─────────────────────────────────────────────────────────────
|
# ── run all tests ─────────────────────────────────────────────────────────────
|
||||||
test_script_syntax
|
test_script_syntax
|
||||||
test_gpt_autoinstall
|
test_gpt_autoinstall
|
||||||
@@ -210,6 +254,10 @@ test_android_init_called
|
|||||||
test_android_symlink_to_bin_dir
|
test_android_symlink_to_bin_dir
|
||||||
test_no_proxychains_for_android
|
test_no_proxychains_for_android
|
||||||
test_android_skill_exists
|
test_android_skill_exists
|
||||||
|
test_opencode_claude_launcher
|
||||||
|
test_opencode_routatic_proxy
|
||||||
|
test_opencode_key_management
|
||||||
|
test_opencode_models
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Results: $PASS passed, $FAIL failed"
|
echo "Results: $PASS passed, $FAIL failed"
|
||||||
|
|||||||
Reference in New Issue
Block a user