@bonesofspring/ai-rules 0.1.40 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/bin/cli.js +22 -1
- package/package.json +2 -1
- package/presets/claude/next/CLAUDE.md +11 -7
- package/presets/claude/next/README.md +2 -2
- package/presets/claude/next/agents/README.md +50 -1
- package/presets/claude/next/agents/accessibility-reviewer.md +65 -0
- package/presets/claude/next/agents/api-contract-reviewer.md +69 -0
- package/presets/claude/next/agents/build-verifier.md +62 -0
- package/presets/claude/next/agents/ci-investigator.md +62 -0
- package/presets/claude/next/agents/code-reviewer.md +7 -1
- package/presets/claude/next/agents/debugger.md +7 -2
- package/presets/claude/next/agents/feature-developer.md +11 -16
- package/presets/claude/next/agents/migration-specialist.md +69 -0
- package/presets/claude/next/agents/performance-auditor.md +68 -0
- package/presets/claude/next/agents/qa-tester.md +4 -2
- package/presets/claude/next/agents/security-reviewer.md +64 -0
- package/presets/claude/next/agents/task-analyst.md +6 -2
- package/presets/claude/next/agents/task-router.md +83 -16
- package/presets/claude/next/agents/tech-writer.md +60 -0
- package/presets/claude/next/agents/unit-test-generator.md +37 -0
- package/presets/claude/next/agents/unit-test-healer.md +38 -0
- package/presets/claude/next/agents/unit-test-planner.md +62 -0
- package/presets/claude/next/commands/README.md +1 -1
- package/presets/claude/next/commands/feature-continue.md +5 -0
- package/presets/claude/next/commands/feature-start.md +5 -0
- package/presets/claude/next/commands/task-continue.md +8 -2
- package/presets/claude/next/commands/task.md +10 -0
- package/presets/claude/next/commands/technical-retro.md +6 -1
- package/presets/claude/next/hooks/README.md +5 -8
- package/presets/claude/next/hooks/chain-team-phases.sh +258 -39
- package/presets/claude/next/hooks/guard-shell-command.sh +77 -0
- package/presets/claude/next/rules/README.md +20 -44
- package/presets/claude/next/rules/architecture/api-public-imports.md +6 -0
- package/presets/claude/next/rules/architecture/architecture-boundaries.md +5 -0
- package/presets/claude/next/rules/architecture/feature-delivery-workflow.md +5 -0
- package/presets/claude/next/rules/architecture/layer-barrel-exports.md +5 -0
- package/presets/claude/next/rules/architecture/reference-features.md +34 -0
- package/presets/claude/next/rules/architecture/types-public-imports.md +6 -0
- package/presets/claude/next/rules/stack/arrow-functions.md +5 -0
- package/presets/claude/next/rules/stack/navigation-router.md +5 -0
- package/presets/claude/next/rules/stack/next-app-router.md +36 -0
- package/presets/claude/next/rules/stack/no-type-assertion.md +6 -0
- package/presets/claude/next/rules/testing/playwright-agents.md +5 -0
- package/presets/claude/next/rules/tooling-and-review/agent-team-orchestrator.md +32 -8
- package/presets/claude/next/rules/ui-and-accessibility/component-styles.md +6 -0
- package/presets/claude/next/rules/ui-and-accessibility/css-property-order.md +6 -0
- package/presets/claude/next/rules/ui-and-accessibility/no-props-spread.md +5 -0
- package/presets/claude/next/rules/ui-and-accessibility/react-a11y-coding.md +37 -0
- package/presets/claude/next/skills/README.md +11 -1
- package/presets/claude/next/skills/ci-investigation/SKILL.md +36 -0
- package/presets/claude/next/skills/code-review/SKILL.md +26 -0
- package/presets/claude/next/skills/debug-investigation/SKILL.md +28 -0
- package/presets/claude/next/skills/feature-delivery/SKILL.md +30 -0
- package/presets/claude/next/skills/playwright-e2e/SKILL.md +31 -0
- package/presets/claude/next/skills/technical-retro/SKILL.md +40 -0
- package/presets/claude/next/skills/unit-testing/SKILL.md +32 -0
- package/presets/claude/next/team/README.md +25 -43
- package/presets/cursor/next/AGENTS.md +43 -0
- package/presets/cursor/next/BUGBOT.md +14 -0
- package/presets/cursor/next/agents/README.md +52 -0
- package/presets/cursor/next/agents/accessibility-reviewer.md +67 -0
- package/presets/cursor/next/agents/api-contract-reviewer.md +71 -0
- package/presets/cursor/next/agents/build-verifier.md +64 -0
- package/presets/cursor/next/agents/ci-investigator.md +64 -0
- package/presets/cursor/next/agents/code-reviewer.md +8 -1
- package/presets/cursor/next/agents/debugger.md +7 -2
- package/presets/cursor/next/agents/feature-developer.md +10 -8
- package/presets/cursor/next/agents/migration-specialist.md +71 -0
- package/presets/cursor/next/agents/performance-auditor.md +70 -0
- package/presets/cursor/next/agents/playwright-test-generator.md +26 -0
- package/presets/cursor/next/agents/playwright-test-healer.md +26 -0
- package/presets/cursor/next/agents/playwright-test-planner.md +28 -0
- package/presets/cursor/next/agents/qa-tester.md +4 -2
- package/presets/cursor/next/agents/security-reviewer.md +66 -0
- package/presets/cursor/next/agents/task-analyst.md +3 -2
- package/presets/cursor/next/agents/task-router.md +84 -17
- package/presets/cursor/next/agents/tech-writer.md +62 -0
- package/presets/cursor/next/agents/unit-test-generator.md +39 -0
- package/presets/cursor/next/agents/unit-test-healer.md +40 -0
- package/presets/cursor/next/agents/unit-test-planner.md +64 -0
- package/presets/cursor/next/commands/README.md +17 -1
- package/presets/cursor/next/commands/feature-continue.md +5 -0
- package/presets/cursor/next/commands/feature-start.md +5 -0
- package/presets/cursor/next/commands/task-continue.md +8 -2
- package/presets/cursor/next/commands/task.md +10 -0
- package/presets/cursor/next/commands/technical-retro.md +6 -1
- package/presets/cursor/next/hooks/README.md +8 -0
- package/presets/cursor/next/hooks/chain-team-phases.sh +192 -28
- package/presets/cursor/next/hooks/guard-shell-command.sh +77 -0
- package/presets/cursor/next/hooks.json +7 -1
- package/presets/cursor/next/rules/README.md +16 -6
- package/presets/cursor/next/rules/agent-team-orchestrator.mdc +32 -8
- package/presets/cursor/next/rules/api-public-imports.mdc +2 -1
- package/presets/cursor/next/rules/architecture-boundaries.mdc +2 -1
- package/presets/cursor/next/rules/arrow-functions.mdc +2 -1
- package/presets/cursor/next/rules/code-review-mr.mdc +1 -1
- package/presets/cursor/next/rules/css-property-order-stylelint.mdc +4 -1
- package/presets/cursor/next/rules/feature-delivery-flow.mdc +1 -1
- package/presets/cursor/next/rules/feature-delivery-workflow.mdc +2 -2
- package/presets/cursor/next/rules/layer-barrel-exports.mdc +2 -1
- package/presets/cursor/next/rules/navigation-router-stack.mdc +2 -1
- package/presets/cursor/next/rules/next-app-router.mdc +36 -0
- package/presets/cursor/next/rules/no-cross-component-styles-import.mdc +4 -1
- package/presets/cursor/next/rules/no-props-spread.mdc +1 -1
- package/presets/cursor/next/rules/no-type-assertion-as-import-export.mdc +2 -1
- package/presets/cursor/next/rules/playwright-agents.mdc +2 -1
- package/presets/cursor/next/rules/react-a11y-coding.mdc +37 -0
- package/presets/cursor/next/rules/reference-features.mdc +35 -0
- package/presets/cursor/next/rules/types-public-imports.mdc +2 -1
- package/presets/cursor/next/skills/README.md +15 -0
- package/presets/cursor/next/skills/ci-investigation/SKILL.md +36 -0
- package/presets/cursor/next/skills/code-review/SKILL.md +26 -0
- package/presets/cursor/next/skills/debug-investigation/SKILL.md +28 -0
- package/presets/cursor/next/skills/feature-delivery/SKILL.md +30 -0
- package/presets/cursor/next/skills/playwright-e2e/SKILL.md +31 -0
- package/presets/cursor/next/skills/technical-retro/SKILL.md +40 -0
- package/presets/cursor/next/skills/unit-testing/SKILL.md +32 -0
- package/presets/cursor/next/team/README.md +38 -40
|
@@ -10,6 +10,8 @@ INPUT="$input" node <<'NODE'
|
|
|
10
10
|
const fs = require('fs');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
|
|
13
|
+
const TEAM_ROOT = path.join(process.cwd(), '.cursor', 'team');
|
|
14
|
+
|
|
13
15
|
const inputRaw = process.env.INPUT || '';
|
|
14
16
|
let hookInput;
|
|
15
17
|
try {
|
|
@@ -24,8 +26,7 @@ if (hookInput.status !== 'completed') {
|
|
|
24
26
|
process.exit(0);
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
const
|
|
28
|
-
const activePath = path.join(teamRoot, 'active-task.json');
|
|
29
|
+
const activePath = path.join(TEAM_ROOT, 'active-task.json');
|
|
29
30
|
|
|
30
31
|
if (!fs.existsSync(activePath)) {
|
|
31
32
|
process.stdout.write('{}');
|
|
@@ -46,7 +47,7 @@ if (!slug) {
|
|
|
46
47
|
process.exit(0);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
const taskDir = path.join(
|
|
50
|
+
const taskDir = path.join(TEAM_ROOT, 'tasks', slug);
|
|
50
51
|
const statusPath = path.join(taskDir, 'status.json');
|
|
51
52
|
const pipelinePath = path.join(taskDir, 'pipeline.json');
|
|
52
53
|
|
|
@@ -74,58 +75,176 @@ function out(message) {
|
|
|
74
75
|
process.stdout.write(JSON.stringify({ followup_message: message }));
|
|
75
76
|
}
|
|
76
77
|
|
|
78
|
+
function readArtifact(name) {
|
|
79
|
+
const p = path.join(taskDir, name);
|
|
80
|
+
if (!fs.existsSync(p)) return '';
|
|
81
|
+
try {
|
|
82
|
+
return fs.readFileSync(p, 'utf8');
|
|
83
|
+
} catch {
|
|
84
|
+
return '';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getStepAgents(step) {
|
|
89
|
+
if (!step) return [];
|
|
90
|
+
return Array.isArray(step.agent) ? step.agent : [step.agent];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function skipIfMatches(skipIf, dir) {
|
|
94
|
+
if (!skipIf) return false;
|
|
95
|
+
if (skipIf === 'debugger.fixed') {
|
|
96
|
+
const text = readArtifact('debug-report.md');
|
|
97
|
+
return /fixApplied:\s*true/i.test(text) || /\*\*Fix applied:\*\*\s*true/i.test(text);
|
|
98
|
+
}
|
|
99
|
+
if (skipIf === 'ci-investigator.resolved') {
|
|
100
|
+
const text = readArtifact('ci-report.md');
|
|
101
|
+
return /fixApplied:\s*true/i.test(text) || /## Verdict\s*\nPASS/i.test(text);
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function findNextExecutableStep(steps, startIdx, dir) {
|
|
107
|
+
for (let i = startIdx; i < steps.length; i++) {
|
|
108
|
+
if (!skipIfMatches(steps[i].skipIf, dir)) {
|
|
109
|
+
return { step: steps[i], index: i };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
77
115
|
const AGENT_HANDOFF = {
|
|
78
116
|
'task-analyst': (s) =>
|
|
79
117
|
`Invoke task-analyst for slug "${s}". Write brief.md and decomposition.md under .cursor/team/tasks/${s}/. ` +
|
|
80
|
-
`Set status.json state
|
|
118
|
+
`Set status.json: phase executing, state awaiting_approval if human gate applies. Do not use legacy phase analysis.`,
|
|
81
119
|
debugger: (s) =>
|
|
82
|
-
`Invoke debugger subagent for slug "${s}". Investigate root cause; write debug-report.md. ` +
|
|
120
|
+
`Invoke debugger subagent for slug "${s}". Investigate root cause; write debug-report.md with fixApplied: true/false. ` +
|
|
83
121
|
`Update status.json when done.`,
|
|
84
122
|
'solution-architect': (s) =>
|
|
85
|
-
`Invoke solution-architect for slug "${s}". Read brief.md; write architecture.md.
|
|
86
|
-
|
|
123
|
+
`Invoke solution-architect for slug "${s}". Read brief.md; write architecture.md. Update status.json when done.`,
|
|
124
|
+
'migration-specialist': (s) =>
|
|
125
|
+
`Invoke migration-specialist for slug "${s}". Read brief.md; write migration-plan.md. Update status.json when done.`,
|
|
126
|
+
'api-contract-reviewer': (s) =>
|
|
127
|
+
`Invoke api-contract-reviewer (readonly) for slug "${s}". Write api-contract-review.md. Update status.json when done.`,
|
|
128
|
+
'ci-investigator': (s) =>
|
|
129
|
+
`Invoke ci-investigator for slug "${s}". Diagnose CI failure; write ci-report.md; apply minimal fix. ` +
|
|
130
|
+
`Use ci-investigation skill. Update status.json when done.`,
|
|
87
131
|
'feature-developer': (s) =>
|
|
88
|
-
`Invoke feature-developer for slug "${s}". Read brief.md, decomposition.md, architecture.md
|
|
89
|
-
`Follow feature-delivery-workflow.mdc. Update status.json when done.`,
|
|
132
|
+
`Invoke feature-developer for slug "${s}". Read brief.md, decomposition.md, validation-report.md, review.md, architecture.md, migration-plan.md, api-contract-review.md, debug-report.md if present. ` +
|
|
133
|
+
`Follow feature-delivery-workflow.mdc and reference-features.mdc. Include unit tests for mappers/logic before handoff. Update status.json when done.`,
|
|
134
|
+
'build-verifier': (s) =>
|
|
135
|
+
`Invoke build-verifier (readonly) for slug "${s}". Run lint:js, lint:css, type-check, and targeted unit tests from app/. ` +
|
|
136
|
+
`Write validation-report.md. Set state completed or validation_failed. Do not edit production code.`,
|
|
137
|
+
'accessibility-reviewer': (s) =>
|
|
138
|
+
`Invoke accessibility-reviewer (readonly) for slug "${s}". Review UI diff; write a11y-review.md. Update status.json when done.`,
|
|
139
|
+
'performance-auditor': (s) =>
|
|
140
|
+
`Invoke performance-auditor (readonly) for slug "${s}". Write perf-report.md. Update status.json when done.`,
|
|
90
141
|
'code-reviewer': (s) =>
|
|
91
142
|
`Invoke code-reviewer subagent (readonly) for slug "${s}". Review git diff vs brief.md per code-review-mr.mdc. ` +
|
|
92
143
|
`Update status.json when done.`,
|
|
144
|
+
'security-reviewer': (s) =>
|
|
145
|
+
`Invoke security-reviewer (readonly) for slug "${s}". Write security-review.md. Update status.json when done.`,
|
|
93
146
|
'qa-tester': (s, scope) =>
|
|
94
147
|
`Invoke qa-tester for slug "${s}"${scope ? ` (scope: ${scope})` : ''}. ` +
|
|
95
|
-
`Add/update
|
|
148
|
+
`Add/update tests per brief. Follow playwright-agents.mdc. Update status.json when done.`,
|
|
149
|
+
'unit-test-planner': (s) =>
|
|
150
|
+
`Invoke unit-test-planner for slug "${s}". Write unit-test-plan.md. Use unit-testing skill. Update status.json when done.`,
|
|
151
|
+
'unit-test-generator': (s) =>
|
|
152
|
+
`Invoke unit-test-generator for slug "${s}". Implement specs from unit-test-plan.md. Use unit-testing skill. Update status.json when done.`,
|
|
153
|
+
'unit-test-healer': (s) =>
|
|
154
|
+
`Invoke unit-test-healer for slug "${s}". Fix failing unit tests. Use unit-testing and debug-investigation skills. Update status.json when done.`,
|
|
155
|
+
'playwright-test-planner': (s) =>
|
|
156
|
+
`Invoke playwright-test-planner for slug "${s}". Create/update app/__tests__/e2e/**/*.cases.md. ` +
|
|
157
|
+
`Follow playwright-agents.mdc and the playwright-e2e skill. Update status.json when done.`,
|
|
158
|
+
'playwright-test-generator': (s) =>
|
|
159
|
+
`Invoke playwright-test-generator for slug "${s}". Generate/update *.spec.ts from matching *.cases.md. ` +
|
|
160
|
+
`Use user-playwright MCP when available. Follow playwright-agents.mdc and the playwright-e2e skill. Update status.json when done.`,
|
|
161
|
+
'playwright-test-healer': (s) =>
|
|
162
|
+
`Invoke playwright-test-healer for slug "${s}". Fix failing/flaky e2e while preserving cases.md assertions. ` +
|
|
163
|
+
`Use user-playwright MCP when available. Follow playwright-agents.mdc and debug-investigation. Update status.json when done.`,
|
|
164
|
+
'tech-writer': (s) =>
|
|
165
|
+
`Invoke tech-writer for slug "${s}". Write documentation.md from task artifacts. Update status.json when done.`,
|
|
96
166
|
};
|
|
97
167
|
|
|
168
|
+
const REVIEW_AGENTS = new Set([
|
|
169
|
+
'code-reviewer',
|
|
170
|
+
'accessibility-reviewer',
|
|
171
|
+
'security-reviewer',
|
|
172
|
+
'api-contract-reviewer',
|
|
173
|
+
]);
|
|
174
|
+
|
|
98
175
|
function handoffForAgent(agent, scope) {
|
|
99
176
|
const fn = AGENT_HANDOFF[agent];
|
|
100
177
|
return fn ? fn(slug, scope) : `Invoke ${agent} subagent for slug "${slug}". Update status.json when done.`;
|
|
101
178
|
}
|
|
102
179
|
|
|
180
|
+
function handoffForParallelStep(step) {
|
|
181
|
+
const agents = getStepAgents(step);
|
|
182
|
+
return (
|
|
183
|
+
`Invoke IN PARALLEL (one message, multiple Task calls): ${agents.join(' AND ')} for slug "${slug}". ` +
|
|
184
|
+
`Each agent writes its artifact and appends itself to status.json parallelCompleted when done.`
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
103
188
|
function hasGateAfter(agent, humanGates) {
|
|
104
189
|
return Array.isArray(humanGates) && humanGates.includes(`after:${agent}`);
|
|
105
190
|
}
|
|
106
191
|
|
|
107
|
-
|
|
192
|
+
function hasGateAfterStep(step, humanGates) {
|
|
193
|
+
return getStepAgents(step).some((a) => hasGateAfter(a, humanGates));
|
|
194
|
+
}
|
|
195
|
+
|
|
108
196
|
function legacyFlow() {
|
|
109
197
|
if (status.phase === 'analysis') {
|
|
110
198
|
process.stdout.write('{}');
|
|
111
199
|
process.exit(0);
|
|
112
200
|
}
|
|
113
201
|
if (status.phase === 'development' && (status.state === 'completed' || status.state === 'in_progress')) {
|
|
114
|
-
writeStatus({ phase: '
|
|
202
|
+
writeStatus({ phase: 'executing', state: 'in_progress', currentAgent: 'build-verifier' });
|
|
203
|
+
out(handoffForAgent('build-verifier'));
|
|
204
|
+
process.exit(0);
|
|
205
|
+
}
|
|
206
|
+
if (status.currentAgent === 'build-verifier' && status.state === 'completed') {
|
|
207
|
+
writeStatus({ phase: 'executing', state: 'in_progress', currentAgent: 'code-reviewer' });
|
|
115
208
|
out(handoffForAgent('code-reviewer'));
|
|
116
209
|
process.exit(0);
|
|
117
210
|
}
|
|
118
211
|
if (status.phase === 'review' && status.state === 'completed') {
|
|
119
|
-
writeStatus({ phase: '
|
|
212
|
+
writeStatus({ phase: 'executing', state: 'in_progress', currentAgent: 'qa-tester' });
|
|
120
213
|
out(handoffForAgent('qa-tester'));
|
|
121
214
|
process.exit(0);
|
|
122
215
|
}
|
|
123
|
-
if (status.
|
|
216
|
+
if (status.state === 'changes_requested' && REVIEW_AGENTS.has(status.currentAgent)) {
|
|
217
|
+
writeStatus({
|
|
218
|
+
currentAgent: 'feature-developer',
|
|
219
|
+
state: 'in_progress',
|
|
220
|
+
phase: 'executing',
|
|
221
|
+
retryAfterFix: status.currentAgent,
|
|
222
|
+
});
|
|
223
|
+
out(
|
|
224
|
+
handoffForAgent('feature-developer') +
|
|
225
|
+
` After fixes, re-run ${status.currentAgent}.`,
|
|
226
|
+
);
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
if (status.state === 'validation_failed' && status.currentAgent === 'build-verifier') {
|
|
230
|
+
writeStatus({
|
|
231
|
+
currentAgent: 'feature-developer',
|
|
232
|
+
state: 'in_progress',
|
|
233
|
+
phase: 'executing',
|
|
234
|
+
retryAfterFix: 'build-verifier',
|
|
235
|
+
});
|
|
124
236
|
out(
|
|
125
|
-
|
|
237
|
+
handoffForAgent('feature-developer') +
|
|
238
|
+
` Read validation-report.md. After fixes, re-run build-verifier.`,
|
|
126
239
|
);
|
|
127
240
|
process.exit(0);
|
|
128
241
|
}
|
|
242
|
+
if (status.state === 'completed' && status.retryAfterFix) {
|
|
243
|
+
const retry = status.retryAfterFix;
|
|
244
|
+
writeStatus({ currentAgent: retry, state: 'in_progress', retryAfterFix: null });
|
|
245
|
+
out(handoffForAgent(retry));
|
|
246
|
+
process.exit(0);
|
|
247
|
+
}
|
|
129
248
|
if (status.phase === 'testing' && status.state === 'completed') {
|
|
130
249
|
writeStatus({ phase: 'done', state: 'completed' });
|
|
131
250
|
out(`Pipeline complete for "${slug}". Run /technical-retro ${slug}.`);
|
|
@@ -152,20 +271,44 @@ if (steps.length === 0 || pipeline.autoChain === false) {
|
|
|
152
271
|
process.exit(0);
|
|
153
272
|
}
|
|
154
273
|
|
|
155
|
-
// Human gate active — do not chain
|
|
156
274
|
if (status.awaitingHumanGate || status.state === 'awaiting_approval') {
|
|
157
275
|
process.stdout.write('{}');
|
|
158
276
|
process.exit(0);
|
|
159
277
|
}
|
|
160
278
|
|
|
161
|
-
|
|
162
|
-
|
|
279
|
+
if (status.state === 'changes_requested' && REVIEW_AGENTS.has(status.currentAgent)) {
|
|
280
|
+
const reviewer = status.currentAgent;
|
|
281
|
+
writeStatus({
|
|
282
|
+
currentAgent: 'feature-developer',
|
|
283
|
+
state: 'in_progress',
|
|
284
|
+
phase: 'executing',
|
|
285
|
+
retryAfterFix: reviewer,
|
|
286
|
+
});
|
|
287
|
+
out(
|
|
288
|
+
handoffForAgent('feature-developer') +
|
|
289
|
+
` After fixes, re-run ${reviewer}.`,
|
|
290
|
+
);
|
|
291
|
+
process.exit(0);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (status.state === 'validation_failed' && status.currentAgent === 'build-verifier') {
|
|
163
295
|
writeStatus({
|
|
164
296
|
currentAgent: 'feature-developer',
|
|
165
297
|
state: 'in_progress',
|
|
166
298
|
phase: 'executing',
|
|
299
|
+
retryAfterFix: 'build-verifier',
|
|
167
300
|
});
|
|
168
|
-
out(
|
|
301
|
+
out(
|
|
302
|
+
handoffForAgent('feature-developer') +
|
|
303
|
+
` Read validation-report.md. After fixes, re-run build-verifier.`,
|
|
304
|
+
);
|
|
305
|
+
process.exit(0);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (status.state === 'completed' && status.retryAfterFix) {
|
|
309
|
+
const retry = status.retryAfterFix;
|
|
310
|
+
writeStatus({ currentAgent: retry, state: 'in_progress', retryAfterFix: null });
|
|
311
|
+
out(handoffForAgent(retry));
|
|
169
312
|
process.exit(0);
|
|
170
313
|
}
|
|
171
314
|
|
|
@@ -177,10 +320,24 @@ if (!currentStep) {
|
|
|
177
320
|
process.exit(0);
|
|
178
321
|
}
|
|
179
322
|
|
|
180
|
-
const completedAgent = status.currentAgent || currentStep
|
|
323
|
+
const completedAgent = status.currentAgent || getStepAgents(currentStep)[0];
|
|
324
|
+
const stepAgents = getStepAgents(currentStep);
|
|
181
325
|
|
|
182
|
-
|
|
183
|
-
|
|
326
|
+
if (currentStep.parallel && stepAgents.length > 1) {
|
|
327
|
+
const done = [...(status.parallelCompleted || [])];
|
|
328
|
+
if (completedAgent && !done.includes(completedAgent)) {
|
|
329
|
+
done.push(completedAgent);
|
|
330
|
+
}
|
|
331
|
+
writeStatus({ parallelCompleted: done });
|
|
332
|
+
const remaining = stepAgents.filter((a) => !done.includes(a));
|
|
333
|
+
if (remaining.length > 0) {
|
|
334
|
+
process.stdout.write('{}');
|
|
335
|
+
process.exit(0);
|
|
336
|
+
}
|
|
337
|
+
writeStatus({ parallelCompleted: [] });
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (hasGateAfterStep(currentStep, pipeline.humanGates)) {
|
|
184
341
|
writeStatus({
|
|
185
342
|
awaitingHumanGate: true,
|
|
186
343
|
state: 'awaiting_approval',
|
|
@@ -190,10 +347,10 @@ if (hasGateAfter(completedAgent, pipeline.humanGates)) {
|
|
|
190
347
|
process.exit(0);
|
|
191
348
|
}
|
|
192
349
|
|
|
193
|
-
const
|
|
194
|
-
if (
|
|
350
|
+
const next = findNextExecutableStep(steps, idx + 1, taskDir);
|
|
351
|
+
if (!next) {
|
|
195
352
|
writeStatus({
|
|
196
|
-
pipelineIndex:
|
|
353
|
+
pipelineIndex: steps.length,
|
|
197
354
|
phase: 'done',
|
|
198
355
|
state: 'completed',
|
|
199
356
|
currentAgent: null,
|
|
@@ -203,14 +360,21 @@ if (nextIdx >= steps.length) {
|
|
|
203
360
|
process.exit(0);
|
|
204
361
|
}
|
|
205
362
|
|
|
206
|
-
const nextStep =
|
|
363
|
+
const { step: nextStep, index: nextIdx } = next;
|
|
364
|
+
const nextAgents = getStepAgents(nextStep);
|
|
365
|
+
|
|
207
366
|
writeStatus({
|
|
208
367
|
pipelineIndex: nextIdx,
|
|
209
|
-
currentAgent:
|
|
368
|
+
currentAgent: nextAgents[0],
|
|
210
369
|
phase: 'executing',
|
|
211
370
|
state: 'in_progress',
|
|
212
371
|
awaitingHumanGate: false,
|
|
372
|
+
parallelCompleted: [],
|
|
213
373
|
});
|
|
214
374
|
|
|
215
|
-
|
|
375
|
+
if (nextStep.parallel && nextAgents.length > 1) {
|
|
376
|
+
out(handoffForParallelStep(nextStep));
|
|
377
|
+
} else {
|
|
378
|
+
out(handoffForAgent(nextAgents[0], nextStep.scope));
|
|
379
|
+
}
|
|
216
380
|
NODE
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Lightweight shell guard for Cursor projects using this preset.
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
input=$(cat)
|
|
7
|
+
|
|
8
|
+
INPUT="$input" node <<'NODE'
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
|
|
11
|
+
const raw = process.env.INPUT || '';
|
|
12
|
+
let event;
|
|
13
|
+
try {
|
|
14
|
+
event = JSON.parse(raw);
|
|
15
|
+
} catch {
|
|
16
|
+
process.stdout.write('{ "permission": "allow" }');
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const command = String(event.command || event.input?.command || '');
|
|
21
|
+
if (!command.trim()) {
|
|
22
|
+
process.stdout.write('{ "permission": "allow" }');
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function out(permission, userMessage, agentMessage) {
|
|
27
|
+
process.stdout.write(JSON.stringify({
|
|
28
|
+
permission,
|
|
29
|
+
user_message: userMessage,
|
|
30
|
+
agent_message: agentMessage || userMessage,
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const dangerousGit = /\bgit\s+(reset\s+--hard|clean\s+-[^\n]*f|push\s+--force|push\s+-f|checkout\s+--\s+)/;
|
|
35
|
+
if (dangerousGit.test(command)) {
|
|
36
|
+
out(
|
|
37
|
+
'ask',
|
|
38
|
+
'This command looks destructive for git state. Review it before continuing.',
|
|
39
|
+
'A project hook flagged a destructive git command. Ask the user before running it.',
|
|
40
|
+
);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const managerByFile = [
|
|
45
|
+
['yarn.lock', 'yarn'],
|
|
46
|
+
['pnpm-lock.yaml', 'pnpm'],
|
|
47
|
+
['package-lock.json', 'npm'],
|
|
48
|
+
].find(([file]) => fs.existsSync(file));
|
|
49
|
+
|
|
50
|
+
let expected = managerByFile?.[1];
|
|
51
|
+
if (!expected && fs.existsSync('package.json')) {
|
|
52
|
+
try {
|
|
53
|
+
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
54
|
+
const pm = typeof pkg.packageManager === 'string' ? pkg.packageManager : '';
|
|
55
|
+
expected = pm.split('@')[0] || undefined;
|
|
56
|
+
} catch {
|
|
57
|
+
// Ignore invalid package.json in the hook; the agent can diagnose it later.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!expected) {
|
|
62
|
+
process.stdout.write('{ "permission": "allow" }');
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const used = command.match(/(^|[;&|]\s*)(npm|yarn|pnpm)\s+/)?.[2];
|
|
67
|
+
if (used && used !== expected) {
|
|
68
|
+
out(
|
|
69
|
+
'ask',
|
|
70
|
+
`This repository appears to use ${expected}, but the command uses ${used}. Confirm before continuing.`,
|
|
71
|
+
`Use ${expected} for package scripts and installs unless the user explicitly approves ${used}.`,
|
|
72
|
+
);
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
process.stdout.write('{ "permission": "allow" }');
|
|
77
|
+
NODE
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
3
|
"hooks": {
|
|
4
|
+
"beforeShellExecution": [
|
|
5
|
+
{
|
|
6
|
+
"command": ".cursor/hooks/guard-shell-command.sh",
|
|
7
|
+
"failClosed": true
|
|
8
|
+
}
|
|
9
|
+
],
|
|
4
10
|
"subagentStop": [
|
|
5
11
|
{
|
|
6
12
|
"command": ".cursor/hooks/chain-team-phases.sh",
|
|
7
|
-
"loop_limit":
|
|
13
|
+
"loop_limit": 15
|
|
8
14
|
}
|
|
9
15
|
]
|
|
10
16
|
}
|
|
@@ -17,20 +17,30 @@
|
|
|
17
17
|
- **Legacy:** `/feature-start` → `/feature-continue`.
|
|
18
18
|
- **Сквозной чеклист слоёв (для developer):** **`feature-delivery-workflow.mdc`**.
|
|
19
19
|
|
|
20
|
-
###
|
|
20
|
+
### Loading strategy
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
- **`alwaysApply: true`** (Cursor) / **без `paths:`** (Claude) — только базовые инварианты:
|
|
23
|
+
- `next-app-core`, `post-change-lint`, `package-manager`, `agent-team-intake`, `code-quality-and-refactoring`
|
|
24
|
+
- **Globs / `paths:`** — architecture, imports, UI, tests, feature-delivery-workflow, reference-features, next-app-router, react-a11y-coding
|
|
25
|
+
- **Skills** — длинные процедуры (`feature-delivery`, `code-review`, …)
|
|
26
|
+
|
|
27
|
+
### Эталонные фичи
|
|
28
|
+
|
|
29
|
+
Заполните **`reference-features.mdc`** (TBD → реальные пути) после `init` в целевом репо.
|
|
23
30
|
|
|
24
31
|
### Каталог ключевых правил
|
|
25
32
|
|
|
26
33
|
| Файл | Назначение |
|
|
27
34
|
|------|------------|
|
|
28
|
-
| `
|
|
35
|
+
| `reference-features.mdc` | Эталонные пути UI/store/API/types/tests |
|
|
36
|
+
| `next-app-router.mdc` | App Router, RSC, loading/error |
|
|
37
|
+
| `react-a11y-coding.mdc` | A11y при написании UI |
|
|
38
|
+
| `feature-delivery-workflow.mdc` | Сквозной чеклист (on-demand, не always-on) |
|
|
29
39
|
| `agent-team-intake.mdc` | Автоподсказка `/task` при постановке задачи (alwaysApply) |
|
|
30
40
|
| `package-manager.mdc` | Перед `install` / `run` в терминале определить менеджер пакетов репо (lockfile, `packageManager`) и использовать только его |
|
|
31
|
-
| `
|
|
32
|
-
| `next-app-core.mdc` | Стек, слои, порты‑адаптеры (
|
|
33
|
-
| `post-change-lint.mdc` | **Обязательный** прогон ESLint + Stylelint после любых изменений
|
|
41
|
+
| `agent-team-orchestrator.mdc` | `/task`, router, `pipeline.json`, build-verifier, parallel steps |
|
|
42
|
+
| `next-app-core.mdc` | Стек, слои, порты‑адаптеры (alwaysApply) |
|
|
43
|
+
| `post-change-lint.mdc` | **Обязательный** прогон ESLint + Stylelint после любых изменений кода |
|
|
34
44
|
| `architecture-boundaries.mdc` | Границы UI / store / API, импорты (`@/types`, `@/api`), порты‑адаптеры, фича как срез |
|
|
35
45
|
| `http-client.mdc` | Один HTTP‑стек, контракты из `@/types`, без разбросанного низкоуровневого API |
|
|
36
46
|
| `api-services.mdc` | Сервисы, мапперы, вызовы через прикладные API‑клиенты |
|
|
@@ -22,12 +22,26 @@ Parent agent = **manager**. Router plans; specialists execute. Artifacts: `.curs
|
|
|
22
22
|
| Agent | readonly | Typical intent |
|
|
23
23
|
|-------|----------|----------------|
|
|
24
24
|
| `task-router` | yes | Every `/task` — writes `pipeline.json` |
|
|
25
|
-
| `task-analyst` | yes | feature, refactor, test-only |
|
|
25
|
+
| `task-analyst` | yes | feature, refactor, test-only, a11y, docs-only, migration |
|
|
26
26
|
| `solution-architect` | yes | spike, complex cross-layer feature |
|
|
27
|
+
| `migration-specialist` | yes | migration — phased upgrade plan |
|
|
28
|
+
| `api-contract-reviewer` | yes | new/changed backend API contracts |
|
|
27
29
|
| `debugger` | no | bugfix |
|
|
28
|
-
| `
|
|
30
|
+
| `ci-investigator` | no | ci-fix — minimal CI repair |
|
|
31
|
+
| `feature-developer` | no | feature, bugfix, refactor, migration, a11y |
|
|
32
|
+
| `build-verifier` | yes | lint/type-check/unit gate after developer |
|
|
33
|
+
| `accessibility-reviewer` | yes | a11y, UI-heavy feature |
|
|
34
|
+
| `performance-auditor` | yes | perf-audit, perf-sensitive feature |
|
|
29
35
|
| `code-reviewer` | yes | most pipelines, review-only |
|
|
36
|
+
| `security-reviewer` | yes | auth, forms, sensitive data |
|
|
30
37
|
| `qa-tester` | no | feature, bugfix, test-only |
|
|
38
|
+
| `unit-test-planner` | yes | unit-only — coverage plan |
|
|
39
|
+
| `unit-test-generator` | no | unit-only — spec generation |
|
|
40
|
+
| `unit-test-healer` | no | failing/flaky unit tests |
|
|
41
|
+
| `playwright-test-planner` | no | e2e scenario planning |
|
|
42
|
+
| `playwright-test-generator` | no | e2e spec generation |
|
|
43
|
+
| `playwright-test-healer` | no | failing/flaky e2e fixes |
|
|
44
|
+
| `tech-writer` | yes | docs-only, feature/migration docs |
|
|
31
45
|
|
|
32
46
|
Full prompts: `.cursor/agents/*.md`. Artifact conventions: `.cursor/team/README.md`.
|
|
33
47
|
|
|
@@ -74,18 +88,28 @@ flowchart TD
|
|
|
74
88
|
| `in_progress` | Current step running |
|
|
75
89
|
| `completed` | Current step done; hook advances |
|
|
76
90
|
| `awaiting_approval` | Human gate; wait for `/task-continue` |
|
|
77
|
-
| `changes_requested` | Reviewer blocked; re-run developer |
|
|
91
|
+
| `changes_requested` | Reviewer blocked; re-run developer (`retryAfterFix`) |
|
|
92
|
+
| `validation_failed` | build-verifier failed; re-run developer then build-verifier |
|
|
93
|
+
|
|
94
|
+
## Pipeline step options
|
|
95
|
+
|
|
96
|
+
| Field | Use |
|
|
97
|
+
|-------|-----|
|
|
98
|
+
| `skipIf` | `debugger.fixed` / `ci-investigator.resolved` — hook skips step when artifact says fix applied |
|
|
99
|
+
| `parallel: true` | `agent` is array — invoke **all** agents in one parent turn; each appends to `parallelCompleted` |
|
|
100
|
+
| `scope` | e.g. `unit-in-dev`, `e2e-only` — passed to developer/qa |
|
|
78
101
|
|
|
79
102
|
## Rules (strict)
|
|
80
103
|
|
|
81
104
|
1. **`/task` always starts with task-router** (except user says "skip router" with documented pipeline).
|
|
82
105
|
2. Read `pipeline.json` before every subagent invocation.
|
|
83
|
-
3. One role per Task
|
|
106
|
+
3. One role per Task call — **except** parallel steps: multiple Task calls in one message.
|
|
84
107
|
4. **Never** skip `humanGates` without `/task-continue` or explicit user approval.
|
|
85
|
-
5. Persist handoffs to disk (`brief.md`, `decomposition.md`, `debug-report.md`, `architecture.md`).
|
|
86
|
-
6. On `changes_requested
|
|
87
|
-
7.
|
|
88
|
-
8.
|
|
108
|
+
5. Persist handoffs to disk (`brief.md`, `decomposition.md`, `debug-report.md`, `validation-report.md`, `architecture.md`, `migration-plan.md`, `ci-report.md`, `a11y-review.md`, `perf-report.md`, `security-review.md`, `api-contract-review.md`, `unit-test-plan.md`, `documentation.md`, `review.md`).
|
|
109
|
+
6. On `changes_requested` from reviewers: hook sets `retryAfterFix` → developer → same reviewer.
|
|
110
|
+
7. On `validation_failed` from `build-verifier`: hook sets `retryAfterFix: build-verifier` → developer → build-verifier.
|
|
111
|
+
8. When all steps complete, suggest `/technical-retro <slug>`.
|
|
112
|
+
9. If `autoChain: false` in pipeline, do not rely on hook — manual step only.
|
|
89
113
|
|
|
90
114
|
## Invoking agents
|
|
91
115
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Сквозной чеклист новой фичи и матрица «слой → правило Cursor
|
|
3
|
-
alwaysApply:
|
|
2
|
+
description: Сквозной чеклист новой фичи и матрица «слой → правило Cursor». Use when implementing features via feature-developer or feature-delivery skill.
|
|
3
|
+
alwaysApply: false
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Доставка фичи (сквозной порядок)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Next.js App Router — Server/Client Components, data fetching, loading and error UI
|
|
3
|
+
globs: app/src/app/**/*,app/**/app/**/*
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Next.js App Router
|
|
8
|
+
|
|
9
|
+
Применять при работе с `app/src/app/**` или маршрутами App Router в целевом репо.
|
|
10
|
+
|
|
11
|
+
## Server vs Client
|
|
12
|
+
|
|
13
|
+
- **Server Components по умолчанию** — без `'use client'`, если не нужны hooks, browser API, event handlers.
|
|
14
|
+
- **`'use client'`** — только для интерактива, `useState`/`useEffect`, browser-only API.
|
|
15
|
+
- Не тянуть store/RTK и тяжёлый client-state в Server Components без необходимости.
|
|
16
|
+
|
|
17
|
+
## Data fetching
|
|
18
|
+
|
|
19
|
+
- Предпочитать fetch/data-loader на **server** (RSC, route handlers, server actions — по принятому в репо паттерну).
|
|
20
|
+
- **Не дублировать** один запрос в RSC и client без причины.
|
|
21
|
+
- Кеш и revalidate — как в существующих страницах репо (`fetch` options, `revalidate`, tags).
|
|
22
|
+
|
|
23
|
+
## Маршруты и UX
|
|
24
|
+
|
|
25
|
+
- Для async routes использовать **`loading.tsx`**, **`error.tsx`**, **`not-found.tsx`** по образцу соседних routes.
|
|
26
|
+
- **Suspense** — для медленных client/server секций; fallback согласован с дизайн-системой.
|
|
27
|
+
- Навигация — `navigation-router-stack.mdc` + router/link паттерны проекта.
|
|
28
|
+
|
|
29
|
+
## Границы слоёв
|
|
30
|
+
|
|
31
|
+
- RSC/route handlers **не импортируют UI-компоненты с client-only зависимостями** напрямую в server tree без `'use client'` границы.
|
|
32
|
+
- Доменные типы — `@/types`; вызовы backend — через `@/api` / services, не raw `fetch` из page.tsx без слоя API.
|
|
33
|
+
|
|
34
|
+
## Эталон
|
|
35
|
+
|
|
36
|
+
Смотри существующий route той же сложности в `app/src/app/**` и повтори структуру (`reference-features.mdc`).
|