@spec-box/sdd 0.6.4 → 0.7.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.
Files changed (84) hide show
  1. package/README.md +28 -1
  2. package/assets/ci/Dockerfile +2 -0
  3. package/assets/hosts/claude/agent.md +13 -0
  4. package/assets/project/testing.md +4 -0
  5. package/assets/roles/challenger.md +4 -0
  6. package/assets/roles/distiller.md +4 -0
  7. package/assets/roles/implementer.md +4 -0
  8. package/assets/roles/planner.md +4 -0
  9. package/assets/roles/researcher.md +8 -3
  10. package/assets/roles/reviewer.md +4 -0
  11. package/assets/roles/tester.md +5 -1
  12. package/assets/roles/verifier.md +5 -1
  13. package/assets/skills/sbox-approve.md +11 -0
  14. package/assets/skills/sbox-browser.md +31 -0
  15. package/assets/skills/sbox-run.md +24 -0
  16. package/bin/sbox-browser.js +5 -0
  17. package/dist/adapters/host/claude/index.js +27 -85
  18. package/dist/adapters/host/claude/index.js.map +1 -1
  19. package/dist/adapters/host/index.js +25 -0
  20. package/dist/adapters/host/index.js.map +1 -0
  21. package/dist/adapters/host/skills.js +27 -0
  22. package/dist/adapters/host/skills.js.map +1 -0
  23. package/dist/browser/cli.js +488 -0
  24. package/dist/browser/cli.js.map +1 -0
  25. package/dist/browser/client.js +182 -0
  26. package/dist/browser/client.js.map +1 -0
  27. package/dist/browser/commands.js +598 -0
  28. package/dist/browser/commands.js.map +1 -0
  29. package/dist/browser/daemon.js +315 -0
  30. package/dist/browser/daemon.js.map +1 -0
  31. package/dist/browser/executable.js +138 -0
  32. package/dist/browser/executable.js.map +1 -0
  33. package/dist/browser/install.js +49 -0
  34. package/dist/browser/install.js.map +1 -0
  35. package/dist/browser/keys.js +44 -0
  36. package/dist/browser/keys.js.map +1 -0
  37. package/dist/browser/paths.js +34 -0
  38. package/dist/browser/paths.js.map +1 -0
  39. package/dist/browser/protocol.js +34 -0
  40. package/dist/browser/protocol.js.map +1 -0
  41. package/dist/browser/selectors.js +53 -0
  42. package/dist/browser/selectors.js.map +1 -0
  43. package/dist/browser/session.js +128 -0
  44. package/dist/browser/session.js.map +1 -0
  45. package/dist/browser/settings.js +51 -0
  46. package/dist/browser/settings.js.map +1 -0
  47. package/dist/browser/snapshot.js +89 -0
  48. package/dist/browser/snapshot.js.map +1 -0
  49. package/dist/cli/args.js +9 -0
  50. package/dist/cli/args.js.map +1 -0
  51. package/dist/cli/commands/change.js +2 -1
  52. package/dist/cli/commands/change.js.map +1 -1
  53. package/dist/cli/commands/doctor.js +16 -0
  54. package/dist/cli/commands/doctor.js.map +1 -1
  55. package/dist/cli/commands/host.js +4 -6
  56. package/dist/cli/commands/host.js.map +1 -1
  57. package/dist/cli/commands/init.js +9 -7
  58. package/dist/cli/commands/init.js.map +1 -1
  59. package/dist/cli/commands/metrics.js +2 -1
  60. package/dist/cli/commands/metrics.js.map +1 -1
  61. package/dist/cli/commands/run.js +5 -4
  62. package/dist/cli/commands/run.js.map +1 -1
  63. package/dist/cli/main.js +2 -12
  64. package/dist/cli/main.js.map +1 -1
  65. package/dist/cli/output.js +7 -3
  66. package/dist/cli/output.js.map +1 -1
  67. package/dist/core/async.js +15 -0
  68. package/dist/core/async.js.map +1 -0
  69. package/dist/core/config.js +14 -0
  70. package/dist/core/config.js.map +1 -1
  71. package/dist/core/lock.js +2 -1
  72. package/dist/core/lock.js.map +1 -1
  73. package/dist/core/packet.js +1 -0
  74. package/dist/core/packet.js.map +1 -1
  75. package/dist/core/paths.js +14 -0
  76. package/dist/core/paths.js.map +1 -1
  77. package/dist/core/roles.js +16 -5
  78. package/dist/core/roles.js.map +1 -1
  79. package/dist/core/run.js +2 -3
  80. package/dist/core/run.js.map +1 -1
  81. package/dist/core/skills.js +60 -0
  82. package/dist/core/skills.js.map +1 -0
  83. package/docs/design.md +15 -1
  84. package/package.json +11 -5
package/README.md CHANGED
@@ -37,11 +37,14 @@ src/core/ доменная модель, конфиг, состояние
37
37
  пакет для роли, приём отчёта, change-set, headless-цикл run, доставка и текст PR, гейты через PR,
38
38
  отчёты тестов и покрытие, категории документации и doctor, архивация
39
39
  src/adapters/ spec/spec-box, spec/openspec — истина и дельты в двух форматах; runner/claude, runner/codex — среды агентов;
