@michaelbel/cuckcoder-mcp 1.6.12 → 1.6.14

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 (40) hide show
  1. package/assets/agents/architect-auditor.md +182 -0
  2. package/assets/agents/bug-hunter.md +185 -0
  3. package/assets/agents/build-engineer.md +148 -0
  4. package/assets/agents/business-analyst.md +178 -0
  5. package/assets/agents/code-refine.md +150 -0
  6. package/assets/agents/code-reviewer.md +180 -0
  7. package/assets/agents/compose-builder.md +192 -0
  8. package/assets/agents/device-ui-tester.md +133 -0
  9. package/assets/agents/devops-expert.md +177 -0
  10. package/assets/agents/explorer.md +132 -0
  11. package/assets/agents/github-project-manager.md +203 -0
  12. package/assets/agents/guide-android-builder.md +81 -0
  13. package/assets/agents/guide-writer.md +63 -0
  14. package/assets/agents/kotlin-engineer.md +215 -0
  15. package/assets/agents/mechanical-operator.md +166 -0
  16. package/assets/agents/notion-project-manager.md +185 -0
  17. package/assets/agents/performance-reviewer.md +188 -0
  18. package/assets/agents/security-auditor.md +203 -0
  19. package/assets/agents/swift-engineer.md +223 -0
  20. package/assets/agents/swiftui-builder.md +236 -0
  21. package/assets/agents/tech-writer.md +214 -0
  22. package/assets/agents/ux-reviewer.md +235 -0
  23. package/assets/rules/kotlin-datetime.md +10 -0
  24. package/assets/rules/resource.md +7 -1
  25. package/assets/workflows/architecture-sweep.js +98 -0
  26. package/assets/workflows/business-feature-sweep.js +218 -0
  27. package/assets/workflows/full-review.js +190 -0
  28. package/assets/workflows/mvi-compliance-sweep.js +74 -0
  29. package/assets/workflows/redesign-sweep.js +152 -0
  30. package/assets/workflows/refactoring-sweep.js +199 -0
  31. package/assets/workflows/security-sweep.js +98 -0
  32. package/assets/workflows/task-batch-create.js +104 -0
  33. package/dist/search.js +38 -0
  34. package/dist/server.js +161 -2
  35. package/dist/source/bundled.js +78 -0
  36. package/dist/source/github-source.js +76 -0
  37. package/dist/validation.js +16 -0
  38. package/dist/workflow-meta.js +29 -0
  39. package/package.json +1 -1
  40. package/assets/rules/app-badging.md +0 -170
