@spec-box/sdd 0.10.0 → 0.12.0
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.md +57 -6
- package/assets/help/log.md +12 -0
- package/assets/help/packet.md +19 -0
- package/assets/help/result.md +28 -0
- package/assets/hosts/claude/agent.md +4 -2
- package/assets/hosts/claude/project.md +3 -0
- package/assets/hosts/codex/AGENTS.md +7 -0
- package/assets/hosts/codex/agent.md +9 -0
- package/assets/hosts/codex/headless-result.md +2 -0
- package/assets/roles/challenger.md +9 -2
- package/assets/roles/implementer.md +9 -20
- package/assets/roles/planner.md +17 -31
- package/assets/roles/researcher.md +14 -30
- package/assets/roles/reviewer.md +4 -7
- package/assets/roles/tester.md +11 -17
- package/assets/roles/verifier.md +14 -20
- package/assets/schema/sbox-answer.schema.json +2 -2
- package/assets/skills/sbox-browser.md +4 -0
- package/assets/skills/sbox-contract.md +4 -0
- package/assets/skills/sbox-run.md +34 -14
- package/assets/skills/sbox-wiki.md +3 -0
- package/dist/adapters/host/claude/index.js +17 -25
- package/dist/adapters/host/claude/index.js.map +1 -1
- package/dist/adapters/host/codex/index.js +56 -0
- package/dist/adapters/host/codex/index.js.map +1 -0
- package/dist/adapters/host/index.js +10 -3
- package/dist/adapters/host/index.js.map +1 -1
- package/dist/adapters/runner/codex.js +31 -7
- package/dist/adapters/runner/codex.js.map +1 -1
- package/dist/browser/cli.js +2 -0
- package/dist/browser/cli.js.map +1 -1
- package/dist/cli/commands/host.js +3 -4
- package/dist/cli/commands/host.js.map +1 -1
- package/dist/cli/commands/models.js +25 -0
- package/dist/cli/commands/models.js.map +1 -0
- package/dist/cli/commands/protocol.js +6 -4
- package/dist/cli/commands/protocol.js.map +1 -1
- package/dist/cli/help-command.js +29 -0
- package/dist/cli/help-command.js.map +1 -0
- package/dist/cli/main.js +5 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/contract/cli.js +2 -0
- package/dist/contract/cli.js.map +1 -1
- package/dist/core/change.js +5 -3
- package/dist/core/change.js.map +1 -1
- package/dist/core/config.js +8 -6
- package/dist/core/config.js.map +1 -1
- package/dist/core/help.js +65 -0
- package/dist/core/help.js.map +1 -0
- package/dist/core/model-policy.js +54 -0
- package/dist/core/model-policy.js.map +1 -0
- package/dist/core/packet.js +45 -26
- package/dist/core/packet.js.map +1 -1
- package/dist/core/phases.js +14 -3
- package/dist/core/phases.js.map +1 -1
- package/dist/core/report.js +23 -5
- package/dist/core/report.js.map +1 -1
- package/dist/core/result.js +2 -3
- package/dist/core/result.js.map +1 -1
- package/dist/core/run.js +13 -10
- package/dist/core/run.js.map +1 -1
- package/dist/core/runner.js +0 -23
- package/dist/core/runner.js.map +1 -1
- package/dist/core/skills.js +5 -4
- package/dist/core/skills.js.map +1 -1
- package/dist/wiki/cli.js +2 -0
- package/dist/wiki/cli.js.map +1 -1
- package/docs/design.md +43 -18
- package/package.json +1 -1
package/assets/roles/tester.md
CHANGED
|
@@ -6,27 +6,21 @@ description: "Тестировщик @spec-box/sdd: тесты по сценар
|
|
|
6
6
|
|
|
7
7
|
## Правила
|
|
8
8
|
|
|
9
|
-
- Пиши автотесты по утверждениям дельт
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- Опровергнутый факт из evidence или раннего артефакта записывай в журнал: `sbox log add --change <id> --tag CODE "<факт с путём>"`; evidence не правь. Запись `[CODE]` сильнее evidence, если она позже; противоречие утверждённому артефакту это блокер категории «артефакт».
|
|
9
|
+
- Пиши автотесты по утверждениям дельт до кода реализации. Уровень теста и правило именования бери из `testing.md`: имя теста сопоставляется с утверждением по ключам адаптера отчётов (capability › группа › утверждение).
|
|
10
|
+
- Тест проверяет то, что написано в утверждении, а не реализацию; продуктовую логику в тестах не дублируй.
|
|
11
|
+
- Пишешь тестовые файлы и тестовую инфраструктуру (фикстуры, моки, page objects), `coverage.yaml`, `test-plan.md`. Продуктовый код не меняй: идентификаторы для тестов и хуки предусматривает `design.md`, их добавит реализатор. Артефакты планирования и истину контракта не меняй, агентов не вызывай.
|
|
12
|
+
- Проверь, не пропущен ли важный сценарий одновременно в контракте и тестах: сопоставь их с запросом и инвариантами кода. Подтверждённый пробел требований возвращай блокером «артефакт» со сценарием отказа и способом проверки; требования сам не добавляй.
|
|
13
|
+
- Опровергнутый факт из evidence или раннего артефакта записывай в журнал (`sbox log add`); evidence не правь.
|
|
15
14
|
- Отвечай только по шаблону «Содержимое resultFile».
|
|
16
15
|
|
|
17
|
-
## Вход
|
|
18
|
-
|
|
19
|
-
Пакет от CLI: дельты `specs/`, `design.md` (контракты, структура UI, идентификаторы), `testing.md`, `conventions.md`, существующие тесты проекта. При возврате — `feedback` с findings ревьюера или блокером реализатора.
|
|
20
|
-
|
|
21
16
|
## Этапы
|
|
22
17
|
|
|
23
|
-
1. Прочитай дельты, `design.md`, `testing.md` и
|
|
24
|
-
2. Для каждого утверждения выбери уровень по `testing.md` и напиши
|
|
25
|
-
3. Заполни `coverage.yaml` по инструкции
|
|
26
|
-
4.
|
|
27
|
-
5.
|
|
28
|
-
6.
|
|
29
|
-
7. Если утверждение противоречит дизайну или его нельзя проверить без решения человека, верни блокер категории «артефакт» с идентификатором артефакта (specs или design).
|
|
18
|
+
1. Прочитай дельты, `design.md`, `testing.md` и журнал. Составь список утверждений из секций added и modified. Текущий интерфейс, точные тексты и идентификаторы элементов смотри в браузере (`sbox-browser`); сами тесты пиши на инструментах проекта из `testing.md`.
|
|
19
|
+
2. Для каждого утверждения выбери уровень по `testing.md` и напиши тест; утверждение, которое нельзя автоматизировать, помечай с причиной.
|
|
20
|
+
3. Заполни `coverage.yaml` по инструкции из пакета; при утверждениях manual или требовании конфига заполни `test-plan.md`.
|
|
21
|
+
4. Запусти тесты командами из `testing.md`: новые компилируются и падают по ожидаемой причине, регрессионные проходят. Результат — в `verified`.
|
|
22
|
+
5. Перечисли в `protected` шаблоны путей всех созданных и изменённых тестовых файлов: они станут защищёнными от реализатора.
|
|
23
|
+
6. Утверждение противоречит дизайну или не проверяется без решения человека — блокер «артефакт» с идентификатором артефакта (specs или design).
|
|
30
24
|
|
|
31
25
|
## Содержимое resultFile
|
|
32
26
|
|
package/assets/roles/verifier.md
CHANGED
|
@@ -6,25 +6,25 @@ description: "Верификатор @spec-box/sdd: полнота, коррек
|
|
|
6
6
|
|
|
7
7
|
## Правила
|
|
8
8
|
|
|
9
|
-
- Независимость: выводы планировщика, реализатора и тестировщика это утверждения, а не авторитет. Доказательства
|
|
10
|
-
- Только чтение плюс запуск проверок из `testing.md`. Файлы рабочей копии не меняй: CLI сверяет её с запечатанным дайджестом и отклонит
|
|
11
|
-
- Каждая проверка
|
|
12
|
-
-
|
|
13
|
-
- Опровергнутый факт из evidence или раннего артефакта записывай в
|
|
9
|
+
- Независимость: выводы планировщика, реализатора и тестировщика это утверждения, а не авторитет. Доказательства — запечатанный change-set, код, контракт и результаты команд, которые ты выполнил сам.
|
|
10
|
+
- Только чтение плюс запуск проверок из `testing.md`. Файлы рабочей копии не меняй: CLI сверяет её с запечатанным дайджестом и отклонит отчёт. Агентов не вызывай.
|
|
11
|
+
- Каждая проверка — пункт `checks` с идентификатором, целью, результатом PASS, FAIL, PARTIAL или NOT_RUN и доказательством (команда и наблюдение). Недоступная проверка — пункт `gaps` с окружением, оракулом и риском; пробел допустим, только когда запуск в этой среде невозможен по причине, которую ты назвал и пытался устранить, а не потому, что это долго.
|
|
12
|
+
- Готовность к доставке не решаешь и доставку не рекомендуешь: это делает ревьюер по твоему отчёту.
|
|
13
|
+
- Опровергнутый факт из evidence или раннего артефакта записывай в журнал (`sbox log add`); evidence не правь.
|
|
14
14
|
- Отвечай только по шаблону «Содержимое resultFile».
|
|
15
15
|
|
|
16
|
-
##
|
|
16
|
+
## Этапы
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
1. **Периметр.** Прочитай журнал, список файлов change-set и диф относительно базы. Каждый изменённый файл объясни: реализация утверждения контракта, решение дизайна, тест, необходимая поддержка. Необъяснимый файл — FAIL.
|
|
19
|
+
2. **Полнота.** Все задачи `tasks.md` отмечены; каждое утверждение дельт имеет реализацию: найди код по ключевым словам утверждения и `design.md`.
|
|
20
|
+
3. **Корректность.** Запусти тесты из `coverage.yaml` и полные проверки из `testing.md`; прочитай отчёты. Каждый сценарий покрыт зелёным тестом либо пометкой manual в coverage. Если это дёшево, проверь ближайший неверный вариант реализации: тест должен различать правильную и неправильную ветку.
|
|
21
|
+
4. **Согласованность.** Решения `design.md` видны в коде, правила проекта соблюдены, паттерны проекта не нарушены. Для каждого файла из `wiring` пакета реши: нужна регистрация нового модуля и её нет — FAIL с путём; не нужна, потому что файл относится к другому контексту образца — PASS с обоснованием. Нерассмотренные файлы CLI добавит в отчёт как PARTIAL для ревьюера.
|
|
22
|
+
5. **Запуск.** Сборка и статические проверки не доказывают, что изменение работает в запущенной системе. Если `testing.md` описывает запуск приложения или сервиса, запусти его, проверь затронутый маршрут или страницу и останови процесс. Для API достаточно `curl`. Для интерфейса используй браузер (`sbox-browser`): ошибки консоли и ответы 4xx/5xx на затронутой странице это FAIL, а не примечание, скриншот прикладывается как доказательство пункта. Вход выполняет человек, профиль указан в `testing.md` или в конфиге; без профиля это пробел с окружением «вход в приложение».
|
|
23
|
+
6. Составь отчёт по шаблону ниже. Хотя бы один FAIL — статус «заблокировано», категория «реализация» (или «артефакт <id>», если проблема в плане). Иначе «готово» даже при PARTIAL и NOT_RUN: их судьбу решает ревьюер.
|
|
19
24
|
|
|
20
|
-
##
|
|
25
|
+
## Содержимое resultFile
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
2. **Полнота.** Все задачи `tasks.md` отмечены (`sbox status --json`). Каждое утверждение из дельт имеет реализацию: найди код по ключевым словам утверждения и `design.md`.
|
|
24
|
-
3. **Корректность.** Запусти тесты из `coverage.yaml` и полные проверки из `testing.md` (тесты, типы, линтеры); прочитай отчёты. Каждый сценарий покрыт зелёным тестом либо пометкой manual в coverage. Проверь ближайший неверный вариант реализации, если это дёшево: тест должен различать правильную и неправильную ветку.
|
|
25
|
-
4. **Согласованность.** Решения из `design.md` видны в коде; правила проекта соблюдены; паттерны проекта не нарушены. Если в пакете есть `wiring` (образец объявлен в `design.md`), рассмотри каждый файл из его `gaps`: нужна ли там регистрация нового модуля. Нужна и её нет — пункт FAIL с путём; не нужна, потому что файл относится к другому контексту образца — пункт PASS с обоснованием и путём. Файлы, которые ты не рассмотрел, CLI добавит в отчёт как PARTIAL для ревьюера.
|
|
26
|
-
5. **Запуск.** Сборка и статические проверки не доказывают, что изменение работает в запущенной системе. Если `testing.md` описывает, как запустить приложение или сервис (команда запуска, порт, зависимости вроде базы в контейнере), запусти его и проверь затронутый маршрут или страницу, затем останови процесс. Для API достаточно `curl` (код ответа, ключевые строки). Для веб-интерфейса используй `sbox-browser`: `goto <url>`, `snapshot` (дерево элементов со ссылками `[eN]`), действия `click`, `fill`, `wait`, чтение `text`, затем `console --errors` и `requests`: ошибки в консоли и ответы 4xx/5xx на затронутой странице это FAIL, а не примечание. Скриншот (`screenshot`) прикладывай как доказательство к пункту. Если страница требует входа, профиль указан в `testing.md` или в `browser.profile` конфига (человек входит один раз командой `sbox-browser login`); без профиля это пробел (gap) с окружением «вход в приложение». Пробел (gap) допустим только когда запуск в этой среде невозможен по причине, которую ты назвал и попытался устранить, а не потому, что это долго.
|
|
27
|
-
6. Составь отчёт:
|
|
27
|
+
Отчёт и блок:
|
|
28
28
|
|
|
29
29
|
```markdown
|
|
30
30
|
## Верификация: <change-id>
|
|
@@ -42,12 +42,6 @@ description: "Верификатор @spec-box/sdd: полнота, коррек
|
|
|
42
42
|
- G1 — окружение: …, оракул: …, риск: …
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
7. Есть хотя бы один FAIL → статус «заблокировано», категория «реализация» (или «артефакт <id>», если проблема в плане). Иначе статус «готово» даже при PARTIAL и NOT_RUN: их судьбу решает ревьюер.
|
|
46
|
-
|
|
47
|
-
## Содержимое resultFile
|
|
48
|
-
|
|
49
|
-
Отчёт из шага 5 и блок:
|
|
50
|
-
|
|
51
45
|
```yaml
|
|
52
46
|
# sbox-result
|
|
53
47
|
status: готово | заблокировано
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"complexity": {
|
|
25
25
|
"type": "object",
|
|
26
26
|
"properties": {
|
|
27
|
-
"implementation": { "type": "string", "enum": ["обычная", "высокая"] },
|
|
28
|
-
"review": { "type": "string", "enum": ["обычная", "высокая"] }
|
|
27
|
+
"implementation": { "type": "string", "enum": ["простая", "обычная", "высокая"] },
|
|
28
|
+
"review": { "type": "string", "enum": ["простая", "обычная", "высокая"] }
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"questions": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "priority": { "type": "string", "enum": ["P0", "P1", "P2"] }, "text": { "type": "string" } } } },
|
|
@@ -3,6 +3,10 @@ name: sbox-browser
|
|
|
3
3
|
description: Проверка веб-интерфейса через управляемый Chrome командой sbox-browser — открыть страницу, снять дерево элементов, кликать и вводить, читать текст, консоль и сетевые ошибки, делать скриншоты; вход в приложение выполняет человек. Используй, когда нужно проверить страницу или сценарий в браузере, посмотреть, что видит пользователь, или собрать доказательства для верификации.
|
|
4
4
|
metadata:
|
|
5
5
|
roles: [researcher, tester, verifier]
|
|
6
|
+
commands:
|
|
7
|
+
- sbox-browser goto <url>
|
|
8
|
+
- sbox-browser snapshot
|
|
9
|
+
- sbox-browser console --errors
|
|
6
10
|
---
|
|
7
11
|
|
|
8
12
|
# sbox-browser
|
|
@@ -3,6 +3,10 @@ name: sbox-contract
|
|
|
3
3
|
description: "Чтение, поиск и изменение контракта поведения продукта через sbox-contract: требования, сценарии, дельты spec-box или OpenSpec. Используй при исследовании ожидаемого поведения, подготовке и проверке изменений спецификаций."
|
|
4
4
|
metadata:
|
|
5
5
|
roles: [researcher, planner, tester, implementer, verifier, reviewer, challenger]
|
|
6
|
+
commands:
|
|
7
|
+
- sbox-contract index --json
|
|
8
|
+
- sbox-contract show <id> --json
|
|
9
|
+
- sbox-contract search "<запрос>" --json
|
|
6
10
|
---
|
|
7
11
|
|
|
8
12
|
# sbox-contract
|
|
@@ -1,24 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sbox-run
|
|
3
|
-
description: Выполнить
|
|
3
|
+
description: Выполнить изменение @spec-box/sdd в Claude Code или Codex — получить следующий шаг CLI, запустить роль и сдать отчёт. Используй при просьбе продвинуть изменение, запустить sbox или выполнить следующий шаг.
|
|
4
4
|
metadata:
|
|
5
|
-
hosts: [claude]
|
|
5
|
+
hosts: [claude, codex]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# sbox-run
|
|
9
9
|
|
|
10
|
-
Ты оркестратор: не
|
|
10
|
+
Ты оркестратор: роли выполняют задачу, CLI управляет состоянием. Делегируй роли последовательно; не исследуй проект и не меняй продуктовый код или артефакты планирования сам. Исключение для Codex — дословное сохранение ответа роли в resultFile.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
2. Запроси следующий шаг: `sbox next --change <id> --brief --json`. Никогда не запрашивай `next` без `--brief` и не читай packet.json сам: пакет нужен субагенту, а не тебе.
|
|
14
|
-
3. По полю `kind` ответа:
|
|
15
|
-
- `role`: если субагент этой роли уже запускался в этой сессии, продолжи его тем же сообщением через SendMessage (он помнит проект и артефакты, повторное чтение не нужно); иначе запусти нового субагента `sbox-<role>`. Сообщение: `packet: <path из поля packetFile>`. Дождись ответа. Затем сдай отчёт: `sbox report --change <id> --role <role> --json`. Покажи пользователю строку `summary` из ответа дословно и ошибки из `diagnostics`; больше ничего не добавляй. Сообщение субагента не пересказывай и не превращай в выводы: его утверждения проверяет CLI, а решение принимает человек на гейте. Если CLI вернул ошибки (например, не создан артефакт или изменены защищённые файлы), передай их тому же субагенту одним сообщением и повтори отчёт; не больше двух повторов. Повторный отчёт для уже принятого ответа безопасен: CLI вернёт `alreadyApplied: true` без нового запуска.
|
|
16
|
-
- `gate`: покажи пользователю пути артефактов из ответа и список `conflicts` дословно (расхождения между запросом, evidence и proposal с решениями планировщика). Если в ответе есть `questions`, покажи их и попроси ответить: ответы передаются при утверждении командой из поля `answer` (`--answer Q1=<вариант>`). Затем спроси: «Утвердить <gate>? Ответьте «да» или замечанием». «да» → `sbox approve <gate> --change <id> --by <user>`; замечание → `sbox reject <gate> --change <id> --comment "<текст>"`. Мелкие правки формулировок пользователь может внести в артефакт сам и ответить «да»: отклонение запускает цикл доработки роли. Затем вернись к шагу 2.
|
|
17
|
-
- `deliver`: покажи чеклист `sbox deliver --change <id> --check` и предложи доставку `sbox deliver --change <id>` (архив, коммит, push, пул-реквест). Не запускай доставку без просьбы пользователя.
|
|
18
|
-
- `wait`: покажи статус и блокер, спроси пользователя, что делать.
|
|
19
|
-
- `done`: сообщи об окончании.
|
|
20
|
-
4. Повторяй шаги 2–3, пока не встретишь gate, wait, deliver или done. Не запускай субагентов параллельно.
|
|
12
|
+
## Подготовка
|
|
21
13
|
|
|
22
|
-
|
|
14
|
+
Определи текущий хост: Claude Code → `claude`, Codex → `codex`. Не выбирай хост по runner.default: эта настройка относится к headless. Определи изменение из запроса или `sbox change list --json`; уточни только если выбор неоднозначен.
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
Запроси `sbox next --change <id> --runner <хост> --brief --json`. Не читай packet.json: передай путь роли. Модель и effort берутся из `execution`; после изменения конфига обнови материалы через `sbox host install --target <хост>` и перезапусти сессию, если хост не подхватил их.
|
|
17
|
+
|
|
18
|
+
## Запуск роли
|
|
19
|
+
|
|
20
|
+
Для `kind: role` используй имя из `execution.agent` и сообщение `packet: <packetFile>`. Каждый запуск должен прочитать свежий пакет. Ключ повторного использования субагента: изменение + runner + agent + model + effort. Не продолжай агента другого изменения или с устаревшими настройками.
|
|
21
|
+
|
|
22
|
+
- **Claude Code:** запусти установленного агента через Agent; повторный запуск — через SendMessage. Агент пишет resultFile и возвращает его путь.
|
|
23
|
+
- **Codex:** запусти пользовательского агента по имени через доступный механизм субагентов (agent_type, если он поддерживается). Не подменяй его встроенным worker с унаследованной моделью. Если доступно продолжение завершённого агента — продолжи его, иначе создай нового с тем же типом. Агент возвращает полный Markdown и блок sbox-result в последнем сообщении. Сохрани ответ дословно в resultFile из brief: используй инструмент записи или безопасную передачу данных, без интерполяции ответа в shell-команду. Роли с read-only песочницей не должны запрашивать запись ради отчёта.
|
|
24
|
+
|
|
25
|
+
Дождись завершения роли. Не создавай отдельные пользовательские задачи вместо субагентов. Промежуточный статус, обрыв или пересказ ответа не являются отчётом.
|
|
26
|
+
|
|
27
|
+
Если текущий клиент Codex не позволяет выбрать установленного пользовательского агента, используй **headless-путь**: `sbox run --runner codex --change <id> --max-runs 1 --json`. Он сам запускает роль с нужными настройками и принимает ответ; повторно report не вызывай. Дождись завершения, покажи итог, снова запроси next. При ошибке запуска, недоступной модели или CLI остановись и покажи диагностику; не заменяй модель молча. Если результат остался в ожидании/ошибке, не запускай бесконечные повторы.
|
|
28
|
+
|
|
29
|
+
## Приём результата
|
|
30
|
+
|
|
31
|
+
После нативного субагента выполни `sbox report --change <id> --role <role> --runner <хост> --json`. Показанные в execution настройки — запрошенные, не доказательство фактического запуска: не заполняй --model/--session предположениями.
|
|
32
|
+
|
|
33
|
+
Покажи строку summary дословно и диагностики. Если отчёт отклонён, снова запроси next для свежих packetFile/resultFile и передай ошибки роли; максимум две попытки исправления, затем остановись с диагностикой. Не продолжай роль, если CLI уже принял блокер и назначил другой следующий шаг. Повторная сдача принятого ответа безопасна: alreadyApplied не создаёт новый запуск.
|
|
34
|
+
|
|
35
|
+
Повторяй next после принятых отчётов до gate, wait, deliver или done.
|
|
36
|
+
|
|
37
|
+
## Остальные шаги
|
|
38
|
+
|
|
39
|
+
- **gate:** покажи пути артефактов, conflicts и questions из CLI. Получи решение человека. «Да» → команда approve из ответа; замечания → reject с текстом. Ответы на вопросы передай через --answer. После решения снова next. Не утверждай гейт самостоятельно.
|
|
40
|
+
- **deliver:** покажи `sbox deliver --change <id> --check`. Запускай доставку только по просьбе пользователя; это архивирование, коммит, push и пул-реквест.
|
|
41
|
+
- **wait:** покажи статус и блокер, остановись. Продолжение выполняется через `sbox change resume` после разрешения причины; при parked нужен новый бюджет --returns.
|
|
42
|
+
- **done:** сообщи о завершении.
|
|
43
|
+
|
|
44
|
+
При просьбе остановить активный headless-запуск используй `sbox stop --change <id>`. При нативном запуске останови также субагента средствами хоста; не сдавай его незавершённый ответ. После утраты контекста восстанови состояние через CLI, а не по памяти о последнем сообщении.
|
|
@@ -3,6 +3,9 @@ name: sbox-wiki
|
|
|
3
3
|
description: Поиск и ведение локальной Markdown-wiki проекта через sbox-wiki. Используй для поиска знаний об области кода, чтения и обновления страниц wiki и проверки ссылок между ними.
|
|
4
4
|
metadata:
|
|
5
5
|
roles: [researcher, planner, tester, implementer, verifier, reviewer, challenger, distiller]
|
|
6
|
+
commands:
|
|
7
|
+
- sbox-wiki search "<задача>" --path <src/module> --json
|
|
8
|
+
- sbox-wiki get <id> --json
|
|
6
9
|
---
|
|
7
10
|
|
|
8
11
|
# sbox-wiki
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import { resolveModel, MODEL_PROFILES, claudeAgentName } from '../../../core/model-policy.js';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { loadRoleDescription, loadRoleText } from '../../../core/roles.js';
|
|
3
4
|
import { ROLES } from '../../../core/phases.js';
|
|
4
|
-
import {
|
|
5
|
-
import { loadSkills, skillsForRole } from '../../../core/skills.js';
|
|
5
|
+
import { READ_ONLY_ROLES } from '../../../core/runner.js';
|
|
6
6
|
import { assetsDir, readText, writeText } from '../../../core/paths.js';
|
|
7
7
|
import { configSchema } from '../../../core/config.js';
|
|
8
8
|
const AGENT_ROLES = ['researcher', 'planner', 'tester', 'implementer', 'reviewer', 'verifier', 'challenger'];
|
|
9
9
|
/**
|
|
10
|
-
* Агенты Claude Code
|
|
11
|
-
* описание из фронтматтера файла роли, инструменты из runner.claude конфига (как в headless-режиме)
|
|
12
|
-
*
|
|
10
|
+
* Агенты Claude Code: базовое имя роли и варианты для каждого профиля. Текст агента это шаблон assets/hosts/claude/agent.md с данными роли:
|
|
11
|
+
* описание из фронтматтера файла роли, инструменты из runner.claude конфига (как в headless-режиме).
|
|
12
|
+
* Скиллы в агентов не предзагружаются: роль видит инструменты в указателе tools пакета и читает руководство через help.
|
|
13
13
|
*/
|
|
14
|
-
export function installClaudeAgents(root, config
|
|
14
|
+
export function installClaudeAgents(root, config) {
|
|
15
15
|
const written = [];
|
|
16
16
|
const cfg = config ?? configSchema.parse({ version: 1, spec: { adapter: 'spec-box' } });
|
|
17
17
|
const template = readText(path.join(assetsDir(), 'hosts', 'claude', 'agent.md'));
|
|
@@ -19,34 +19,26 @@ export function installClaudeAgents(root, config, skills = loadSkills(root)) {
|
|
|
19
19
|
if (!AGENT_ROLES.includes(role))
|
|
20
20
|
continue;
|
|
21
21
|
const file = path.join(root, '.claude', 'agents', `sbox-${role}.md`);
|
|
22
|
-
writeText(file, agentFile(template, root, role, cfg
|
|
22
|
+
writeText(file, agentFile(template, root, role, cfg));
|
|
23
23
|
written.push(file);
|
|
24
|
+
for (const profile of MODEL_PROFILES) {
|
|
25
|
+
const variant = path.join(root, '.claude', 'agents', `${claudeAgentName(role, profile)}.md`);
|
|
26
|
+
writeText(variant, agentFile(template, root, role, cfg, profile));
|
|
27
|
+
written.push(variant);
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
30
|
return written;
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (!configured)
|
|
30
|
-
return null;
|
|
31
|
-
const v = configured.toLowerCase();
|
|
32
|
-
if (v.includes('opus'))
|
|
33
|
-
return 'opus';
|
|
34
|
-
if (v.includes('sonnet'))
|
|
35
|
-
return 'sonnet';
|
|
36
|
-
if (v.includes('haiku'))
|
|
37
|
-
return 'haiku';
|
|
38
|
-
return configured;
|
|
39
|
-
}
|
|
40
|
-
function agentFile(template, root, role, config, skills) {
|
|
32
|
+
function agentFile(template, root, role, config, profile) {
|
|
33
|
+
const execution = resolveModel(config, 'claude', role, undefined, profile);
|
|
41
34
|
const tools = (READ_ONLY_ROLES.has(role) ? config.runner.claude.readOnlyTools : config.runner.claude.allowedTools).join(', ');
|
|
42
35
|
const values = {
|
|
43
36
|
role,
|
|
37
|
+
name: profile ? claudeAgentName(role, profile) : `sbox-${role}`,
|
|
44
38
|
description: JSON.stringify(loadRoleDescription(root, role)),
|
|
45
39
|
tools,
|
|
46
|
-
model:
|
|
47
|
-
|
|
48
|
-
effort: config.runner.efforts[role] ?? config.runner.defaultEffort,
|
|
49
|
-
skills: skills.length ? `skills:\n${skills.map((s) => ` - ${s}`).join('\n')}\n` : '',
|
|
40
|
+
model: JSON.stringify(execution.model),
|
|
41
|
+
effort: execution.effort,
|
|
50
42
|
body: loadRoleText(root, role).trim(),
|
|
51
43
|
};
|
|
52
44
|
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/host/claude/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,KAAK,EAAa,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/host/claude/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { configSchema } from '../../../core/config.js';
|
|
4
|
+
import { SboxError } from '../../../core/errors.js';
|
|
5
|
+
import { MODEL_PROFILES, resolveModel, hostAgentName } from '../../../core/model-policy.js';
|
|
6
|
+
import { assetsDir, exists, readText } from '../../../core/paths.js';
|
|
7
|
+
import { ROLES } from '../../../core/phases.js';
|
|
8
|
+
import { loadRoleDescription, loadRoleText } from '../../../core/roles.js';
|
|
9
|
+
import { READ_ONLY_ROLES } from '../../../core/runner.js';
|
|
10
|
+
const START = '<!-- sbox:begin -->';
|
|
11
|
+
const END = '<!-- sbox:end -->';
|
|
12
|
+
const GENERATED = '# Generated by @spec-box/sdd; run sbox host install --target codex';
|
|
13
|
+
// JSON basic strings are TOML-compatible except form feed and literal DEL.
|
|
14
|
+
export const tomlString = (s) => JSON.stringify(s).replace(/\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})/g, escape => escape === '\\f' ? '\\u000c' : escape).replace(/\x7f/g, '\\u007f');
|
|
15
|
+
export function updateAgentsSection(text, body) {
|
|
16
|
+
const starts = text.split(START).length - 1;
|
|
17
|
+
const ends = text.split(END).length - 1;
|
|
18
|
+
const section = `${START}\n${body.trim()}\n${END}`;
|
|
19
|
+
if (!starts && !ends)
|
|
20
|
+
return `${text}${text && !text.endsWith('\n') ? '\n' : ''}${text ? '\n' : ''}${section}\n`;
|
|
21
|
+
if (starts !== 1 || ends !== 1 || text.indexOf(END) < text.indexOf(START)) {
|
|
22
|
+
throw new SboxError('HOST_SECTION_INVALID', 'Повреждён раздел sbox в AGENTS.md: нужны ровно одна пара sbox:begin / sbox:end.');
|
|
23
|
+
}
|
|
24
|
+
return text.slice(0, text.indexOf(START)) + section + text.slice(text.indexOf(END) + END.length);
|
|
25
|
+
}
|
|
26
|
+
/** Build all output before writing, preserving user config and unrelated AGENTS.md content. Skills are not preloaded into agents: roles read tool guides via help. */
|
|
27
|
+
export function codexMaterials(root, config) {
|
|
28
|
+
const cfg = config ?? configSchema.parse({ version: 1, spec: { adapter: 'spec-box' } });
|
|
29
|
+
const template = readText(path.join(assetsDir(), 'hosts', 'codex', 'agent.md'));
|
|
30
|
+
const files = new Map();
|
|
31
|
+
for (const role of ROLES.filter(r => r !== 'distiller')) {
|
|
32
|
+
const values = { role, body: loadRoleText(root, role).trim() };
|
|
33
|
+
const instructions = template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
|
|
34
|
+
for (const profile of [undefined, ...MODEL_PROFILES]) {
|
|
35
|
+
const execution = resolveModel(cfg, 'codex', role, undefined, profile);
|
|
36
|
+
const name = profile ? hostAgentName(role, profile) : `sbox-${role}`;
|
|
37
|
+
const file = path.join(root, '.codex', 'agents', `${name}.toml`);
|
|
38
|
+
if (exists(file) && !readText(file).startsWith(GENERATED)) {
|
|
39
|
+
throw new SboxError('HOST_AGENT_CONFLICT', `Файл ${file} не создан sbox; переименуйте его перед установкой.`);
|
|
40
|
+
}
|
|
41
|
+
files.set(file, `${GENERATED}\n` + Object.entries({
|
|
42
|
+
name, description: loadRoleDescription(root, role), model: execution.model,
|
|
43
|
+
model_reasoning_effort: execution.effort,
|
|
44
|
+
sandbox_mode: READ_ONLY_ROLES.has(role) ? cfg.runner.codex.sandboxRead : cfg.runner.codex.sandboxWrite,
|
|
45
|
+
developer_instructions: instructions,
|
|
46
|
+
}).map(([key, value]) => `${key} = ${tomlString(value)}`).join('\n') + '\n');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const agentsFile = path.join(root, 'AGENTS.md');
|
|
50
|
+
if (fs.existsSync(agentsFile) && fs.lstatSync(agentsFile).isSymbolicLink()) {
|
|
51
|
+
throw new SboxError('HOST_SECTION_SYMLINK', 'AGENTS.md является ссылкой; sbox не изменяет её целевой файл.');
|
|
52
|
+
}
|
|
53
|
+
files.set(agentsFile, updateAgentsSection(exists(agentsFile) ? readText(agentsFile) : '', readText(path.join(assetsDir(), 'hosts', 'codex', 'AGENTS.md'))));
|
|
54
|
+
return files;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/host/codex/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { codexMaterials } from './codex/index.js';
|
|
2
|
+
import { writeText } from '../../core/paths.js';
|
|
1
3
|
import { SboxError } from '../../core/errors.js';
|
|
2
4
|
import { loadSkills } from '../../core/skills.js';
|
|
3
5
|
import { installClaudeAgents } from './claude/index.js';
|
|
@@ -7,17 +9,22 @@ export function installHostMaterials(root, target, config) {
|
|
|
7
9
|
if (!isHostTarget(target))
|
|
8
10
|
throw new SboxError('HOST_UNKNOWN', `Неизвестный хост ${target}; доступны ${HOST_TARGETS.join(' и ')}.`);
|
|
9
11
|
const skills = loadSkills(root);
|
|
12
|
+
const codex = target === 'codex' ? codexMaterials(root, config) : new Map();
|
|
10
13
|
const files = installSkills(root, target, skills);
|
|
11
14
|
const notes = [];
|
|
12
15
|
let next;
|
|
13
16
|
switch (target) {
|
|
14
17
|
case 'claude':
|
|
15
|
-
files.push(...installClaudeAgents(root, config
|
|
18
|
+
files.push(...installClaudeAgents(root, config));
|
|
16
19
|
next = 'В Claude Code: `/sbox-run` после `sbox change new <id> --title "..." --request "..."`.';
|
|
17
20
|
break;
|
|
18
21
|
case 'codex':
|
|
19
|
-
|
|
20
|
-
|
|
22
|
+
for (const [file, text] of codex) {
|
|
23
|
+
writeText(file, text);
|
|
24
|
+
files.push(file);
|
|
25
|
+
}
|
|
26
|
+
notes.push('Перезапустите сессию Codex, чтобы загрузить новые агенты. Проектные материалы должны быть доверенными в Codex.');
|
|
27
|
+
next = 'В Codex: `$sbox-run` после `sbox change new <id> --title "..." --request "..."`. Headless: `sbox run --runner codex --change <id>`.';
|
|
21
28
|
break;
|
|
22
29
|
}
|
|
23
30
|
return { target, files, notes, next };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/host/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAUzF,8GAA8G;AAC9G,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,MAAc,EAAE,MAAe;IAChF,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,oBAAoB,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpI,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAY,CAAC;IACjB,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,IAAI,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/host/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAUzF,8GAA8G;AAC9G,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,MAAc,EAAE,MAAe;IAChF,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,SAAS,CAAC,cAAc,EAAE,oBAAoB,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpI,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAkB,CAAC;IAC5F,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAY,CAAC;IACjB,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YACjD,IAAI,GAAG,wFAAwF,CAAC;YAChG,MAAM;QACR,KAAK,OAAO;YACV,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;gBAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;YAC9E,KAAK,CAAC,IAAI,CAAC,gHAAgH,CAAC,CAAC;YAC7H,IAAI,GAAG,qIAAqI,CAAC;YAC7I,MAAM;IACV,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { execFileSync, spawn } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { SboxError } from '../../core/errors.js';
|
|
5
|
-
import { assetsDir } from '../../core/paths.js';
|
|
5
|
+
import { assetsDir, readText } from '../../core/paths.js';
|
|
6
6
|
import { jsonAnswerToMarkdown } from '../../core/result.js';
|
|
7
7
|
import { registerRunner } from '../../core/runner.js';
|
|
8
8
|
const REQUIRED_FLAGS = ['--output-schema', '--output-last-message', '--json', '--cd', '--model'];
|
|
@@ -16,7 +16,7 @@ export class CodexRunner {
|
|
|
16
16
|
executable;
|
|
17
17
|
options;
|
|
18
18
|
name = 'codex';
|
|
19
|
-
supportsResume
|
|
19
|
+
get supportsResume() { return this.probe().resume; }
|
|
20
20
|
capabilities = null;
|
|
21
21
|
constructor(executable, options) {
|
|
22
22
|
this.executable = executable;
|
|
@@ -35,7 +35,13 @@ export class CodexRunner {
|
|
|
35
35
|
throw new SboxError('CODEX_UNAVAILABLE', `Не удалось запустить ${this.executable}: ${e.message}`, 'Установите Codex CLI или укажите runner.codex.executable.');
|
|
36
36
|
}
|
|
37
37
|
const missing = REQUIRED_FLAGS.filter((f) => !help.includes(f));
|
|
38
|
-
|
|
38
|
+
let resume = false;
|
|
39
|
+
try {
|
|
40
|
+
const resumeHelp = execFileSync(this.executable, ['exec', 'resume', '--help'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
41
|
+
resume = ['--output-schema', '--output-last-message', '--json', '--model', '--config'].every(flag => resumeHelp.includes(flag));
|
|
42
|
+
}
|
|
43
|
+
catch { /* Older clients can still start fresh sessions. */ }
|
|
44
|
+
this.capabilities = { ok: missing.length === 0, missing, version, resume };
|
|
39
45
|
return this.capabilities;
|
|
40
46
|
}
|
|
41
47
|
async run(req) {
|
|
@@ -49,7 +55,7 @@ export class CodexRunner {
|
|
|
49
55
|
const schema = path.join(assetsDir(), 'schema', 'sbox-answer.schema.json');
|
|
50
56
|
const args = [
|
|
51
57
|
'exec',
|
|
52
|
-
'--cd', req.cwd,
|
|
58
|
+
...(req.resumeSession && caps.resume ? ['resume'] : ['--cd', req.cwd]),
|
|
53
59
|
'--model', req.model,
|
|
54
60
|
'--skip-git-repo-check',
|
|
55
61
|
'--json',
|
|
@@ -57,12 +63,13 @@ export class CodexRunner {
|
|
|
57
63
|
'--output-last-message', lastMessage,
|
|
58
64
|
'-c', `model_reasoning_effort="${req.effort ?? 'medium'}"`,
|
|
59
65
|
'-c', 'agents.enabled=false',
|
|
60
|
-
'
|
|
66
|
+
'-c', `sandbox_mode=${JSON.stringify(req.readOnly ? this.options.sandboxRead : this.options.sandboxWrite)}`,
|
|
61
67
|
'-c', `approval_policy="${this.options.approvalPolicy}"`,
|
|
62
68
|
'-c', 'approvals_reviewer="auto_review"',
|
|
63
69
|
...this.options.extraConfig.flatMap((c) => ['-c', c]),
|
|
70
|
+
...(req.resumeSession && caps.resume ? [req.resumeSession, '-'] : ['-']),
|
|
64
71
|
];
|
|
65
|
-
const prompt = `${req.prompt}\n\n
|
|
72
|
+
const prompt = `${req.prompt}\n\n${readText(path.join(assetsDir(), 'hosts', 'codex', 'headless-result.md'))}`;
|
|
66
73
|
const started = new Date().toISOString();
|
|
67
74
|
return new Promise((resolve) => {
|
|
68
75
|
const events = fs.createWriteStream(eventsPath, { flags: 'a' });
|
|
@@ -71,6 +78,16 @@ export class CodexRunner {
|
|
|
71
78
|
let lastProgress = Date.now();
|
|
72
79
|
let finishedBy = null;
|
|
73
80
|
let stderrText = '';
|
|
81
|
+
let eventBuffer = '';
|
|
82
|
+
let session;
|
|
83
|
+
const readEvent = (line) => {
|
|
84
|
+
try {
|
|
85
|
+
const event = JSON.parse(line);
|
|
86
|
+
if (event.type === 'thread.started' && typeof event.thread_id === 'string')
|
|
87
|
+
session = event.thread_id;
|
|
88
|
+
}
|
|
89
|
+
catch { /* Keep non-JSON diagnostics in the raw events log. */ }
|
|
90
|
+
};
|
|
74
91
|
const killGroup = (sig) => {
|
|
75
92
|
try {
|
|
76
93
|
if (child.pid)
|
|
@@ -103,7 +120,9 @@ export class CodexRunner {
|
|
|
103
120
|
events.end();
|
|
104
121
|
stderr.end();
|
|
105
122
|
const finished = new Date().toISOString();
|
|
106
|
-
|
|
123
|
+
if (eventBuffer.trim())
|
|
124
|
+
readEvent(eventBuffer);
|
|
125
|
+
const base = { started, finished, eventsPath, stderrPath, exitCode: code, ...(session ? { session } : {}) };
|
|
107
126
|
if (finishedBy === 'stopped')
|
|
108
127
|
return resolve({ ...base, usable: false, markdown: null, failure: 'stopped', failureMessage: 'остановлено' });
|
|
109
128
|
if (finishedBy === 'timeout')
|
|
@@ -129,6 +148,11 @@ export class CodexRunner {
|
|
|
129
148
|
child.stdout.on('data', (chunk) => {
|
|
130
149
|
lastProgress = Date.now();
|
|
131
150
|
events.write(chunk);
|
|
151
|
+
eventBuffer += chunk.toString();
|
|
152
|
+
const lines = eventBuffer.split('\n');
|
|
153
|
+
eventBuffer = lines.pop();
|
|
154
|
+
for (const line of lines)
|
|
155
|
+
readEvent(line);
|
|
132
156
|
});
|
|
133
157
|
child.stderr.on('data', (chunk) => {
|
|
134
158
|
stderrText += chunk.toString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/adapters/runner/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/adapters/runner/codex.ts"],"names":[],"mappings":"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"}
|