40
- repo/github, repo/local — хостинг репозитория; host/claude — материалы для Claude Code
40
+ repo/github, repo/local — хостинг репозитория; host/skills — раскладки скиллов по хостам, host/claude — агенты Claude Code
41
41
  src/cli/ команды commander: init, doctor, host, change, next, report, approve, reject,
42
42
  status, instructions, validate, spec, archive
43
+ src/browser/ sbox-browser: демон с Chrome на сессию, клиент через локальный сокет, команды страницы,
44
+ снимок дерева доступности со ссылками, поиск и установка браузера, вход человеком, перенос состояния
43
45
  assets/roles/ определения ролей (Markdown): researcher, planner, tester, implementer, reviewer, verifier…
44
46
  assets/schema/ граф артефактов по умолчанию и инструкции к ним
47
+ assets/skills/ скиллы хостов (единый источник): sbox-run, sbox-approve, sbox-browser; копируются в папку хоста при init и host install
45
48
  assets/templates/ шаблоны артефактов изменения
46
49
  assets/project/ шаблоны категорий проектной документации
47
50
  assets/ci/ шаблоны GitHub Actions и Dockerfile
@@ -70,6 +73,28 @@ sbox prompt show project-docs # промпт для заполн
70
73
 
71
74
  Модели и усилие по ролям задаются в `runner.models` и `runner.efforts` (по умолчанию opus только для planner и challenger, effort medium); после правки выполните `sbox host install --target claude`. Среды: `claude` через Claude Agent SDK (нужен `ANTHROPIC_API_KEY` для CI; локально годится вход Claude Code), `codex` через `codex exec` (в конфиге `runner.codex.executable`, например бинарник из ChatGPT.app). Репозиторий: `repo.adapter: github` с токеном в `GITHUB_TOKEN`; `local` только коммитит.
72
75
 
76
+ ## Браузер для проверки интерфейса
77
+
78
+ Отдельный бинарник `sbox-browser` даёт агентам и людям управляемый Chrome: верификатор проверяет затронутую страницу по-настоящему, а не только сборкой, исследователь и тестировщик смотрят текущий интерфейс глазами пользователя. Пакет браузер не скачивает: `puppeteer-core` подключается к тому, что есть, а установка отдельная и необязательная.
79
+
80
+ ```bash
81
+ sbox-browser doctor # какой браузер будет использован и откуда
82
+ sbox-browser install # скачать Chrome for Testing в ~/.sbox/browser/cache (по желанию)
83
+ sbox-browser install --browser chrome-headless-shell # лёгкий вариант только для headless
84
+ sbox-browser login https://app.local --profile app # человек входит в окне; вход остаётся в профиле
85
+ sbox-browser goto https://app.local/orders # первая команда сама поднимает сессию (headless)
86
+ sbox-browser snapshot # дерево элементов со ссылками [eN]
87
+ sbox-browser click e7 # действия по ссылкам или селекторам: css, text=, aria=, xpath=
88
+ sbox-browser fill e3 "кофе" && sbox-browser press Enter
89
+ sbox-browser wait --text "Найдено" && sbox-browser text
90
+ sbox-browser console --errors && sbox-browser requests # ошибки консоли, ответы 4xx/5xx и неудачные запросы
91
+ sbox-browser screenshot # PNG в ~/.sbox/browser/shots, путь печатается
92
+ sbox-browser state save auth.json # перенести вход в CI: там sbox-browser state load auth.json
93
+ sbox-browser stop
94
+ ```
95
+
96
+ Существующий браузер вместо установки: флаг `--executable`, переменная `SBOX_BROWSER_EXECUTABLE` или `browser.executable` в `.sbox/config.yaml`; без них по порядку проверяются кэш инструмента, кэш puppeteer, системный Chrome, Chromium, Edge и Brave. Сессия это фоновый процесс с браузером: команды идут к нему через локальный сокет, поэтому страница, куки, консоль и сетевые ошибки сохраняются между вызовами; `--session <имя>` даёт несколько независимых браузеров, простой 30 минут завершает сессию. Настройки в секции `browser` конфига: `executable`, `headless`, `profile`, `baseUrl`, `cacheDir`, `viewport`, `timeoutMs`, `idleMinutes`; те же значения задаются переменными `SBOX_BROWSER_EXECUTABLE`, `SBOX_BROWSER_HEADLESS`, `SBOX_BROWSER_PROFILE`, `SBOX_BROWSER_BASE_URL`, `SBOX_BROWSER_CACHE_DIR` (каталог инструмента: `SBOX_BROWSER_HOME`) и глобальными флагами `--profile`, `--session`, `--timeout`, `--cwd`. Все команды поддерживают `--json`, ошибки разбора аргументов тоже приходят в JSON-конверте. Профили и файлы состояния содержат секреты входа и живут в `~/.sbox/browser`, вне репозитория. Скилл `sbox-browser` лежит в `assets/skills` и копируется в папку хоста командой `sbox host install --target claude | codex`; агентам researcher, tester и verifier он подключается по `metadata.roles` (в Claude Code полем `skills`).
97
+
73
98
  ## Состояние
74
99
 
