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