@@ -0,0 +1,218 @@
1
+ export const meta = {
2
+ name: 'business-feature-sweep',
3
+ description:
4
+ 'Реализация фичи целиком: параллельный research (архитектура/UX/security/бизнес/ ' +
5
+ 'devops), план, DoD/DoR-спека, параллельная реализация по платформам в ' +
6
+ 'изолированных worktree на feature-ветке и валидация сборки/тестов против спеки.',
7
+ whenToUse: 'Новая фича, новый экран, новый endpoint — новая фича, новый экран, доработка.',
8
+ }
9
+
10
+ // ── args ────────────────────────────────────────────────────────────────
11
+ // request : описание фичи от пользователя (обязателен)
12
+ // baseBranch : ветка, от которой бранчеваться (по умолчанию 'main')
13
+ const A = typeof args === 'string' ? JSON.parse(args) || {} : args || {}
14
+ const REQUEST = A.request || ''
15
+ const BASE_BRANCH = A.baseBranch || 'main'
16
+
17
+ if (!REQUEST) {
18
+ return { status: 'skipped', reason: 'Не передано описание фичи.' }
19
+ }
20
+
21
+ phase('Research')
22
+ const lenses = [
23
+ {
24
+ role: 'architecture',
25
+ agentType: 'cuckcoder:architect-auditor',
26
+ focus:
27
+ 'как эта фича впишется в существующие границы модулей, слои и ' +
28
+ 'зависимости без нарушения инвариантов',
29
+ },
30
+ {
31
+ role: 'ux',
32
+ agentType: 'cuckcoder:ux-reviewer',
33
+ focus:
34
+ 'необходимые визуальные состояния (loading/empty/error/offline/populated), ' +
35
+ 'навигация, accessibility и консистентность с соседними экранами',
36
+ },
37
+ {
38
+ role: 'security',
39
+ agentType: 'cuckcoder:security-auditor',
40
+ focus: 'авторизация, валидация ввода, секреты и другие риски, которые вносит эта фича',
41
+ },
42
+ {
43
+ role: 'business',
44
+ agentType: 'cuckcoder:business-analyst',
45
+ focus:
46
+ 'scope, ожидаемые пользователи, критерии успеха и любая неоднозначность ' +
47
+ 'или пропущенные acceptance criteria в запросе',
48
+ },
49
+ {
50
+ role: 'devops',
51
+ agentType: 'cuckcoder:devops-expert',
52
+ focus: 'конфигурация, feature flags, окружения и вопросы rollout/релиза',
53
+ },
54
+ ]
55
+
56
+ const findings = await parallel(
57
+ lenses.map((l) => () =>
58
+ agent(
59
+ `Запрос на фичу: "${REQUEST}". Твоя линза — ${l.role}: ${l.focus}.
60
+ Исследуй кодовую базу (read, grep) на предмет того, что важно для
61
+ этой фичи с твоей точки зрения. Верни analysis, concerns/риски и
62
+ конкретные recommendations.`,
63
+ {
64
+ label: `research:${l.role}`,
65
+ phase: 'Research',
66
+ agentType: l.agentType,
67
+ schema: {
68
+ type: 'object',
69
+ required: ['analysis', 'concerns', 'recommendations'],
70
+ properties: {
71
+ analysis: { type: 'string' },
72
+ concerns: { type: 'array', items: { type: 'string' } },
73
+ recommendations: { type: 'array', items: { type: 'string' } },
74
+ },
75
+ },
76
+ },
77
+ ),
78
+ ),
79
+ )
80
+
81
+ phase('Plan')
82
+ const plan = await agent(
83
+ `Собери план реализации фичи "${REQUEST}" по этому research:
84
+ ${JSON.stringify(findings.filter(Boolean))}
85
+ Дай пошаговые steps, какие слои платформы затронуты (shared-kotlin,
86
+ android-compose, ios-swift, ios-swiftui — любое подмножество) и
87
+ ключевые риски.`,
88
+ {
89
+ label: 'plan',
90
+ phase: 'Plan',
91
+ schema: {
92
+ type: 'object',
93
+ required: ['steps', 'affectedLayers', 'risks'],
94
+ properties: {
95
+ steps: { type: 'array', items: { type: 'string' } },
96
+ affectedLayers: {
97
+ type: 'array',
98
+ items: {
99
+ type: 'string',
100
+ enum: ['shared-kotlin', 'android-compose', 'ios-swift', 'ios-swiftui'],
101
+ },
102
+ },
103
+ risks: { type: 'array', items: { type: 'string' } },
104
+ },
105
+ },
106
+ },
107
+ )
108
+
109
+ phase('Spec')
110
+ const spec = await agent(
111
+ `Напиши контракт приёмки для фичи "${REQUEST}".
112
+ План: ${JSON.stringify(plan)}
113
+ UX-research: ${JSON.stringify(findings.find((f) => f))}
114
+ Дай: DoD (что значит "готово"), DoR (что должно быть готово до старта),
115
+ каждое обязательное визуальное состояние (loading, empty, error,
116
+ offline, populated), edge cases и бизнес-правила/инварианты. Ничто в
117
+ Executing не может пропустить состояние или edge case из этого списка.`,
118
+ {
119
+ label: 'spec',
120
+ phase: 'Spec',
121
+ agentType: 'cuckcoder:business-analyst',
122
+ schema: {
123
+ type: 'object',
124
+ required: ['dod', 'dor', 'states', 'edgeCases'],
125
+ properties: {
126
+ dod: { type: 'array', items: { type: 'string' } },
127
+ dor: { type: 'array', items: { type: 'string' } },
128
+ states: {
129
+ type: 'object',
130
+ properties: {
131
+ loading: { type: 'string' },
132
+ empty: { type: 'string' },
133
+ error: { type: 'string' },
134
+ offline: { type: 'string' },
135
+ populated: { type: 'string' },
136
+ },
137
+ },
138
+ edgeCases: { type: 'array', items: { type: 'string' } },
139
+ },
140
+ },
141
+ },
142
+ )
143
+
144
+ phase('Executing')
145
+ const affectedLayers =
146
+ plan.affectedLayers && plan.affectedLayers.length ? plan.affectedLayers : ['shared-kotlin']
147
+ const layerAgents = {
148
+ 'shared-kotlin': 'cuckcoder:kotlin-engineer',
149
+ 'android-compose': 'cuckcoder:compose-builder',
150
+ 'ios-swift': 'cuckcoder:swift-engineer',
151
+ 'ios-swiftui': 'cuckcoder:swiftui-builder',
152
+ }
153
+
154
+ const branchSlug = REQUEST.toLowerCase()
155
+ .replace(/[^a-z0-9]+/g, '-')
156
+ .slice(0, 40)
157
+ .replace(/(^-|-$)/g, '')
158
+
159
+ const execResults = await parallel(
160
+ affectedLayers.map((layer) => () =>
161
+ agent(
162
+ `Реализуй свою часть фичи "${REQUEST}" на слое "${layer}".
163
+ Ветвись от origin/${BASE_BRANCH}: git fetch origin ${BASE_BRANCH} &&
164
+ git checkout -b feature/${branchSlug} origin/${BASE_BRANCH}.
165
+ План: ${JSON.stringify(plan)}
166
+ Спека (DoD/DoR): ${JSON.stringify(spec)}
167
+ Реализуй каждое состояние и edge case из спеки, а не только happy
168
+ path. Верни изменённые файлы и summary реализованного.`,
169
+ {
170
+ label: `execute:${layer}`,
171
+ phase: 'Executing',
172
+ agentType: layerAgents[layer] || 'cuckcoder:kotlin-engineer',
173
+ isolation: 'worktree',
174
+ schema: {
175
+ type: 'object',
176
+ required: ['changedFiles', 'summary'],
177
+ properties: {
178
+ changedFiles: { type: 'array', items: { type: 'string' } },
179
+ summary: { type: 'string' },
180
+ },
181
+ },
182
+ },
183
+ ),
184
+ ),
185
+ )
186
+
187
+ phase('Validate')
188
+ const changedFiles = execResults.filter(Boolean).flatMap((r) => r.changedFiles || [])
189
+ const validation = await agent(
190
+ `Провалидируй фичу "${REQUEST}". Изменённые файлы: ${JSON.stringify(changedFiles)}.
191
+ Спека: ${JSON.stringify(spec)}.
192
+ Собери проект и запусти тесты. Затем сверь со спекой: реализовано ли
193
+ каждое перечисленное состояние и edge case? Верни passed, buildPassed,
194
+ dodChecked (boolean) и details.`,
195
+ {
196
+ label: 'validate',
197
+ phase: 'Validate',
198
+ agentType: 'cuckcoder:build-engineer',
199
+ schema: {
200
+ type: 'object',
201
+ required: ['passed', 'buildPassed', 'dodChecked', 'details'],
202
+ properties: {
203
+ passed: { type: 'boolean' },
204
+ buildPassed: { type: 'boolean' },
205
+ dodChecked: { type: 'boolean' },
206
+ details: { type: 'string' },
207
+ },
208
+ },
209
+ },
210
+ )
211
+
212
+ return {
213
+ status: validation && validation.passed ? 'done' : 'partial',
214
+ plan,
215
+ spec,
216
+ execResults: execResults.filter(Boolean),
217
+ validation,
218
+ }
@@ -0,0 +1,190 @@
1
+ export const meta = {
2
+ name: 'full-review',
3
+ description:
4
+ 'Мульти-линзовое ревью диффа, ветки или PR: собирает изменение, параллельно ' +
5
+ 'прогоняет correctness/security/performance/architecture/UX-ревью и сводит ' +
6
+ 'всё в один приоритизированный отчёт.',
7
+ whenToUse:
8
+ 'Полное ревью изменений или GitHub PR перед мёрджем — code-review, ревью PR, ' +
9
+ 'отревьюй диф.',
10
+ }
11
+
12
+ // ── args ────────────────────────────────────────────────────────────────
13
+ // target : 'branch' (по умолчанию, дифф от base) | 'staged' | 'pr:<N>'
14
+ // base : базовая ветка для target='branch' (по умолчанию 'main')
15
+ // postComments : постить ли инлайн-комменты в PR (только при target='pr:<N>',
16
+ // по умолчанию false)
17
+ const A = typeof args === 'string' ? JSON.parse(args) || {} : args || {}
18
+ const TARGET = A.target || 'branch'
19
+ const BASE = A.base || 'main'
20
+ const POST_COMMENTS = !!A.postComments
21
+
22
+ const PR_MATCH = /^pr:(.+)$/.exec(TARGET)
23
+ const PR_NUMBER = PR_MATCH ? PR_MATCH[1] : null
24
+
25
+ const diffCmd = PR_NUMBER
26
+ ? `gh pr diff ${PR_NUMBER} (файлы: gh pr diff ${PR_NUMBER} --name-only; метаданные: ` +
27
+ `gh pr view ${PR_NUMBER} --json title,body,baseRefName,headRefName,files)`
28
+ : TARGET === 'staged'
29
+ ? 'git diff --staged (файлы: git diff --staged --name-only)'
30
+ : `git diff ${BASE}..HEAD (файлы: git diff ${BASE}..HEAD --name-only)`
31
+
32
+ phase('Diff')
33
+ const diff = await agent(
34
+ `Собери набор изменений для этого ревью. Target: ${TARGET}.
35
+ Выполни: ${diffCmd}.
36
+ Верни hasChanges, краткое summary того, что делает изменение (title/description
37
+ из "gh pr view", если это PR), список изменённых файлов и сам unified diff
38
+ (при большом объёме — усеки, оставив содержательные хунки). Ничего не меняй —
39
+ только сбор данных.`,
40
+ {
41
+ label: 'collect-diff',
42
+ phase: 'Diff',
43
+ model: 'sonnet',
44
+ schema: {
45
+ type: 'object',
46
+ required: ['hasChanges', 'summary', 'files'],
47
+ properties: {
48
+ hasChanges: { type: 'boolean' },
49
+ summary: { type: 'string' },
50
+ files: { type: 'array', items: { type: 'string' } },
51
+ diff: { type: 'string' },
52
+ },
53
+ },
54
+ },
55
+ )
56
+
57
+ if (!diff || diff.hasChanges === false || !(diff.files && diff.files.length)) {
58
+ return { status: 'no-changes', target: TARGET, findings: [] }
59
+ }
60
+
61
+ phase('Review')
62
+ const FINDING_SCHEMA = {
63
+ type: 'object',
64
+ required: ['severity', 'location', 'summary', 'fix'],
65
+ properties: {
66
+ severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low', 'info'] },
67
+ location: { type: 'string' },
68
+ summary: { type: 'string' },
69
+ fix: { type: 'string' },
70
+ },
71
+ }
72
+
73
+ const lenses = [
74
+ { dimension: 'correctness', agentType: 'cuckcoder:code-reviewer' },
75
+ { dimension: 'security', agentType: 'cuckcoder:security-auditor' },
76
+ { dimension: 'performance', agentType: 'cuckcoder:performance-reviewer' },
77
+ { dimension: 'architecture', agentType: 'cuckcoder:architect-auditor' },
78
+ { dimension: 'ux', agentType: 'cuckcoder:ux-reviewer' },
79
+ ]
80
+
81
+ const perDimension = await parallel(
82
+ lenses.map((lens) => () =>
83
+ agent(
84
+ `Проревьюй этот дифф только в зоне своей ответственности. Не повторяй
85
+ находки, относящиеся к другой дисциплине.
86
+
87
+ Summary изменения: ${diff.summary}
88
+ Изменённые файлы: ${JSON.stringify(diff.files)}
89
+ Diff: ${diff.diff || '(прочитай сам через ' + diffCmd + ')'}
90
+
91
+ Указывай только находки, которые видны конкретно в диффе. Если сказать
92
+ нечего — верни пустой массив, не выдумывай общие советы.`,
93
+ {
94
+ label: `review:${lens.dimension}`,
95
+ phase: 'Review',
96
+ agentType: lens.agentType,
97
+ schema: {
98
+ type: 'object',
99
+ required: ['findings'],
100
+ properties: { findings: { type: 'array', items: FINDING_SCHEMA } },
101
+ },
102
+ },
103
+ ).then((result) =>
104
+ result ? result.findings.map((f) => ({ dimension: lens.dimension, ...f })) : [],
105
+ ),
106
+ ),
107
+ )
108
+
109
+ const findings = perDimension.flat()
110
+
111
+ phase('Synthesize')
112
+ let synthesis = {
113
+ verdict: 'APPROVE',
114
+ findings: [],
115
+ summary: 'Находок нет ни по одному из пяти направлений ревью.',
116
+ }
117
+ if (findings.length > 0) {
118
+ synthesis = await agent(
119
+ `Вот находки из пяти независимых ревью (correctness, security, performance,
120
+ architecture, UX) одного и того же диффа:
121
+
122
+ ${JSON.stringify(findings, null, 2)}
123
+
124
+ Объедини дублирующиеся или пересекающиеся находки (оставь максимальный
125
+ severity и перечисли все направления-источники), убери всё, что не
126
+ вызвано этим диффом, отсортируй по severity и напиши короткое
127
+ приоритизированное summary. Правило verdict: любая critical или high
128
+ находка → REQUEST_CHANGES; только medium/low → COMMENT; только info
129
+ или пусто → APPROVE.`,
130
+ {
131
+ label: 'synthesize',
132
+ phase: 'Synthesize',
133
+ schema: {
134
+ type: 'object',
135
+ required: ['verdict', 'findings', 'summary'],
136
+ properties: {
137
+ verdict: { type: 'string', enum: ['APPROVE', 'COMMENT', 'REQUEST_CHANGES'] },
138
+ findings: {
139
+ type: 'array',
140
+ items: {
141
+ type: 'object',
142
+ required: ['severity', 'location', 'summary', 'fix', 'dimensions'],
143
+ properties: {
144
+ severity: { type: 'string' },
145
+ location: { type: 'string' },
146
+ summary: { type: 'string' },
147
+ fix: { type: 'string' },
148
+ dimensions: { type: 'array', items: { type: 'string' } },
149
+ },
150
+ },
151
+ },
152
+ summary: { type: 'string' },
153
+ },
154
+ },
155
+ },
156
+ )
157
+ }
158
+
159
+ let commentResult = null
160
+ if (POST_COMMENTS && PR_NUMBER && synthesis.findings.length > 0) {
161
+ phase('Comment')
162
+ commentResult = await agent(
163
+ `Запости это ревью инлайн-комментариями в PR #${PR_NUMBER} через gh CLI.
164
+ Находки: ${JSON.stringify(synthesis.findings)}.
165
+ Для каждой находки добавь инлайн-коммент на file:line через
166
+ "gh api repos/:owner/:repo/pulls/${PR_NUMBER}/comments" (или
167
+ "gh pr review ${PR_NUMBER} --comment" со сводным телом, если инлайн-позиция
168
+ не резолвится). Формат тела: "[severity][dimensions] summary → fix".
169
+ НЕ аппрувь, не мёрджи, не пуш и не меняй код — только оставляй
170
+ ревью-комментарии. Верни posted (boolean) и details.`,
171
+ {
172
+ label: 'comment-pr',
173
+ phase: 'Comment',
174
+ schema: {
175
+ type: 'object',
176
+ required: ['posted', 'details'],
177
+ properties: { posted: { type: 'boolean' }, details: { type: 'string' } },
178
+ },
179
+ },
180
+ )
181
+ }
182
+
183
+ return {
184
+ status: 'reviewed',
185
+ target: TARGET,
186
+ verdict: synthesis.verdict,
187
+ summary: synthesis.summary,
188
+ findings: synthesis.findings,
189
+ comments: commentResult,
190
+ }
@@ -0,0 +1,74 @@
1
+ export const meta = {
2
+ name: 'mvi-compliance-sweep',
3
+ description:
4
+ 'Параллельная проверка каждого ViewModel и Screen на соответствие MVI-правилам ' +
5
+ 'этого репозитория с конкретными, обоснованными правилом нарушениями.',
6
+ }
7
+
8
+ const discovery = await agent(
9
+ `Найди каждую MVI-фичу в этом проекте: для каждой фичи — её ViewModel,
10
+ её Screen (Composable) и определения Intent/Model/Event/State, если
11
+ они вынесены в отдельные файлы. Сгруппируй их по фиче. Верни по одной
12
+ записи на фичу с её именем и списком относительных путей к файлам.`,
13
+ {
14
+ schema: {
15
+ type: 'object',
16
+ required: ['features'],
17
+ properties: {
18
+ features: {
19
+ type: 'array',
20
+ items: {
21
+ type: 'object',
22
+ required: ['name', 'files'],
23
+ properties: {
24
+ name: { type: 'string' },
25
+ files: { type: 'array', items: { type: 'string' } },
26
+ },
27
+ },
28
+ },
29
+ },
30
+ },
31
+ },
32
+ )
33
+
34
+ const perFeature = await pipeline(discovery.features, (feature) =>
35
+ agent(
36
+ `Вызови MCP-инструмент cuckcoder "get_rule" с именами "android/MVI_RULES",
37
+ "android/MVI_STATE_RULES" и "android/MVI_ERROR_HANDLING_RULES", чтобы
38
+ получить актуальные MVI-правила проекта. Затем проверь по этим
39
+ правилам только файлы фичи "${feature.name}":
40
+
41
+ ${feature.files.join('\n')}
42
+
43
+ Указывай только конкретные нарушения, которые видны в коде — цитируй
44
+ нарушающую строку и называй конкретное правило. Не сообщай о стиле,
45
+ не покрытом загруженными правилами. Если фича полностью соответствует
46
+ правилам, верни пустой массив.`,
47
+ {
48
+ label: feature.name,
49
+ schema: {
50
+ type: 'object',
51
+ required: ['violations'],
52
+ properties: {
53
+ violations: {
54
+ type: 'array',
55
+ items: {
56
+ type: 'object',
57
+ required: ['file', 'rule', 'description', 'fix'],
58
+ properties: {
59
+ file: { type: 'string' },
60
+ rule: { type: 'string' },
61
+ description: { type: 'string' },
62
+ fix: { type: 'string' },
63
+ },
64
+ },
65
+ },
66
+ },
67
+ },
68
+ },
69
+ ).then((result) =>
70
+ result ? result.violations.map((v) => ({ feature: feature.name, ...v })) : [],
71
+ ),
72
+ )
73
+
74
+ return perFeature.flat()
@@ -0,0 +1,152 @@
1
+ export const meta = {
2
+ name: 'redesign-sweep',
3
+ description:
4
+ 'Визуальный редизайн экрана или компонента: параллельный UX/архитектурный аудит ' +
5
+ 'текущего UI, design brief, реализация по платформам в изолированном worktree ' +
6
+ 'и проверка сборки. Бизнес-логика не трогается.',
7
+ whenToUse:
8
+ 'Редизайн UI без изменения поведения — редизайн, обнови дизайн экрана, ' +
9
+ 'поменяй стиль.',
10
+ }
11
+
12
+ // ── args ────────────────────────────────────────────────────────────────
13
+ // target : экран или компонент для редизайна (свободный текст, обязателен)
14
+ const A = typeof args === 'string' ? JSON.parse(args) || {} : args || {}
15
+ const TARGET = A.target || A.request || ''
16
+
17
+ if (!TARGET) {
18
+ return { status: 'skipped', reason: 'Не передан target — экран или компонент для редизайна.' }
19
+ }
20
+
21
+ phase('Design')
22
+ const lenses = [
23
+ {
24
+ role: 'ux',
25
+ agentType: 'cuckcoder:ux-reviewer',
26
+ focus:
27
+ 'текущие визуальные состояния (loading/empty/error/populated), навигация, ' +
28
+ 'accessibility, консистентность с соседними экранами и дизайн-системой',
29
+ },
30
+ {
31
+ role: 'architecture',
32
+ agentType: 'cuckcoder:architect-auditor',
33
+ focus:
34
+ 'насколько сильно визуальный слой связан с бизнес-логикой и состоянием, ' +
35
+ 'чтобы визуальное изменение осталось изолированным',
36
+ },
37
+ ]
38
+
39
+ const audits = await parallel(
40
+ lenses.map((l) => () =>
41
+ agent(
42
+ `Цель редизайна: "${TARGET}". Твоя линза — ${l.role}: ${l.focus}.
43
+ Проанализируй ТЕКУЩЕЕ состояние этого UI, читая реальный код.
44
+ Изменится только визуальный слой — бизнес-логика и поведение остаются
45
+ нетронутыми. Верни наблюдения и конкретные рекомендации.`,
46
+ {
47
+ label: `design:${l.role}`,
48
+ phase: 'Design',
49
+ agentType: l.agentType,
50
+ schema: {
51
+ type: 'object',
52
+ required: ['observations', 'recommendations'],
53
+ properties: {
54
+ observations: { type: 'string' },
55
+ recommendations: { type: 'array', items: { type: 'string' } },
56
+ },
57
+ },
58
+ },
59
+ ),
60
+ ),
61
+ )
62
+
63
+ const brief = await agent(
64
+ `Собери design brief для редизайна "${TARGET}".
65
+ Находки аудита: ${JSON.stringify(audits.filter(Boolean))}.
66
+ Перечисли компоненты к изменению, визуальные токены (цвет, типографика,
67
+ spacing, форма), какие платформы затронуты (android-compose и/или
68
+ ios-swiftui), и явный список того, что должно остаться неизменным
69
+ (вся бизнес-логика, обработка состояния и поведение). Каждый пункт —
70
+ атомарное визуальное изменение.`,
71
+ {
72
+ label: 'design-brief',
73
+ phase: 'Design',
74
+ schema: {
75
+ type: 'object',
76
+ required: ['components', 'platforms', 'unchanged'],
77
+ properties: {
78
+ components: { type: 'array', items: { type: 'string' } },
79
+ tokens: { type: 'string' },
80
+ platforms: {
81
+ type: 'array',
82
+ items: { type: 'string', enum: ['android-compose', 'ios-swiftui'] },
83
+ },
84
+ unchanged: { type: 'array', items: { type: 'string' } },
85
+ },
86
+ },
87
+ },
88
+ )
89
+
90
+ phase('Implement')
91
+ const platforms = brief.platforms && brief.platforms.length ? brief.platforms : ['android-compose']
92
+ const targets = platforms.map((p) =>
93
+ p === 'ios-swiftui'
94
+ ? { name: p, agentType: 'cuckcoder:swiftui-builder' }
95
+ : { name: p, agentType: 'cuckcoder:compose-builder' },
96
+ )
97
+
98
+ const impls = await parallel(
99
+ targets.map((t) => () =>
100
+ agent(
101
+ `Цель редизайна: "${TARGET}". Платформа: ${t.name}.
102
+ Design brief: ${JSON.stringify(brief)}.
103
+ Примени ТОЛЬКО визуальные изменения (стили, layout, токены) из этого
104
+ brief. НЕ трогай бизнес-логику, обработчики событий, состояние или
105
+ контракты навигации — они перечислены в "unchanged". Используй токены
106
+ дизайн-системы, а не захардкоженные значения. Верни изменённые файлы
107
+ и краткое summary.`,
108
+ {
109
+ label: `implement:${t.name}`,
110
+ phase: 'Implement',
111
+ agentType: t.agentType,
112
+ isolation: 'worktree',
113
+ schema: {
114
+ type: 'object',
115
+ required: ['changedFiles', 'summary'],
116
+ properties: {
117
+ changedFiles: { type: 'array', items: { type: 'string' } },
118
+ summary: { type: 'string' },
119
+ },
120
+ },
121
+ },
122
+ ),
123
+ ),
124
+ )
125
+
126
+ phase('Validate')
127
+ const changedFiles = impls.filter(Boolean).flatMap((r) => r.changedFiles || [])
128
+ const validation = await agent(
129
+ `Провалидируй этот редизайн. Изменённые файлы: ${JSON.stringify(changedFiles)}.
130
+ Собери проект (найди build-инструмент: gradlew, swift build и т.п.) и
131
+ убедись, что нет ошибок компиляции. Если в окружении доступен инструмент
132
+ скриншота устройства/эмулятора/симулятора — сделай один скриншот
133
+ "${TARGET}" после изменения для визуального подтверждения; иначе пропусти
134
+ этот шаг и напиши об этом. Верни passed (boolean) и details.`,
135
+ {
136
+ label: 'validate',
137
+ phase: 'Validate',
138
+ agentType: 'cuckcoder:build-engineer',
139
+ schema: {
140
+ type: 'object',
141
+ required: ['passed', 'details'],
142
+ properties: { passed: { type: 'boolean' }, details: { type: 'string' } },
143
+ },
144
+ },
145
+ )
146
+
147
+ return {
148
+ status: validation && validation.passed ? 'redesigned' : 'redesign-unverified',
149
+ brief,
150
+ changedFiles,
151
+ validation,
152
+ }