75
100
  Готово (этапы 1 и 2): конфиг и раскладка `.sbox/`, жизненный цикл изменения с гейтами, возвратами и бюджетом (`parked`), ревизия и lock `change.yaml`, пакеты и receipt запусков, приём отчётов с проверками (артефакты, дельты, задачи, защищённые тесты, дрейф change-set, disposition и `delivery_narrative` ревьюера), запечатывание change-set после реализации, адаптер spec-box, категории документации и структурный `doctor`, материалы для Claude Code, адаптеры сред Claude и Codex с надзором и одним транспортным повтором, `run`/`stop`/`watch`, адаптер GitHub с идемпотентной доставкой и каналом гейтов через комментарии, отчёты тестов jest/vitest/playwright и покрытие, шаблоны CI и Dockerfile.
@@ -78,4 +103,6 @@ sbox prompt show project-docs # промпт для заполн
78
103
 
79
104
  Готово также: wiki проекта в `.sbox/wiki/` (индекс страниц с `read_when` попадает в пакет каждой роли), метрики `sbox metrics` и оценка `sbox change rate`.
80
105
 
106
+ Готово также: `sbox-browser` для проверки интерфейса (сессии с Chrome через `puppeteer-core`, необязательная установка браузера, вход человеком с постоянным профилем, снимок дерева доступности для агентов, перенос состояния входа), проверка браузера в `sbox doctor`.
107
+
81
108
  Не готово: дискавери и правила (этап 3), Arcadia и Codex-материалы для хоста (этап 4), межрепозиторный протокол (этап 5), роутер и дистилляция wiki (этап 6), продолжение сессий Codex, семантический `doctor --deep`.
