feat(mimo): add ai-mimo launcher for Xiaomi MiMo V2.6 Pro
ai-mimo runs Claude Code through Xiaomi's Anthropic-compatible API (Token Plan or pay-as-you-go). The key's endpoint is found by probing token-plan-sgp, token-plan-ams and api.xiaomimimo.com (a key only works in its own region) and is saved to mimo_base_url; MIMO_BASE_URL overrides. Unreachable endpoints are skipped, token-plan-cn is left out of the probe since it times out from our network, and a 402 on the pay-as-you-go endpoint explains that a tp- Token Plan key is needed. Always the smartest model: mimo-v2.6-pro in every slot and for subagents, --model opus and --effort max on each start, 128000 output tokens (Claude Code's ceiling), real 1M context window. Measured on 13.10: MiMo ignores output_config.effort (even "bogus" is accepted, no length trend from low to max) and treats thinking adaptive like enabled, so reasoning is always on; EFFORT_MAPPING.md records this. /logout-mimo is registered as a command and handled by the logout hook (removes mimo_key and mimo_base_url). setup.sh status, statusline brand color, README, QUICK_START and AGENTS.md list the new launcher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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-glm`, `ai-eltex`, `ai-eltex-qwen`, `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-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-openrouter`, `ai-gemini`, `ai-api-helpers.sh`, `ai-claude`, `claude-gpt-effort-proxy.py`) должны быть **полностью перезаписаны** актуальными версиями. Запрещено выполнять слияние (merge) старого и нового содержимого или дополнение (append). Скрипт обязан привести все генерируемые файлы к эталонному виду, однозначно определяемому текущей конфигурацией.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Как это работает
|
||||
|
||||
`/effort` и `AI_EFFORT` относятся к лаунчерам, которые запускают Claude Code:
|
||||
`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`.
|
||||
`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-mimo`, `ai-openrouter`, `ai-opencode`.
|
||||
|
||||
Нативные лаунчеры `ai-gpt` (OpenAI Codex), `ai-gemini` (Antigravity `agy`) и `ai-cursor`
|
||||
(Cursor CLI `agent`) не используют эту схему. У них свои настройки reasoning внутри
|
||||
@@ -99,6 +99,35 @@ low -> high -> max
|
||||
Effort не преобразуется локально — thinking budget не имеет прямого эффекта на OpenCode Go бекенд.
|
||||
Дефолт `ai-opencode`: `high`.
|
||||
|
||||
### Xiaomi MiMo V2.6
|
||||
|
||||
```text
|
||||
thinking on (единственный уровень)
|
||||
```
|
||||
|
||||
- `ai-mimo` работает через Claude Code с Anthropic-эндпоинтом Xiaomi (Token Plan региона
|
||||
подписки или `api.xiaomimimo.com`).
|
||||
- Claude Code 2.1.294 отправляет `thinking: {type: "adaptive"}` и `output_config.effort` со всеми
|
||||
5 уровнями и для `mimo-v2.6-pro`, и для `mimo-v2.6-flash`, даже без
|
||||
`CLAUDE_CODE_ALWAYS_ENABLE_EFFORT` (проверено перехватом запроса).
|
||||
- MiMo effort игнорирует. В доке Anthropic API MiMo из параметров рассуждения есть только
|
||||
`thinking.type` (`enabled` по умолчанию / `disabled` / `adaptive`), `effort` и `budget_tokens` нет.
|
||||
Невалидные `output_config.effort=bogus` и `thinking.type=bogus` дают HTTP 200.
|
||||
- Замер 2026-10-13, по 3 запроса на уровень, средний `output_tokens`. Pro, счётная задача:
|
||||
без effort ~310, `low` ~340, `high` ~280, `max` ~315. Pro, задача на включения-исключения:
|
||||
`low` ~970, `max` ~825. Flash на ней же: `low` ~460, `max` ~580. Разброс внутри уровня больше
|
||||
разницы между уровнями, тренда нет.
|
||||
- Реально переключается только thinking: `thinking.type=disabled` даёт 4 токена без размышлений
|
||||
и неверные ответы (2 из 3). Claude Code его для MiMo не отправляет.
|
||||
- `thinking.type=adaptive` (его шлёт Claude Code) MiMo отрабатывает так же, как `enabled`:
|
||||
размышления есть даже на «скажи привет», на задаче на включения-исключения `adaptive` ~670,
|
||||
`enabled` ~600 токенов при разбросе 356-1161. `CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1`
|
||||
в Claude Code 2.1.294 запрос не меняет, да и не нужен.
|
||||
- Глубину размышлений ограничивает только `max_tokens`: `ai-mimo` выставляет
|
||||
`CLAUDE_CODE_MAX_OUTPUT_TOKENS=128000` (потолок Claude Code, MiMo принимает до 131072).
|
||||
- Дефолт `ai-mimo`: `max`, задаётся через CLI `--effort` при каждом запуске (как у `ai-eltex-qwen`).
|
||||
На размышления не влияет, но если Xiaomi начнёт учитывать effort, лаунчер сразу будет на максимуме.
|
||||
|
||||
`claude-gpt-effort-proxy.py` все еще генерируется как совместимый helper для старого
|
||||
`claude-code-proxy` backend-а. Если использовать его вручную, он маппит только
|
||||
`xhigh` -> `high`, потому что `claude-code-proxy` принимает `low`, `medium`, `high`, `max`.
|
||||
@@ -111,13 +140,14 @@ Effort не преобразуется локально — thinking budget не
|
||||
| DeepSeek V4 | DeepSeek API | На стороне сервера |
|
||||
| Kimi K2.7/K2.6 | Moonshot API | На стороне сервера |
|
||||
| GLM 5.3 | Z.ai API (`low,medium→low`, `high,xhigh→high`, `max`) | На стороне сервера |
|
||||
| Xiaomi MiMo V2.6 | Не маппится: MiMo принимает `output_config.effort`, но игнорирует его | - |
|
||||
| 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` |
|
||||
|
||||
## Persistence effort между сессиями
|
||||
|
||||
Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-openrouter`, `ai-opencode`)
|
||||
Каждый Claude Code лаунчер (`ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-mimo`, `ai-openrouter`, `ai-opencode`)
|
||||
запоминает свой уровень effort отдельно в `settings.json` лаунчера.
|
||||
|
||||
`/effort` внутри сессии работает для всех уровней. `CLAUDE_CODE_EFFORT_LEVEL` не используется.
|
||||
@@ -130,8 +160,8 @@ AI_EFFORT=high ai-deepseek # включить high
|
||||
ai-deepseek # без флага - использовать уровень из settings.json
|
||||
```
|
||||
|
||||
Дефолты: `max` для `ai-glm`, `ai-eltex` и `ai-eltex-qwen`, `xhigh` для `ai-claude`, `high` для
|
||||
остальных Claude Code лаунчеров. `ai-glm`, `ai-eltex` и `ai-eltex-qwen` передают уровень через CLI
|
||||
Дефолты: `max` для `ai-glm`, `ai-eltex`, `ai-eltex-qwen` и `ai-mimo`, `xhigh` для `ai-claude`, `high` для
|
||||
остальных Claude Code лаунчеров. `ai-glm`, `ai-eltex`, `ai-eltex-qwen` и `ai-mimo` передают уровень через CLI
|
||||
`--effort`, поэтому каждый запуск стартует на `max` (или на `AI_EFFORT`), а `/effort` внутри сессии
|
||||
действует до её конца.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ bash setup.sh
|
||||
```
|
||||
|
||||
Установит лаунчеры
|
||||
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-openrouter`, `ai-opencode`, `ai-gemini`, `ai-cursor`
|
||||
`ai-claude`, `ai-gpt`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-openrouter`, `ai-opencode`, `ai-gemini`, `ai-cursor`
|
||||
в `~/bin`, если он уже есть в `PATH`, иначе в `~/.local/bin/`, и запишет API-ключи.
|
||||
|
||||
После установки, если команды не видны:
|
||||
|
||||
@@ -163,6 +163,7 @@ bash tests/test_network.sh # полные тесты
|
||||
- `ai-glm` - Claude Code через Zhipu AI GLM 5.3 API (`api.z.ai/api/anthropic`)
|
||||
- `ai-eltex` - Claude Code через корпоративный LLM-прокси Eltex (`http://llm.eltex.loc:4000`, LiteLLM, team-подписка GLM). Ключ выдают админы ([дока](https://intdocs.eltex.loc/pages/viewpage.action?pageId=262329878)), модель `anth-glm-5.3` (Anthropic-эндпоинт Z.ai: настоящая GLM 5.3 и картинки); если ключу она недоступна, лаунчер выходит с понятной ошибкой; переопределение: `ELTEX_MODEL`, `ELTEX_BASE_URL`
|
||||
- `ai-eltex-qwen` - то же через корпоративный LLM-прокси Eltex, но на моделях Qwen со своим ключом от админов: по умолчанию `Eltex-Coder-Senior` (Qwen3.8-27B), если она есть у ключа, иначе `Eltex-Qwen3_8-Flash-Next`; ключ можно задать в `AI_ELTEX_LLM_API_KEY`, как в онбординге Eltex AI; переопределение: `ELTEX_QWEN_MODEL`, `ELTEX_BASE_URL`
|
||||
- `ai-mimo` - Claude Code через Xiaomi MiMo V2.6 (Anthropic-совместимый API, Token Plan или pay-as-you-go): всегда самая умная модель `mimo-v2.6-pro` (во всех слотах и сабагентах, `--model opus` на каждом запуске), effort `max`, вывод до 128000 токенов, окно 1M. Эндпоинт региона подписки (`token-plan-sgp`/`-ams`, для `sk-` ключа `api.xiaomimimo.com`) находится перебором при вводе ключа; переопределение: `MIMO_BASE_URL` (нужно для `token-plan-cn`: он в перебор не входит, с наших машин не отвечает)
|
||||
- `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`
|
||||
@@ -222,6 +223,7 @@ android init
|
||||
- `~/.config/ai-setup/glm_key` - Zhipu AI (GLM) API key (права 600)
|
||||
- `~/.config/ai-setup/eltex_key` - ключ корпоративного LLM-прокси Eltex от админов (права 600)
|
||||
- `~/.config/ai-setup/eltex_qwen_key` - ключ для моделей Qwen на том же прокси (права 600)
|
||||
- `~/.config/ai-setup/mimo_key` - Xiaomi MiMo API key (права 600), `mimo_base_url` - найденный для него эндпоинт
|
||||
- `~/.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` - глобальные правила агентов
|
||||
@@ -230,7 +232,7 @@ android init
|
||||
## Права запуска агентов
|
||||
|
||||
- `ai-gpt` использует `--dangerously-bypass-approvals-and-sandbox`
|
||||
- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions`
|
||||
- `ai-claude`, `ai-deepseek`, `ai-kimi`, `ai-glm`, `ai-eltex`, `ai-eltex-qwen`, `ai-mimo`, `ai-openrouter`, `ai-opencode`, `ai-gemini` используют `--dangerously-skip-permissions`
|
||||
- `ai-cursor` использует `--force` (алиас `--yolo`)
|
||||
|
||||
Удобно для локального coding workflow, но это не sandbox для недоверенного кода.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright (c) 2026 Виталий Никитенко. MIT License.
|
||||
# UserPromptSubmit hook: перехватывает /logout, /logout-glm, /logout-eltex, /logout-eltex-qwen, /logout-deepseek, /logout-kimi.
|
||||
# UserPromptSubmit hook: перехватывает /logout, /logout-glm, /logout-eltex, /logout-eltex-qwen, /logout-mimo, /logout-deepseek, /logout-kimi.
|
||||
# Удаляет сохранённый API-ключ провайдера, чтобы при следующем запуске лаунчер
|
||||
# запросил новый.
|
||||
# /logout-glm | /logout-eltex | /logout-eltex-qwen | /logout-deepseek | /logout-kimi — явно указанный провайдер.
|
||||
# /logout (без суффикса) — провайдер по AI_LAUNCHER (glm/eltex/eltex-qwen/deepseek/kimi).
|
||||
# /logout-glm | /logout-eltex | /logout-eltex-qwen | /logout-mimo | /logout-deepseek | /logout-kimi — явно указанный провайдер.
|
||||
# /logout (без суффикса) — провайдер по AI_LAUNCHER (glm/eltex/eltex-qwen/mimo/deepseek/kimi).
|
||||
# Для ai-claude и прочих лаунчеров /logout отступает (exit 0) — пусть работает
|
||||
# нативный oauth-logout. exit 2 после удаления: LLM не нужна, и нативная
|
||||
# /logout не пытается сделать бессмысленный oauth-logout для api-key провайдеров.
|
||||
@@ -19,11 +19,12 @@ case "$cmd" in
|
||||
logout-glm) target=glm ;;
|
||||
logout-eltex) target=eltex ;;
|
||||
logout-eltex-qwen) target=eltex-qwen ;;
|
||||
logout-mimo) target=mimo ;;
|
||||
logout-deepseek) target=deepseek ;;
|
||||
logout-kimi) target=kimi ;;
|
||||
logout)
|
||||
case "${AI_LAUNCHER:-claude}" in
|
||||
glm|eltex|eltex-qwen|deepseek|kimi) target="$AI_LAUNCHER" ;;
|
||||
glm|eltex|eltex-qwen|mimo|deepseek|kimi) target="$AI_LAUNCHER" ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
;;
|
||||
@@ -45,6 +46,10 @@ case "$target" in
|
||||
rm -f "$CFG/eltex_qwen_key"
|
||||
echo "✓ Eltex Qwen ключ удалён. Перезапусти ai-eltex-qwen, чтобы ввести новый." >&2
|
||||
;;
|
||||
mimo)
|
||||
rm -f "$CFG/mimo_key" "$CFG/mimo_base_url"
|
||||
echo "✓ MiMo ключ удалён. Перезапусти ai-mimo, чтобы ввести новый." >&2
|
||||
;;
|
||||
deepseek)
|
||||
rm -f "$CFG/deepseek_key"
|
||||
echo "✓ DeepSeek ключ удалён. Перезапусти ai-deepseek, чтобы ввести новый." >&2
|
||||
|
||||
@@ -39,6 +39,7 @@ _brand_color() {
|
||||
claude) printf '\033[38;5;173m' ;; # Anthropic оранжевый
|
||||
kimi) printf '\033[38;5;81m' ;; # Kimi голубой
|
||||
glm) printf '\033[38;5;223m' ;; # Z.ai кремовый (бренд-фон z.ai, #FFE4B5)
|
||||
mimo) printf '\033[38;5;202m' ;; # Xiaomi оранжевый (#FF6900)
|
||||
openrouter) printf '\033[38;5;135m' ;; # OpenRouter фиолетовый
|
||||
*) printf '\033[38;5;223m' ;; # кремовый (fallback)
|
||||
esac
|
||||
|
||||
@@ -1995,6 +1995,192 @@ claude --dangerously-skip-permissions --effort "${AI_EFFORT:-max}" --system-prom
|
||||
ELTEXQWENEOF
|
||||
chmod +x "$BIN_DIR/ai-eltex-qwen"
|
||||
|
||||
# === ai-mimo ===
|
||||
cat > "$BIN_DIR/ai-mimo" << 'MIMOEOF'
|
||||
#!/usr/bin/env bash
|
||||
# ai-mimo - запуск Claude Code через Xiaomi MiMo V2.6 (Anthropic-compatible API, Token Plan)
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/null || true
|
||||
|
||||
key_file="$HOME/.config/ai-setup/mimo_key"
|
||||
url_file="$HOME/.config/ai-setup/mimo_base_url"
|
||||
api_key=""
|
||||
reauth=0
|
||||
|
||||
# Принудительный сброс сохранённого ключа через AI_RESET_KEY=1
|
||||
if [ "${AI_RESET_KEY:-0}" == "1" ]; then
|
||||
rm -f "$key_file" "$url_file"
|
||||
fi
|
||||
|
||||
[ -f "$key_file" ] && api_key=$(cat "$key_file")
|
||||
|
||||
# Ключ Token Plan (tp-...) работает только на эндпоинте региона подписки (sgp/ams/cn),
|
||||
# ключ pay-as-you-go (sk-...) - на api.xiaomimimo.com. Эндпоинт находим перебором при
|
||||
# проверке ключа и запоминаем в mimo_base_url; MIMO_BASE_URL перебивает.
|
||||
mimo_base_url="${MIMO_BASE_URL:-}"
|
||||
[ -z "$mimo_base_url" ] && [ -f "$url_file" ] && mimo_base_url=$(cat "$url_file")
|
||||
|
||||
# _mimo_check_key: 1-токенный запрос с ключом $1. Без известного эндпоинта перебирает
|
||||
# регионы: чужой регион отвечает 401/403, первый другой ответ задаёт mimo_base_url.
|
||||
# Недоступный эндпоинт (код 000*: _claude_test_api при сетевой ошибке отдаёт 000000)
|
||||
# пропускаем. token-plan-cn в переборе нет: с наших машин он не отвечает (таймаут 15 с),
|
||||
# для него MIMO_BASE_URL=https://token-plan-cn.xiaomimimo.com/anthropic.
|
||||
# Bearer, как у Claude Code с ANTHROPIC_AUTH_TOKEN.
|
||||
_mimo_check_key() {
|
||||
local url auth_code="" auth_body=""
|
||||
if [ -n "$mimo_base_url" ]; then
|
||||
_claude_test_api "$mimo_base_url/v1/messages" "Authorization: Bearer $1" "mimo-v2.6-flash"
|
||||
return
|
||||
fi
|
||||
for url in https://token-plan-sgp.xiaomimimo.com/anthropic \
|
||||
https://token-plan-ams.xiaomimimo.com/anthropic \
|
||||
https://api.xiaomimimo.com/anthropic; do
|
||||
_claude_test_api "$url/v1/messages" "Authorization: Bearer $1" "mimo-v2.6-flash"
|
||||
case "$_CLAUDE_TEST_CODE" in
|
||||
401|403) auth_code="$_CLAUDE_TEST_CODE"; auth_body="$_CLAUDE_TEST_BODY" ;;
|
||||
000*) ;;
|
||||
*) mimo_base_url="$url"; return ;;
|
||||
esac
|
||||
done
|
||||
# Ни один эндпоинт не принял ключ. Отказ в авторизации разберёт _handle_api_response,
|
||||
# а без сети эндпоинт не узнать и запускать Claude Code некуда.
|
||||
if [ -n "$auth_code" ]; then
|
||||
_CLAUDE_TEST_CODE="$auth_code"
|
||||
_CLAUDE_TEST_BODY="$auth_body"
|
||||
return
|
||||
fi
|
||||
echo ""
|
||||
echo -e "\033[0;31m[СЕТЬ]\033[0m Эндпоинты MiMo недоступны, ключ не проверен."
|
||||
echo " Задай эндпоинт явно: MIMO_BASE_URL=https://token-plan-sgp.xiaomimimo.com/anthropic ai-mimo"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# _mimo_check_result: разбор ответа проверки. 402 на pay-as-you-go эндпоинте значит ключ
|
||||
# sk-... с нулевым балансом: подписку Token Plan он не тратит, для неё свой ключ tp-...
|
||||
_mimo_check_result() {
|
||||
_handle_api_response "MiMo" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Лимит Token Plan: https://platform.xiaomimimo.com"
|
||||
if [ "$_API_RET" = "402" ] && [ "$mimo_base_url" = "https://api.xiaomimimo.com/anthropic" ]; then
|
||||
echo " Это ключ pay-as-you-go (sk-...), подписку Token Plan он не использует."
|
||||
echo " Для Token Plan создай ключ на странице Token Plan: Dedicated API Key -> Create API Key (tp-...)."
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$api_key" ]; then
|
||||
echo -n "Проверка сохранённого MiMo ключа... "
|
||||
_mimo_check_key "$api_key"
|
||||
_mimo_check_result
|
||||
ret=$_API_RET
|
||||
if [ $ret -eq 401 ]; then
|
||||
rm -f "$key_file" "$url_file"
|
||||
api_key=""
|
||||
mimo_base_url="${MIMO_BASE_URL:-}"
|
||||
reauth=1
|
||||
elif [ $ret -eq 429 ]; then
|
||||
echo -n "Продолжить всё равно? (запросы могут не проходить) [y/N] "
|
||||
read -r _ans
|
||||
case "${_ans:-N}" in
|
||||
[Yy]*) ;;
|
||||
*)
|
||||
echo -n "Хотите ввести новый MiMo ключ? [Y/n] "
|
||||
read -r _ans2
|
||||
case "${_ans2:-Y}" in
|
||||
[Yy]*)
|
||||
rm -f "$key_file" "$url_file"
|
||||
api_key=""
|
||||
mimo_base_url="${MIMO_BASE_URL:-}"
|
||||
reauth=1
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
elif [ $ret -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$api_key" ] && [ "$reauth" -eq 1 ]; then
|
||||
echo -n "Хотите ввести новый MiMo ключ? [Y/n] "
|
||||
read -r _ans; case "${_ans:-Y}" in [Yy]*) ;; *) exit 1 ;; esac
|
||||
fi
|
||||
|
||||
if [ -z "$api_key" ]; then
|
||||
echo "Получить ключ: https://platform.xiaomimimo.com (Token Plan - tp-..., pay-as-you-go - sk-...)"
|
||||
read -r -p "Введите ваш Xiaomi MiMo API ключ: " api_key
|
||||
[ -z "$api_key" ] && { echo "Выход."; exit 1; }
|
||||
|
||||
echo -n "Проверяю ключ... "
|
||||
_mimo_check_key "$api_key"
|
||||
_mimo_check_result
|
||||
ret=$_API_RET
|
||||
if [ $ret -eq 0 ] || [ $ret -eq 429 ]; then
|
||||
mkdir -p "$(dirname "$key_file")"
|
||||
echo "$api_key" > "$key_file"
|
||||
echo "$mimo_base_url" > "$url_file"
|
||||
chmod 600 "$key_file" "$url_file"
|
||||
echo "Ключ сохранён (эндпоинт: $mimo_base_url)."
|
||||
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=mimo
|
||||
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/mimo"
|
||||
# Модель: всегда самая умная MiMo - mimo-v2.6-pro во всех трёх слотах и в сабагентах, как
|
||||
# у ai-glm. Flash не используем: ai-mimo задуман как максимум качества, а не экономия
|
||||
# кредитов. pro-ultraspeed - тот же Pro, только быстрее и в ~10 раз дороже.
|
||||
# mimo-v2.5-pro/mimo-v2.5 сняты 21.10.2026 (с 14.10 их роутят на v2.6-pro/v2.6-flash):
|
||||
# https://mimo.mi.com/docs/en-US/updates/deprecate
|
||||
# availableModels НЕ задаём (он схлопывает пикер). --model opus при каждом запуске: выбор
|
||||
# через /model живёт до конца сессии, следующий запуск снова на Pro.
|
||||
# CLAUDE_CODE_MAX_CONTEXT_TOKENS: mimo-* нет в реестре моделей Claude Code, без env окно
|
||||
# считалось бы = 200K (ctx: врал бы в ~5 раз, автокомпакт жал бы сессию). У Pro реальное
|
||||
# окно 1M, поэтому CLAUDE_CODE_DISABLE_1M_CONTEXT не выставляем.
|
||||
# CLAUDE_CODE_MAX_OUTPUT_TOKENS=128000: потолок Claude Code (131072 он режет до 128000),
|
||||
# MiMo V2.6 отдаёт до 131072. По умолчанию незнакомой модели досталось бы 32000 на
|
||||
# размышления + ответ.
|
||||
# Размышления: MiMo думает всегда. Claude Code шлёт thinking adaptive, а MiMo отрабатывает
|
||||
# его так же, как enabled (замер 13.10: даже на "скажи привет" есть thinking, длина та же).
|
||||
# Effort MiMo игнорирует: Claude Code шлёт output_config.effort (и без
|
||||
# CLAUDE_CODE_ALWAYS_ENABLE_EFFORT), MiMo принимает даже effort=bogus, а длина размышлений
|
||||
# от low до max не меняется (см. EFFORT_MAPPING.md). Стартуем на max через CLI --effort,
|
||||
# как ai-eltex-qwen: если Xiaomi начнёт его учитывать, будет максимум.
|
||||
_setup_isolated_config mimo opus high ''
|
||||
# /logout-mimo: без зарегистрированной команды Claude Code отвечает "Unknown command" и
|
||||
# не зовёт UserPromptSubmit-хук (см. ai-eltex).
|
||||
mkdir -p "$CLAUDE_CONFIG_DIR/commands"
|
||||
cat > "$CLAUDE_CONFIG_DIR/commands/logout-mimo.md" <<'CMDEOF'
|
||||
---
|
||||
description: Удалить сохранённый ключ ai-mimo (обрабатывает хук, без LLM)
|
||||
---
|
||||
Хук не сработал: удали ~/.config/ai-setup/mimo_key вручную и перезапусти ai-mimo (или запусти AI_RESET_KEY=1 ai-mimo).
|
||||
CMDEOF
|
||||
ANTHROPIC_BASE_URL="$mimo_base_url" \
|
||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL=mimo-v2.6-pro \
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="MiMo V2.6 Pro" \
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="Xiaomi MiMo V2.6 Pro - флагман для сложных задач" \
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL=mimo-v2.6-pro \
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="MiMo V2.6 Pro" \
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="Xiaomi MiMo V2.6 Pro - флагман для сложных задач" \
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=mimo-v2.6-pro \
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="MiMo V2.6 Pro" \
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="Xiaomi MiMo V2.6 Pro - флагман для сложных задач" \
|
||||
CLAUDE_CODE_SUBAGENT_MODEL=mimo-v2.6-pro \
|
||||
CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000 \
|
||||
CLAUDE_CODE_MAX_OUTPUT_TOKENS=128000 \
|
||||
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
||||
claude --dangerously-skip-permissions --model opus --effort "${AI_EFFORT:-max}" --system-prompt-file "$_PROMPT_FILE" "$@"
|
||||
MIMOEOF
|
||||
chmod +x "$BIN_DIR/ai-mimo"
|
||||
|
||||
# === ai-openrouter ===
|
||||
cat > "$BIN_DIR/ai-openrouter" << 'OPENROUTEREOF'
|
||||
#!/usr/bin/env bash
|
||||
@@ -2298,6 +2484,7 @@ _setup_isolated_config kimi opus high ''
|
||||
_setup_isolated_config glm opus xhigh ''
|
||||
_setup_isolated_config eltex opus xhigh ''
|
||||
_setup_isolated_config eltex-qwen opus high ''
|
||||
_setup_isolated_config mimo opus high ''
|
||||
_setup_isolated_config openrouter "openai/gpt-5.5" high ''
|
||||
_setup_isolated_config opencode deepseek-v4-pro high ''
|
||||
|
||||
@@ -2308,7 +2495,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-glm" "$HOME/.local/bin/ai-eltex" "$HOME/.local/bin/ai-eltex-qwen" "$HOME/.local/bin/ai-openrouter" "$HOME/.local/bin/ai-gemini" "$HOME/.local/bin/ai-cursor" "$HOME/.local/bin/ai-claude" \
|
||||
"$HOME/.local/bin/ai-glm" "$HOME/.local/bin/ai-eltex" "$HOME/.local/bin/ai-eltex-qwen" "$HOME/.local/bin/ai-mimo" "$HOME/.local/bin/ai-openrouter" "$HOME/.local/bin/ai-gemini" "$HOME/.local/bin/ai-cursor" "$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"
|
||||
fi
|
||||
@@ -2330,6 +2517,7 @@ echo -e " ${CYAN}ai-kimi${NC} - Kimi K2.7 Code (через Claude
|
||||
echo -e " ${CYAN}ai-glm${NC} - GLM 5.3 (через Claude Code, Zhipu AI API)"
|
||||
echo -e " ${CYAN}ai-eltex${NC} - Корпоративный LLM-прокси Eltex (через Claude Code, ключ от админов)"
|
||||
echo -e " ${CYAN}ai-eltex-qwen${NC} - Корпоративный LLM-прокси Eltex, модели Qwen (через Claude Code, свой ключ)"
|
||||
echo -e " ${CYAN}ai-mimo${NC} - Xiaomi MiMo V2.6 Pro, максимум рассуждений (через Claude Code, Token Plan)"
|
||||
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 ""
|
||||
|
||||
6
setup.sh
6
setup.sh
@@ -230,7 +230,7 @@ case "$choice" in
|
||||
fi
|
||||
|
||||
echo -e "${BLD}AI инструменты:${CLR}"
|
||||
for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-eltex ai-eltex-qwen ai-openrouter ai-opencode ai-gemini android; do
|
||||
for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-glm ai-eltex ai-eltex-qwen ai-mimo ai-openrouter ai-opencode ai-gemini android; do
|
||||
if command -v "$cmd" &>/dev/null; then
|
||||
echo -e " ${GRN}✓${CLR} $cmd"
|
||||
else
|
||||
@@ -241,7 +241,7 @@ case "$choice" in
|
||||
echo ""
|
||||
echo -e "${BLD}API ключи:${CLR}"
|
||||
cfg="$HOME/.config/ai-setup"
|
||||
for f in deepseek_key kimi_key glm_key eltex_key eltex_qwen_key openrouter_key opencode_key; do
|
||||
for f in deepseek_key kimi_key glm_key eltex_key eltex_qwen_key mimo_key openrouter_key opencode_key; do
|
||||
name="${f/_key/}"
|
||||
if [ -s "$cfg/$f" ]; then
|
||||
echo -e " ${GRN}✓${CLR} $name"
|
||||
@@ -252,7 +252,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" "GLM:api.z.ai" "OpenRouter:openrouter.ai" "OpenCode:opencode.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" "MiMo:api.xiaomimimo.com" "OpenRouter:openrouter.ai" "OpenCode:opencode.ai"; do
|
||||
_name="${entry%%:*}"
|
||||
_host="${entry##*:}"
|
||||
_ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null)
|
||||
|
||||
@@ -19,6 +19,7 @@ KIMI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-kimi"/,/^KIMIEOF/' "$SCRIPT")
|
||||
GLM_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-glm"/,/^GLMEOF/' "$SCRIPT")
|
||||
ELTEX_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex"/,/^ELTEXEOF/' "$SCRIPT")
|
||||
ELTEX_QWEN_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-eltex-qwen"/,/^ELTEXQWENEOF/' "$SCRIPT")
|
||||
MIMO_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-mimo"/,/^MIMOEOF/' "$SCRIPT")
|
||||
LOGOUT_HOOK="$(cd "$(dirname "$0")/.." && pwd)/home-configs/claude/hooks/logout-account-hook.sh"
|
||||
GEMINI_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-gemini"/,/^GEMINIEOF/' "$SCRIPT")
|
||||
OPENCODE_SECTION=$(awk '/^cat > "\$BIN_DIR\/ai-opencode"/,/^OPENCODEEOF/' "$SCRIPT")
|
||||
@@ -230,6 +231,117 @@ test_logout_eltex() {
|
||||
rm -rf "$tmp_home"
|
||||
}
|
||||
|
||||
# ── ai-mimo: Claude Code через Xiaomi MiMo V2.6 ───────────────────────────
|
||||
test_mimo_launcher() {
|
||||
if echo "$MIMO_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
||||
&& echo "$MIMO_SECTION" | grep -q 'key_file="$HOME/.config/ai-setup/mimo_key"' \
|
||||
&& echo "$MIMO_SECTION" | grep -q 'CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/mimo"' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^ANTHROPIC_BASE_URL="$mimo_base_url"' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^ANTHROPIC_DEFAULT_OPUS_MODEL=mimo-v2.6-pro' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^ANTHROPIC_DEFAULT_SONNET_MODEL=mimo-v2.6-pro' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^ANTHROPIC_DEFAULT_HAIKU_MODEL=mimo-v2.6-pro' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^CLAUDE_CODE_SUBAGENT_MODEL=mimo-v2.6-pro' \
|
||||
&& echo "$MIMO_SECTION" | grep -q -- 'claude --dangerously-skip-permissions --model opus ' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^CLAUDE_CODE_MAX_OUTPUT_TOKENS=128000' \
|
||||
&& echo "$MIMO_SECTION" | grep -q '^CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000' \
|
||||
&& ! echo "$MIMO_SECTION" | grep -q '^CLAUDE_CODE_DISABLE_1M_CONTEXT=' \
|
||||
&& echo "$MIMO_SECTION" | grep -q 'cat > "$CLAUDE_CONFIG_DIR/commands/logout-mimo.md"'; then
|
||||
ok "ai-mimo: own key/config, Pro in every slot and subagents, --model opus, 128000 output, 1M window, /logout-mimo"
|
||||
else
|
||||
fail "ai-mimo: must use mimo_key, cfg/mimo, mimo-v2.6-pro everywhere, --model opus, 128000 output, 1M window and logout-mimo.md"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── ai-mimo: эндпоинт региона Token Plan находится перебором и запоминается ──
|
||||
test_mimo_region_probe() {
|
||||
local tmp ok_run=1
|
||||
tmp=$(mktemp -d)
|
||||
mkdir -p "$tmp/bin" "$tmp/mock" "$tmp/home"
|
||||
echo "$HELPERS_SECTION" | HELPERS_FILE="$tmp/bin/ai-api-helpers.sh" bash
|
||||
echo "$MIMO_SECTION" | BIN_DIR="$tmp/bin" bash
|
||||
# Ключ подходит только к региону ams, sgp недоступен по сети (как curl: -w печатает
|
||||
# 000 и exit 28), остальные эндпоинты отвечают 401. MOCK_DOWN=1 - сети нет совсем.
|
||||
cat > "$tmp/mock/curl" <<CURLEOF
|
||||
#!/usr/bin/env bash
|
||||
for a in "\$@"; do
|
||||
case "\$a" in
|
||||
https://*) echo "\$a" >> "$tmp/curl.log" ;;
|
||||
esac
|
||||
case "\$a" in
|
||||
https://*) [ -n "\${MOCK_DOWN:-}" ] && { printf '\n000'; exit 28; } ;;
|
||||
esac
|
||||
case "\$a" in
|
||||
https://api.xiaomimimo.com/*) [ -n "\${MOCK_SK:-}" ] && { printf '{"error":{"message":"Insufficient account balance"}}\n402'; exit 0; } ;;
|
||||
https://token-plan-*) [ -n "\${MOCK_SK:-}" ] && { printf '{"error":{"message":"invalid api key"}}\n401'; exit 0; } ;;
|
||||
esac
|
||||
case "\$a" in
|
||||
https://token-plan-sgp.xiaomimimo.com/*) printf '\n000'; exit 28 ;;
|
||||
https://token-plan-ams.xiaomimimo.com/*) printf '{"content":[]}\n200'; exit 0 ;;
|
||||
https://*) printf '{"error":{"message":"invalid api key"}}\n401'; exit 0 ;;
|
||||
esac
|
||||
done
|
||||
CURLEOF
|
||||
printf '#!/usr/bin/env bash\necho "$ANTHROPIC_BASE_URL" > "%s/claude.url"\n' "$tmp" > "$tmp/mock/claude"
|
||||
chmod +x "$tmp/mock/curl" "$tmp/mock/claude"
|
||||
_run_mimo() {
|
||||
(cd "$tmp" && printf 'tp-test\n' | HOME="$tmp/home" PATH="$tmp/mock:$PATH" \
|
||||
MIMO_BASE_URL= AI_RESET_KEY= AI_EFFORT= bash "$tmp/bin/ai-mimo" >/dev/null 2>&1)
|
||||
}
|
||||
local ams=https://token-plan-ams.xiaomimimo.com/anthropic
|
||||
_run_mimo || ok_run=0
|
||||
[ "$(cat "$tmp/claude.url" 2>/dev/null)" = "$ams" ] || ok_run=0
|
||||
[ "$(cat "$tmp/home/.config/ai-setup/mimo_base_url" 2>/dev/null)" = "$ams" ] || ok_run=0
|
||||
[ "$(cat "$tmp/home/.config/ai-setup/mimo_key" 2>/dev/null)" = "tp-test" ] || ok_run=0
|
||||
# Повторный запуск: сохранённый эндпоинт, без перебора регионов.
|
||||
rm -f "$tmp/curl.log" "$tmp/claude.url"
|
||||
_run_mimo || ok_run=0
|
||||
[ "$(cat "$tmp/curl.log" 2>/dev/null)" = "$ams/v1/messages" ] || ok_run=0
|
||||
[ "$(cat "$tmp/claude.url" 2>/dev/null)" = "$ams" ] || ok_run=0
|
||||
# Без сети: ключ не сохраняется и Claude Code не запускается с пустым эндпоинтом.
|
||||
rm -rf "$tmp/home" "$tmp/claude.url"
|
||||
MOCK_DOWN=1 _run_mimo && ok_run=0
|
||||
[ ! -e "$tmp/claude.url" ] && [ ! -e "$tmp/home/.config/ai-setup/mimo_key" ] || ok_run=0
|
||||
# Ключ pay-as-you-go без баланса: Token Plan отвечает 401, api.xiaomimimo.com - 402,
|
||||
# нужна подсказка про ключ tp-...
|
||||
rm -rf "$tmp/home"
|
||||
local out
|
||||
out=$(cd "$tmp" && printf 'sk-test\n' | HOME="$tmp/home" PATH="$tmp/mock:$PATH" MOCK_SK=1 \
|
||||
MIMO_BASE_URL= AI_RESET_KEY= AI_EFFORT= bash "$tmp/bin/ai-mimo" 2>&1) && ok_run=0
|
||||
echo "$out" | grep -q 'Dedicated API Key' || ok_run=0
|
||||
[ ! -e "$tmp/claude.url" ] && [ ! -e "$tmp/home/.config/ai-setup/mimo_key" ] || ok_run=0
|
||||
if [ "$ok_run" -eq 1 ]; then
|
||||
ok "ai-mimo: finds the Token Plan region by probing (skips unreachable), saves and reuses it"
|
||||
else
|
||||
fail "ai-mimo: region probe must skip unreachable regions, pick the one that accepts the key and reuse it"
|
||||
fi
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
|
||||
# ── ai-mimo: effort max по умолчанию через CLI (MiMo effort игнорирует) ────
|
||||
test_mimo_effort() {
|
||||
if echo "$MIMO_SECTION" | grep -q -- '--effort "${AI_EFFORT:-max}"' \
|
||||
&& ! echo "$MIMO_SECTION" | grep -q '^_apply_effort'; then
|
||||
ok "ai-mimo: starts with --effort max by default, AI_EFFORT via CLI"
|
||||
else
|
||||
fail "ai-mimo: must start with --effort \"\${AI_EFFORT:-max}\", no _apply_effort"
|
||||
fi
|
||||
}
|
||||
|
||||
test_logout_mimo() {
|
||||
local tmp_home rc=0
|
||||
tmp_home=$(mktemp -d)
|
||||
mkdir -p "$tmp_home/.config/ai-setup"
|
||||
echo "tp-test" > "$tmp_home/.config/ai-setup/mimo_key"
|
||||
echo "https://token-plan-ams.xiaomimimo.com/anthropic" > "$tmp_home/.config/ai-setup/mimo_base_url"
|
||||
echo '{"prompt":"/logout-mimo"}' | HOME="$tmp_home" AI_LAUNCHER=claude bash "$LOGOUT_HOOK" 2>/dev/null || rc=$?
|
||||
if [ "$rc" -eq 2 ] && [ ! -f "$tmp_home/.config/ai-setup/mimo_key" ] && [ ! -f "$tmp_home/.config/ai-setup/mimo_base_url" ]; then
|
||||
ok "logout hook: /logout-mimo removes mimo_key and mimo_base_url"
|
||||
else
|
||||
fail "logout hook: /logout-mimo must remove mimo_key and mimo_base_url (rc=$rc)"
|
||||
fi
|
||||
rm -rf "$tmp_home"
|
||||
}
|
||||
|
||||
# ── ai-glm: default effort is max (still overridable via AI_EFFORT) ───────
|
||||
test_glm_default_effort() {
|
||||
if echo "$GLM_SECTION" | grep -q -- '--effort "${AI_EFFORT:-max}"' \
|
||||
@@ -449,6 +561,10 @@ test_eltex_qwen_effort
|
||||
test_logout_eltex
|
||||
test_eltex_qwen_launcher
|
||||
test_logout_eltex_qwen
|
||||
test_mimo_launcher
|
||||
test_mimo_region_probe
|
||||
test_mimo_effort
|
||||
test_logout_mimo
|
||||
test_gemini_native_launcher
|
||||
test_cursor_native_launcher
|
||||
test_global_rules_source_installed
|
||||
|
||||
Reference in New Issue
Block a user