Compare commits
2 Commits
main
...
901af7d17d
| Author | SHA1 | Date | |
|---|---|---|---|
| 901af7d17d | |||
| 22b4daa5ce |
@@ -13,12 +13,12 @@
|
|||||||
|
|
||||||
## Таблица маппинга
|
## Таблица маппинга
|
||||||
|
|
||||||
| Claude Code `/effort` | Anthropic (`ai-claude`) | DeepSeek V4 (`ai-deepseek`) | Kimi K2.7/K2.6 (`ai-kimi`) | GLM 5.3 (`ai-glm`) | OpenRouter/GPT-5.5 (`ai-openrouter`) | OpenCode Go (`ai-opencode`) |
|
| 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` | нативно `low` | 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` | провайдер поднимает до `high` | thinking on | на стороне сервера | без локального маппинга | без локального маппинга |
|
| `xhigh` | нативно `xhigh` | провайдер поднимает до `max` | thinking on | на стороне сервера | без локального маппинга | без локального маппинга |
|
||||||
| `max` | нативно `max` | нативно `max` | thinking on | на стороне сервера | без локального маппинга | без локального маппинга |
|
| `max` | нативно `max` | нативно `max` | thinking on | на стороне сервера | без локального маппинга | без локального маппинга |
|
||||||
|
|
||||||
Для OpenRouter текущий лаунчер не делает локального преобразования effort и отправляет
|
Для OpenRouter текущий лаунчер не делает локального преобразования effort и отправляет
|
||||||
@@ -45,13 +45,12 @@ low -> medium -> high -> xhigh -> max
|
|||||||
### DeepSeek V4
|
### DeepSeek V4
|
||||||
|
|
||||||
```text
|
```text
|
||||||
low -> high -> max
|
high -> max
|
||||||
```
|
```
|
||||||
|
|
||||||
- 3 реальных уровня.
|
- 2 реальных уровня.
|
||||||
- `low` остаётся `low` — реально снижает thinking бюджет.
|
- `low` и `medium` фактически поднимаются до `high`.
|
||||||
- `medium` и `xhigh` фактически поднимаются до `high`.
|
- `xhigh` фактически поднимается до `max`.
|
||||||
- `max` остаётся `max` — максимальный бюджет thinking.
|
|
||||||
- Маппинг выполняется на стороне DeepSeek API.
|
- Маппинг выполняется на стороне DeepSeek API.
|
||||||
- Дефолт `ai-deepseek`: `high`.
|
- Дефолт `ai-deepseek`: `high`.
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ on / off
|
|||||||
- Градаций глубины reasoning нет.
|
- Градаций глубины reasoning нет.
|
||||||
- Дефолт `ai-kimi`: `high`.
|
- Дефолт `ai-kimi`: `high`.
|
||||||
|
|
||||||
### GLM 5.3 (Zhipu AI)
|
### GLM 5.2 (Zhipu AI)
|
||||||
|
|
||||||
```text
|
```text
|
||||||
high / max
|
high / max
|
||||||
@@ -100,7 +99,7 @@ Effort не преобразуется локально — thinking budget не
|
|||||||
| 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.3 | 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 |
|
| 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` |
|
||||||
@@ -126,4 +125,4 @@ ai-deepseek # без флага - использовать ур
|
|||||||
|
|
||||||
- Для повседневной работы: `high` или `xhigh`.
|
- Для повседневной работы: `high` или `xhigh`.
|
||||||
- `max` effort имеет реальный эффект у Anthropic и DeepSeek; у Kimi и GLM это всё тот же thinking on / маппинг на стороне сервера.
|
- `max` effort имеет реальный эффект у Anthropic и DeepSeek; у Kimi и GLM это всё тот же thinking on / маппинг на стороне сервера.
|
||||||
- `low`/`medium` у Kimi и GLM фактически не снижают reasoning; у DeepSeek `low` теперь даёт реальный уровень `low` и экономит бюджет.
|
- `low`/`medium` у DeepSeek, Kimi и GLM фактически не снижают reasoning.
|
||||||
|
|||||||
@@ -15,11 +15,6 @@ bash setup.sh
|
|||||||
exec bash
|
exec bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Обновление всех AI-инструментов одной командой:
|
|
||||||
```bash
|
|
||||||
./setup.sh update
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. Настроить сеть (Amnezia + ru-bypass)
|
## 2. Настроить сеть (Amnezia + ru-bypass)
|
||||||
|
|
||||||
Нужно один раз на каждой машине. .ru трафик идёт напрямую,
|
Нужно один раз на каждой машине. .ru трафик идёт напрямую,
|
||||||
|
|||||||
17
README.md
17
README.md
@@ -56,15 +56,6 @@ bash setup.sh
|
|||||||
exec bash
|
exec bash
|
||||||
```
|
```
|
||||||
|
|
||||||
### Обновление одной командой
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./setup.sh update # или: ./setup.sh --update
|
|
||||||
```
|
|
||||||
|
|
||||||
То же, что пункт меню `7) Обновить`: `git pull --ff-only` + перегенерация всех
|
|
||||||
`ai-*` лаунчеров через `scripts/ai-setup.sh`. Без аргументов открывается меню.
|
|
||||||
|
|
||||||
## Сеть: ru-bypass + kill switch
|
## Сеть: ru-bypass + kill switch
|
||||||
|
|
||||||
Полная документация: [`home-configs/network/README.md`](home-configs/network/README.md)
|
Полная документация: [`home-configs/network/README.md`](home-configs/network/README.md)
|
||||||
@@ -160,7 +151,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.3 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-opencode` - Claude Code через OpenCode Go + routatic-proxy (DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)
|
||||||
- `ai-gemini` - нативный Antigravity CLI `agy`
|
- `ai-gemini` - нативный Antigravity CLI `agy`
|
||||||
@@ -233,9 +224,9 @@ android init
|
|||||||
|
|
||||||
## Правила агентов
|
## Правила агентов
|
||||||
|
|
||||||
В `home-configs/GLOBAL_RULES.md` - компактные правила о границах автономности, минимальных
|
В `home-configs/GLOBAL_RULES.md` - правила Карпати (Think Before Coding, Simplicity First,
|
||||||
изменениях, пропорциональной проверке, работе с Git и контекстом проекта, а также пользовательские
|
Surgical Changes, Goal-Driven Execution) плюс пользовательские правила (отвечать по-русски,
|
||||||
настройки: русский язык, доступ к Redmine и запрет на commit/staging без явной команды.
|
не коммитить без команды, не делать git add без команды и др.).
|
||||||
|
|
||||||
`scripts/ai-setup.sh` копирует их в native rule-файлы всех CLI. Лаунчеры обновляют их при каждом запуске.
|
`scripts/ai-setup.sh` копирует их в native rule-файлы всех CLI. Лаунчеры обновляют их при каждом запуске.
|
||||||
|
|
||||||
|
|||||||
@@ -1,92 +1,100 @@
|
|||||||
# Global AI Agent Rules
|
# Global AI Agent Rules
|
||||||
|
|
||||||
Use these defaults across projects, then apply any more specific repository instructions. Prefer clear outcomes and proportional safeguards over process for its own sake.
|
Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.
|
||||||
|
|
||||||
## 1. Resolve Intent Without Needless Blocking
|
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
|
||||||
|
|
||||||
- Inspect the available context before asking the user for information.
|
## 1. Think Before Coding
|
||||||
- Ask a focused question only when an ambiguity would materially change the result, create meaningful risk, or cannot be resolved from the repository or task context.
|
|
||||||
- Otherwise choose the simplest reasonable interpretation and state only assumptions that materially affect the result.
|
|
||||||
- Surface important tradeoffs and recommend a simpler or safer approach when it better serves the user's goal.
|
|
||||||
|
|
||||||
## 2. Keep Changes Minimal and Scoped
|
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
||||||
|
|
||||||
- Implement only the requested behavior and the support required to make it correct.
|
Before implementing:
|
||||||
- Do not add speculative features, single-use abstractions, unrequested configurability, or handling for implausible scenarios.
|
- State your assumptions explicitly. If uncertain, ask.
|
||||||
- Preserve existing public behavior and local conventions unless the task requires changing them.
|
- If multiple interpretations exist, present them - don't pick silently.
|
||||||
- Do not refactor, reformat, or clean up unrelated code. Mention unrelated issues only when they are relevant risks or blockers.
|
- If a simpler approach exists, say so. Push back when warranted.
|
||||||
- Remove imports, variables, functions, files, or comments made obsolete by your own changes; leave pre-existing dead code alone unless asked.
|
- If something is unclear, stop. Name what's confusing. Ask.
|
||||||
- Every changed line should trace to the requested outcome.
|
|
||||||
|
|
||||||
## 3. Act Autonomously Within the Request
|
## 2. Simplicity First
|
||||||
|
|
||||||
- For requests to answer, explain, review, diagnose, or plan, inspect the relevant materials and report the result. Do not implement changes unless the request also asks for them.
|
**Minimum code that solves the problem. Nothing speculative.**
|
||||||
- For requests to change, build, or fix, perform safe in-scope local edits and validation without asking for routine confirmation.
|
|
||||||
- Ask before destructive or difficult-to-recover actions, external writes or publication, purchases, or a material expansion of scope.
|
|
||||||
- Exception for Eltex merge-request reviews: a bare review request or explicit `eltex-review` invocation authorizes the skill's documented GitLab writes, including inline discussions, approval, and its thank-you note. Explicit chat-only wording keeps the review read-only.
|
|
||||||
- Preserve unrelated user changes and adapt to a dirty working tree. Never discard or overwrite work you did not create.
|
|
||||||
|
|
||||||
## 4. Plan and Verify Proportionally
|
- No features beyond what was asked.
|
||||||
|
- No abstractions for single-use code.
|
||||||
|
- No "flexibility" or "configurability" that wasn't requested.
|
||||||
|
- No error handling for impossible scenarios.
|
||||||
|
- If you write 200 lines and it could be 50, rewrite it.
|
||||||
|
|
||||||
- Define observable success criteria before changing code.
|
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
||||||
- For non-trivial multi-step work, keep a brief plan whose steps include their verification. Skip planning ceremony for simple tasks.
|
|
||||||
- For a bug fix, reproduce the failure first when feasible. Add a focused regression test when it provides durable value and the repository has an appropriate test layer.
|
|
||||||
- Run the smallest relevant checks first, then broader checks when the change's risk justifies them.
|
|
||||||
- Do not claim completion without fresh evidence. Report the commands run, their results, and anything that remains unverified.
|
|
||||||
|
|
||||||
## 5. Keep Git Changes Reviewable
|
## 3. Surgical Changes
|
||||||
|
|
||||||
- Never run `git commit` unless the user explicitly asks for a commit.
|
**Touch only what you must. Clean up only your own mess.**
|
||||||
- Do not stage changes unless the user explicitly asks for staging, committing, or another operation that requires it. Do not disturb changes already staged by the user.
|
|
||||||
- Leave tracked edits unstaged so they remain visible in `git diff`.
|
|
||||||
- Remember that untracked files do not appear in ordinary `git diff`. Show them with `git status --short`, list their paths in the handoff, and use `git diff --no-index -- /dev/null <path>` when a patch view is useful.
|
|
||||||
- Before handing off, inspect both `git diff` and `git status --short` and distinguish your changes from unrelated existing work.
|
|
||||||
|
|
||||||
## 6. Load Relevant Project Context
|
When editing existing code:
|
||||||
|
- Don't "improve" adjacent code, comments, or formatting.
|
||||||
|
- Don't refactor things that aren't broken.
|
||||||
|
- Match existing style, even if you'd do it differently.
|
||||||
|
- If you notice unrelated dead code, mention it - don't delete it.
|
||||||
|
|
||||||
- Before acting, read the applicable agent instruction files and the project documentation directly relevant to the task.
|
When your changes create orphans:
|
||||||
- Follow referenced documents when they are needed to understand requirements, commands, architecture, or validation. Do not scan unrelated Markdown files indiscriminately.
|
- Remove imports/variables/functions that YOUR changes made unused.
|
||||||
- Use the repository's existing tools, conventions, and test commands unless the task requires otherwise.
|
- Don't remove pre-existing dead code unless asked.
|
||||||
|
|
||||||
## 7. Communication Style
|
The test: Every changed line should trace directly to the user's request.
|
||||||
|
|
||||||
- Reply in Russian, use informal "ты", and communicate like a friendly programmer teammate.
|
## 4. Goal-Driven Execution
|
||||||
- Lead with the outcome and keep the explanation concise while preserving evidence, material caveats, and next steps.
|
|
||||||
- Keep identifiers, commands, exact error messages, and source quotations in their original language when accuracy matters.
|
|
||||||
- Humor, irony, and swearing are welcome when they fit the conversation; clarity and respect come first.
|
|
||||||
|
|
||||||
## 8. Reusable Skills
|
**Define success criteria. Loop until verified.**
|
||||||
|
|
||||||
- After completing the current task, propose a focused reusable skill only when the user has repeated a workflow and reuse would clearly help.
|
Transform tasks into verifiable goals:
|
||||||
- Do not interrupt active work to create a skill, and do not create or edit skill files without explicit user approval.
|
- "Add validation" -> "Write tests for invalid inputs, then make them pass"
|
||||||
- If approved skill changes live outside the current repository, report their exact paths and how the user can inspect them.
|
- "Fix the bug" -> "Write a test that reproduces it, then make it pass"
|
||||||
|
- "Refactor X" -> "Ensure tests pass before and after"
|
||||||
|
|
||||||
## 9. Redmine (red.eltex.loc)
|
For multi-step tasks, state a brief plan:
|
||||||
|
```
|
||||||
|
1. [Step] -> verify: [check]
|
||||||
|
2. [Step] -> verify: [check]
|
||||||
|
3. [Step] -> verify: [check]
|
||||||
|
```
|
||||||
|
|
||||||
- When the request or an Eltex branch identifies a Redmine issue, read its specification, status, and comments before implementing. Eltex branches commonly start with the issue number (for example, `485448_keyboard_opening_fix` maps to issue `485448`).
|
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
|
||||||
- Use the personal API key stored only in `~/.config/ai-setup/redmine_key` (mode 600):
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.
|
||||||
|
|
||||||
|
# Global Rules for All AI Agents
|
||||||
|
|
||||||
|
The rules below are mandatory for every interaction and task. They are intentionally placed after the general coding guidelines above, but they have higher priority when a conflict exists.
|
||||||
|
|
||||||
|
1. **Communication style:**
|
||||||
|
Always reply in Russian, in a friendly peer-to-peer tone, using informal "ты". Appropriate swearing, humor, sarcasm, and irony are allowed and welcome. Communicate like a live programmer teammate, not like a dry robot.
|
||||||
|
|
||||||
|
2. **No commits without an explicit request:**
|
||||||
|
Never run `git commit` unless the user has directly and unambiguously asked for it. The final commit always remains with the user, or is made strictly by the user's command.
|
||||||
|
|
||||||
|
3. **Plain git diff visibility:**
|
||||||
|
All changes must remain visible to the user through the standard `git diff` command. Leave modified files in the working directory unstaged. Do not add files to the Git index with `git add` unless the user explicitly asks for staging, committing, or another action that requires staging, because staging hides changes from plain `git diff`.
|
||||||
|
|
||||||
|
4. **Project context:**
|
||||||
|
At the start of work, pay close attention to all provided project `.md` files, because they are provided automatically and contain the current repository's context and specifics.
|
||||||
|
|
||||||
|
5. **Reusable skills:**
|
||||||
|
When the user repeats the same instruction, output format, correction, or workflow, treat it as a candidate for a reusable skill.
|
||||||
|
|
||||||
|
Do not interrupt active work just to create a skill. Finish the current task first, then briefly propose the skill name, trigger description, and what files or tools it should contain.
|
||||||
|
|
||||||
|
Do not create or edit skill files silently. Create or update a skill only after explicit user approval.
|
||||||
|
|
||||||
|
Keep skills focused: prefer several small skills over one broad skill. A useful skill should have a precise description for when to use it, short instructions for how to act, and reusable tools, templates, references, or examples when they make the result more stable.
|
||||||
|
|
||||||
|
If skill files are outside the current git repository, clearly state the exact paths changed and how the user can inspect them, because those changes are not visible in the project `git diff`.
|
||||||
|
|
||||||
|
6. **Redmine (red.eltex.loc) access:**
|
||||||
|
Redmine issues require authentication. To read a task's spec and comments, use the personal API key stored in `~/.config/ai-setup/redmine_key` (chmod 600). Eltex branches usually start with the issue number (e.g. `485448_keyboard_opening_fix` → issue `485448` → https://red.eltex.loc/issues/485448). Fetch the issue with its comments (journals) via:
|
||||||
```bash
|
```bash
|
||||||
curl -fsS -H "X-Redmine-API-Key: $(cat ~/.config/ai-setup/redmine_key)" \
|
curl -s -H "X-Redmine-API-Key: $(cat ~/.config/ai-setup/redmine_key)" \
|
||||||
"https://red.eltex.loc/issues/<N>.json?include=journals"
|
"https://red.eltex.loc/issues/<N>.json?include=journals"
|
||||||
```
|
```
|
||||||
- Read `issue.description`, `issue.status.name`, and recent non-empty `issue.journals[].notes`. If the key is missing or the request fails, report that instead of guessing the task requirements.
|
Read `issue.description` for the spec, `issue.journals[].notes` for comments (recent non-empty ones matter most), `issue.status.name` for status. Keep the key only in that file — never write it into files tracked by git.
|
||||||
- Never print, log, or write the API key into repository files.
|
|
||||||
|
|
||||||
## 10. GitLab (gitlab.eltex.loc)
|
|
||||||
|
|
||||||
- GitLab access uses **per-project** tokens stored in `~/.config/ai-setup/` (mode 600). Each one is a project access token and works only for its own project:
|
|
||||||
|
|
||||||
| File | Project | id |
|
|
||||||
| :--- | :--- | :--- |
|
|
||||||
| `gitlab_token_superapp` | `voip/vp-apps/superapp-launcher` | 4928 |
|
|
||||||
| `gitlab_token_common_library` | `voip/vp-apps/common-library` | 4825 |
|
|
||||||
| `gitlab_token_smart_home` | `android_apps/smart_home` | 1409 |
|
|
||||||
|
|
||||||
- Pick the file matching the project you are working with. A token from another project returns HTTP 404, not 403, so a wrong token looks exactly like a missing project — check the token before concluding the resource does not exist.
|
|
||||||
```bash
|
|
||||||
curl -fsS -H "PRIVATE-TOKEN: $(cat ~/.config/ai-setup/gitlab_token_superapp)" \
|
|
||||||
"https://gitlab.eltex.loc/api/v4/projects/4928/merge_requests/241"
|
|
||||||
```
|
|
||||||
- There is no generic `gitlab_token` fallback any more. Tools that accept an explicit token path (for example the `eltex-review` helper) must be given `--token-file <path>`.
|
|
||||||
- `local.properties` in superapp-launcher also holds `gitlab.token` and `redmine.apiKey`; it is gitignored and must stay that way.
|
|
||||||
- Never print, log, or write these tokens into repository files.
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ The custom statusline script renders **only ASCII-safe characters and ANSI color
|
|||||||
|
|
||||||
- ASCII brackets `[ ]` for git branch and effort level
|
- ASCII brackets `[ ]` for git branch and effort level
|
||||||
- ANSI 256-color escape sequences for model names, effort levels, and rate-limit percentages
|
- ANSI 256-color escape sequences for model names, effort levels, and rate-limit percentages
|
||||||
- The `$` symbol for the DeepSeek balance (USD only)
|
- The `¥` symbol (U+00A5) for CNY balance in DeepSeek output
|
||||||
|
|
||||||
It does **not** use Nerd Font glyphs, powerline separators, or emoji.
|
It does **not** use Nerd Font glyphs, powerline separators, or emoji.
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@ input=$(cat)
|
|||||||
cwd=$(echo "$input" | jq -r '.cwd')
|
cwd=$(echo "$input" | jq -r '.cwd')
|
||||||
model=$(echo "$input" | jq -r '.model.display_name // empty')
|
model=$(echo "$input" | jq -r '.model.display_name // empty')
|
||||||
model_id=$(echo "$input" | jq -r '.model.id // empty')
|
model_id=$(echo "$input" | jq -r '.model.id // empty')
|
||||||
# Суффикс [1m] в отображении не нужен: окно контекста задаётся
|
|
||||||
# CLAUDE_CODE_MAX_CONTEXT_TOKENS, а не суффиксом модели
|
|
||||||
model="${model/\[1m\]/}"
|
|
||||||
model="${model% \[1M\]}"
|
|
||||||
model="${model% (1M context)}"
|
|
||||||
model_id="${model_id/\[1m\]/}"
|
|
||||||
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
|
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
|
||||||
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
|
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
|
||||||
week_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
|
week_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
|
||||||
@@ -17,18 +11,15 @@ week_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
|
|||||||
ctx_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
|
ctx_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
|
||||||
|
|
||||||
|
|
||||||
# Разделитель сегментов: жирная серая средняя точка ·
|
|
||||||
_sep() { printf " \033[1m\033[38;5;240m·\033[00m "; }
|
|
||||||
|
|
||||||
# Цвет effort: насыщенные, глубже чем пастельные (jewel tones)
|
# Цвет effort: насыщенные, глубже чем пастельные (jewel tones)
|
||||||
_effort_color() {
|
_effort_color() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
low) printf '\033[38;5;220mlow\033[00m' ;; # золотой
|
low) printf '\033[38;5;220m[low]\033[00m' ;; # золотой
|
||||||
medium) printf '\033[38;5;50mmedium\033[00m' ;; # насыщенный teal
|
medium) printf '\033[38;5;50m[medium]\033[00m' ;; # насыщенный teal
|
||||||
high) printf '\033[38;5;38mhigh\033[00m' ;; # глубокий голубой
|
high) printf '\033[38;5;38m[high]\033[00m' ;; # глубокий голубой
|
||||||
xhigh) printf '\033[38;5;206mxhigh\033[00m' ;; # насыщенный фиолетовый
|
xhigh) printf '\033[38;5;206m[xhigh]\033[00m' ;; # насыщенный фиолетовый
|
||||||
max) printf '\033[38;5;220mm\033[38;5;114ma\033[38;5;50mx\033[38;5;206m\033[00m' ;; # радуга
|
max) printf '\033[38;5;210m[\033[38;5;220mm\033[38;5;114ma\033[38;5;50mx\033[38;5;206m]\033[00m' ;; # радуга
|
||||||
*) printf '\033[38;5;252m%s\033[00m' "$1" ;;
|
*) printf '\033[38;5;252m[%s]\033[00m' "$1" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +29,6 @@ _brand_color() {
|
|||||||
deepseek) printf '\033[38;5;69m' ;; # DeepSeek фирменный синий
|
deepseek) printf '\033[38;5;69m' ;; # DeepSeek фирменный синий
|
||||||
claude) printf '\033[38;5;173m' ;; # Anthropic оранжевый
|
claude) printf '\033[38;5;173m' ;; # Anthropic оранжевый
|
||||||
kimi) printf '\033[38;5;81m' ;; # Kimi голубой
|
kimi) printf '\033[38;5;81m' ;; # Kimi голубой
|
||||||
glm) printf '\033[38;5;223m' ;; # Z.ai кремовый (бренд-фон z.ai, #FFE4B5)
|
|
||||||
openrouter) printf '\033[38;5;135m' ;; # OpenRouter фиолетовый
|
openrouter) printf '\033[38;5;135m' ;; # OpenRouter фиолетовый
|
||||||
*) printf '\033[38;5;223m' ;; # кремовый (fallback)
|
*) printf '\033[38;5;223m' ;; # кремовый (fallback)
|
||||||
esac
|
esac
|
||||||
@@ -49,7 +39,7 @@ branch=$(git -C "$cwd" --no-optional-locks symbolic-ref --short HEAD 2>/dev/null
|
|||||||
short_cwd="${cwd/#$HOME/\~}"
|
short_cwd="${cwd/#$HOME/\~}"
|
||||||
printf "\033[38;5;252m%s\033[00m" "$short_cwd"
|
printf "\033[38;5;252m%s\033[00m" "$short_cwd"
|
||||||
|
|
||||||
[ -n "$branch" ] && { _sep; printf "\033[38;5;111m%s\033[00m" "$branch"; }
|
[ -n "$branch" ] && printf " \033[38;5;252m[%s]\033[00m" "$branch"
|
||||||
if [ -n "$model" ]; then
|
if [ -n "$model" ]; then
|
||||||
brand_color=$(_brand_color "${AI_LAUNCHER:-}")
|
brand_color=$(_brand_color "${AI_LAUNCHER:-}")
|
||||||
effort=$(echo "$input" | jq -r ".effort.level // empty")
|
effort=$(echo "$input" | jq -r ".effort.level // empty")
|
||||||
@@ -94,20 +84,18 @@ if [ -n "$model" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
[ -n "$account" ] && { _sep; printf "%s%s\033[00m" "$brand_color" "$account"; }
|
[ -n "$account" ] && printf " %s[%s]\033[00m" "$brand_color" "$account"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Аккаунт/ключ Kimi — показываем alias (account1/account2/...).
|
# Аккаунт/ключ Kimi — показываем alias (account1/account2/...).
|
||||||
if [ "${AI_LAUNCHER:-}" = "kimi" ]; then
|
if [ "${AI_LAUNCHER:-}" = "kimi" ]; then
|
||||||
kimi_account=$(cat "$HOME/.config/ai-setup/kimi_keys/current" 2>/dev/null)
|
kimi_account=$(cat "$HOME/.config/ai-setup/kimi_keys/current" 2>/dev/null)
|
||||||
[ -n "$kimi_account" ] && { _sep; printf "%s%s\033[00m" "$brand_color" "$kimi_account"; }
|
[ -n "$kimi_account" ] && printf " %s[%s]\033[00m" "$brand_color" "$kimi_account"
|
||||||
fi
|
fi
|
||||||
if [ -n "$effort" ]; then
|
if [ -n "$effort" ]; then
|
||||||
_sep
|
|
||||||
printf " %s%s " "$brand_color" "$model"
|
printf " %s%s " "$brand_color" "$model"
|
||||||
_effort_color "$effort"
|
_effort_color "$effort"
|
||||||
else
|
else
|
||||||
_sep
|
|
||||||
printf " %s%s\033[00m" "$brand_color" "$model"
|
printf " %s%s\033[00m" "$brand_color" "$model"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -150,7 +138,7 @@ if [[ "$model_id" == *deepseek* ]]; then
|
|||||||
cache_file="$HOME/.cache/ai-setup/deepseek_balance"
|
cache_file="$HOME/.cache/ai-setup/deepseek_balance"
|
||||||
if [ -f "$cache_file" ]; then
|
if [ -f "$cache_file" ]; then
|
||||||
balance=$(head -1 "$cache_file")
|
balance=$(head -1 "$cache_file")
|
||||||
[ -n "$balance" ] && { _sep; printf "\033[38;5;78m%s\033[00m" "$balance"; }
|
[ -n "$balance" ] && printf " \033[38;5;78m%s\033[00m" "$balance"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Фоновое обновление баланса (не чаще раза в 30 секунд)
|
# Фоновое обновление баланса (не чаще раза в 30 секунд)
|
||||||
@@ -171,12 +159,13 @@ if [[ "$model_id" == *deepseek* ]]; then
|
|||||||
import sys, json
|
import sys, json
|
||||||
d = json.load(sys.stdin)
|
d = json.load(sys.stdin)
|
||||||
infos = d.get('balance_infos', [])
|
infos = d.get('balance_infos', [])
|
||||||
|
symbols = {'USD': '\$', 'CNY': '\u00a5'}
|
||||||
parts = []
|
parts = []
|
||||||
for info in infos:
|
for info in infos:
|
||||||
if info.get('currency', '').upper() != 'USD':
|
curr = info.get('currency', '')
|
||||||
continue
|
|
||||||
total = info.get('total_balance', '0')
|
total = info.get('total_balance', '0')
|
||||||
parts.append(f'\${total}')
|
sym = symbols.get(curr, curr)
|
||||||
|
parts.append(f'{sym}{total}')
|
||||||
if parts:
|
if parts:
|
||||||
print(' '.join(parts))
|
print(' '.join(parts))
|
||||||
" 2>/dev/null)
|
" 2>/dev/null)
|
||||||
@@ -193,7 +182,7 @@ elif [ "${AI_LAUNCHER:-}" = "openrouter" ]; then
|
|||||||
cache_file="$HOME/.cache/ai-setup/openrouter_balance"
|
cache_file="$HOME/.cache/ai-setup/openrouter_balance"
|
||||||
if [ -f "$cache_file" ]; then
|
if [ -f "$cache_file" ]; then
|
||||||
balance=$(head -1 "$cache_file")
|
balance=$(head -1 "$cache_file")
|
||||||
[ -n "$balance" ] && { _sep; printf "\033[38;5;78m%s\033[00m" "$balance"; }
|
[ -n "$balance" ] && printf " \033[38;5;78m%s\033[00m" "$balance"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Фоновое обновление баланса (не чаще раза в 30 секунд)
|
# Фоновое обновление баланса (не чаще раза в 30 секунд)
|
||||||
@@ -258,13 +247,13 @@ else
|
|||||||
five_int=$(printf '%.0f' "$five_pct")
|
five_int=$(printf '%.0f' "$five_pct")
|
||||||
remaining=$(fmt_remaining "$five_reset")
|
remaining=$(fmt_remaining "$five_reset")
|
||||||
color=$(pct_color "$five_int")
|
color=$(pct_color "$five_int")
|
||||||
_sep; printf "%s%s:%s%%\033[00m" "$color" "$remaining" "$five_int"
|
printf " %s%s:%s%%\033[00m" "$color" "$remaining" "$five_int"
|
||||||
fi
|
fi
|
||||||
if [ -n "$week_pct" ] && [ -n "$week_reset" ]; then
|
if [ -n "$week_pct" ] && [ -n "$week_reset" ]; then
|
||||||
week_int=$(printf '%.0f' "$week_pct")
|
week_int=$(printf '%.0f' "$week_pct")
|
||||||
remaining=$(fmt_remaining "$week_reset")
|
remaining=$(fmt_remaining "$week_reset")
|
||||||
color=$(pct_color "$week_int")
|
color=$(pct_color "$week_int")
|
||||||
_sep; printf "%s%s:%s%%\033[00m" "$color" "$remaining" "$week_int"
|
printf " %s%s:%s%%\033[00m" "$color" "$remaining" "$week_int"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -274,7 +263,7 @@ fi
|
|||||||
if [ -n "$ctx_pct" ]; then
|
if [ -n "$ctx_pct" ]; then
|
||||||
ctx_int=$(printf '%.0f' "$ctx_pct")
|
ctx_int=$(printf '%.0f' "$ctx_pct")
|
||||||
color=$(pct_color "$ctx_int")
|
color=$(pct_color "$ctx_int")
|
||||||
_sep; printf "%sctx:%s%%\033[00m" "$color" "$ctx_int"
|
printf " %sctx:%s%%\033[00m" "$color" "$ctx_int"
|
||||||
|
|
||||||
# Звуковой сигнал при первом достижении 60%
|
# Звуковой сигнал при первом достижении 60%
|
||||||
alert_file="$HOME/.cache/ai-setup/ctx_alert_state"
|
alert_file="$HOME/.cache/ai-setup/ctx_alert_state"
|
||||||
|
|||||||
@@ -706,24 +706,25 @@ try:
|
|||||||
d = json.load(sys.stdin)
|
d = json.load(sys.stdin)
|
||||||
available = d.get('is_available', False)
|
available = d.get('is_available', False)
|
||||||
infos = d.get('balance_infos', [])
|
infos = d.get('balance_infos', [])
|
||||||
# Показываем только USD (CNY не выводим)
|
|
||||||
infos = [i for i in infos if i.get('currency', '').upper() == 'USD']
|
|
||||||
if not infos:
|
if not infos:
|
||||||
print(' \033[0;33m[БАЛАНС]\033[0m Нет данных о балансе')
|
print(' \033[0;33m[БАЛАНС]\033[0m Нет данных о балансе')
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
symbols = {'USD': '\$', 'CNY': '¥'}
|
||||||
cache_parts = []
|
cache_parts = []
|
||||||
for info in infos:
|
for info in infos:
|
||||||
|
curr = info.get('currency', '???')
|
||||||
total = info.get('total_balance', '0')
|
total = info.get('total_balance', '0')
|
||||||
granted = info.get('granted_balance', '0')
|
granted = info.get('granted_balance', '0')
|
||||||
topped_up = info.get('topped_up_balance', '0')
|
topped_up = info.get('topped_up_balance', '0')
|
||||||
|
sym = symbols.get(curr, curr)
|
||||||
status = '✅ доступен' if available else '❌ не активен'
|
status = '✅ доступен' if available else '❌ не активен'
|
||||||
print(f' \033[1;36m💰 Баланс DeepSeek:\033[0m \${total} {status}')
|
print(f' \033[1;36m💰 Баланс DeepSeek:\033[0m {total} {curr} {status}')
|
||||||
if float(granted) > 0:
|
if float(granted) > 0:
|
||||||
print(f' └─ Начислено: \${granted}')
|
print(f' └─ Начислено: {granted} {curr}')
|
||||||
if float(topped_up) > 0:
|
if float(topped_up) > 0:
|
||||||
print(f' └─ Пополнено: \${topped_up}')
|
print(f' └─ Пополнено: {topped_up} {curr}')
|
||||||
cache_parts.append(f'\${total}')
|
cache_parts.append(f'{sym}{total}')
|
||||||
# Cache USD balance for statusline
|
# Cache all currencies with symbols for statusline
|
||||||
if cache_parts:
|
if cache_parts:
|
||||||
cache_dir = os.path.expanduser('~/.cache/ai-setup')
|
cache_dir = os.path.expanduser('~/.cache/ai-setup')
|
||||||
os.makedirs(cache_dir, exist_ok=True)
|
os.makedirs(cache_dir, exist_ok=True)
|
||||||
@@ -1242,9 +1243,7 @@ fi
|
|||||||
|
|
||||||
_build_ai_sys_prompt > /dev/null # сохраняет в ~/.codex/AGENTS.md (codex читает авто)
|
_build_ai_sys_prompt > /dev/null # сохраняет в ~/.codex/AGENTS.md (codex читает авто)
|
||||||
_setup_codex_sound_hooks
|
_setup_codex_sound_hooks
|
||||||
exec "$codex_bin" --dangerously-bypass-approvals-and-sandbox \
|
exec "$codex_bin" --dangerously-bypass-approvals-and-sandbox "$@"
|
||||||
-c 'tui.status_line=["model-with-reasoning","git-branch","context-used","five-hour-limit","current-dir"]' \
|
|
||||||
"$@"
|
|
||||||
GPTEOF
|
GPTEOF
|
||||||
chmod +x "$BIN_DIR/ai-gpt"
|
chmod +x "$BIN_DIR/ai-gpt"
|
||||||
|
|
||||||
@@ -1561,7 +1560,7 @@ chmod +x "$BIN_DIR/ai-kimi"
|
|||||||
# === ai-glm ===
|
# === ai-glm ===
|
||||||
cat > "$BIN_DIR/ai-glm" << 'GLMEOF'
|
cat > "$BIN_DIR/ai-glm" << 'GLMEOF'
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# ai-glm - запуск Claude Code через Zhipu AI GLM 5.3 (Anthropic-compatible API)
|
# 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
|
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ai-api-helpers.sh" 2>/dev/null || true
|
||||||
|
|
||||||
key_file="$HOME/.config/ai-setup/glm_key"
|
key_file="$HOME/.config/ai-setup/glm_key"
|
||||||
@@ -1581,7 +1580,7 @@ glm_base_url="${GLM_BASE_URL:-https://api.z.ai/api/anthropic}"
|
|||||||
|
|
||||||
if [ -n "$api_key" ]; then
|
if [ -n "$api_key" ]; then
|
||||||
echo -n "Проверка сохранённого GLM ключа... "
|
echo -n "Проверка сохранённого GLM ключа... "
|
||||||
_claude_test_api "$glm_base_url/v1/messages" "x-api-key: $api_key" "glm-5.3"
|
_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"
|
_handle_api_response "GLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Пополните баланс: https://z.ai/manage-apikey/apikey-list"
|
||||||
ret=$_API_RET
|
ret=$_API_RET
|
||||||
if [ $ret -eq 401 ]; then
|
if [ $ret -eq 401 ]; then
|
||||||
@@ -1622,7 +1621,7 @@ if [ -z "$api_key" ]; then
|
|||||||
[ -z "$api_key" ] && { echo "Выход."; exit 1; }
|
[ -z "$api_key" ] && { echo "Выход."; exit 1; }
|
||||||
|
|
||||||
echo -n "Проверяю ключ... "
|
echo -n "Проверяю ключ... "
|
||||||
_claude_test_api "$glm_base_url/v1/messages" "x-api-key: $api_key" "glm-5.3"
|
_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"
|
_handle_api_response "GLM" "$_CLAUDE_TEST_CODE" "$_CLAUDE_TEST_BODY" "Пополните баланс: https://z.ai/manage-apikey/apikey-list"
|
||||||
ret=$_API_RET
|
ret=$_API_RET
|
||||||
if [ $ret -eq 0 ] || [ $ret -eq 429 ]; then
|
if [ $ret -eq 0 ] || [ $ret -eq 429 ]; then
|
||||||
@@ -1645,37 +1644,31 @@ trap 'rm -f "$_PROMPT_FILE"' EXIT INT TERM
|
|||||||
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
_build_ai_sys_prompt > "$_PROMPT_FILE"
|
||||||
export AI_LAUNCHER=glm
|
export AI_LAUNCHER=glm
|
||||||
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/glm"
|
export CLAUDE_CONFIG_DIR="$HOME/.config/ai-setup/cfg/glm"
|
||||||
# Пикер: все три слота = glm-5.3. availableModels НЕ задаём (он схлопывает пикер).
|
# Пикер: Opus/Sonnet = GLM 5.2, Haiku = GLM 5.2[1m]. availableModels НЕ задаём
|
||||||
# Claude Code навязывает 3 слота; незаданный показал бы чужой Claude, поэтому
|
# (он схлопывает пикер). Claude Code навязывает 3 слота; незаданный показал бы
|
||||||
# opus+sonnet+haiku = glm-5.3. Окно контекста у всех слотов задаёт env
|
# чужой Claude, поэтому opus+sonnet = glm-5.2, haiku = glm-5.2[1m].
|
||||||
# CLAUDE_CODE_MAX_CONTEXT_TOKENS ниже — суффикс [1m] больше не нужен.
|
|
||||||
_setup_isolated_config glm opus high ''
|
_setup_isolated_config glm opus high ''
|
||||||
# ai-glm стартует на /effort max. max невалиден в settings.json (там только
|
# ai-glm стартует на /effort max. max невалиден в settings.json (там только
|
||||||
# low/medium/high/xhigh), поэтому задаём через CLI --effort, а не _apply_effort.
|
# low/medium/high/xhigh), поэтому задаём через CLI --effort, а не _apply_effort.
|
||||||
# CLAUDE_CODE_ALWAYS_ENABLE_EFFORT заставляет Claude Code отправлять effort в API
|
# CLAUDE_CODE_ALWAYS_ENABLE_EFFORT заставляет Claude Code отправлять effort в API
|
||||||
# для GLM (иначе glm-5.3 не распознан как effort-capable и параметр не уходит).
|
# для GLM (иначе glm-5.2 не распознан как effort-capable и параметр не уходит).
|
||||||
# /effort внутри сессии работает; ручной override запуска: AI_EFFORT=high ai-glm.
|
# /effort внутри сессии работает; ручной override запуска: AI_EFFORT=high ai-glm.
|
||||||
# CLAUDE_CODE_DISABLE_1M_CONTEXT НЕ выставляем: GLM 5.3 реально держит 1M контекста,
|
# CLAUDE_CODE_DISABLE_1M_CONTEXT НЕ выставляем: GLM 5.2 реально держит 1M контекста,
|
||||||
# а флаг заставлял бы счётчик ctx: считать окно = 200K (врал в ~5 раз). Прочие
|
# а флаг заставлял бы счётчик ctx: считать окно = 200K (врал в ~5 раз). Прочие
|
||||||
# лаунчеры (deepseek/kimi/openrouter/opencode) флаг оставляют — у них другой контекст
|
# лаунчеры (deepseek/kimi/openrouter/opencode) флаг оставляют — у них другой контекст
|
||||||
# и флаг убирает [1M]-дубли из пикера; ai-claude его и так не использует.
|
# и флаг убирает [1M]-дубли из пикера; ai-claude его и так не использует.
|
||||||
# CLAUDE_CODE_MAX_CONTEXT_TOKENS: glm-* нет в реестре моделей Claude Code, поэтому
|
|
||||||
# окно по умолчанию считается = 200K — ctx: врал бы в ~5 раз, а автокомпакт жал бы
|
|
||||||
# сессию в 200K. Задаём реальное окно 1M явно; env применяется к не-claude моделям
|
|
||||||
# независимо от суффикса, поэтому [1m] у Haiku-слота не нужен и убран.
|
|
||||||
ANTHROPIC_BASE_URL="$glm_base_url" \
|
ANTHROPIC_BASE_URL="$glm_base_url" \
|
||||||
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
ANTHROPIC_AUTH_TOKEN="$api_key" \
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.3 \
|
ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.2 \
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="GLM 5.3" \
|
ANTHROPIC_DEFAULT_OPUS_MODEL_NAME="GLM 5.2" \
|
||||||
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="GLM 5.3 — флагман Zhipu AI" \
|
ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION="GLM 5.2 — флагман Zhipu AI" \
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL=glm-5.3 \
|
ANTHROPIC_DEFAULT_SONNET_MODEL=glm-5.2 \
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="GLM 5.3" \
|
ANTHROPIC_DEFAULT_SONNET_MODEL_NAME="GLM 5.2" \
|
||||||
ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="GLM 5.3 — флагман Zhipu AI" \
|
ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION="GLM 5.2 — флагман Zhipu AI" \
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL=glm-5.3 \
|
ANTHROPIC_DEFAULT_HAIKU_MODEL='glm-5.2[1m]' \
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="GLM 5.3" \
|
ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME="GLM 5.2 [1M]" \
|
||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="GLM 5.3 — флагман Zhipu AI" \
|
ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION="GLM 5.2 [1M] — расширенный контекст" \
|
||||||
CLAUDE_CODE_SUBAGENT_MODEL=glm-5.3 \
|
CLAUDE_CODE_SUBAGENT_MODEL=glm-5.2 \
|
||||||
CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000 \
|
|
||||||
CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 \
|
CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1 \
|
||||||
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
|
||||||
claude --dangerously-skip-permissions --effort "${AI_EFFORT:-max}" --system-prompt-file "$_PROMPT_FILE" "$@"
|
claude --dangerously-skip-permissions --effort "${AI_EFFORT:-max}" --system-prompt-file "$_PROMPT_FILE" "$@"
|
||||||
@@ -2012,7 +2005,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.3 (через 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 -e " ${CYAN}ai-opencode${NC} - OpenCode Go (через Claude Code + routatic-proxy: DeepSeek, Kimi, Qwen, GLM, MiniMax, MiMo)"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
35
setup.sh
35
setup.sh
@@ -18,34 +18,6 @@ mkdir -p "$HOME/.config/ai-setup"
|
|||||||
LOG="$HOME/.config/ai-setup/setup.log"
|
LOG="$HOME/.config/ai-setup/setup.log"
|
||||||
_log() { printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" "$2" >> "$LOG"; }
|
_log() { printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" "$2" >> "$LOG"; }
|
||||||
|
|
||||||
# Обновление: git pull + перегенерация всех ai-* лаунчеров (пункт меню 7)
|
|
||||||
do_update() {
|
|
||||||
local repo_dir
|
|
||||||
repo_dir="$(pwd)"
|
|
||||||
echo -e "${BLD}Обновляем репозиторий...${CLR}"
|
|
||||||
git -C "$repo_dir" pull --ff-only
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLD}Перегенерация скриптов...${CLR}"
|
|
||||||
bash "$repo_dir/scripts/ai-setup.sh"
|
|
||||||
}
|
|
||||||
|
|
||||||
# CLI-режим: ./setup.sh update (или --update) — обновление без меню
|
|
||||||
case "${1:-}" in
|
|
||||||
update|--update)
|
|
||||||
_log "setup" "update (CLI) на $(hostname)"
|
|
||||||
do_update
|
|
||||||
exit $?
|
|
||||||
;;
|
|
||||||
"")
|
|
||||||
# без аргументов — интерактивное меню ниже
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Неизвестный аргумент: $1"
|
|
||||||
echo "Использование: ./setup.sh [update] — без аргументов открывается меню"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if command -v whiptail >/dev/null 2>&1; then
|
if command -v whiptail >/dev/null 2>&1; then
|
||||||
MENU_ARGS=()
|
MENU_ARGS=()
|
||||||
MENU_ARGS+=("1" "AI-инструменты (установить лаунчеры + ключи)")
|
MENU_ARGS+=("1" "AI-инструменты (установить лаунчеры + ключи)")
|
||||||
@@ -276,7 +248,12 @@ case "$choice" in
|
|||||||
bash tests/test_network.sh
|
bash tests/test_network.sh
|
||||||
;;
|
;;
|
||||||
7)
|
7)
|
||||||
do_update
|
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
echo -e "${BLD}Обновляем репозиторий...${CLR}"
|
||||||
|
git -C "$REPO_DIR" pull --ff-only
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLD}Перегенерация скриптов...${CLR}"
|
||||||
|
bash "$REPO_DIR/scripts/ai-setup.sh"
|
||||||
;;
|
;;
|
||||||
8)
|
8)
|
||||||
bash scripts/ai-setup.sh
|
bash scripts/ai-setup.sh
|
||||||
|
|||||||
@@ -41,15 +41,6 @@ test_gpt_no_proxy() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── ai-gpt: informative Codex status line ───────────────────────────────────
|
|
||||||
test_gpt_status_line() {
|
|
||||||
if echo "$GPT_SECTION" | grep -Fq 'tui.status_line=["model-with-reasoning","git-branch","context-used","five-hour-limit","current-dir"]'; then
|
|
||||||
ok "ai-gpt: shows model, branch, context usage, primary limit, and directory"
|
|
||||||
else
|
|
||||||
fail "ai-gpt: missing configured Codex status line"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ── ai-kimi: launches claude with Kimi backend ────────────────────────────
|
# ── ai-kimi: launches claude with Kimi backend ────────────────────────────
|
||||||
test_kimi_claude_launcher() {
|
test_kimi_claude_launcher() {
|
||||||
if echo "$KIMI_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
if echo "$KIMI_SECTION" | grep -q 'claude --dangerously-skip-permissions' \
|
||||||
@@ -94,13 +85,12 @@ test_glm_claude_launcher() {
|
|||||||
# ── ai-glm: uses official Zhipu AI API ────────────────────────────────────
|
# ── ai-glm: uses official Zhipu AI API ────────────────────────────────────
|
||||||
test_glm_official_api() {
|
test_glm_official_api() {
|
||||||
if echo "$GLM_SECTION" | grep -q 'api.z.ai/api/anthropic' \
|
if echo "$GLM_SECTION" | grep -q 'api.z.ai/api/anthropic' \
|
||||||
&& echo "$GLM_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.3' \
|
&& echo "$GLM_SECTION" | grep -q 'ANTHROPIC_DEFAULT_OPUS_MODEL=glm-5.2' \
|
||||||
&& echo "$GLM_SECTION" | grep -q 'ANTHROPIC_DEFAULT_HAIKU_MODEL=glm-5.3' \
|
&& echo "$GLM_SECTION" | grep -q "ANTHROPIC_DEFAULT_HAIKU_MODEL='glm-5.2\[1m\]'" \
|
||||||
&& echo "$GLM_SECTION" | grep -q 'CLAUDE_CODE_MAX_CONTEXT_TOKENS=1000000' \
|
|
||||||
&& echo "$GLM_SECTION" | grep -q 'x-api-key'; then
|
&& echo "$GLM_SECTION" | grep -q 'x-api-key'; then
|
||||||
ok "ai-glm: uses official Zhipu AI API (glm-5.3 everywhere, ctx window 1M via env)"
|
ok "ai-glm: uses official Zhipu AI API (glm-5.2 opus/sonnet, glm-5.2[1m] haiku)"
|
||||||
else
|
else
|
||||||
fail "ai-glm: must use official Zhipu AI API with glm-5.3, 1M context window and x-api-key"
|
fail "ai-glm: must use official Zhipu AI API with glm-5.2 and x-api-key"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,14 +114,20 @@ test_cursor_native_launcher() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── global rules: source and native rule files ───────────────────────
|
# ── global rules: Karpathy-style guidelines and native rule files ───────────
|
||||||
test_global_rules_source_installed() {
|
test_global_rules_include_quality_guidelines() {
|
||||||
if [ -s "$GLOBAL_RULES_SOURCE" ] \
|
karpathy_line=$(grep -n '^## 1\. Think Before Coding$' "$GLOBAL_RULES_SOURCE" | head -1 | cut -d: -f1)
|
||||||
|
global_line=$(grep -n '^# Global Rules for All AI Agents$' "$GLOBAL_RULES_SOURCE" | head -1 | cut -d: -f1)
|
||||||
|
if [ -n "$karpathy_line" ] \
|
||||||
|
&& [ -n "$global_line" ] \
|
||||||
|
&& [ "$karpathy_line" -lt "$global_line" ] \
|
||||||
|
&& grep -q 'Always reply in Russian' "$GLOBAL_RULES_SOURCE" \
|
||||||
|
&& grep -q 'Plain git diff visibility' "$GLOBAL_RULES_SOURCE" \
|
||||||
&& grep -q 'GLOBAL_RULES_SOURCE=' "$SCRIPT" \
|
&& grep -q 'GLOBAL_RULES_SOURCE=' "$SCRIPT" \
|
||||||
&& grep -q 'cp "$GLOBAL_RULES_SOURCE" "$CONFIG_DIR/global_rules.md"' "$SCRIPT"; then
|
&& grep -q 'cp "$GLOBAL_RULES_SOURCE" "$CONFIG_DIR/global_rules.md"' "$SCRIPT"; then
|
||||||
ok "global rules: non-empty source file is installed as global_rules.md"
|
ok "global rules: source file includes English Karpathy guidelines before user rules"
|
||||||
else
|
else
|
||||||
fail "global rules: missing source file or installation wiring"
|
fail "global rules: missing source file, English Karpathy guidelines, or user rules"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +291,6 @@ test_add_hook_syntax() {
|
|||||||
test_script_syntax
|
test_script_syntax
|
||||||
test_gpt_autoinstall
|
test_gpt_autoinstall
|
||||||
test_gpt_no_proxy
|
test_gpt_no_proxy
|
||||||
test_gpt_status_line
|
|
||||||
test_kimi_claude_launcher
|
test_kimi_claude_launcher
|
||||||
test_kimi_official_api
|
test_kimi_official_api
|
||||||
test_kimi_no_artemox
|
test_kimi_no_artemox
|
||||||
@@ -303,7 +298,7 @@ test_glm_claude_launcher
|
|||||||
test_glm_official_api
|
test_glm_official_api
|
||||||
test_gemini_native_launcher
|
test_gemini_native_launcher
|
||||||
test_cursor_native_launcher
|
test_cursor_native_launcher
|
||||||
test_global_rules_source_installed
|
test_global_rules_include_quality_guidelines
|
||||||
test_native_rule_files_generated
|
test_native_rule_files_generated
|
||||||
test_codex_sound_hooks_detach_stdio
|
test_codex_sound_hooks_detach_stdio
|
||||||
test_fix7_trap_tmp
|
test_fix7_trap_tmp
|
||||||
|
|||||||
Reference in New Issue
Block a user