@@ -3,6 +3,8 @@ FROM node:22-bookworm-slim
3
3
  RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates && rm -rf /var/lib/apt/lists/*
4
4
  RUN npm install -g pnpm @spec-box/sdd
5
5
  # Codex CLI ставится отдельно, если нужен адаптер codex: npm install -g @openai/codex
6
+ # Проверка интерфейса верификатором: RUN sbox-browser install --browser chrome-headless-shell
7
+ # (в Debian/Ubuntu Chrome требует системные библиотеки: libnss3, libatk-bridge2.0-0, libgbm1, libasound2 и другие)
6
8
  WORKDIR /work
7
9
  ENV SBOX_HOME=/work/.sbox-runs
8
10
  ENTRYPOINT ["sbox"]
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: sbox-{{role}}
3
+ description: {{description}}
4
+ tools: {{tools}}
5
+ model: {{model}}
6
+ effort: {{effort}}
7
+ {{skills}}---
8
+
9
+ Ты выполняешь роль {{role}} инструмента @spec-box/sdd. Во входном сообщении путь к JSON-пакету (`packet`). Прочитай пакет целиком: там цель, допущенные файлы, ограничения, правила проекта, инструкции к артефактам и путь `resultFile`.
10
+
11
+ Порядок работы: прочитай пакет → выполни этапы роли ниже → запиши полный ответ (Markdown и завершающий блок `# sbox-result`) в файл `resultFile` из пакета → в сообщении верни только две строки: путь к resultFile и статус.
12
+
13
+ {{body}}
@@ -17,6 +17,10 @@ verification: needs-review
17
17
  <!-- Узкий прогон одного файла, полный прогон, проверки типов и линтеров. Команды в обратных кавычках, например `pnpm test`.
18
18
  Обязательно опишите дымовой запуск: как поднять приложение или сервис локально (зависимости, порт) и какой URL или команда подтверждает, что оно работает. Верификатор запускает его, когда изменение добавляет модуль, маршрут или сборку. -->
19
19
 
20
+ ## Проверка интерфейса в браузере
21
+
22
+ <!-- Если у продукта есть веб-интерфейс: базовый URL локального запуска (`browser.baseUrl` в .sbox/config.yaml), нужен ли вход и под каким профилем: человек входит один раз командой `sbox-browser login <url> --profile <имя>`, имя профиля укажите здесь и в `browser.profile`. Какие маршруты считать дымовыми для верификатора. Если интерфейса нет — «—». -->
23
+
20
24
  ## Отчёты
21
25
 
22
26
  <!-- Куда пишутся отчёты тестов (jest --json, playwright json) и как их получить в CI. -->
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Аудитор плана @spec-box/sdd. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: challenger (аудитор плана)
2
6
 
3
7
  ## Правила
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Дистиллятор знаний @spec-box/sdd."
3
+ ---
4
+
1
5
  # Роль: distiller (дистиллятор знаний)
2
6
 
3
7
  ## Правила
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Реализатор @spec-box/sdd: выполняет tasks.md, не трогая защищённые тесты. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: implementer (реализатор)
2
6
 
3
7
  ## Правила
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Планировщик @spec-box/sdd: proposal, дельты спецификаций, design, tasks. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: planner (планировщик)
2
6
 
3
7
  ## Правила
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Исследователь @spec-box/sdd: Evidence Pack по изменению. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: researcher (исследователь)
2
6
 
3
7
  ## Правила
@@ -19,8 +23,9 @@
19
23
  2. Определи затронутые capability: `sbox spec list --json`, затем `sbox spec show <code> --json` для каждой релевантной.
20
24
  3. Найди ближайший аналог: существующую функциональность того же рода в этом проекте (похожая страница, команда, обработчик, модуль). Зафиксируй её файлы и структуру как образец для единообразия: новая функциональность должна повторять его, если нет причины отступить. Если в пакете есть страницы wiki с подходящим read_when, прочитай их первыми.
21
25
  Места подключения: выполни `git grep -l -F --untracked -- '<идентификатор аналога>'` и перечисли все файлы вне каталога аналога, где он упоминается. Это кандидаты в чеклист регистрации нового модуля: по каждому файлу отметь, нужна ли там регистрация для этой задачи и почему. Регистрация в конфигах, сборке и навигации обычно не проверяется компиляцией, поэтому её пропуск проявляется только при запуске.
22
- 4. Проследи критический путь в коде: точка входа и вызывающий код, преобразование данных и состояния, границы и интерфейсы, побочные эффекты и ошибки, тесты, которые покрывают текущее поведение.
23
- 5. Запиши Evidence Pack в `evidence/research.md` с разделами:
26
+ 4. Если запрос касается веб-интерфейса и `testing.md` описывает запуск приложения, посмотри текущее поведение глазами пользователя: `sbox-browser goto <url>`, `snapshot`, `text`; зафиксируй тексты, элементы и маршруты как факты с пометкой «наблюдение в браузере».
27
+ 5. Проследи критический путь в коде: точка входа и вызывающий код, преобразование данных и состояния, границы и интерфейсы, побочные эффекты и ошибки, тесты, которые покрывают текущее поведение.
28
+ 6. Запиши Evidence Pack в `evidence/research.md` с разделами:
24
29
  - **Цель и критерий готовности** — нормализованная формулировка запроса;
25
30
  - **Текущее поведение** — как работает сейчас, с путями;
26
31
  - **Затронутые capability** — идентификаторы и требования, которые изменятся;
@@ -30,7 +35,7 @@
30
35
  - **Ограничения и паттерны** — правила проекта и решения, которые нужно сохранить;
31
36
  - **Поверхности изменения и проверки** — где вероятно править и чем проверять, без выбора дизайна;
32
37
  - **Допущения и пробелы** — что не удалось подтвердить.
33
- 6. Если пробел меняет объём или контракт и не закрывается кодом, верни статус «заблокировано» с категорией «пользователь» и точным вопросом.
38
+ 7. Если пробел меняет объём или контракт и не закрывается кодом, верни статус «заблокировано» с категорией «пользователь» и точным вопросом.
34
39
 
35
40
  ## Бюджет
36
41
 
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Ревьюер @spec-box/sdd: тесты против спецификаций, код против артефактов. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: reviewer (ревьюер)
2
6
 
3
7
  ## Правила
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Тестировщик @spec-box/sdd: тесты по сценариям до реализации. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: tester (тестировщик)
2
6
 
3
7
  ## Правила
@@ -15,7 +19,7 @@
15
19
 
16
20
  ## Этапы
17
21
 
18
- 1. Прочитай дельты, `design.md` и `testing.md`. Составь список всех утверждений из секций added и modified.
22
+ 1. Прочитай дельты, `design.md` и `testing.md`. Составь список всех утверждений из секций added и modified. Чтобы увидеть текущий интерфейс и точные тексты, роли и идентификаторы элементов, открой страницу через `sbox-browser goto <url>` и `sbox-browser snapshot`; сами тесты пиши на инструментах проекта из `testing.md`, а не на `sbox-browser`.
19
23
  2. Для каждого утверждения выбери уровень по `testing.md` и напиши тест. Если утверждение нельзя автоматизировать, зафиксируй причину.
20
24
  3. Заполни `coverage.yaml` по инструкции `sbox instructions coverage --change <id> --json`.
21
25
  4. Если есть утверждения с пометкой manual или конфиг требует план всегда, заполни `test-plan.md`.
@@ -1,3 +1,7 @@
1
+ ---
2
+ description: "Верификатор @spec-box/sdd: полнота, корректность, согласованность. Вызывается только скиллом sbox-run."
3
+ ---
4
+
1
5
  # Роль: verifier (верификатор)
2
6
 
3
7
  ## Правила
@@ -18,7 +22,7 @@
18
22
  2. **Полнота.** Все задачи `tasks.md` отмечены (`sbox status --json`). Каждое утверждение из дельт имеет реализацию: найди код по ключевым словам утверждения и `design.md`.
19
23
  3. **Корректность.** Запусти тесты из `coverage.yaml` и полные проверки из `testing.md` (тесты, типы, линтеры); прочитай отчёты. Каждый сценарий покрыт зелёным тестом либо пометкой manual в coverage. Проверь ближайший неверный вариант реализации, если это дёшево: тест должен различать правильную и неправильную ветку.
20
24
  4. **Согласованность.** Решения из `design.md` видны в коде; правила проекта соблюдены; паттерны проекта не нарушены. Если в пакете есть `wiring` (образец объявлен в `design.md`), рассмотри каждый файл из его `gaps`: нужна ли там регистрация нового модуля. Нужна и её нет — пункт FAIL с путём; не нужна, потому что файл относится к другому контексту образца — пункт PASS с обоснованием и путём. Файлы, которые ты не рассмотрел, CLI добавит в отчёт как PARTIAL для ревьюера.
21
- 5. **Запуск.** Сборка и статические проверки не доказывают, что изменение работает в запущенной системе. Если `testing.md` описывает, как запустить приложение или сервис (команда запуска, порт, зависимости вроде базы в контейнере), запусти его и проверь доступность затронутого маршрута или страницы (`curl`, код ответа, ключевые строки ответа), затем останови процесс. Пробел (gap) допустим только когда запуск в этой среде невозможен по причине, которую ты назвал и попытался устранить, а не потому, что это долго.
25
+ 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) допустим только когда запуск в этой среде невозможен по причине, которую ты назвал и попытался устранить, а не потому, что это долго.
22
26
  6. Составь отчёт:
23
27
 
24
28
  ```markdown
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: sbox-approve
3
+ description: Утвердить или отклонить гейт изменения @spec-box/sdd (proposal, plan, tests). Используй, когда пользователь говорит «утверждаю», «одобряю план», «отклоняю с замечанием».
4
+ ---
5
+
6
+ # sbox-approve
7
+
8
+ 1. Определи изменение и гейт: `sbox status --change <id> --json` показывает ожидающий гейт.
9
+ 2. Утверждение: `sbox approve <gate> --change <id> --by <user> [--comment "..."] [--answer Q1=B]`.
10
+ 3. Отклонение: `sbox reject <gate> --change <id> --by <user> --comment "<замечание>"`.
11
+ 4. Покажи результат и предложи продолжить скиллом sbox-run.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: sbox-browser
3
+ description: Проверка веб-интерфейса через управляемый Chrome командой sbox-browser — открыть страницу, снять дерево элементов, кликать и вводить, читать текст, консоль и сетевые ошибки, делать скриншоты; вход в приложение выполняет человек. Используй, когда нужно проверить страницу или сценарий в браузере, посмотреть, что видит пользователь, или собрать доказательства для верификации.
4
+ metadata:
5
+ roles: [researcher, tester, verifier]
6
+ ---
7
+
8
+ # sbox-browser
9
+
10
+ Управляемый Chrome для проверки интерфейса. Первая команда сама поднимает сессию (headless), она живёт между вызовами: страница, куки, консоль и сетевые ошибки сохраняются. Все команды поддерживают `--json`; ошибки приходят с кодами `BROWSER_*` и подсказкой, что делать.
11
+
12
+ ## Порядок работы
13
+
14
+ 1. Один раз `sbox-browser doctor`: какой браузер и профиль будут использованы. Браузера нет → предложи человеку `sbox-browser install` или путь в `browser.executable` конфига; сам не устанавливай без просьбы.
15
+ 2. `sbox-browser goto <url>`; относительный путь считается от `browser.baseUrl`.
16
+ 3. `sbox-browser snapshot` даёт дерево элементов со ссылками `[eN]`. Действуй по ним: `click e3`, `fill e5 "текст"`, `press Enter`, `select e7 значение`, `check e2`. После изменения страницы снимай snapshot заново: ссылки нумеруются при каждом снимке, старая ссылка даёт `BROWSER_REF_STALE`.
17
+ 4. Проверяй результат: `wait --text "…"` или `wait --url '*/orders*'`, затем `text`, `exists`, `value`.
18
+ 5. Собирай доказательства: `console --errors`, `requests` (ответы 4xx/5xx и неудачные запросы), `screenshot` (путь к PNG печатается). Ошибки консоли и ответы 4xx/5xx на проверяемой странице это дефект, а не примечание.
19
+ 6. В конце `sbox-browser stop`, если сессия больше не нужна; иначе она завершится по простою.
20
+
21
+ ## Селекторы
22
+
23
+ CSS по умолчанию; `text=Войти`, `aria=Сохранить`, `xpath=//button`. Предпочитай ссылки `[eN]` из снимка: они не зависят от вёрстки.
24
+
25
+ ## Вход в приложение
26
+
27
+ Пароли, коды и токены не вводи и не спрашивай. Если страница требует входа, попроси человека выполнить `sbox-browser login <url> --profile <имя>`: откроется окно браузера, он войдёт сам и нажмёт Enter в терминале, затем `sbox-browser stop`. После этого команды с глобальным флагом `--profile <имя>` перед командой (`sbox-browser --profile <имя> goto <url>`) или с `browser.profile` в конфиге работают под входом без окна. В CI вход переносится файлом: `sbox-browser state load auth.json` из секрета.
28
+
29
+ ## Полезное
30
+
31
+ `status`, `sessions`, `--session <имя>` для второго браузера; `pages`, `page new | switch | close`; `back`, `reload`; `html`, `attr`, `count`, `eval "<js>"`; `cookies list | set | clear`; `dialog accept | dismiss`; `viewport 375x812` для мобильной ширины; глобальный `--timeout <мс>` для медленных страниц. Полная справка: `sbox-browser --help`.
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: sbox-run
3
+ description: Выполнить следующий шаг изменения @spec-box/sdd — запросить пакет у CLI, выполнить роль субагентом и сдать отчёт. Используй, когда пользователь просит продвинуть изменение, запустить sbox, выполнить следующий шаг.
4
+ metadata:
5
+ hosts: [claude]
6
+ ---
7
+
8
+ # sbox-run
9
+
10
+ Ты оркестратор: не исследуешь проект и не решаешь задачу сам. Роли выполняют субагенты `sbox-<role>`.
11
+
12
+ 1. Определи изменение: из аргумента, из контекста или `sbox change list --json`. Если активных изменений несколько и не ясно, какое брать, спроси пользователя.
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`. Ответ `report` уже содержит статус и диагностику: не читай result.md и evidence целиком, покажи пользователю только строку статуса и ошибки. Если CLI вернул ошибки (например, не создан артефакт или изменены защищённые файлы), передай их тому же субагенту одним сообщением и повтори отчёт; не больше двух повторов.
16
+ - `gate`: покажи пользователю пути артефактов из ответа и спроси: «Утвердить <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. Не запускай субагентов параллельно.
21
+
22
+ Полезные команды: `sbox status --change <id>` (состояние, change-set, привязка ревью), `sbox changeset show` (запечатанный диф и дрейф), `sbox coverage --report jest=<path>` (покрытие утверждений тестами), `sbox change resume --returns N` (продолжить после parked).
23
+
24
+ Экономия контекста: не читай артефакты изменения (design.md, спецификации, отчёты) целиком; тебе нужны только ответы CLI. Запрещено: переформулировать задачу пользователя, редактировать артефакты, вызывать роли напрямую в обход пакета, менять код.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/browser/cli.js').then((m) => m.main(process.argv)).catch((err) => {
3
+ console.error(err instanceof Error ? err.message : String(err));
4
+ process.exit(1);
5
+ });
@@ -1,43 +1,25 @@
1
1
  import path from 'node:path';
2
- import { loadRoleText } from '../../../core/roles.js';
2
+ import { loadRoleDescription, loadRoleText } from '../../../core/roles.js';
3
3
  import { ROLES } from '../../../core/phases.js';
4
- import { defaultHostModel } from '../../../core/runner.js';
5
- import { writeText } from '../../../core/paths.js';
4
+ import { defaultHostModel, READ_ONLY_ROLES } from '../../../core/runner.js';
5
+ import { loadSkills, skillsForRole } from '../../../core/skills.js';
6
+ import { assetsDir, readText, writeText } from '../../../core/paths.js';
7
+ import { configSchema } from '../../../core/config.js';
6
8
  const AGENT_ROLES = ['researcher', 'planner', 'tester', 'implementer', 'reviewer', 'verifier', 'challenger'];
7
- const TOOLS = {
8
- researcher: 'Read, Grep, Glob, Bash',
9
- planner: 'Read, Write, Edit, Grep, Glob, Bash',
10
- challenger: 'Read, Grep, Glob, Bash',
11
- tester: 'Read, Write, Edit, Grep, Glob, Bash',
12
- implementer: 'Read, Write, Edit, Grep, Glob, Bash',
13
- reviewer: 'Read, Grep, Glob, Bash',
14
- verifier: 'Read, Grep, Glob, Bash',
15
- distiller: 'Read, Write, Edit, Grep, Glob',
16
- };
17
- const DESCRIPTIONS = {
18
- researcher: 'Исследователь @spec-box/sdd: Evidence Pack по изменению. Вызывается только скиллом sbox-run.',
19
- planner: 'Планировщик @spec-box/sdd: proposal, дельты спецификаций, design, tasks. Вызывается только скиллом sbox-run.',
20
- challenger: 'Аудитор плана @spec-box/sdd. Вызывается только скиллом sbox-run.',
21
- tester: 'Тестировщик @spec-box/sdd: тесты по сценариям до реализации. Вызывается только скиллом sbox-run.',
22
- implementer: 'Реализатор @spec-box/sdd: выполняет tasks.md, не трогая защищённые тесты. Вызывается только скиллом sbox-run.',
23
- reviewer: 'Ревьюер @spec-box/sdd: тесты против спецификаций, код против артефактов. Вызывается только скиллом sbox-run.',
24
- verifier: 'Верификатор @spec-box/sdd: полнота, корректность, согласованность. Вызывается только скиллом sbox-run.',
25
- distiller: 'Дистиллятор знаний @spec-box/sdd.',
26
- };
27
- /** Материалы для Claude Code: тонкий скилл-оркестратор и по агенту на роль (docs/design.md, раздел 11). */
28
- export function installClaudeMaterials(root, config) {
9
+ /**
10
+ * Агенты Claude Code по одному на роль. Текст агента это шаблон assets/hosts/claude/agent.md с данными роли:
11
+ * описание из фронтматтера файла роли, инструменты из runner.claude конфига (как в headless-режиме),
12
+ * скиллы из metadata.roles полем skills (субагенты не видят скиллы проекта сами).
13
+ */
14
+ export function installClaudeAgents(root, config, skills = loadSkills(root)) {
29
15
  const written = [];
30
- const skill = path.join(root, '.claude', 'skills', 'sbox-run', 'SKILL.md');
31
- writeText(skill, RUN_SKILL);
32
- written.push(skill);
33
- const approve = path.join(root, '.claude', 'skills', 'sbox-approve', 'SKILL.md');
34
- writeText(approve, APPROVE_SKILL);
35
- written.push(approve);
16
+ const cfg = config ?? configSchema.parse({ version: 1, spec: { adapter: 'spec-box' } });
17
+ const template = readText(path.join(assetsDir(), 'hosts', 'claude', 'agent.md'));
36
18
  for (const role of ROLES) {
37
19
  if (!AGENT_ROLES.includes(role))
38
20
  continue;
39
21
  const file = path.join(root, '.claude', 'agents', `sbox-${role}.md`);
40
- writeText(file, agentFile(root, role, config?.runner.models[role], config?.runner.efforts[role] ?? config?.runner.defaultEffort ?? 'medium'));
22
+ writeText(file, agentFile(template, root, role, cfg, skillsForRole(skills, role)));
41
23
  written.push(file);
42
24
  }
43
25
  return written;
@@ -55,58 +37,18 @@ function agentModel(configured) {
55
37
  return 'haiku';
56
38
  return configured;
57
39
  }
58
- function agentFile(root, role, configuredModel, effort = 'medium') {
59
- const body = loadRoleText(root, role);
60
- const model = agentModel(configuredModel) ?? defaultHostModel(role);
61
- // Без явного effort субагент наследует усилие сессии (в пилоте это был xhigh на каждом ходе).
62
- return `---
63
- name: sbox-${role}
64
- description: ${DESCRIPTIONS[role]}
65
- tools: ${TOOLS[role]}
66
- model: ${model}
67
- effort: ${effort}
68
- ---
69
-
70
- Ты выполняешь роль ${role} инструмента @spec-box/sdd. Во входном сообщении путь к JSON-пакету (\`packet\`). Прочитай пакет целиком: там цель, допущенные файлы, ограничения, правила проекта, инструкции к артефактам и путь \`resultFile\`.
71
-
72
- Порядок работы: прочитай пакет → выполни этапы роли ниже → запиши полный ответ (Markdown и завершающий блок \`# sbox-result\`) в файл \`resultFile\` из пакета → в сообщении верни только две строки: путь к resultFile и статус.
73
-
74
- ${body.trim()}
75
- `;
40
+ function agentFile(template, root, role, config, skills) {
41
+ const tools = (READ_ONLY_ROLES.has(role) ? config.runner.claude.readOnlyTools : config.runner.claude.allowedTools).join(', ');
42
+ const values = {
43
+ role,
44
+ description: JSON.stringify(loadRoleDescription(root, role)),
45
+ tools,
46
+ model: agentModel(config.runner.models[role]) ?? defaultHostModel(role),
47
+ // Без явного effort субагент наследует усилие сессии (в пилоте это был xhigh на каждом ходе).
48
+ effort: config.runner.efforts[role] ?? config.runner.defaultEffort,
49
+ skills: skills.length ? `skills:\n${skills.map((s) => ` - ${s}`).join('\n')}\n` : '',
50
+ body: loadRoleText(root, role).trim(),
51
+ };
52
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => values[key] ?? '');
76
53
  }
