mister-wolf 1.0.3 → 2.0.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/dist/adapters/cli/cli-entry.d.ts.map +1 -1
- package/dist/adapters/cli/cli-entry.js +4 -0
- package/dist/adapters/cli/cli-entry.js.map +1 -1
- package/dist/adapters/cli/commands/memory-complain.d.ts.map +1 -1
- package/dist/adapters/cli/commands/memory-complain.js +41 -17
- package/dist/adapters/cli/commands/memory-complain.js.map +1 -1
- package/dist/adapters/cli/commands/memory-init.d.ts +21 -0
- package/dist/adapters/cli/commands/memory-init.d.ts.map +1 -1
- package/dist/adapters/cli/commands/memory-init.js +194 -16
- package/dist/adapters/cli/commands/memory-init.js.map +1 -1
- package/dist/adapters/cli/commands/memory-search.d.ts.map +1 -1
- package/dist/adapters/cli/commands/memory-search.js +8 -0
- package/dist/adapters/cli/commands/memory-search.js.map +1 -1
- package/dist/adapters/cli/commands/memory-sync.d.ts +3 -0
- package/dist/adapters/cli/commands/memory-sync.d.ts.map +1 -0
- package/dist/adapters/cli/commands/memory-sync.js +36 -0
- package/dist/adapters/cli/commands/memory-sync.js.map +1 -0
- package/dist/adapters/cli/commands/memory-update.d.ts +3 -0
- package/dist/adapters/cli/commands/memory-update.d.ts.map +1 -0
- package/dist/adapters/cli/commands/memory-update.js +105 -0
- package/dist/adapters/cli/commands/memory-update.js.map +1 -0
- package/dist/adapters/mcp/mcp-schemas.d.ts +1 -1
- package/dist/adapters/mcp/mcp-schemas.d.ts.map +1 -1
- package/dist/adapters/mcp/mcp-schemas.js +8 -2
- package/dist/adapters/mcp/mcp-schemas.js.map +1 -1
- package/dist/adapters/mcp/mcp-tools.d.ts.map +1 -1
- package/dist/adapters/mcp/mcp-tools.js +10 -8
- package/dist/adapters/mcp/mcp-tools.js.map +1 -1
- package/dist/adapters/platforms/claude-adapter.d.ts +2 -2
- package/dist/adapters/platforms/claude-adapter.d.ts.map +1 -1
- package/dist/adapters/platforms/claude-adapter.js +2 -2
- package/dist/adapters/platforms/claude-adapter.js.map +1 -1
- package/dist/adapters/platforms/opencode-adapter.d.ts +4 -2
- package/dist/adapters/platforms/opencode-adapter.d.ts.map +1 -1
- package/dist/adapters/platforms/opencode-adapter.js +16 -4
- package/dist/adapters/platforms/opencode-adapter.js.map +1 -1
- package/dist/adapters/render/manifest.d.ts +14 -0
- package/dist/adapters/render/manifest.d.ts.map +1 -0
- package/dist/adapters/render/manifest.js +25 -0
- package/dist/adapters/render/manifest.js.map +1 -0
- package/dist/adapters/render/opencode/opencode-renderer.d.ts +29 -0
- package/dist/adapters/render/opencode/opencode-renderer.d.ts.map +1 -0
- package/dist/adapters/render/opencode/opencode-renderer.js +198 -0
- package/dist/adapters/render/opencode/opencode-renderer.js.map +1 -0
- package/dist/adapters/render/stamp.d.ts +8 -0
- package/dist/adapters/render/stamp.d.ts.map +1 -0
- package/dist/adapters/render/stamp.js +23 -0
- package/dist/adapters/render/stamp.js.map +1 -0
- package/dist/adapters/render/templates-root.d.ts +6 -0
- package/dist/adapters/render/templates-root.d.ts.map +1 -0
- package/dist/adapters/render/templates-root.js +30 -0
- package/dist/adapters/render/templates-root.js.map +1 -0
- package/dist/adapters/sqlite/sqlite-search-index.d.ts +10 -1
- package/dist/adapters/sqlite/sqlite-search-index.d.ts.map +1 -1
- package/dist/adapters/sqlite/sqlite-search-index.js +48 -10
- package/dist/adapters/sqlite/sqlite-search-index.js.map +1 -1
- package/dist/app/use-cases/bootstrap-project.d.ts +4 -2
- package/dist/app/use-cases/bootstrap-project.d.ts.map +1 -1
- package/dist/app/use-cases/bootstrap-project.js +29 -8
- package/dist/app/use-cases/bootstrap-project.js.map +1 -1
- package/dist/app/use-cases/generate-recap.d.ts +8 -0
- package/dist/app/use-cases/generate-recap.d.ts.map +1 -1
- package/dist/app/use-cases/generate-recap.js +34 -1
- package/dist/app/use-cases/generate-recap.js.map +1 -1
- package/dist/app/use-cases/get-call-injections.d.ts.map +1 -1
- package/dist/app/use-cases/get-call-injections.js +7 -3
- package/dist/app/use-cases/get-call-injections.js.map +1 -1
- package/dist/app/use-cases/init-project.d.ts +57 -9
- package/dist/app/use-cases/init-project.d.ts.map +1 -1
- package/dist/app/use-cases/init-project.js +131 -24
- package/dist/app/use-cases/init-project.js.map +1 -1
- package/dist/app/use-cases/model-routing.d.ts +30 -0
- package/dist/app/use-cases/model-routing.d.ts.map +1 -0
- package/dist/app/use-cases/model-routing.js +39 -0
- package/dist/app/use-cases/model-routing.js.map +1 -0
- package/dist/app/use-cases/seed-base-playbooks.d.ts +26 -0
- package/dist/app/use-cases/seed-base-playbooks.d.ts.map +1 -0
- package/dist/app/use-cases/seed-base-playbooks.js +43 -0
- package/dist/app/use-cases/seed-base-playbooks.js.map +1 -0
- package/dist/app/use-cases/sync-base-set.d.ts +13 -0
- package/dist/app/use-cases/sync-base-set.d.ts.map +1 -0
- package/dist/app/use-cases/sync-base-set.js +11 -0
- package/dist/app/use-cases/sync-base-set.js.map +1 -0
- package/dist/domain/governance.d.ts.map +1 -1
- package/dist/domain/governance.js +4 -2
- package/dist/domain/governance.js.map +1 -1
- package/dist/domain/memory-types.d.ts +45 -1
- package/dist/domain/memory-types.d.ts.map +1 -1
- package/dist/domain/memory-types.js +20 -0
- package/dist/domain/memory-types.js.map +1 -1
- package/dist/domain/schemas/article-schema.d.ts +1 -1
- package/dist/domain/schemas/blocker-schema.d.ts +1 -1
- package/dist/domain/schemas/decision-schema.d.ts +1 -1
- package/dist/domain/schemas/info-request-schema.d.ts +1 -1
- package/dist/domain/schemas/rule-schema.d.ts +1 -1
- package/dist/domain/schemas/session-checkpoint-schema.d.ts +1 -1
- package/dist/domain/schemas/thread-schema.d.ts +1 -1
- package/dist/domain/type-schema-builder.d.ts +11 -2
- package/dist/domain/type-schema-builder.d.ts.map +1 -1
- package/dist/domain/type-schema-builder.js +41 -0
- package/dist/domain/type-schema-builder.js.map +1 -1
- package/dist/ports/base-set-renderer.port.d.ts +34 -0
- package/dist/ports/base-set-renderer.port.d.ts.map +1 -0
- package/dist/ports/base-set-renderer.port.js +2 -0
- package/dist/ports/base-set-renderer.port.js.map +1 -0
- package/dist/ports/platform-adapter.port.d.ts +7 -1
- package/dist/ports/platform-adapter.port.d.ts.map +1 -1
- package/package.json +11 -8
- package/templates/base/AGENTS.md +28 -0
- package/templates/base/README.md +1 -0
- package/templates/base/agents/executor-lead.md +96 -0
- package/templates/base/agents/mr-wolf.md +89 -0
- package/templates/base/agents/steward.md +60 -0
- package/templates/base/agents/worker-implementer.md +59 -0
- package/templates/base/agents/worker-researcher.md +60 -0
- package/templates/base/agents/worker-reviewer.md +59 -0
- package/templates/base/commands/analyze-doc.md +11 -0
- package/templates/base/commands/complain.md +13 -0
- package/templates/base/commands/doc-review.md +15 -0
- package/templates/base/playbooks/complaint-protocol.md +112 -0
- package/templates/base/playbooks/steward-nastavnik.md +40 -0
- package/templates/base/playbooks/wolf-review-lenses.md +50 -0
- package/templates/base/playbooks/worker-implementer-playbook.md +59 -0
- package/templates/base/playbooks/worker-researcher-playbook.md +59 -0
- package/templates/base/playbooks/worker-reviewer-playbook.md +61 -0
- package/templates/base/skills/finishing-a-development-branch/SKILL.md +213 -0
- package/templates/base/skills/requesting-code-review/SKILL.md +123 -0
- package/templates/base/skills/test-driven-development/SKILL.md +391 -0
- package/templates/base/skills/using-git-worktrees/SKILL.md +178 -0
- package/templates/base/skills/using-skills/SKILL.md +128 -0
- package/templates/base/skills/verification-before-completion/SKILL.md +157 -0
- package/templates/base/skills/wolf-brainstorm/SKILL.md +167 -0
- package/templates/base/skills/wolf-debug/SKILL.md +293 -0
- package/templates/base/skills/wolf-execute/SKILL.md +96 -0
- package/templates/base/skills/wolf-handoff/SKILL.md +101 -0
- package/templates/base/skills/wolf-plan/SKILL.md +177 -0
- package/templates/base/skills/wolf-review/SKILL.md +61 -0
- package/templates/base/skills/wolf-sdd/SKILL.md +239 -0
- package/templates/opencode/README.md +1 -0
- package/templates/opencode/plugins/wolf-router.ts +104 -0
- package/templates/opencode/plugins/wolf-session-start.js +144 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wolf-plan
|
|
3
|
+
description: "Используй, когда есть спека или требования для многошаговой задачи — до касания кода. Пишет zero-context планы: каждая задача = самодостаточный бриф воркера, исполнитель не обязан знать кодовую базу."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# wolf-plan: план для zero-context исполнителя
|
|
7
|
+
|
|
8
|
+
## Обзор
|
|
9
|
+
|
|
10
|
+
Пиши исчерпывающие планы реализации в предположении, что исполнитель имеет **нулевой контекст** кодовой базы этой задачи и сомнительный вкус. Задокументируй всё, что ему нужно знать: какие файлы трогать в каждой задаче, код, тесты, какие доки проверить, как проверить работу. Отдай весь план как bite-sized задачи. DRY. YAGNI. TDD. Частые коммиты.
|
|
11
|
+
|
|
12
|
+
Считай, что исполнитель — умелый разработчик, но почти ничего не знает о нашем тулсете и проблемном домене. Считай, что он плохо умеет в хороший дизайн тестов.
|
|
13
|
+
|
|
14
|
+
**Вход воркеров — по брифам:** каждая задача плана становится брифом однозадачного воркера (worker-implementer). Воркер не читает кодовую базу и не видит твою сессию — план обязан содержать всё. Сомнительное качество плана = гарантированные вопросы и переделки на исполнении.
|
|
15
|
+
|
|
16
|
+
**Анонс на старте:** «Использую скилл wolf-plan для создания плана реализации».
|
|
17
|
+
|
|
18
|
+
**Контекст:** исполнение плана начинается только в worktree `.worktrees/<имя-задачи>` (правило проекта; создаётся ДО старта исполнения — см. wolf-sdd / wolf-execute). Сам план можно писать и до worktree.
|
|
19
|
+
|
|
20
|
+
**Куда сохранять:** `docs/plans/YYYY-MM-DD-<имя-фичи>.md` (предпочтения проекта приоритетнее дефолта).
|
|
21
|
+
|
|
22
|
+
## Проверка масштаба
|
|
23
|
+
|
|
24
|
+
Если спека покрывает несколько независимых подсистем, её нужно было разбить на подпроекты ещё на wolf-brainstorm. Если это не сделано — предложи разбить план на отдельные, по одному на подсистему. Каждый план должен давать работающее, тестируемое ПО сам по себе.
|
|
25
|
+
|
|
26
|
+
## Структура файлов
|
|
27
|
+
|
|
28
|
+
До определения задач спроектируй, какие файлы будут созданы или изменены и за что каждый отвечает. Здесь фиксируются решения декомпозиции.
|
|
29
|
+
|
|
30
|
+
- Проектируй блоки с ясными границами и определёнными интерфейсами. У каждого файла — одна ясная ответственность.
|
|
31
|
+
- Над кодом, который держится в контексте целиком, ты рассуждаешь лучше, а правки точечнее. Предпочитай маленькие сфокусированные файлы разросшимся.
|
|
32
|
+
- Файлы, меняющиеся вместе, живут вместе. Дели по ответственности, не по техническим слоям.
|
|
33
|
+
- В существующей кодовой базе следуй устоявшимся паттернам. Если она использует большие файлы — не перестраивай в одиночку; но если файл, который ты правишь, разросся — включить разбиение в план разумно.
|
|
34
|
+
|
|
35
|
+
Эта структура определяет декомпозицию задач. Каждая задача должна давать самодостаточные изменения, осмысленные независимо.
|
|
36
|
+
|
|
37
|
+
## Гранулярность bite-sized
|
|
38
|
+
|
|
39
|
+
**Каждый шаг — одно действие (2–5 минут):**
|
|
40
|
+
- «Напиши падающий тест» — шаг
|
|
41
|
+
- «Запусти и убедись, что он падает» — шаг
|
|
42
|
+
- «Напиши минимальный код, чтобы тест прошёл» — шаг
|
|
43
|
+
- «Запусти тесты и убедись, что проходят» — шаг
|
|
44
|
+
- «Закоммить» — шаг
|
|
45
|
+
|
|
46
|
+
## Заголовок плана
|
|
47
|
+
|
|
48
|
+
**Каждый план ОБЯЗАН начинаться с этого заголовка:**
|
|
49
|
+
|
|
50
|
+
```markdown
|
|
51
|
+
# [Имя фичи] — план реализации
|
|
52
|
+
|
|
53
|
+
> **Исполнителям:** REQUIRED-СКИЛЛ: используй wolf-sdd (рекомендуется) ИЛИ wolf-execute
|
|
54
|
+
> для поэтапной реализации этого плана. Шаги оформлены чекбоксами (`- [ ]`) для трекинга.
|
|
55
|
+
|
|
56
|
+
**Цель:** [Одно предложение — что строим]
|
|
57
|
+
|
|
58
|
+
**Архитектура:** [2–3 предложения о подходе]
|
|
59
|
+
|
|
60
|
+
**Стек:** [Ключевые технологии/библиотеки]
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Структура задачи
|
|
66
|
+
|
|
67
|
+
````markdown
|
|
68
|
+
### Задача N: [Имя компонента]
|
|
69
|
+
|
|
70
|
+
**Файлы:**
|
|
71
|
+
- Create: `точный/путь/к/file.ts`
|
|
72
|
+
- Modify: `точный/путь/к/existing.ts:123-145`
|
|
73
|
+
- Test: `tests/точный/путь/к/test.ts`
|
|
74
|
+
|
|
75
|
+
- [ ] **Шаг 1: Напиши падающий тест**
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
it("конкретное поведение", () => {
|
|
79
|
+
expect(fn(input)).toBe(expected);
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- [ ] **Шаг 2: Запусти тест — убедись, что падает**
|
|
84
|
+
|
|
85
|
+
Запуск: `npx vitest run tests/path/test.ts -t "конкретное поведение"`
|
|
86
|
+
Ожидание: FAIL — «fn is not defined»
|
|
87
|
+
|
|
88
|
+
- [ ] **Шаг 3: Напиши минимальную реализацию**
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
export function fn(input: string): string {
|
|
92
|
+
return "expected";
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- [ ] **Шаг 4: Запусти тест — убедись, что проходит**
|
|
97
|
+
|
|
98
|
+
Запуск: `npx vitest run tests/path/test.ts -t "конкретное поведение"`
|
|
99
|
+
Ожидание: PASS
|
|
100
|
+
|
|
101
|
+
- [ ] **Шаг 5: Закоммить**
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git add tests/path/test.ts src/path/file.ts
|
|
105
|
+
git commit -m "feat: add specific feature"
|
|
106
|
+
```
|
|
107
|
+
````
|
|
108
|
+
|
|
109
|
+
## Никаких плейсхолдеров
|
|
110
|
+
|
|
111
|
+
Каждый шаг обязан содержать фактический контент, нужный исполнителю. Это **провалы плана** — никогда так не пиши:
|
|
112
|
+
|
|
113
|
+
- «TBD», «TODO», «сделаем позже», «заполнить детали»
|
|
114
|
+
- «Добавить соответствующую обработку ошибок» / «добавить валидацию» / «обработать краевые случаи»
|
|
115
|
+
- «Написать тесты для вышенаписанного» (без фактического кода теста)
|
|
116
|
+
- «Аналогично задаче N» (повтори код — исполнитель может читать задачи не по порядку)
|
|
117
|
+
- Шаги, описывающие ЧТО делать, без КАК (для шагов с кодом — блоки кода обязательны)
|
|
118
|
+
- Ссылки на типы, функции или методы, не определённые ни в одной задаче
|
|
119
|
+
|
|
120
|
+
## Помни
|
|
121
|
+
|
|
122
|
+
- Всегда точные пути файлов
|
|
123
|
+
- Полный код в каждом шаге — если шаг меняет код, покажи код
|
|
124
|
+
- Точные команды с ожидаемым выводом
|
|
125
|
+
- DRY, YAGNI, TDD, частые коммиты
|
|
126
|
+
|
|
127
|
+
## Саморевью
|
|
128
|
+
|
|
129
|
+
После написания полного плана посмотри на него свежим взглядом и сверь со спекой. Это чеклист для себя, не диспетчеризация субагентов.
|
|
130
|
+
|
|
131
|
+
**1. Покрытие спеки:** пробегись по каждой секции/требованию спеки. Можешь указать задачу, которая её реализует? Перечисли пробелы.
|
|
132
|
+
|
|
133
|
+
**2. Скан плейсхолдеров:** поищи в плане red flags — паттерны из секции «Никаких плейсхолдеров» выше. Исправь.
|
|
134
|
+
|
|
135
|
+
**3. Консистентность типов:** совпадают ли типы, сигнатуры методов и имена свойств в поздних задачах с определёнными в ранних? Функция `clearLayers()` в задаче 3 и `clearFullLayers()` в задаче 7 — это баг.
|
|
136
|
+
|
|
137
|
+
Нашёл проблемы — исправь на месте. Пересматривать заново не нужно. Требование спеки без задачи — добавь задачу.
|
|
138
|
+
|
|
139
|
+
## Передача в исполнение
|
|
140
|
+
|
|
141
|
+
После сохранения плана предложи выбор режима исполнения:
|
|
142
|
+
|
|
143
|
+
**«План готов и сохранён в `docs/plans/<файл>.md`. Два режима исполнения:**
|
|
144
|
+
|
|
145
|
+
**1. Через субагентов (wolf-sdd, рекомендуется)** — свежий воркер на каждую задачу через executor-lead, 2-стадийное ревью между задачами, быстрая итерация
|
|
146
|
+
|
|
147
|
+
**2. Линейно (wolf-execute)** — исполнение задач в этой сессии без субагентов, батчами с чекпоинтами
|
|
148
|
+
|
|
149
|
+
**Какой режим?»**
|
|
150
|
+
|
|
151
|
+
**Выбран wolf-sdd:** свежий воркер на задачу + двухстадийное ревью (спека → качество) силами worker-reviewer.
|
|
152
|
+
|
|
153
|
+
**Выбран wolf-execute:** батч-исполнение с чекпоинтами; верификация — `npm run check` после завершённых блоков работы.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Трассировка адаптации
|
|
158
|
+
|
|
159
|
+
> Источник: `~/.config/opencode/superpowers/skills/writing-plans/SKILL.md`, upstream 6efe32c (2026-04-23)
|
|
160
|
+
|
|
161
|
+
| Пункт источника | Судьба | Почему |
|
|
162
|
+
|---|---|---|
|
|
163
|
+
| Zero-context принцип | сохранено + усилено «вход воркеров по брифам» | Спека §5.2 |
|
|
164
|
+
| «created by brainstorming skill» (worktree) | заменено: worktree до старта исполнения, правило `.worktrees/<имя-задачи>` | H5; upstream-ребро brainstorm→worktree одностороннее, не воспроизводим |
|
|
165
|
+
| Путь `docs/superpowers/plans/` | заменено → `docs/plans/…` | Harness-привязка (research §1) |
|
|
166
|
+
| Заголовок «REQUIRED SUB-SKILL: sdd or executing-plans» | заменено → wolf-sdd ИЛИ wolf-execute | Рёбра набора Wolf |
|
|
167
|
+
| Проверка масштаба | сохранено | Ядро |
|
|
168
|
+
| Структура файлов | сохранено | Ядро |
|
|
169
|
+
| Bite-sized гранулярность | сохранено | Ядро |
|
|
170
|
+
| Структура задачи (пример) | сохранено; пример переведён (vitest вместо pytest) | Нейтральная иллюстрация под стек проекта |
|
|
171
|
+
| «No Placeholders» (6 провалов) | сохранено полностью (6/6) | H7 |
|
|
172
|
+
| «Remember» (4) | сохранено полностью (4/4) | H7 |
|
|
173
|
+
| Саморевью (3 проверки) | сохранено полностью (3/3) | Чеклист-ядро |
|
|
174
|
+
| Execution Handoff (2 опции) | сохранено; sdd-опция → executor-lead/worker-*, ревью → worker-reviewer; добавлен `npm run check` | Wolf-переплетение |
|
|
175
|
+
| — | добавлено: задача = бриф воркера (worker-implementer) | Zero-context вход по брифам |
|
|
176
|
+
|
|
177
|
+
Перенесённые списки: anti-patterns «No Placeholders» 6/6, «Remember» 4/4, саморевью 3/3.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wolf-review
|
|
3
|
+
description: Мульти-линзовое ревью документов (doc-review): mr-wolf оркестрирует линзы-воркеров, цикл до сходимости. Use when the user asks to review a document, run doc-review, or critique a spec/plan/report.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# wolf-review — мульти-линзовое ревью документов
|
|
7
|
+
|
|
8
|
+
> Источник: новый; рамка analyze-doc (PoC) + REVIEW-001 (архив v2.0 §2.5) +
|
|
9
|
+
> практика мульти-линзового ревью; отклонение: security-линза опущена
|
|
10
|
+
> (спека §6).
|
|
11
|
+
|
|
12
|
+
## Трассировка переноса
|
|
13
|
+
|
|
14
|
+
| Пункт источника | Судьба |
|
|
15
|
+
| --------------- | ------ |
|
|
16
|
+
| Рамочный паттерн analyze-doc: методика в памяти, файл — тонкая рамка | Сохранено |
|
|
17
|
+
| Протокол подтягивания playbook перед прогоном | Сохранено; запрос `wolf search "wolf-review playbook"`, наибольшая версия |
|
|
18
|
+
| Мульти-линзовость, изоляция линз в чистых сессиях (REVIEW-001) | Сохранено |
|
|
19
|
+
| Перспектива линз полнота → консистентность → типоспецифичные (REVIEW-001) | Сохранено |
|
|
20
|
+
| Контракты SUMMARY/VERDICT (REVIEW-001: вердикт «CHANGES») | Сохранено; «CHANGES» заменён на `CHANGES_REQUIRED` (стандартизация по спеке §6) |
|
|
21
|
+
| Дедуп находок, подсчёт, счётчик раундов, критерий сходимости (REVIEW-001) | Сохранено |
|
|
22
|
+
| Конфликты находок между линзами решает владелец (REVIEW-001) | Сохранено |
|
|
23
|
+
| Security-линза (REVIEW-001) | Отброшено: осознанное отклонение — для документов не тянем (спека §6) |
|
|
24
|
+
| Самомутация playbook по фидбеку (analyze-doc PoC, п. 3) | Заменено: фидбек о методике/линзах → жалобный контур (`wolf complain`, тег complaint); мутатор — Стюард |
|
|
25
|
+
| Исполнитель-аналитик PoC (apprentice) | Заменено: линзы исполняют worker-reviewer; оркестратор цикла — mr-wolf |
|
|
26
|
+
| Продуктовый код оркестрации | Отброшено: весь цикл ведёт mr-wolf по протоколу этого скилла (спека §10) |
|
|
27
|
+
|
|
28
|
+
## Рамка (методика — НЕ в этом файле)
|
|
29
|
+
|
|
30
|
+
Линзы — playbook-объекты памяти Wolf: они эволюционируют без рестарта
|
|
31
|
+
(мутатор — Стюард, через жалобы). Этот файл — только рамка: протокол цикла
|
|
32
|
+
и границы.
|
|
33
|
+
|
|
34
|
+
### Протокол цикла (оркестратор — mr-wolf)
|
|
35
|
+
|
|
36
|
+
1. **До прогона** получи актуальный playbook линз:
|
|
37
|
+
`wolf search "wolf-review playbook"` — запись с наибольшей версией.
|
|
38
|
+
Состав и параметры каждой линзы — из playbook, не отсюда.
|
|
39
|
+
2. **Порядок линз**: полнота → консистентность → типоспецифичные.
|
|
40
|
+
3. **Спавн**: каждую линзу исполняет ОТДЕЛЬНЫЙ worker-reviewer в чистой
|
|
41
|
+
сессии через {{tool.task}}. Изоляция бьёт по слепым зонам саморевью.
|
|
42
|
+
Узкий ревьюер: чужие замечания запрещены — воркер получает только свой
|
|
43
|
+
мандат (документ + своя линза), находки других линз ему не показываются.
|
|
44
|
+
4. **Контракты** — обязательные строки отчёта каждой линзы:
|
|
45
|
+
- `SUMMARY: X critical / Y major / Z minor`
|
|
46
|
+
- `VERDICT: APPROVED | CHANGES_REQUIRED`
|
|
47
|
+
5. **Дедуп и подсчёт**: mr-wolf сводит находки всех линз, убирает
|
|
48
|
+
дубликаты, считает critical/major/minor по итоговому набору.
|
|
49
|
+
6. **Сходимость**: цикл останавливается при 0 critical / 0 blocking ИЛИ
|
|
50
|
+
по лимиту раундов (по умолчанию 3).
|
|
51
|
+
7. **Цикл правок**: автор правит документ → перезапуск ТОЛЬКО упавшей
|
|
52
|
+
линзы; прошедшие линзы не перегоняются.
|
|
53
|
+
8. **Конфликты**: противоречащие находки разных линз разрешает владелец
|
|
54
|
+
(слепой судьи в MVP нет) — mr-wolf докладывает конфликт, не выбирает сам.
|
|
55
|
+
|
|
56
|
+
### Границы рамки
|
|
57
|
+
|
|
58
|
+
- Критичные запреты: `rm -rf`, `sudo`, деструктивный git, секреты.
|
|
59
|
+
- Продуктового кода оркестрации нет — цикл ведёт mr-wolf по этому протоколу.
|
|
60
|
+
- Этот файл не содержит методику линз и не должен её содержать:
|
|
61
|
+
версии линз живут в памяти Wolf.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wolf-sdd
|
|
3
|
+
description: "Используй для исполнения планов реализации с независимыми задачами через субагентов: свежий воркер на каждую задачу через executor-lead + двухстадийное ревью worker-reviewer (соответствие брифу, затем качество)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# wolf-sdd: разработка через субагентов
|
|
7
|
+
|
|
8
|
+
Исполняй план, диспетчеризуя свежего воркера на каждую задачу, с двухстадийным ревью после каждой: сначала соответствие брифу, затем качество кода.
|
|
9
|
+
|
|
10
|
+
**Почему субагенты:** ты делегируешь задачи специализированным воркерам с изолированным контекстом. Точно формулируя их инструкции и контекст, ты удерживаешь их в фокусе и обеспечиваешь успех. Воркеры никогда не наследуют контекст и историю твоей сессии — ты конструируешь ровно то, что им нужно. Это же бережёт твой контекст для координации.
|
|
11
|
+
|
|
12
|
+
**Ядро принципа:** свежий воркер на задачу + двухстадийное ревью (бриф → качество) = высокое качество, быстрая итерация.
|
|
13
|
+
|
|
14
|
+
**Роли:** диспетчеризация — через executor-lead (или напрямую `{{tool.task}}` с типом воркера): исполнение — worker-implementer, ревью обеих стадий — worker-reviewer. Generic-субагентов не спавнь.
|
|
15
|
+
|
|
16
|
+
**Методики воркеров:** воркер перед задачей подтягивает своё лицо из памяти — `wolf search "worker-implementer playbook"` / `wolf search "worker-reviewer playbook"` (брать наибольшую версию); в брифе укажи это воркеру, если harness не доставляет лица автоматически.
|
|
17
|
+
|
|
18
|
+
## REQUIRED-предусловие: worktree
|
|
19
|
+
|
|
20
|
+
**До старта исполнения worktree ОБЯЗАН существовать:** `.worktrees/<имя-задачи>` внутри проекта (правило проекта). Trunk-based: main — истина, работа идёт в ветке внутри worktree. Нет worktree — создай его ДО первой задачи (см. скилл using-git-worktrees). Никогда не начинай исполнение в main без явного согласия владельца.
|
|
21
|
+
|
|
22
|
+
## Когда использовать
|
|
23
|
+
|
|
24
|
+
```dot
|
|
25
|
+
digraph when_to_use {
|
|
26
|
+
"Есть план реализации?" [shape=diamond];
|
|
27
|
+
"Задачи в основном независимы?" [shape=diamond];
|
|
28
|
+
"Остаемся в этой сессии?" [shape=diamond];
|
|
29
|
+
"wolf-sdd" [shape=box];
|
|
30
|
+
"wolf-execute" [shape=box];
|
|
31
|
+
"Ручное исполнение или сначала wolf-brainstorm" [shape=box];
|
|
32
|
+
|
|
33
|
+
"Есть план реализации?" -> "Задачи в основном независимы?" [label="да"];
|
|
34
|
+
"Есть план реализации?" -> "Ручное исполнение или сначала wolf-brainstorm" [label="нет"];
|
|
35
|
+
"Задачи в основном независимы?" -> "Остаемся в этой сессии?" [label="да"];
|
|
36
|
+
"Задачи в основном независимы?" -> "Ручное исполнение или сначала wolf-brainstorm" [label="нет - задачи сцеплены"];
|
|
37
|
+
"Остаемся в этой сессии?" -> "wolf-sdd" [label="да"];
|
|
38
|
+
"Остаемся в этой сессии?" -> "wolf-execute" [label="нет - параллельная сессия"];
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**vs wolf-execute (параллельная/линейная сессия):**
|
|
43
|
+
- Та же сессия (без переключения контекста)
|
|
44
|
+
- Свежий воркер на задачу (без загрязнения контекста)
|
|
45
|
+
- Двухстадийное ревью после каждой задачи: сначала бриф, затем качество
|
|
46
|
+
- Быстрее итерация (без человека между задачами)
|
|
47
|
+
|
|
48
|
+
## Ход процесса
|
|
49
|
+
|
|
50
|
+
```dot
|
|
51
|
+
digraph process {
|
|
52
|
+
rankdir=TB;
|
|
53
|
+
|
|
54
|
+
subgraph cluster_per_task {
|
|
55
|
+
label="На каждую задачу";
|
|
56
|
+
"Спавнь worker-implementer с полным текстом задачи" [shape=box];
|
|
57
|
+
"Воркер задаёт вопросы?" [shape=diamond];
|
|
58
|
+
"Ответь, дай контекст" [shape=box];
|
|
59
|
+
"Воркер реализует, тестирует, коммитит, само-ревью" [shape=box];
|
|
60
|
+
"Спавнь worker-reviewer: стадия 1 - соответствие брифу" [shape=box];
|
|
61
|
+
"Код соответствует брифу?" [shape=diamond];
|
|
62
|
+
"Воркер правит пробелы" [shape=box];
|
|
63
|
+
"Спавнь worker-reviewer: стадия 2 - качество кода" [shape=box];
|
|
64
|
+
"Ревьюер аппрувает?" [shape=diamond];
|
|
65
|
+
"Воркер правит замечания качества" [shape=box];
|
|
66
|
+
"Отметь задачу завершённой ({{tool.todowrite}})" [shape=box];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
"Прочитай план, извлеки все задачи с полным текстом, зафиксируй контекст, заведи {{tool.todowrite}}" [shape=box];
|
|
70
|
+
"Остались задачи?" [shape=diamond];
|
|
71
|
+
"Финальное ревью всего исполнения (worker-reviewer)" [shape=box];
|
|
72
|
+
"Скилл finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen];
|
|
73
|
+
|
|
74
|
+
"Прочитай план, извлеки все задачи с полным текстом, зафиксируй контекст, заведи {{tool.todowrite}}" -> "Спавнь worker-implementer с полным текстом задачи";
|
|
75
|
+
"Спавнь worker-implementer с полным текстом задачи" -> "Воркер задаёт вопросы?";
|
|
76
|
+
"Воркер задаёт вопросы?" -> "Ответь, дай контекст" [label="да"];
|
|
77
|
+
"Ответь, дай контекст" -> "Спавнь worker-implementer с полным текстом задачи";
|
|
78
|
+
"Воркер задаёт вопросы?" -> "Воркер реализует, тестирует, коммитит, само-ревью" [label="нет"];
|
|
79
|
+
"Воркер реализует, тестирует, коммитит, само-ревью" -> "Спавнь worker-reviewer: стадия 1 - соответствие брифу";
|
|
80
|
+
"Спавнь worker-reviewer: стадия 1 - соответствие брифу" -> "Код соответствует брифу?";
|
|
81
|
+
"Код соответствует брифу?" -> "Воркер правит пробелы" [label="нет"];
|
|
82
|
+
"Воркер правит пробелы" -> "Спавнь worker-reviewer: стадия 1 - соответствие брифу" [label="повторное ревью"];
|
|
83
|
+
"Код соответствует брифу?" -> "Спавнь worker-reviewer: стадия 2 - качество кода" [label="да"];
|
|
84
|
+
"Спавнь worker-reviewer: стадия 2 - качество кода" -> "Ревьюер аппрувает?";
|
|
85
|
+
"Ревьюер аппрувает?" -> "Воркер правит замечания качества" [label="нет"];
|
|
86
|
+
"Воркер правит замечания качества" -> "Спавнь worker-reviewer: стадия 2 - качество кода" [label="повторное ревью"];
|
|
87
|
+
"Ревьюер аппрувает?" -> "Отметь задачу завершённой ({{tool.todowrite}})" [label="да"];
|
|
88
|
+
"Отметь задачу завершённой ({{tool.todowrite}})" -> "Остались задачи?";
|
|
89
|
+
"Остались задачи?" -> "Спавнь worker-implementer с полным текстом задачи" [label="да"];
|
|
90
|
+
"Остались задачи?" -> "Финальное ревью всего исполнения (worker-reviewer)" [label="нет"];
|
|
91
|
+
"Финальное ревью всего исполнения (worker-reviewer)" -> "Скилл finishing-a-development-branch";
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Тиринг задач
|
|
96
|
+
|
|
97
|
+
Используй наименее мощную модель, которая справится с ролью — это экономит стоимость и время. Конкретные имена моделей — зона конфига проекта (тиринг), не этого скилла.
|
|
98
|
+
|
|
99
|
+
**Механические задачи реализации** (изолированные функции, ясные брифы, 1–2 файла): быстрая воркерская модель. Большинство задач механичны при хорошо написанном плане.
|
|
100
|
+
|
|
101
|
+
**Интеграционные задачи и задачи суждения** (координация многих файлов, сопоставление паттернов, дебаг): стандартная модель.
|
|
102
|
+
|
|
103
|
+
**Архитектура, дизайн и ревью:** самая способная доступная модель.
|
|
104
|
+
|
|
105
|
+
**Сигналы сложности задачи:**
|
|
106
|
+
- Трогает 1–2 файла с полным брифом → воркерская модель
|
|
107
|
+
- Трогает много файлов с интеграционными рисками → стандартная
|
|
108
|
+
- Требует дизайнерского суждения или широкого понимания кодовой базы → самая способная
|
|
109
|
+
|
|
110
|
+
## Обработка статусов воркера
|
|
111
|
+
|
|
112
|
+
Воркеры (worker-implementer) отчитываются одним из четырёх статусов. Обрабатывай каждый соответственно:
|
|
113
|
+
|
|
114
|
+
**DONE:** переходи к ревью соответствия брифу.
|
|
115
|
+
|
|
116
|
+
**DONE_WITH_CONCERNS:** воркер закончил, но обозначил сомнения. Прочитай их до продолжения. Сомнения о корректности или scope — уладь до ревью. Наблюдения («файл разрастается») — зафиксируй (`wolf add --type lesson`, если переиспользуемо) и переходи к ревью.
|
|
117
|
+
|
|
118
|
+
**NEEDS_CONTEXT:** воркеру не хватило информации. Дай недостающий контекст и перезапусти.
|
|
119
|
+
|
|
120
|
+
**BLOCKED:** воркер не может завершить задачу. Оцени блокер:
|
|
121
|
+
1. Проблема контекста — дай больше контекста, перезапусти
|
|
122
|
+
2. Задача требует больше рассуждений — поднимись на уровень выше тирингом
|
|
123
|
+
3. Задача слишком велика — разбей на меньшие части
|
|
124
|
+
4. План сам ошибочен — эскалируй владельцу
|
|
125
|
+
|
|
126
|
+
**Никогда** не игнорируй эскалацию и не заставляй ту же модель ретраить без изменений. Если воркер сказал, что застрял, — что-то должно измениться.
|
|
127
|
+
|
|
128
|
+
## Пример цикла
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
Ты: использую wolf-sdd для исполнения плана.
|
|
132
|
+
|
|
133
|
+
[Читаю план один раз: docs/plans/feature-plan.md]
|
|
134
|
+
[Извлекаю все 5 задач с полным текстом и контекстом]
|
|
135
|
+
[Заведи {{tool.todowrite}} со всеми задачами]
|
|
136
|
+
|
|
137
|
+
Задача 1: скрипт установки хука.
|
|
138
|
+
|
|
139
|
+
[Спавню worker-implementer через executor-lead: полный текст задачи + контекст]
|
|
140
|
+
|
|
141
|
+
Воркер: «До старта — хук ставится на уровне пользователя или системы?»
|
|
142
|
+
Ты: «На уровне пользователя.»
|
|
143
|
+
|
|
144
|
+
Воркер: [позже]
|
|
145
|
+
- Реализовал команду install-hook
|
|
146
|
+
- Тесты 5/5 зелёные
|
|
147
|
+
- Само-ревью: заметил пропуск --force, добавил
|
|
148
|
+
- Закоммитил
|
|
149
|
+
|
|
150
|
+
[Спавню worker-reviewer, стадия 1: соответствие брифу]
|
|
151
|
+
Ревьюер: ✅ Соответствует брифу — все требования закрыты, лишнего нет.
|
|
152
|
+
|
|
153
|
+
[Спавню worker-reviewer, стадия 2: качество кода]
|
|
154
|
+
Ревьюер: Сильные стороны: покрытие тестами, чисто. Замечаний нет. Approved.
|
|
155
|
+
|
|
156
|
+
[Отмечаю задачу 1 завершённой]
|
|
157
|
+
... [далее задачи 2..N аналогично, финальное ревью всего исполнения]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Преимущества и цена
|
|
161
|
+
|
|
162
|
+
**vs ручное исполнение:** воркеры естественно следуют TDD; свежий контекст на задачу (без путаницы); параллельная безопасность (воркеры не мешают друг другу — но НЕ диспетчь несколько исполнителей concurrently, конфликты); воркер может задавать вопросы до и во время работы.
|
|
163
|
+
|
|
164
|
+
**vs wolf-execute:** та же сессия (без handoff); непрерывный прогресс; ревью-чекпоинты автоматичны.
|
|
165
|
+
|
|
166
|
+
**Эффективность:** нет накладных расходов на чтение файлов (диспетчер даёт полный текст); диспетчер курирует ровно нужный контекст; вопросы всплывают до работы, а не после.
|
|
167
|
+
|
|
168
|
+
**Гейты качества:** само-ревью ловит проблемы до сдачи; двухстадийное ревью (бриф → качество); циклы ревью гарантируют, что правки реально работают; соответствие брифу страхует от over/under-building; стадия качества — что реализация хорошо сделана.
|
|
169
|
+
|
|
170
|
+
**Цена:** больше вызовов воркеров (исполнитель + 2 ревью на задачу); диспетчер готовит больше (извлечение всех задач upfront); циклы ревью добавляют итераций; но ловят проблемы рано (дешевле, чем дебаг потом).
|
|
171
|
+
|
|
172
|
+
## Red Flags
|
|
173
|
+
|
|
174
|
+
**Никогда:**
|
|
175
|
+
- Не начинай исполнение в main без явного согласия владельца (работа — только в worktree-ветке)
|
|
176
|
+
- Не пропускай ревью (соответствие брифу ИЛИ качество — оба обязательны)
|
|
177
|
+
- Не продолжай с незакрытыми замечаниями
|
|
178
|
+
- Не диспетчь несколько воркеров-исполнителей параллельно (конфликты)
|
|
179
|
+
- Не заставляй воркера читать файл плана (давай полный текст)
|
|
180
|
+
- Не пропускай установочный контекст (воркер обязан понимать, куда задача встраивается)
|
|
181
|
+
- Не игнорируй вопросы воркера (ответь до продолжения работы)
|
|
182
|
+
- Не принимай «примерно соответствует» по брифу (ревьюер нашёл проблемы = не готово)
|
|
183
|
+
- Не пропускай циклы ревью (ревьюер нашёл = воркер правит = ревью заново)
|
|
184
|
+
- Не позволяй само-ревью воркера заменить настоящее ревью (нужно и то и другое)
|
|
185
|
+
- **Не начинай ревью качества до ✅ по соответствию брифу** (порядок нарушен)
|
|
186
|
+
- Не переходи к следующей задаче, пока любое из ревью имеет открытые замечания
|
|
187
|
+
|
|
188
|
+
**Если воркер задаёт вопросы:**
|
|
189
|
+
- Отвечай ясно и полностью
|
|
190
|
+
- Дай дополнительный контекст при необходимости
|
|
191
|
+
- Не подгоняй его к реализации
|
|
192
|
+
|
|
193
|
+
**Если ревьюер нашёл проблемы:**
|
|
194
|
+
- Правит тот же воркер-исполнитель
|
|
195
|
+
- Ревьюер смотрит снова
|
|
196
|
+
- Повторять до аппрува
|
|
197
|
+
- Не пропускай повторное ревью
|
|
198
|
+
|
|
199
|
+
**Если воркер завалил задачу:**
|
|
200
|
+
- Спавнь чинящего воркера с точными инструкциями
|
|
201
|
+
- Не чини сам (загрязнение контекста)
|
|
202
|
+
|
|
203
|
+
## Интеграция
|
|
204
|
+
|
|
205
|
+
**Обязательные скиллы воркфлоу:**
|
|
206
|
+
- **using-git-worktrees** — REQUIRED: изолированный worktree `.worktrees/<имя-задачи>` ДО старта исполнения
|
|
207
|
+
- **wolf-plan** — создаёт план, который этот скилл исполняет
|
|
208
|
+
- **requesting-code-review** — рамка ревью для воркеров-ревьюеров
|
|
209
|
+
- **finishing-a-development-branch** — завершение разработки после всех задач
|
|
210
|
+
|
|
211
|
+
**Воркеры используют:**
|
|
212
|
+
- **test-driven-development** — воркеры следуют TDD на каждой задаче
|
|
213
|
+
|
|
214
|
+
**Альтернатива:**
|
|
215
|
+
- **wolf-execute** — линейное исполнение без субагентов, когда диспетчеризация недоступна
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Трассировка адаптации
|
|
220
|
+
|
|
221
|
+
> Источник: `~/.config/opencode/superpowers/skills/subagent-driven-development/SKILL.md`, upstream 6efe32c (2026-04-23)
|
|
222
|
+
|
|
223
|
+
| Пункт источника | Судьба | Почему |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| «Fresh subagent per task + two-stage review» | сохранено | Ядро принципа |
|
|
226
|
+
| «Why subagents» (изоляция контекста) | сохранено | Ядро |
|
|
227
|
+
| When-to-use флоучарт | сохранено; executing-plans → wolf-execute | Рёбра набора |
|
|
228
|
+
| Process-флоучарт | сохранено; диспетч субагентов → executor-lead/worker-implementer/worker-reviewer; TodoWrite → `{{tool.todowrite}}` | Research §1: диспетч субагентов непереносим — заменён ролями Wolf |
|
|
229
|
+
| Model Selection | заменено → тиринг проекта без имён моделей | Research §1: выбор моделей непереносим |
|
|
230
|
+
| Implementer Status (DONE/DONE_WITH_CONCERNS/NEEDS_CONTEXT/BLOCKED) | сохранено полностью (4/4) | Контракт статусов воркера |
|
|
231
|
+
| Prompt-templates (3 sibling-файла) | отброшено | Файлы каталога скилла не переносятся; заменено ролями worker-* |
|
|
232
|
+
| Example Workflow | сжато сохранено; сущность цикла сохранена | Иллюстрация |
|
|
233
|
+
| Advantages/Cost | сохранено сжато | Ядро |
|
|
234
|
+
| Red Flags «Never» (12) | сохранено полностью (12/12); main/master → trunk-based формулировка | H7 |
|
|
235
|
+
| «Если спрашивает / нашёл / завалил» (3+4+2) | сохранено полностью (9/9) | H7 |
|
|
236
|
+
| Integration | заменено: worktrees → H5-предусловие `.worktrees/<имя-задачи>`; writing-plans → wolf-plan; code-reviewer → worker-reviewer; TDD — воркерам | Wolf-переплетение |
|
|
237
|
+
| — | добавлено: REQUIRED-предусловие worktree (H5) | Спека §5.2 |
|
|
238
|
+
|
|
239
|
+
Перенесённые списки: «Never» 12/12, вспомогательные 3+4+2 (9/9), статусы воркера 4/4.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Harness-specific templates (opencode plugins). Content ships in phase B.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mr.Wolf router plugin (шаблон базового набора, спека §5.4).
|
|
3
|
+
*
|
|
4
|
+
* Слой доставки №1 playbook-контекста (канон §7.1): детерминированная
|
|
5
|
+
* доставка вместо вероятностного wolf search агентом. Маркер
|
|
6
|
+
* `agent-id: <id>` В ТЕЛЕ рамки агента (frontmatter в system-промпт не
|
|
7
|
+
* попадает — известная грабля) → wolf search --type playbook → get +
|
|
8
|
+
* гвард owner_skill === agentId | `skill:${agentId}` (legacy) → максимальная
|
|
9
|
+
* version → инжект в system-промпт на каждое сообщение.
|
|
10
|
+
*
|
|
11
|
+
* Fallback — слой доставки №2: если плагин ничего не нашёл, рамка сама зовёт
|
|
12
|
+
* `wolf search` (см. рамки агентов базового набора). Реестр доставок = сами
|
|
13
|
+
* playbook-объекты через owner_skill, отдельного конфига нет.
|
|
14
|
+
*
|
|
15
|
+
* Ноль зависимостей (Node stdlib; ai-sdk НЕ используется). Fail-safe: всё в
|
|
16
|
+
* try/catch — плагин не имеет права уронить сессию (лог: .wolf/router.log —
|
|
17
|
+
* agent-id, hit/miss, injected). Через этот файл при рендере проходят
|
|
18
|
+
* подстановка {{tool.*}} и штамп `// wolf:rendered` (ставит рендерер).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import path from 'path';
|
|
22
|
+
import fs from 'fs';
|
|
23
|
+
import { execFile } from 'child_process';
|
|
24
|
+
import { promisify } from 'util';
|
|
25
|
+
import { fileURLToPath } from 'url';
|
|
26
|
+
|
|
27
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const PROJECT_ROOT = path.join(__dirname, '..', '..');
|
|
29
|
+
const LOCAL_CLI = path.join(PROJECT_ROOT, 'dist', 'bootstrap', 'cli.js');
|
|
30
|
+
const LOG = path.join(PROJECT_ROOT, '.wolf', 'router.log');
|
|
31
|
+
const INJECT_HEADER =
|
|
32
|
+
'# Актуальный playbook (источник: память Wolf, доставлен плагином; обязательный формат ответа)';
|
|
33
|
+
// [ \t] вместо \s: \s съедает переводы строк и вытаскивает id с чужой строки.
|
|
34
|
+
const AGENT_ID_RE = /^agent-id:[ \t]*([\w-]+)[ \t]*$/m;
|
|
35
|
+
const CACHE_TTL_MS = 2500;
|
|
36
|
+
|
|
37
|
+
const run = promisify(execFile);
|
|
38
|
+
// execFile: args array, no shell. Целевой проект — глобальный `wolf`;
|
|
39
|
+
// догфуд в репо Wolf — локальный dist. Ошибка обоих → исключение наверх (fail-safe).
|
|
40
|
+
const runWolf = (args: string[]): Promise<{ stdout: string }> => {
|
|
41
|
+
const opts = { cwd: PROJECT_ROOT, timeout: 5000 };
|
|
42
|
+
return run('wolf', args, opts).catch(() => run('node', [LOCAL_CLI, ...args], opts));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function logRoute(line: string): void {
|
|
46
|
+
try {
|
|
47
|
+
fs.mkdirSync(path.dirname(LOG), { recursive: true });
|
|
48
|
+
fs.appendFileSync(LOG, `${new Date().toISOString()} ${line}\n`);
|
|
49
|
+
} catch {
|
|
50
|
+
/* fail-safe */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ponytail: per-agent кэш 2.5с — свежесть между сообщениями, без CLI-спавна на каждый чих.
|
|
55
|
+
const cache = new Map<string, { value: string | null; at: number }>();
|
|
56
|
+
|
|
57
|
+
async function resolvePlaybook(agentId: string): Promise<string | null> {
|
|
58
|
+
const hit = cache.get(agentId);
|
|
59
|
+
if (hit && Date.now() - hit.at < CACHE_TTL_MS) return hit.value;
|
|
60
|
+
let body: string | null = null;
|
|
61
|
+
try {
|
|
62
|
+
const { stdout } = await runWolf(['search', agentId, '--type', 'playbook', '--hide-superseded']);
|
|
63
|
+
const ids = [...stdout.matchAll(/^([\w-]+) \[playbook\]/gm)].map((m) => m[1]);
|
|
64
|
+
let best: { body?: string } | null = null;
|
|
65
|
+
let bestVersion = -1;
|
|
66
|
+
for (const id of ids) {
|
|
67
|
+
const { stdout: json } = await runWolf(['get', id]);
|
|
68
|
+
const obj = JSON.parse(json);
|
|
69
|
+
const owner = obj.owner_skill ?? obj.extra?.owner_skill;
|
|
70
|
+
if (owner !== agentId && owner !== `skill:${agentId}`) continue; // гвард владельца
|
|
71
|
+
const version = Number(String(obj.version ?? '').match(/\d+/)?.[0] ?? 0);
|
|
72
|
+
if (version > bestVersion) {
|
|
73
|
+
bestVersion = version;
|
|
74
|
+
best = obj;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
body = best?.body ?? null;
|
|
78
|
+
} catch {
|
|
79
|
+
/* fail-safe: без playbook — рамка работает через wolf search */
|
|
80
|
+
}
|
|
81
|
+
cache.set(agentId, { value: body, at: Date.now() });
|
|
82
|
+
return body;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const WolfPlaybookPlugin = async () => ({
|
|
86
|
+
'experimental.chat.system.transform': async (_input, output) => {
|
|
87
|
+
try {
|
|
88
|
+
const joined = output.system.join('\n');
|
|
89
|
+
const m = joined.match(AGENT_ID_RE);
|
|
90
|
+
if (!m) return; // рамка без маркера — не наша забота
|
|
91
|
+
if (joined.includes(INJECT_HEADER)) return; // идемпотентность: не вставляем дважды
|
|
92
|
+
const agentId = m[1];
|
|
93
|
+
const body = await resolvePlaybook(agentId);
|
|
94
|
+
if (!body) {
|
|
95
|
+
logRoute(`agent-id=${agentId} playbook=miss injected=no`);
|
|
96
|
+
return; // fail-safe: fallback на wolf search самой рамкой
|
|
97
|
+
}
|
|
98
|
+
output.system.push(`\n\n${INJECT_HEADER}\n\n${body}`);
|
|
99
|
+
logRoute(`agent-id=${agentId} playbook=hit injected=yes`);
|
|
100
|
+
} catch {
|
|
101
|
+
/* fail-safe: не роняем сессию */
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
});
|