opencode-orchestrator-uni 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ru.md CHANGED
@@ -1,587 +1,315 @@
1
- # opencode-orchestrator-uni
2
-
3
- [English](./README.md) · **Русский**
4
-
5
- Нативный пакетный плагин [OpenCode V2](https://opencode.ai/v2/docs/build/plugins),
6
- который поставляет **комплект агентов-оркестраторов**:
7
-
8
- - `orchestrator` — root-оркестратор (основной агент) со встроенным режимом
9
- аудиторского цикла;
10
- - read-only субагенты аудита — `factcheck`, `empiric`, `invariant`,
11
- `arbiter`, `meta`, `redteam`, `context-lint`;
12
- - `fix-runner` — единственный пишущий субагент (применяет список «к закрытию»);
13
- - процессные документы комплекта, доступные как **reference `audit-kit`**
14
- (`call-mechanics.md`, `process-ready-loop.md`, `root-runbook.md`,
15
- `instruction-other-session.md`, `context-efficiency.md`, `session-discipline.md`);
16
- - пять детерминированных read-only инструментов — `orch_uni_validate_report`,
17
- `orch_uni_context_lint`, `orch_uni_snapshot`, `orch_uni_sessions`,
18
- `orch_uni_session_stats` (см. [Инструменты](#инструменты));
19
- - три слэш-команды — `/agents-md`, `/spec` и `/handoff` (см. [Команды](#команды)).
20
-
21
- Read-only аудиторы держатся на `edit: deny` плюс запрете в промпте; shell-разрешение
22
- остаётся, чтобы запускать проверки (принятый риск, ни одно разрешение не ослаблено).
23
-
24
- Пакет загружается напрямую из TypeScript: `exports` указывает на
25
- [`index.ts`](./index.ts). **Шага сборки и каталога `dist/` нет** — Bun-овый
26
- рантайм OpenCode сам разрешает и загружает точку входа (тот же приём, что в
27
- официальном пакете `@opencode/plugin-figma`).
28
-
29
- ## Что регистрирует плагин
30
-
31
- При setup (`ctx.agent.transform` / `ctx.reference.transform`):
32
-
33
- | Агент | Режим | Роль |
34
- | -------------- | ---------- | --------------------------------------------------------------- |
35
- | `orchestrator` | `primary` | Root-оркестратор; аудиторский цикл как встроенный режим |
36
- | `factcheck` | `subagent` | Read-only: пред-проход на устаревание («уже сделано» / устарело) |
37
- | `empiric` | `subagent` | Read-only: воспроизведения, замеры, первоисточники |
38
- | `invariant` | `subagent` | Read-only: состояния, отмены, гонки, враждебный ввод |
39
- | `arbiter` | `subagent` | Read-only: разбирает только спорные находки |
40
- | `meta` | `subagent` | Read-only: мета-аудит отчётов (гейт pass/fail) |
41
- | `redteam` | `subagent` | Read-only: приёмочный ред-тим (релизные ворота) |
42
- | `context-lint` | `subagent` | Read-only: аудит AGENTS.md/SPEC.md на token-эффективность |
43
- | `fix-runner` | `subagent` | Пишущий: применяет список правок и доказывает закрытие |
1
+ <a id="readme-top"></a>
2
+
3
+ [![npm version][npm-shield]][npm-url]
4
+ [![CI][ci-shield]][ci-url]
5
+ [![License][license-shield]][license-url]
6
+ [![OpenCode V2][opencode-shield]][opencode-url]
7
+
8
+ <br />
9
+
10
+ <div align="center">
11
+ <h3 align="center">opencode-orchestrator-uni</h3>
12
+
13
+ <p align="center">
14
+ Плагин OpenCode V2, который ведёт работу как аудиторский цикл, опирающийся на доказательства.
15
+ <br />
16
+ <a href="https://github.com/OniVe/opencode-orchestrator-uni/tree/main/docs/ru"><strong>Документация »</strong></a>
17
+ <br />
18
+ <br />
19
+ <a href="https://github.com/OniVe/opencode-orchestrator-uni/issues/new">Сообщить об ошибке</a>
20
+ &middot;
21
+ <a href="https://github.com/OniVe/opencode-orchestrator-uni/issues/new">Предложить улучшение</a>
22
+ </p>
23
+
24
+ <p align="center">
25
+ <a href="https://github.com/OniVe/opencode-orchestrator-uni/blob/main/README.md">English</a> &middot; <strong>Русский</strong>
26
+ </p>
27
+ </div>
28
+
29
+ <details>
30
+ <summary>Содержание</summary>
31
+ <ol>
32
+ <li><a href="#о-проекте">О проекте</a>
33
+ <ul>
34
+ <li><a href="#что-входит">Что входит</a></li>
35
+ <li><a href="#собрано-с">Собрано с</a></li>
36
+ </ul>
37
+ </li>
38
+ <li><a href="#начало-работы">Начало работы</a>
39
+ <ul>
40
+ <li><a href="#требования">Требования</a></li>
41
+ <li><a href="#установка">Установка</a></li>
42
+ <li><a href="#настройка">Настройка</a></li>
43
+ </ul>
44
+ </li>
45
+ <li><a href="#использование">Использование</a>
46
+ <ul>
47
+ <li><a href="#быстрый-старт">Быстрый старт</a></li>
48
+ <li><a href="#аудиторский-цикл">Аудиторский цикл</a></li>
49
+ <li><a href="#агенты">Агенты</a></li>
50
+ <li><a href="#команды">Команды</a></li>
51
+ </ul>
52
+ </li>
53
+ <li><a href="#справочник">Справочник</a></li>
54
+ <li><a href="#разработка">Разработка</a></li>
55
+ <li><a href="#дорожная-карта">Дорожная карта</a></li>
56
+ <li><a href="#участие">Участие</a></li>
57
+ <li><a href="#лицензия">Лицензия</a></li>
58
+ <li><a href="#контакты">Контакты</a></li>
59
+ <li><a href="#благодарности">Благодарности</a></li>
60
+ </ol>
61
+ </details>
62
+
63
+ ## О проекте
64
+
65
+ Сессии агентов дрейфуют: один и тот же агент пишет код, сам оценивает результат
66
+ и сам подводит итог. Этот плагин делает такое разделение явным для
67
+ [OpenCode V2](https://opencode.ai/v2/docs/build/plugins). Он поставляет
68
+ **комплект агентов-оркестраторов**: root-оркестратор со встроенным аудиторским
69
+ циклом, read-only субагенты аудита, один пишущий субагент, детерминированные
70
+ инструменты проверки и процессные документы, которые не дают циклу превратиться
71
+ в самоотчёт. Id плагина: `orchestrator.uni`.
72
+
73
+ Комплект — это протокол, а не песочница. Аудиторы read-only на уровне
74
+ разрешений инструментов и промпта; оркестратор делегирует любую правку
75
+ кода/документации/тестов; артефакты аудита остаются в доступных для записи
76
+ путях. Guard не пускает оркестратор в исходники — см.
77
+ [Защиту записи](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md#защита-записи).
78
+
79
+ ### Что входит
80
+
81
+ | Слой | Что поставляется |
82
+ | --- | --- |
83
+ | Агенты | `orchestrator` (primary); read-only `factcheck`, `empiric`, `invariant`, `arbiter`, `meta`, `redteam`, `context-lint`; пишущий `fix-runner` |
84
+ | Инструменты | Пять read-only инструментов: `orch_uni_validate_report`, `orch_uni_context_lint`, `orch_uni_snapshot`, `orch_uni_sessions`, `orch_uni_session_stats` |
85
+ | Команды | Три слэш-команды: `/agents-md`, `/spec`, `/handoff` |
86
+ | Справочник | Процессные документы как reference `audit-kit`; подробности — в [Справочнике](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md) |
44
87
 
45
- Все агенты поставляются **без модели**: модели — это конфигурация развёртывания
46
- (см. [Модели](#модели)). Определения живут в [`agents/`](./agents) как обычные
47
- Markdown-файлы агентов и парсятся при setup — файлы являются единственным
48
- источником истины.
88
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
49
89
 
50
- «Read-only» здесь означает: `edit` запрещён и промпт запрещает запись; `shell`
51
- остаётся разрешён, чтобы аудитор мог выполнить нужные проверки (принятый риск
52
- I-M15). Аудиторский цикл считает это контрактом, а не песочницей.
90
+ ### Собрано с
53
91
 
54
- Reference `audit-kit` указывает на per-locale каталог `docs/<locale>/` пакета
55
- (см. [Локаль](#локаль)). OpenCode перечисляет его в контексте сессии как
56
- дополнительный локальный каталог, поэтому оркестратор (и любой другой агент)
57
- может читать процессные документы напрямую, например
58
- `<reference path>/call-mechanics.md`.
92
+ - [![OpenCode V2][opencode-shield]][opencode-url]
93
+ - [![TypeScript][typescript-shield]][typescript-url]
94
+ - [![Bun][bun-shield]][bun-url]
95
+ - [![Biome][biome-shield]][biome-url]
96
+ - [![semantic-release][semantic-release-shield]][semantic-release-url]
59
97
 
60
- Плагин также регистрирует пять детерминированных **read-only** инструментов в
61
- пространстве имён `orch_uni` и три слэш-команды — см. [Инструменты](#инструменты)
62
- и [Команды](#команды).
98
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
63
99
 
64
- ## Команды
100
+ ## Начало работы
65
101
 
66
- | Команда | Что делает |
67
- | --- | --- |
68
- | `/agents-md` | Вставляет workflow аудита/черновика AGENTS.md: шаблон `context-efficiency.md`, `orch_uni_context_lint`, `context-lint`, подтверждение перед записью. |
69
- | `/spec` | Вставляет workflow SPEC.md: бриф, уточняющие вопросы, EARS/AC/трассировка, `orch_uni_context_lint`, `context-lint`, подтверждение перед записью. |
70
- | `/handoff` | Вставляет workflow закрытия среза: факты сессии и рабочего дерева, шаблон handoff из `session-discipline.md`, запись `docs/planning/handoff-<YYYY-MM-DD>.md`. |
102
+ ### Требования
71
103
 
72
- Команда — это промпт, а не писатель: обработчик вставляет workflow-промпт в
73
- текущую сессию. Дальше оркестратор работает по обычным правилам evidence и
74
- подтверждения.
104
+ - **OpenCode 2.x** с V2 plugin API (поле `plugins`). Загрузчик V1 ожидает
105
+ legacy-экспорт `server()` и этот плагин не загрузит.
106
+ - **Bun** для тестов и скриптов проверки, **Node.js 22.14+** для релизного
107
+ инструментария. У плагина нет шага сборки и каталога `dist/`.
108
+ - Git-чекаут для `npm run check:locales` и `npm run verify:kit`; в npm-пакете
109
+ каталог `tools/` не поставляется.
75
110
 
76
- ## Инструменты
111
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
77
112
 
78
- | Имя | Read-only | Что делает |
79
- | -------------------------- | --------- | ----------------------------------------------------------------------------- |
80
- | `orch_uni_validate_report` | да | Достаёт SGR JSON-блок отчёта, разрешает его схему, валидирует |
81
- | `orch_uni_context_lint` | да | Детерминированный аудит AGENTS.md/SPEC.md: бюджет, vague, ссылки, секции |
82
- | `orch_uni_snapshot` | да | Детерминированная ревизия дерева каталогов (sha256 на файл + агрегатный хэш) |
83
- | `orch_uni_sessions` | да | Дочерние сессии сессии: агент, модель, стоимость, токены, время |
84
- | `orch_uni_session_stats` | да | Счётчики протокола сессии: промпт, компакции, тулы/ход, урезанные выводы |
113
+ ### Установка
85
114
 
86
- Каждый инструмент отвечает JSON-текстом. Ошибки — **типизированные коды** внутри
87
- тела (`E_INPUT`, `E_NO_JSON`, …), а не исключения, чтобы агент мог ветвиться по
88
- коду, не разбирая прозу. Ни один из пяти ничего не пишет в воркспейс, хранилище
89
- сессий или конфигурацию.
115
+ Через CLI OpenCode:
90
116
 
91
- ### `orch_uni_validate_report`
92
-
93
- ```jsonc
94
- { "text": "<текст отчёта>" } // или
95
- { "path": "reports/empiric-r1.md", // абсолютный или относительно каталога локации
96
- "schema": "empiric/v1" } // опционально: ожидаемый id схемы
117
+ ```sh
118
+ opencode plugin add opencode-orchestrator-uni
97
119
  ```
98
120
 
99
- Укажите ровно одно из `text` / `path`. Инструмент берёт **последний** fenced-блок ```` ```json ````,
100
- который парсится и несёт поле `schema`, разрешает схему по этому полю и валидирует документ.
121
+ Или добавьте пакет в массив `plugins` в `~/.config/opencode/opencode.json(c)`:
101
122
 
102
123
  ```jsonc
103
- { "valid": true, "schema": "empiric/v1", "errors": [], "warnings": [ … ] }
104
- { "valid": false, "code": "E_INVALID", "schema": "empiric/v1",
105
- "errors": [ { "path": "$.findings[0].severity", "message": "expected one of …" } ],
106
- "warnings": [] }
124
+ {
125
+ "$schema": "https://opencode.ai/config.json",
126
+ "plugins": ["opencode-orchestrator-uni"]
127
+ }
107
128
  ```
108
129
 
109
- | Код | Значение |
110
- | ------------------- | -------------------------------------------------------------------- |
111
- | `E_INPUT` | Плохой вызов: нет/оба `text`/`path`, неверные типы, нечитаемый файл |
112
- | `E_NO_JSON` | Fenced-блок ```` ```json ```` не найден |
113
- | `E_PARSE` | Блок есть, но ни один не парсится как JSON |
114
- | `E_UNKNOWN_SCHEMA` | Отчёт называет id, которого нет в комплекте (или не называет вовсе) |
115
- | `E_SCHEMA_MISMATCH` | Отчёт называет схему, отличную от ожидаемой |
116
- | `E_INVALID` | Документ не удовлетворяет своей схеме (см. `errors`) |
117
- | `E_SCHEMA_IO` | Схемы комплекта недоступны или битые (см. `directory`, `file`) |
118
- | `E_ABORTED` | Сессия остановлена во время чтения отчёта |
119
-
120
- `warnings` несут правила промпта, которые *структурно валидный* отчёт всё ещё
121
- может нарушить — то, что JSON Schema выразить не может: отсутствующий `rc` у
122
- claim'а `empiric` с `method` = `run|measure|compare_base`, элементы `self_check`
123
- вне 1–19, инвариант `invariant`, помеченный `violated` без контрпримера,
124
- непокрытая обязательная строка `lines_checked`, расхождение `verdict` и `gate` у
125
- `meta`, инварианты `closing_list`/`verdict` у `redteam`.
126
-
127
- Схемы лежат в `schemas/*.json` и выведены **строго** из SGR-секций
128
- `agents/*.md`, которые остаются источником истины: тестовый набор парсит
129
- SGR-шаблон каждого агента и падает, когда поле промпта или значение enum не
130
- принимается его схемой. `context-lint-failure/v1` — типизированный конверт ошибки
131
- `orch_uni_context_lint`: у него нет шаблона агента, и отчётом он не является. Схемы
132
- разрешают `additionalProperties` — агенты могут
133
- добавлять свои поля (`verdict_label`, `check`, …).
134
-
135
- ### `orch_uni_context_lint`
130
+ Зафиксировать версию можно так: `opencode-orchestrator-uni@0.5.1`. Для настройки
131
+ моделей используйте объектную форму — см. [Настройку](#настройка) и
132
+ [Модели](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md#модели).
136
133
 
137
- ```jsonc
138
- { "path": "AGENTS.md" } // файл или каталог, относительно локации
139
- { "path": ".", "max_lines": 150, "max_tokens": 2000 }
140
- { "path": ".", "max_words": 2000 } // бюджет слов SPEC; по умолчанию 1500 (цель), потолок 2000
141
- { "path": ".", "max_file_bytes": 500000, "max_files": 100, "max_findings": 50, "max_total_findings": 500 }
142
- ```
134
+ Перезапустите сервис после изменения конфига:
143
135
 
144
- Детерминированный read-only аудит `AGENTS.md`, `SPEC.md` и `CLAUDE.md`. Возвращает
145
- `{ schema: "context-lint/v1", ok: true, verdict, closing_list, files, summary, truncated? }`;
146
- каждая находка несёт `id`, `severity`, `kind`, `evidence`, `detail` и `fix`. Проверки:
147
- бюджет строк/токенов/слов, различные vague-фразы, дубли строк, битые относительные ссылки,
148
- плейсхолдеры, даты/версии в первых трёх строках, обязательные секции и колонка Test
149
- у AC. Ссылки и явные цели ограничены **реальным** путём: symlink/junction, ведущий за
150
- пределы корня, пропускается, а такая цель отклоняется (`E_OUT_OF_ROOT`). Код-фенсы,
151
- inline-код и HTML-комментарии маскируются: пример не считается правилом — структурные
152
- проверки (команды, границы, проверка) читают полную маску, а требования, AC-id и
153
- non-goals — маску фенсов. Цели ссылок передаются из построчного сканера по одной
154
- (массива кандидатов нет), поэтому память не растёт с числом ссылок; проверки ограничены
155
- на файл 50 000 кандидатами, сигнал проверяется на каждой строке и каждые 100 кандидатов,
156
- а кэши ссылок держат не более 5 000 записей, поэтому abort срабатывает; 2001 ссылка
157
- проверяется обычным образом, 50 000 валидных ссылок дают pass, а 50 001-й кандидат делает
158
- список неполным (`truncated: true` плюс MAJOR-маркер `link candidates truncated` в
159
- `closing_list`), он не может дать pass.
160
- Отдельного потолка на
161
- битые ссылки нет: вывод ограничивают общие лимиты находок, а переполнение помечается.
162
- Строка сканируется любой длины: сканер ссылок и регулярное выражение плейсхолдеров линейны,
163
- поэтому 4100-символьная строка проверяется как любая другая, а битая ссылка или
164
- плейсхолдер на ней — настоящая находка, а не маркер. Внутреннего потолка дублей нет. Цели
165
- UNC/сетевые пути никогда не пробуются. Замер (bun 1.4.2, Windows, свежий процесс):
166
- 50 001 битая ссылка с `max_findings: 2` → ~1,4 с и ~67 МБ пикового RSS; 50 тыс.
167
- обычных строк → ~0,14 с / ~65 МБ; одна строка 2 МБ со ссылками → ~3,1 с / ~116 МБ
168
- (~41 МБ без ссылок). Маскирование переиспользует строку как есть, если в ней нет
169
- backtick и `<pre>`/`<code>`/`<!--`, поэтому не копирует строку посимвольно, а строка
170
- в 2 МБ остаётся ограниченной 50 000 кандидатами, а не материализует все ссылки.
171
- Лимиты: ≤ 2 МБ на файл, ≤ 500 файлов за прогон. `max_findings` (на файл) — это N на
172
- severity: сохраняются до N MAJOR и N MINOR/INFO, излишек заменяется одним маркером
173
- (MAJOR, если выпал MAJOR, иначе INFO); MAJOR-маркер остаётся в `closing_list`.
174
- `max_total_findings` (глобально, по умолчанию 1000)
175
- сохраняет сначала MAJOR; при переполнении MAJOR остаются `max_total` находок плюс один
176
- MAJOR-маркер `truncated`. Усечённый список помечается `truncated: true`, а не скрывается.
177
- Маркеры дополнительны к `max_findings` и не расходуют его бюджет: маркер усечённых
178
- кандидатов-ссылок и маркер усечённых находок дают по маркеру в одном прогоне, поэтому
179
- `max_findings: 2` на 20 001 битой ссылке даёт 2 сохранённые находки плюс 2 маркера. Маркеры
180
- указывают на `file:1` в `evidence`.
181
- Non-goals считаются как элементы верхнего уровня: перенесённый абзац — один элемент,
182
- inline `;`/`,`/`and`/`и` делят только верхний уровень (не внутри `(…)`, `[…]`, бэктиков
183
- любой длины или `<code>`), а bullet с отступом 0–4 пробела под лейблом — элемент; фенсы,
184
- `<pre>` и код с большим отступом — нет.
185
- Плейсхолдеры — `<...>` (три и более точки) и `TODO`/`TBD`/`FIXME`; `<DoD>` и `<name>` —
186
- разметка.
187
- `max_lines` — единственный бюджет корня (200 строк), который применяет инструмент;
188
- цифры 60/200/100 по уровням в [`docs/`](./docs) — ориентир для авторов, а не отдельные
189
- лимиты инструмента. `max_words` по умолчанию равен цели 1500 слов SPEC; передайте
190
- `max_words: 2000`, чтобы применять документированный потолок. Типизированные ошибки: `E_INPUT`, `E_NOT_FOUND`, `E_NO_FILES`,
191
- `E_IO`, `E_ABORTED`, `E_LIMIT_FILE`, `E_LIMIT_FILES`, `E_OUT_OF_ROOT`.
192
- Ошибка — типизированный payload `{schema:"context-lint-failure/v1", ok:false, code, message, path?, bytes?, files?, max?}`,
193
- который валидируется только по `context-lint-failure/v1`; отчёт —
194
- `{schema:"context-lint/v1", ok, verdict, closing_list, files, summary, truncated?}`, и каждый файл несёт `lines`,
195
- `words`, `chars` и `tokens_est` (токены оцениваются как кириллица/3 + прочее/4). Каталог
196
- сканируется до глубины 3, а `max_files` отказывает рано: обход останавливается на первом файле
197
- выше лимита. Ничего не пропадает молча: каталог ниже лимита глубины, ссылка или junction вне
198
- корня workspace и незакрытые fence, `<pre>` или HTML-комментарий дают INFO-находки, поэтому `pass`
199
- не скрывает непроверенную область. Незакрытый `<code>` — строчная маска: он скрывает
200
- остаток своей строки и не репортится (INFO дают только fence, `<pre>` и HTML-комментарий,
201
- которые тянутся через строки). Отмена наблюдается между файлами, каждые 2048 строк
202
- построчной проверки и в каждом гейте, поэтому худшая латентность — один проход маски по
203
- файлу под `max_file_bytes` (десятки мс на 2 МБ), а не весь скан. Команды считаются только в коде, таблице задач или секции
204
- Commands, HTML-комментарий вроде `<!-- npm install -->` командой не является, а `make` требует
205
- цели, поэтому проза «Make sure …» — не команда. Скан от корня подхватывает и фикстуры вроде
206
- `eval/`; передайте явный путь, если нужны только канонические файлы.
207
-
208
- ### `orch_uni_snapshot`
209
-
210
- ```jsonc
211
- { "path": "lab/stack-test", "exclude": ["tmp"] } // exclude опционален и аддитивен
136
+ ```sh
137
+ opencode service restart
212
138
  ```
213
139
 
214
- ```jsonc
215
- { "root": "C:\\…\\lab\\stack-test",
216
- "files": [ { "path": "a.txt", "sha256": "…", "bytes": 1 } ],
217
- "aggregate": "…" }
218
- ```
140
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
219
141
 
220
- - `aggregate = sha256` по отсортированным строкам `"<relpath>\0<sha256>\n"`
221
- (разделители `/`, порядок кодпойнтов) — стабилен между прогонами, машинами и
222
- порядком обхода и меняется, когда меняется путь или содержимое любого файла.
223
- - По умолчанию (всегда) исключены: `node_modules`, `.git`, `.ae`; `exclude`
224
- добавляет имена, целые относительные пути или относительные префиксы
225
- (`lab/tmp`). Симлинки пропускаются.
226
- - Лимиты: ≤ 5000 файлов, ≤ 50 МиБ на файл — `E_LIMIT_FILES` / `E_LIMIT_BYTES`
227
- (падает весь снапшот; усечённый снапшот дал бы неверный агрегат). `E_NOT_FOUND`
228
- для отсутствующего пути или не-каталога, `E_ABORTED`, когда сессия остановлена.
142
+ ### Настройка
229
143
 
230
- ### `orch_uni_sessions`
144
+ Все опции необязательны и живут в записи плагина:
231
145
 
232
- ```jsonc
233
- {} // дети вызывающей сессии
234
- { "sessionID": "ses_…", "recursive": true } // всё поддерево другой сессии
235
- ```
146
+ - `locale` — `"ru"` или `"en"`; полные теги вроде `"ru-RU"` принимаются.
147
+ - `model` / `agents` — модель по умолчанию и переопределения по агентам в форме
148
+ `"provider/model[#variant]"` или `{ providerID, model, variant }`.
149
+ - `sessionGuard` — напоминания о бюджете промпта и лимит компакций.
150
+ - `toolOutputGuard` — урезает большие выводы `shell`/`bash`/`webfetch`.
236
151
 
237
- ```jsonc
238
- { "sessionID": "ses_parent", "recursive": false, "source": "session.index",
239
- "authoritative": false, "indexSize": 1, "count": 1,
240
- "limitations": [ … ],
241
- "sessions": [ { "sessionID": "ses_child", "parentID": "ses_parent", "agent": "explore",
242
- "model": "deepseek/deepseek-flash", "variant": "default", "title": "…",
243
- "cost": 0.0005, "tokens": { "input": 3491, "output": 2 },
244
- "created": "2026-10-15T04:01:06.627Z", "updated": "…" } ] }
245
- ```
152
+ Неверные значения игнорируются с предупреждением `[orchestrator.uni] …`. Полный
153
+ справочник опций: [Модели](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md#модели),
154
+ [Локаль](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md#локаль) и
155
+ [Гигиена сессии](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md#гигиена-сессии).
246
156
 
247
- `source` говорит, какой маршрут дал ответ:
248
-
249
- - `session.list` — эта сборка предоставляет API листинга сессий; ответ
250
- **авторитетный** и полный (`recursive` обходит поддерево постранично).
251
- - `session.index` — фолбэк, используемый OpenCode 2.0.28: у `ctx.session` есть
252
- `get/create/…`, но **нет `list`**, поэтому детей нельзя перечислить из
253
- хранилища. Плагин при setup подписывается на события `session.created` /
254
- `session.deleted` и хранит `child → parent` в собственном хранилище плагина;
255
- детали по каждому ребёнку читаются из `ctx.session.get()` в момент вызова.
256
- Ответ **не авторитетный**; оговорки возвращаются в `limitations` (сессии,
257
- созданные до старта инстанса плагина, не видны; пропуск событий скрывает
258
- детей, созданных пока плагин был выгружен).
259
- - `E_NO_API` — нет ни одного маршрута. Фолбэк через сканирование контекста
260
- (поиск частей инструмента `subagent` в `ctx.session.context`) был оценён и
261
- отклонён: у летящих детей нет id сессии в их tool-части, а компакция стирает
262
- историю. Открытый вопрос: листинг сессий со стороны плагина (или фильтр по
263
- `parentID` в `ctx.session.context`) убрал бы фолбэк целиком.
264
-
265
- `E_INPUT` при некорректных аргументах, `E_NOT_FOUND`, когда родительской сессии
266
- нет, `E_ABORTED`, когда сессия остановлена.
267
-
268
- ### `orch_uni_session_stats`
157
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
269
158
 
270
- ```jsonc
271
- {} // счётчики вызывающей сессии
272
- { "sessionID": "ses_…" } // любая сессия на этом сервере, не только дочерняя
273
- ```
159
+ ## Использование
274
160
 
275
- ```jsonc
276
- { "ok": true, "sessionID": "ses_…",
277
- "counters": {
278
- "requests": 12, "promptTokensLast": 151204, "promptTokensMax": 161002,
279
- "promptTokensMedian": 148900, "band": 1, "compactions": 1,
280
- "compactionAttempts": 1, "compactionFailures": 0, "compactionSource": "event",
281
- "reminders": 2, "toolCalls": 31, "outputsCapped": 1,
282
- "outputCharsSaved": 18422, "errors": 0,
283
- "toolCallsByTool": { "shell": 18, "bash": 6, "webfetch": 2, "read": 5 },
284
- "toolOutputsCappedByTool": { "shell": 1, "bash": 0, "webfetch": 0, "read": 0 }
285
- },
286
- "limits": { "promptTokensSoft": 150000, "maxCompactions": 1, "maxToolOutputChars": 20000 },
287
- "overBudget": true, "compactionLimitReached": true, "toolsPerTurn": 2.58,
288
- "tracked": true,
289
- "guard": { "available": true, "hooksRegistered": true, "sessionEnabled": true,
290
- "toolOutputEnabled": true,
291
- "toolOutputTools": ["shell", "bash", "webfetch"],
292
- "compactionSource": "event", "eventLive": true,
293
- "streamFailures": 0, "unkeyedCalls": 0 } }
294
- ```
161
+ ### Быстрый старт
295
162
 
296
- `sessionID` может называть **любую сессию на этом сервере**, не только дочернюю
297
- вызывающего; это осознанно — по отчёту оркестратор контролирует все свои срезы.
298
- Счётчики принадлежат инстансу плагина, а `tracked` равен `true`, как только сессию
299
- наблюдало любое событие или хук; событие `session.deleted` её забывает. `band` —
300
- максимум достигнутого уровня бюджета (`0` ниже мягкого порога);
301
- `promptTokensMedian` — медиана по окну последних 256 запросов; `toolCalls` и
302
- per-tool счётчики включают вложенные вызовы Code Mode; `toolCallsByTool` и
303
- `toolOutputsCappedByTool` разносят вызовы и урезанные выводы по нормализованному
304
- имени инструмента (namespace снят, регистр нижний); `outputCharsSaved` — число
305
- символов, не байтов, и верхняя оценка (внедрённая заглушка вычитается).
306
- `compactions` считает только подтверждённые `session.compaction.ended`;
307
- `compactionAttempts` — каждый вызов хука `session.compaction`, поэтому на хосте с
308
- умершим или отсутствующим потоком событий попытки растут, а `compactions` и
309
- `compactionLimitReached` стоят (неудачная попытка не становится стоп-сигналом).
310
- Умерший поток событий один раз виден в `guard.streamFailures`; per-session
311
- `errors` считает только ошибки хуков, поэтому транспортная авария не
312
- приписывается каждой сессии. Дубликаты событий компакции считаются один раз
313
- только при наличии `event.id` или durable-позиции; без identity повторная
314
- доставка может пересчитать событие (fail-open в сторону счёта).
315
- Сессия, которую не отдаёт хранилище и не наблюдал этот инстанс, — `E_NOT_FOUND`
316
- (распознаётся по типизированным `_tag`/`name`/`code` — `Session.NotFoundError`,
317
- `SessionNotFoundError`, `NotFoundError`, `ENOENT` — с узким fallback по сообщению);
318
- `session.get`, вернувший `undefined` для ненаблюдаемой сессии, — тот же ответ
319
- «не найдено»; transient-ошибка `session.get` (блокировка, права, `unknown
320
- database`) — `E_INTERNAL`; известная сессия без запросов — валидный отчёт с
321
- `tracked: false`. Без `session.get` ненаблюдаемая сессия —
322
- `E_NO_API`, наблюдаемая — `ok` с `session: null` и записью в `limitations`.
323
- Коды: `E_INPUT`, `E_NOT_FOUND`, `E_INTERNAL`, `E_NO_API`, `E_UNAVAILABLE`
324
- (guard не зарегистрирован или его хуки не установились), `E_ABORTED`.
325
-
326
- ## Гигиена сессии
327
-
328
- Плагин реализует протокол [`session-discipline.md`](./docs/ru/session-discipline.md):
329
- сессия = один срез, бюджет промпта ≤150k токенов, ≤1 компакция, вывод инструментов
330
- — в файл, в конце среза — handoff.
331
-
332
- Runtime-часть — три хука (`session.context`, `session.compaction`,
333
- `tool.execute.after`) и подписка на события компакции:
334
-
335
- - `session.context` — оценивает промпт (system + messages) и при переходе на
336
- новый уровень бюджета добавляет одно короткое напоминание. Напоминание
337
- инжектится **один раз при переходе уровня**, а не в каждом запросе; внутри
338
- уровня текст стабилен, поэтому префикс-кэш не рвётся.
339
- - события компакции — хук `session.compaction` регистрируется **всегда**: он
340
- считает попытки (`compactionAttempts`) и отдаёт tentative-напоминание ближайшему
341
- запросу; напоминание не называет номер компакции и не заявляет лимит.
342
- Подтверждает компакцию только `session.compaction.ended` (дедуп по `event.id`
343
- или durable-позиции) и выставляет confirmed-note с номером и лимитом;
344
- `session.compaction.failed` увеличивает `compactionFailures`, снимает
345
- tentative-note и сохраняет confirmed-note, ещё ждущий доставки. Если поток
346
- событий завершился или упал, `guard.eventLive` становится `false`,
347
- `guard.compactionSource` — `"hook"`, а `guard.streamFailures` — `1`
348
- (per-session `errors` остаётся `0`); хук продолжает считать попытки, но
349
- подтверждённых компакций и ложного «лимит исчерпан» на этом пути нет.
350
- - `tool.execute.after` — для `shell`, `bash`, `webfetch` урезает вывод больше
351
- `maxChars`: полный текст пишется в приватный корень на инстанс плагина
352
- `os.tmpdir()/opencode-tool-output-<random>/` (POSIX: 0700 на корень и каталог
353
- сессии, 0600 на файл), модель получает голову и путь. На Windows mode не
354
- действует (замер: 0666), приватность там держится только на ACL каталога
355
- `os.tmpdir()` и кодом не проверяется. Корень создаётся `mkdtemp` при setup,
356
- поэтому заранее созданный каталог или
357
- junction `opencode-tool-output` не используется; на POSIX корень обязан
358
- принадлежать текущему uid и не давать доступа group/other, иначе guard
359
- отключается с warning (fail-open: результат не трогается). Каталог сессии
360
- (`s-<uuid>`) и файл (`c-<uuid>.txt`, запись `wx`) — случайные, их `realpath`
361
- проверяется внутри корня. При выгрузке плагина корень удаляется best effort.
362
- Строка с lone surrogate нормализуется один раз (U+FFFD), поэтому файл, голова и
363
- счётчики описывают одну и ту же строку. Остаточный риск принят: same-user
364
- атакующий всё ещё может подменить каталог
365
- сессии между `realpath` и `writeFile` (в Node нет `openat`). Если `TMPDIR`
366
- указывает внутрь воркспейса, файлы попадут туда. `read`, `write`, `edit`,
367
- `execute` и инструменты комплекта не урезаются; kit-имя без namespace
368
- (`session_stats`) отбрасывается в конфиге с warning.
369
-
370
- `maxCompactions: 0` отключает лимит компакций. `guard.toolOutputEnabled` равен
371
- `true` только когда приватный корень создан **и** эффективный список инструментов
372
- непуст; `guard.toolOutputTools` — этот список, `guard.unkeyedCalls` — вызовы
373
- хуков без непустого `sessionID` (отбрасываются, а не сливаются в бакет `""`).
374
- Пустой `tools` выключает кап с warning. Guard fail-open: ошибка хука не
375
- ломает запрос и не портит результат. Отключается флагами `enabled`:
163
+ 1. Установите плагин, перезапустите OpenCode и откройте сессию в каталоге проекта.
164
+ 2. Задайте `model` — или оставьте пусто, чтобы субагенты наследовали модель сессии.
165
+ 3. Дайте оркестратору срез. Используйте `/spec` перед реализацией, `/agents-md`
166
+ для `AGENTS.md` и `/handoff`, чтобы закрыть срез.
376
167
 
377
- ```jsonc
378
- {
379
- "plugins": [
380
- {
381
- "package": "opencode-orchestrator-uni",
382
- "options": {
383
- "sessionGuard": { "enabled": true, "promptTokensSoft": 150000, "maxCompactions": 1 },
384
- "toolOutputGuard": {
385
- "enabled": true,
386
- "maxChars": 20000,
387
- "headChars": 4000,
388
- "tools": ["shell", "bash", "webfetch"]
389
- }
390
- }
391
- }
392
- ]
393
- }
394
- ```
168
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
395
169
 
396
- Метрики среза — `orch_uni_session_stats`; закрытие среза — команда `/handoff`.
170
+ ### Аудиторский цикл
397
171
 
398
- ## Модели
172
+ `factcheck` отмечает устаревшую работу; `empiric` воспроизводит и измеряет;
173
+ `invariant` проверяет состояния и враждебный ввод; `arbiter` разбирает споры.
174
+ `meta` проводит гейт отчётов, `redteam` проверяет приёмку, а `fix-runner`
175
+ закрывает список. Процессные документы поставляются как reference `audit-kit` и
176
+ лежат в [`docs/ru`](https://github.com/OniVe/opencode-orchestrator-uni/tree/main/docs/ru).
399
177
 
400
- Определения агентов не несут `model`; модели настраиваются у записи плагина в
401
- `opencode.json(c)`:
178
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
402
179
 
403
- ```jsonc
404
- {
405
- "$schema": "https://opencode.ai/config.json",
406
- "plugins": [
407
- {
408
- "package": "opencode-orchestrator-uni",
409
- "options": {
410
- // Модель по умолчанию для всех агентов комплекта.
411
- "model": "deepseek/deepseek-flash",
412
- // Переопределения по агентам (id -> строка или развёрнутая форма).
413
- "agents": {
414
- "meta": "deepseek/deepseek-reasoner",
415
- "fix-runner": { "providerID": "anthropic", "model": "claude-sonnet-4-5", "variant": "high" }
416
- }
417
- }
418
- }
419
- ]
420
- }
421
- ```
180
+ ### Агенты
422
181
 
423
- - `model` — модель по умолчанию для всех агентов комплекта; `agents.<id>` —
424
- переопределение по агенту. Оба принимают `"provider/model[#variant]"` или
425
- `{ providerID, model, variant }`.
426
- - Без опций агенты комплекта остаются без модели — субагенты наследуют модель
427
- сессии.
428
- - Неверные значения игнорируются с предупреждением (`[orchestrator.uni] …`).
429
- - Субагенты работают на своей настроенной модели; основной `orchestrator` — на
430
- модели сессии, поэтому модель, заданная для `orchestrator`, — информационная
431
- для клиентов (на момент OpenCode 2.0.28).
432
- - Запись `agents` в конфиге или локальный Markdown-файл агента со своей моделью
433
- всё равно побеждает — конфигурация применяется после пакетных плагинов.
434
-
435
- ## Локаль
436
-
437
- Определения агентов и процессные документы поставляются per-locale — в
438
- `agents/<locale>/` и `docs/<locale>/`; сейчас это `ru` и `en` (английский
439
- контент — перевод русских оригиналов). Комплект выбирает локаль в таком порядке:
440
-
441
- 1. `options.locale` (`"ru"` или `"en"`; полные теги вроде `"ru-RU"` принимаются);
442
- 2. автодетект: `LC_ALL` / `LC_MESSAGES` / `LANG`, затем Intl-локаль рантайма
443
- (настройка ОС);
444
- 3. дефолт: `en`.
182
+ | Агент | Режим | Роль |
183
+ | -------------- | ---------- | --------------------------------------------------------------- |
184
+ | `orchestrator` | `primary` | Root-оркестратор; делегирует правки; пишет артефакты аудита/состояния |
185
+ | `factcheck` | `subagent` | Read-only: пред-проход на устаревание («уже сделано» / устарело) |
186
+ | `empiric` | `subagent` | Read-only: воспроизведения, замеры, первоисточники |
187
+ | `invariant` | `subagent` | Read-only: состояния, отмены, гонки, враждебный ввод |
188
+ | `arbiter` | `subagent` | Read-only: разбирает только спорные находки |
189
+ | `meta` | `subagent` | Read-only: мета-аудит отчётов (гейт pass/fail) |
190
+ | `redteam` | `subagent` | Read-only: приёмочный ред-тим (релизные ворота) |
191
+ | `context-lint` | `subagent` | Read-only: аудит AGENTS.md/SPEC.md на token-эффективность |
192
+ | `fix-runner` | `subagent` | Пишущий: применяет список правок и доказывает закрытие |
445
193
 
446
- ```jsonc
447
- {
448
- "$schema": "https://opencode.ai/config.json",
449
- "plugins": [
450
- {
451
- "package": "opencode-orchestrator-uni",
452
- "options": { "locale": "ru", "model": "deepseek/deepseek-flash" }
453
- }
454
- ]
455
- }
456
- ```
194
+ Все агенты поставляются без модели; определения лежат в [`agents/`](https://github.com/OniVe/opencode-orchestrator-uni/tree/main/agents) и
195
+ парсятся при setup. «Read-only» означает: `edit` запрещён и промпт запрещает
196
+ запись; `shell` остаётся для проверок (принятый риск I-M15).
457
197
 
458
- Если для запрошенной локали контент не поставлен, происходит откат к дефолтной
459
- локали с предупреждением в логе плагина. Обе локали регистрируют одних и тех же
460
- агентов под одними и теми же id — переключение локали меняет только язык
461
- промптов, процессных документов и описания reference.
198
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
462
199
 
463
- ## Требования
200
+ ### Команды
464
201
 
465
- - **OpenCode 2.x** с V2 plugin API (поле `plugins` в конфиге). Загрузчик плагинов
466
- V1 ожидает legacy-экспорт `server()` и этот плагин не загрузит.
202
+ | Команда | Что делает |
203
+ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
204
+ | `/agents-md` | Вставляет workflow аудита/черновика AGENTS.md: шаблон `context-efficiency.md`, `orch_uni_context_lint`, `context-lint`, подтверждение перед записью. |
205
+ | `/spec` | Вставляет workflow SPEC.md: бриф, уточняющие вопросы, EARS/AC/трассировка, `orch_uni_context_lint`, `context-lint`, подтверждение перед записью. |
206
+ | `/handoff` | Вставляет workflow закрытия среза: факты сессии и рабочего дерева, шаблон handoff из `session-discipline.md`, запись `docs/planning/handoff-<YYYY-MM-DD>.md`. |
467
207
 
468
- ## Установка
208
+ Команда — это промпт, а не писатель: она вставляет workflow в текущую сессию, а
209
+ оркестратор дальше работает по обычным правилам evidence и подтверждения.
469
210
 
470
- ### Через CLI OpenCode
211
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
471
212
 
472
- ```sh
473
- opencode plugin add opencode-orchestrator-uni
474
- ```
213
+ ## Справочник
475
214
 
476
- ### Вручную
215
+ Глубокий справочник — в [`docs/ru/reference.md`](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/docs/ru/reference.md):
216
+ защита записи, все пять инструментов со схемами и лимитами, гигиена сессии,
217
+ модели, локаль, приоритет и заметки.
477
218
 
478
- Добавьте пакет в массив `plugins` вашего глобального
479
- `~/.config/opencode/opencode.json(c)`:
219
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
480
220
 
481
- ```jsonc
482
- {
483
- "$schema": "https://opencode.ai/config.json",
484
- "plugins": ["opencode-orchestrator-uni"]
485
- }
486
- ```
221
+ ## Разработка
487
222
 
488
- При желании зафиксируйте версию:
223
+ Сборки нет. `index.ts` — поставляемая точка входа.
489
224
 
490
- ```jsonc
491
- {
492
- "$schema": "https://opencode.ai/config.json",
493
- "plugins": ["opencode-orchestrator-uni@0.1.0"]
494
- }
225
+ ```sh
226
+ npm install
227
+ npm run typecheck
228
+ npm test
229
+ npm run check:locales
230
+ npm run verify:kit
231
+ npm run lint
232
+ npm run lint:fix
495
233
  ```
496
234
 
497
- Чтобы заодно настроить модели комплекта, используйте объектную форму — см.
498
- [Модели](#модели):
235
+ `npm test` сканирует только `./test/` и сейчас насчитывает **438 тестов в 11 файлах** — 437 pass и 1 skip. Голый `bun test` из корня красный по замыслу: он
236
+ подхватывает и специально падающие фикстуры в `eval/cases/`, и черновики в
237
+ `lab/`; используйте `npm test`.
499
238
 
500
- ```jsonc
501
- {
502
- "$schema": "https://opencode.ai/config.json",
503
- "plugins": [
504
- {
505
- "package": "opencode-orchestrator-uni",
506
- "options": { "model": "deepseek/deepseek-flash" }
507
- }
508
- ]
509
- }
510
- ```
239
+ `check:locales` и `verify:kit` требуют git-чекаута — в npm-пакете каталог
240
+ `tools/` не поставляется (`stand: unavailable`). [Biome](https://biomejs.org)
241
+ ([`biome.json`](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/biome.json)) покрывает `index.ts`, `lib/`, `test/` и
242
+ `eval/*.ts`, пропускает `lab/` и `eval/results/`, а `eval/cases/**` и
243
+ `eval/baselines/**` заморожены; записи baseline используют стиль
244
+ `JSON.stringify(…, null, 2)`, поэтому переформатирование давало бы churn на
245
+ `eval:recompute`. Выключено одно правило — `lint/style/noNonNullAssertion`.
511
246
 
512
- Перезапустите сервис OpenCode после изменения конфига:
247
+ Для живого сервера направьте конфиг проекта на чекаут:
248
+ `"plugins": ["file:///C:/path/to/opencode-orchestrator-uni"]`. Локальные пути
249
+ плагинов должны быть каталогами; OpenCode перезагружает их при изменениях.
513
250
 
514
- ```sh
515
- opencode service restart
516
- ```
251
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
517
252
 
518
- ## Приоритет
253
+ ## Дорожная карта
519
254
 
520
- **Определения** агентов заполняются только для id, не определённых где-либо ещё:
521
- агент с тем же id из вашей конфигурации — запись `agents` в конфиге или
522
- Markdown-файл в `~/.config/opencode/agents/` (либо `.opencode/agents/`) —
523
- побеждает, и плагин пропускает своё определение. **Настроенная модель** (см.
524
- [Модели](#модели)) всё равно применяется к агентам комплекта; модель,
525
- определённая вашей записью агента или файлом, побеждает её, потому что
526
- конфигурация применяется после пакетных плагинов. То же правило «занято —
527
- пропускаем» действует для reference `audit-kit`.
255
+ Текущий опубликованный релиз — **0.5.1**. До 1.0 ломающее изменение повышает
256
+ минорную версию. Заметки о релизах — в [GitHub Releases][releases-url];
257
+ запланированная работа и известные проблемы — в [issue tracker][issues-url].
528
258
 
529
- Если вы раньше устанавливали комплект копированием файлов агентов в свой
530
- конфиг-каталог, **удалите эти копии** после включения плагина, иначе устаревшие
531
- копии продолжат перекрывать определения, поставляемые плагином.
259
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
532
260
 
533
- ## Разработка
261
+ ## Участие
534
262
 
535
- Сборки нет. `index.ts` — поставляемая точка входа.
263
+ См. [`CONTRIBUTING.md`](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/CONTRIBUTING.md). Сделайте форк, создайте ветку
264
+ (`git checkout -b feature/AmazingFeature`), закоммитьте по
265
+ [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`,
266
+ `docs:`; формат проверяет `commitlint`), запушьте и откройте pull request. `ru` —
267
+ референсная локаль, `en` должен её зеркалировать. После правки агентов или
268
+ доков запустите `npm run check:locales`; после правки README — `npm test`
269
+ (паритет заголовков и фенсов).
536
270
 
537
- ```sh
538
- npm install # ставит gray-matter + dev-инструменты
539
- npm run typecheck # tsc --noEmit
540
- npm test # bun test ./test/ (герметично: регистрация, инструменты, валидатор, снапшот, промпт↔схемы + стражи идентификаторов)
541
- npm run check:locales # bun tools/locale-check.ts (паритет ru↔en: агенты + документы)
542
- npm run verify:kit # bun tools/kit-verify.ts (локали, тесты, линт, типы — стенд комплекта)
543
- npm run lint # biome check . (линт + формат + порядок импортов; только чтение)
544
- npm run lint:fix # biome check --write . (применяет безопасные фиксы)
545
- ```
271
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
546
272
 
547
- Команды `check:locales` и `verify:kit` требуют git-чекаута комплекта — в npm-пакете каталог `tools/` не поставляется, поэтому в установленном пакете они недоступны (`stand: unavailable` и собственные воспроизводимые проверки).
273
+ ## Лицензия
548
274
 
549
- `npm test` сканирует только `./test/` — поставляемый набор (400 тестов в 10 файлах;
550
- до стражей идентификаторов было 72 в 5). Голый `bun test` из корня репозитория
551
- красный по замыслу: позиционный аргумент `bun test` — это фильтр-подстрока пути,
552
- поэтому голая команда подхватывает и специально падающие фикстуры в
553
- `eval/cases/`, и черновики в `lab/`. Используйте `npm test` [F5].
275
+ Распространяется по лицензии MIT. См. [`LICENSE`](https://github.com/OniVe/opencode-orchestrator-uni/blob/main/LICENSE).
554
276
 
555
- [Biome](https://biomejs.org) ([`biome.json`](./biome.json)) покрывает кодовую
556
- поверхность — `index.ts`, `lib/`, `test/`, `eval/*.ts` — и пропускает `lab/` и
557
- `eval/results/` через git-ignore файл, плюс два замороженных вида данных:
558
- `eval/cases/**` (фикстуры с умышленными дефектами) и `eval/baselines/**`
559
- (записи, генерируемые в `JSON.stringify(…, null, 2)`-стиле; переформатирование
560
- давало бы churn на следующем `eval:recompute`). Выключено одно правило —
561
- `lint/style/noNonNullAssertion`: dev-контур и тесты осознанно используют `!`
562
- после проверок в коде.
277
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
563
278
 
564
- Проверка против живого сервера — направьте конфиг проекта на чекаут:
279
+ ## Контакты
565
280
 
566
- ```jsonc
567
- {
568
- "$schema": "https://opencode.ai/config.json",
569
- "plugins": ["file:///C:/path/to/opencode-orchestrator-uni"]
570
- }
571
- ```
281
+ Вопросы, баги и предложения: [GitHub Issues][issues-url].
572
282
 
573
- Локальные пути плагинов должны быть каталогами (или `file://`-URL каталогов);
574
- OpenCode следит за ними и перезагружает при изменениях.
283
+ Ссылка на проект: [https://github.com/OniVe/opencode-orchestrator-uni][repo-url]
575
284
 
576
- ## Заметки
285
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
577
286
 
578
- - Одна рантайм-зависимость: [`gray-matter`](https://www.npmjs.com/package/gray-matter)
579
- для парсинга фронтматтера. OpenCode сам устанавливает зависимости пакетных
580
- плагинов.
581
- - Id плагина: `orchestrator.uni`.
582
- - Поставляются только файлы из `package.json#files`: `index.ts`, `lib/`, `schemas/`,
583
- `agents/`, `docs/`, `README.md`, `README.ru.md`, `LICENSE`.
287
+ ## Благодарности
584
288
 
585
- ## Лицензия
289
+ - [Best-README-Template](https://github.com/othneildrew/Best-README-Template) — структура README.
290
+ - [Документация OpenCode V2 по плагинам](https://opencode.ai/v2/docs/build/plugins) — API плагинов.
291
+ - [shields.io](https://shields.io) — badges.
292
+ - [Bun](https://bun.sh), [Biome](https://biomejs.org) и
293
+ [semantic-release](https://semantic-release.gitbook.io/) — инструменты.
294
+
295
+ <p align="right">(<a href="#readme-top">наверх</a>)</p>
586
296
 
587
- MIT
297
+ [npm-shield]: https://img.shields.io/npm/v/opencode-orchestrator-uni?style=for-the-badge
298
+ [npm-url]: https://www.npmjs.com/package/opencode-orchestrator-uni
299
+ [ci-shield]: https://img.shields.io/github/actions/workflow/status/OniVe/opencode-orchestrator-uni/ci.yml?branch=main&style=for-the-badge
300
+ [ci-url]: https://github.com/OniVe/opencode-orchestrator-uni/actions/workflows/ci.yml
301
+ [license-shield]: https://img.shields.io/github/license/OniVe/opencode-orchestrator-uni?style=for-the-badge
302
+ [license-url]: https://github.com/OniVe/opencode-orchestrator-uni/blob/main/LICENSE
303
+ [opencode-shield]: https://img.shields.io/badge/OpenCode-V2-000000?style=for-the-badge
304
+ [opencode-url]: https://opencode.ai/v2/docs/build/plugins
305
+ [typescript-shield]: https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white
306
+ [typescript-url]: https://www.typescriptlang.org/
307
+ [bun-shield]: https://img.shields.io/badge/Bun-000000?style=for-the-badge&logo=bun&logoColor=white
308
+ [bun-url]: https://bun.sh/
309
+ [biome-shield]: https://img.shields.io/badge/Biome-60A5FA?style=for-the-badge&logo=biome&logoColor=white
310
+ [biome-url]: https://biomejs.org/
311
+ [semantic-release-shield]: https://img.shields.io/badge/semantic--release-E10079?style=for-the-badge
312
+ [semantic-release-url]: https://semantic-release.gitbook.io/
313
+ [repo-url]: https://github.com/OniVe/opencode-orchestrator-uni
314
+ [issues-url]: https://github.com/OniVe/opencode-orchestrator-uni/issues
315
+ [releases-url]: https://github.com/OniVe/opencode-orchestrator-uni/releases