77
- const RUN_SKILL = `---
78
- name: sbox-run
79
- description: Выполнить следующий шаг изменения @spec-box/sdd — запросить пакет у CLI, выполнить роль субагентом и сдать отчёт. Используй, когда пользователь просит продвинуть изменение, запустить sbox, выполнить следующий шаг.
80
- ---
81
-
82
- # sbox-run
83
-
84
- Ты оркестратор: не исследуешь проект и не решаешь задачу сам. Роли выполняют субагенты \`sbox-<role>\`.
85
-
86
- 1. Определи изменение: из аргумента, из контекста или \`sbox change list --json\`. Если активных изменений несколько и не ясно, какое брать, спроси пользователя.
87
- 2. Запроси следующий шаг: \`sbox next --change <id> --brief --json\`. Никогда не запрашивай \`next\` без \`--brief\` и не читай packet.json сам: пакет нужен субагенту, а не тебе.
88
- 3. По полю \`kind\` ответа:
89
- - \`role\`: если субагент этой роли уже запускался в этой сессии, продолжи его тем же сообщением через SendMessage (он помнит проект и артефакты, повторное чтение не нужно); иначе запусти нового субагента \`sbox-<role>\`. Сообщение: \`packet: <path из поля packetFile>\`. Дождись ответа. Затем сдай отчёт: \`sbox report --change <id> --role <role> --json\`. Ответ \`report\` уже содержит статус и диагностику: не читай result.md и evidence целиком, покажи пользователю только строку статуса и ошибки. Если CLI вернул ошибки (например, не создан артефакт или изменены защищённые файлы), передай их тому же субагенту одним сообщением и повтори отчёт; не больше двух повторов.
90
- - \`gate\`: покажи пользователю пути артефактов из ответа и спроси: «Утвердить <gate>? Ответьте «да» или замечанием». «да» → \`sbox approve <gate> --change <id> --by <user>\`; замечание → \`sbox reject <gate> --change <id> --comment "<текст>"\`. Мелкие правки формулировок пользователь может внести в артефакт сам и ответить «да»: отклонение запускает цикл доработки роли. Затем вернись к шагу 2.
91
- - \`deliver\`: покажи чеклист \`sbox deliver --change <id> --check\` и предложи доставку \`sbox deliver --change <id>\` (архив, коммит, push, пул-реквест). Не запускай доставку без просьбы пользователя.
92
- - \`wait\`: покажи статус и блокер, спроси пользователя, что делать.
93
- - \`done\`: сообщи об окончании.
94
- 4. Повторяй шаги 2–3, пока не встретишь gate, wait, deliver или done. Не запускай субагентов параллельно.
95
-
96
- Полезные команды: \`sbox status --change <id>\` (состояние, change-set, привязка ревью), \`sbox changeset show\` (запечатанный диф и дрейф), \`sbox coverage --report jest=<path>\` (покрытие утверждений тестами), \`sbox change resume --returns N\` (продолжить после parked).
97
-
98
- Экономия контекста: не читай артефакты изменения (design.md, спецификации, отчёты) целиком; тебе нужны только ответы CLI. Запрещено: переформулировать задачу пользователя, редактировать артефакты, вызывать роли напрямую в обход пакета, менять код.
99
- `;
100
- const APPROVE_SKILL = `---
101
- name: sbox-approve
102
- description: Утвердить или отклонить гейт изменения @spec-box/sdd (proposal, plan, tests). Используй, когда пользователь говорит «утверждаю», «одобряю план», «отклоняю с замечанием».
103
- ---
104
-
105
- # sbox-approve
106
-
107
- 1. Определи изменение и гейт: \`sbox status --change <id> --json\` показывает ожидающий гейт.
108
- 2. Утверждение: \`sbox approve <gate> --change <id> --by <user> [--comment "..."] [--answer Q1=B]\`.
109
- 3. Отклонение: \`sbox reject <gate> --change <id> --by <user> --comment "<замечание>"\`.
110
- 4. Покажи результат и предложи продолжить скиллом sbox-run.
111
- `;
112
54
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/host/claude/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/host/claude/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { SboxError } from '../../core/errors.js';
2
+ import { loadSkills } from '../../core/skills.js';
3
+ import { installClaudeAgents } from './claude/index.js';
4
+ import { HOST_TARGETS, installSkills, isHostTarget } from './skills.js';
5
+ /** Материалы хоста: скиллы из единого источника для любого хоста плюс агенты, если адаптер хоста их умеет. */
6
+ export function installHostMaterials(root, target, config) {
7
+ if (!isHostTarget(target))
8
+ throw new SboxError('HOST_UNKNOWN', `Неизвестный хост ${target}; доступны ${HOST_TARGETS.join(' и ')}.`);
9
+ const skills = loadSkills(root);
10
+ const files = installSkills(root, target, skills);
11
+ const notes = [];
12
+ let next;
13
+ switch (target) {
14
+ case 'claude':
15
+ files.push(...installClaudeAgents(root, config, skills));
16
+ next = 'В Claude Code: `/sbox-run` после `sbox change new <id> --title "..." --request "..."`.';
17
+ break;
18
+ case 'codex':
19
+ notes.push('Для Codex установлены скиллы sbox-approve и sbox-browser в .agents/skills; оркестратор sbox-run, агенты ролей и раздел AGENTS.md для Codex появятся на этапе 4 плана.');
20
+ next = 'В Codex: скиллы из .agents/skills доступны сразу; изменения пока ведутся из Claude Code или командами `sbox next` и `sbox report` вручную.';
21
+ break;
22
+ }
23
+ return { target, files, notes, next };
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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,EAAE,MAAM,CAAC,CAAC,CAAC;YACzD,IAAI,GAAG,wFAAwF,CAAC;YAChG,MAAM;QACR,KAAK,OAAO;YACV,KAAK,CAAC,IAAI,CAAC,uKAAuK,CAAC,CAAC;YACpL,IAAI,GAAG,4IAA4I,CAAC;YACpJ,MAAM;IACV,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import path from 'node:path';
2
+ import { loadSkills, skillsForHost } from '../../core/skills.js';
3
+ import { writeText } from '../../core/paths.js';
4
+ /**
5
+ * Где хост читает скиллы проекта. Claude Code: .claude/skills/<имя>/SKILL.md.
6
+ * Codex: .agents/skills/<имя>/SKILL.md (Agent Skills; пользовательские ~/.agents/skills и ~/.codex/skills инструмент не трогает).
7
+ * Новый хост это новая строка здесь.
8
+ */
9
+ export const SKILL_LAYOUT = {
10
+ claude: (name) => path.join('.claude', 'skills', name, 'SKILL.md'),
11
+ codex: (name) => path.join('.agents', 'skills', name, 'SKILL.md'),
12
+ };
13
+ export const HOST_TARGETS = Object.keys(SKILL_LAYOUT);
14
+ export function isHostTarget(value) {
15
+ return Object.hasOwn(SKILL_LAYOUT, value);
16
+ }
17
+ /** Копирует скиллы из единого источника (assets/skills и .sbox/skills), применимые к хосту, в его раскладку без изменений текста. */
18
+ export function installSkills(root, target, skills = loadSkills(root)) {
19
+ const written = [];
20
+ for (const skill of skillsForHost(skills, target)) {
21
+ const file = path.join(root, SKILL_LAYOUT[target](skill.name));
22
+ writeText(file, skill.text);
23
+ written.push(file);
24
+ }
25
+ return written;
26
+ }
27
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/adapters/host/skills.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,aAAa,EAAwB,MAAM,sBAAsB,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC;IAC1E,KAAK,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC;CACjE,CAAC;AAIX,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAiB,CAAC;AAEtE,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,qIAAqI;AACrI,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,MAAkB,EAAE,MAAM,GAAsB,UAAU,CAAC,IAAI,CAAC;IAC1G,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,KAAK,IAAI,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/D,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}