@bonesofspring/ai-rules 0.1.40 → 0.1.42
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 +12 -3
- package/bin/cli.js +211 -50
- 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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# Chains agent team phases after subagent completion when wired into Claude Code hooks.
|
|
3
|
-
# Reads stdin JSON from a subagent-stop style hook; writes followup_message to stdout.
|
|
4
3
|
|
|
5
4
|
set -euo pipefail
|
|
6
5
|
|
|
@@ -10,6 +9,8 @@ INPUT="$input" node <<'NODE'
|
|
|
10
9
|
const fs = require('fs');
|
|
11
10
|
const path = require('path');
|
|
12
11
|
|
|
12
|
+
const TEAM_ROOT = path.join(process.cwd(), '.claude', 'team');
|
|
13
|
+
|
|
13
14
|
const inputRaw = process.env.INPUT || '';
|
|
14
15
|
let hookInput;
|
|
15
16
|
try {
|
|
@@ -24,8 +25,7 @@ if (hookInput.status !== 'completed') {
|
|
|
24
25
|
process.exit(0);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const
|
|
28
|
-
const activePath = path.join(teamRoot, 'active-task.json');
|
|
28
|
+
const activePath = path.join(TEAM_ROOT, 'active-task.json');
|
|
29
29
|
|
|
30
30
|
if (!fs.existsSync(activePath)) {
|
|
31
31
|
process.stdout.write('{}');
|
|
@@ -46,7 +46,10 @@ if (!slug) {
|
|
|
46
46
|
process.exit(0);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const taskDir = path.join(TEAM_ROOT, 'tasks', slug);
|
|
50
|
+
const statusPath = path.join(taskDir, 'status.json');
|
|
51
|
+
const pipelinePath = path.join(taskDir, 'pipeline.json');
|
|
52
|
+
|
|
50
53
|
if (!fs.existsSync(statusPath)) {
|
|
51
54
|
process.stdout.write('{}');
|
|
52
55
|
process.exit(0);
|
|
@@ -63,61 +66,277 @@ try {
|
|
|
63
66
|
const now = new Date().toISOString();
|
|
64
67
|
|
|
65
68
|
function writeStatus(next) {
|
|
66
|
-
|
|
69
|
+
status = { ...status, ...next, slug, updatedAt: now };
|
|
70
|
+
fs.writeFileSync(statusPath, JSON.stringify(status, null, 2) + '\n');
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
function out(message) {
|
|
70
74
|
process.stdout.write(JSON.stringify({ followup_message: message }));
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
function readArtifact(name) {
|
|
78
|
+
const p = path.join(taskDir, name);
|
|
79
|
+
if (!fs.existsSync(p)) return '';
|
|
80
|
+
try {
|
|
81
|
+
return fs.readFileSync(p, 'utf8');
|
|
82
|
+
} catch {
|
|
83
|
+
return '';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getStepAgents(step) {
|
|
88
|
+
if (!step) return [];
|
|
89
|
+
return Array.isArray(step.agent) ? step.agent : [step.agent];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function skipIfMatches(skipIf) {
|
|
93
|
+
if (!skipIf) return false;
|
|
94
|
+
if (skipIf === 'debugger.fixed') {
|
|
95
|
+
const text = readArtifact('debug-report.md');
|
|
96
|
+
return /fixApplied:\s*true/i.test(text) || /\*\*Fix applied:\*\*\s*true/i.test(text);
|
|
97
|
+
}
|
|
98
|
+
if (skipIf === 'ci-investigator.resolved') {
|
|
99
|
+
const text = readArtifact('ci-report.md');
|
|
100
|
+
return /fixApplied:\s*true/i.test(text) || /## Verdict\s*\nPASS/i.test(text);
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function findNextExecutableStep(steps, startIdx) {
|
|
106
|
+
for (let i = startIdx; i < steps.length; i++) {
|
|
107
|
+
if (!skipIfMatches(steps[i].skipIf)) {
|
|
108
|
+
return { step: steps[i], index: i };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const AGENT_HANDOFF = {
|
|
115
|
+
'task-analyst': (s) =>
|
|
116
|
+
`Invoke task-analyst for slug "${s}". Write brief.md and decomposition.md under .claude/team/tasks/${s}/. ` +
|
|
117
|
+
`Set status.json: phase executing, state awaiting_approval if human gate applies.`,
|
|
118
|
+
debugger: (s) =>
|
|
119
|
+
`Invoke debugger subagent for slug "${s}". Write debug-report.md with fixApplied: true/false. Update status.json when done.`,
|
|
120
|
+
'solution-architect': (s) =>
|
|
121
|
+
`Invoke solution-architect for slug "${s}". Read brief.md; write architecture.md. Update status.json when done.`,
|
|
122
|
+
'migration-specialist': (s) =>
|
|
123
|
+
`Invoke migration-specialist for slug "${s}". Read brief.md; write migration-plan.md. Update status.json when done.`,
|
|
124
|
+
'api-contract-reviewer': (s) =>
|
|
125
|
+
`Invoke api-contract-reviewer for slug "${s}". Write api-contract-review.md. Update status.json when done.`,
|
|
126
|
+
'ci-investigator': (s) =>
|
|
127
|
+
`Invoke ci-investigator for slug "${s}". Use ci-investigation skill. Write ci-report.md. Update status.json when done.`,
|
|
128
|
+
'feature-developer': (s) =>
|
|
129
|
+
`Invoke feature-developer for slug "${s}". Read brief.md, decomposition.md, validation-report.md, review.md if present. ` +
|
|
130
|
+
`Follow rules/architecture/feature-delivery-workflow.md and architecture/reference-features.md. Include unit tests before handoff. Update status.json when done.`,
|
|
131
|
+
'build-verifier': (s) =>
|
|
132
|
+
`Invoke build-verifier for slug "${s}". Run lint:js, lint:css, type-check, targeted unit tests from app/. ` +
|
|
133
|
+
`Write validation-report.md. Set state completed or validation_failed. Do not edit production code.`,
|
|
134
|
+
'accessibility-reviewer': (s) =>
|
|
135
|
+
`Invoke accessibility-reviewer for slug "${s}". Write a11y-review.md. Update status.json when done.`,
|
|
136
|
+
'performance-auditor': (s) =>
|
|
137
|
+
`Invoke performance-auditor for slug "${s}". Write perf-report.md. Update status.json when done.`,
|
|
138
|
+
'code-reviewer': (s) =>
|
|
139
|
+
`Invoke code-reviewer for slug "${s}". Review git diff per rules/tooling-and-review/code-review-mr.md. Update status.json when done.`,
|
|
140
|
+
'security-reviewer': (s) =>
|
|
141
|
+
`Invoke security-reviewer for slug "${s}". Write security-review.md. Update status.json when done.`,
|
|
142
|
+
'qa-tester': (s, scope) =>
|
|
143
|
+
`Invoke qa-tester for slug "${s}"${scope ? ` (scope: ${scope})` : ''}. Update status.json when done.`,
|
|
144
|
+
'unit-test-planner': (s) =>
|
|
145
|
+
`Invoke unit-test-planner for slug "${s}". Use unit-testing skill. Update status.json when done.`,
|
|
146
|
+
'unit-test-generator': (s) =>
|
|
147
|
+
`Invoke unit-test-generator for slug "${s}". Use unit-testing skill. Update status.json when done.`,
|
|
148
|
+
'unit-test-healer': (s) =>
|
|
149
|
+
`Invoke unit-test-healer for slug "${s}". Use unit-testing and debug-investigation skills. Update status.json when done.`,
|
|
150
|
+
'playwright-test-planner': (s) =>
|
|
151
|
+
`Invoke playwright-test-planner for slug "${s}". Follow rules/testing/playwright-agents.md and playwright-e2e skill. Update status.json when done.`,
|
|
152
|
+
'playwright-test-generator': (s) =>
|
|
153
|
+
`Invoke playwright-test-generator for slug "${s}". Use Playwright MCP tools when available. Update status.json when done.`,
|
|
154
|
+
'playwright-test-healer': (s) =>
|
|
155
|
+
`Invoke playwright-test-healer for slug "${s}". Use Playwright MCP when available. Update status.json when done.`,
|
|
156
|
+
'tech-writer': (s) =>
|
|
157
|
+
`Invoke tech-writer for slug "${s}". Write documentation.md. Update status.json when done.`,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const REVIEW_AGENTS = new Set([
|
|
161
|
+
'code-reviewer',
|
|
162
|
+
'accessibility-reviewer',
|
|
163
|
+
'security-reviewer',
|
|
164
|
+
'api-contract-reviewer',
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
function handoffForAgent(agent, scope) {
|
|
168
|
+
const fn = AGENT_HANDOFF[agent];
|
|
169
|
+
return fn ? fn(slug, scope) : `Invoke ${agent} subagent for slug "${slug}". Update status.json when done.`;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function handoffForParallelStep(step) {
|
|
173
|
+
const agents = getStepAgents(step);
|
|
174
|
+
return (
|
|
175
|
+
`Invoke IN PARALLEL (one message, multiple Task calls): ${agents.join(' AND ')} for slug "${slug}". ` +
|
|
176
|
+
`Each agent appends itself to status.json parallelCompleted when done.`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function hasGateAfter(agent, humanGates) {
|
|
181
|
+
return Array.isArray(humanGates) && humanGates.includes(`after:${agent}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function hasGateAfterStep(step, humanGates) {
|
|
185
|
+
return getStepAgents(step).some((a) => hasGateAfter(a, humanGates));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function legacyFlow() {
|
|
189
|
+
if (status.phase === 'development' && status.state === 'completed') {
|
|
190
|
+
writeStatus({ phase: 'executing', state: 'in_progress', currentAgent: 'build-verifier' });
|
|
191
|
+
out(handoffForAgent('build-verifier'));
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
if (status.currentAgent === 'build-verifier' && status.state === 'completed') {
|
|
195
|
+
writeStatus({ phase: 'executing', state: 'in_progress', currentAgent: 'code-reviewer' });
|
|
196
|
+
out(handoffForAgent('code-reviewer'));
|
|
197
|
+
process.exit(0);
|
|
198
|
+
}
|
|
199
|
+
if (status.phase === 'review' && status.state === 'completed') {
|
|
200
|
+
writeStatus({ phase: 'executing', state: 'in_progress', currentAgent: 'qa-tester' });
|
|
201
|
+
out(handoffForAgent('qa-tester'));
|
|
202
|
+
process.exit(0);
|
|
203
|
+
}
|
|
204
|
+
if (status.state === 'changes_requested' && REVIEW_AGENTS.has(status.currentAgent)) {
|
|
205
|
+
writeStatus({
|
|
206
|
+
currentAgent: 'feature-developer',
|
|
207
|
+
state: 'in_progress',
|
|
208
|
+
phase: 'executing',
|
|
209
|
+
retryAfterFix: status.currentAgent,
|
|
210
|
+
});
|
|
211
|
+
out(handoffForAgent('feature-developer') + ` After fixes, re-run ${status.currentAgent}.`);
|
|
212
|
+
process.exit(0);
|
|
213
|
+
}
|
|
214
|
+
if (status.state === 'validation_failed') {
|
|
215
|
+
writeStatus({
|
|
216
|
+
currentAgent: 'feature-developer',
|
|
217
|
+
state: 'in_progress',
|
|
218
|
+
retryAfterFix: 'build-verifier',
|
|
219
|
+
});
|
|
220
|
+
out(handoffForAgent('feature-developer') + ` Read validation-report.md. Re-run build-verifier after fixes.`);
|
|
221
|
+
process.exit(0);
|
|
222
|
+
}
|
|
223
|
+
if (status.state === 'completed' && status.retryAfterFix) {
|
|
224
|
+
const retry = status.retryAfterFix;
|
|
225
|
+
writeStatus({ currentAgent: retry, state: 'in_progress', retryAfterFix: null });
|
|
226
|
+
out(handoffForAgent(retry));
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
if (status.phase === 'testing' && status.state === 'completed') {
|
|
230
|
+
writeStatus({ phase: 'done', state: 'completed' });
|
|
231
|
+
out(`Pipeline complete for "${slug}". Run /technical-retro ${slug}.`);
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
75
234
|
process.stdout.write('{}');
|
|
76
235
|
process.exit(0);
|
|
77
236
|
}
|
|
78
237
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
238
|
+
if (!fs.existsSync(pipelinePath)) {
|
|
239
|
+
legacyFlow();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let pipeline;
|
|
243
|
+
try {
|
|
244
|
+
pipeline = JSON.parse(fs.readFileSync(pipelinePath, 'utf8'));
|
|
245
|
+
} catch {
|
|
246
|
+
legacyFlow();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const steps = pipeline.steps || [];
|
|
250
|
+
if (steps.length === 0 || pipeline.autoChain === false) {
|
|
251
|
+
process.stdout.write('{}');
|
|
89
252
|
process.exit(0);
|
|
90
253
|
}
|
|
91
254
|
|
|
92
|
-
if (status.
|
|
93
|
-
|
|
94
|
-
out(
|
|
95
|
-
`Code review completed for slug "${slug}". ` +
|
|
96
|
-
`Invoke the qa-tester subagent. ` +
|
|
97
|
-
`Add or update unit and e2e tests per brief acceptance criteria. ` +
|
|
98
|
-
`Follow rules/testing/playwright-agents.md and rules/testing/tests-e2e-structure.md. ` +
|
|
99
|
-
`Update status.json when done.`,
|
|
100
|
-
);
|
|
255
|
+
if (status.awaitingHumanGate || status.state === 'awaiting_approval') {
|
|
256
|
+
process.stdout.write('{}');
|
|
101
257
|
process.exit(0);
|
|
102
258
|
}
|
|
103
259
|
|
|
104
|
-
if (status.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
260
|
+
if (status.state === 'changes_requested' && REVIEW_AGENTS.has(status.currentAgent)) {
|
|
261
|
+
const reviewer = status.currentAgent;
|
|
262
|
+
writeStatus({
|
|
263
|
+
currentAgent: 'feature-developer',
|
|
264
|
+
state: 'in_progress',
|
|
265
|
+
phase: 'executing',
|
|
266
|
+
retryAfterFix: reviewer,
|
|
267
|
+
});
|
|
268
|
+
out(handoffForAgent('feature-developer') + ` After fixes, re-run ${reviewer}.`);
|
|
109
269
|
process.exit(0);
|
|
110
270
|
}
|
|
111
271
|
|
|
112
|
-
if (status.
|
|
113
|
-
writeStatus({
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
);
|
|
272
|
+
if (status.state === 'validation_failed' && status.currentAgent === 'build-verifier') {
|
|
273
|
+
writeStatus({
|
|
274
|
+
currentAgent: 'feature-developer',
|
|
275
|
+
state: 'in_progress',
|
|
276
|
+
phase: 'executing',
|
|
277
|
+
retryAfterFix: 'build-verifier',
|
|
278
|
+
});
|
|
279
|
+
out(handoffForAgent('feature-developer') + ` Read validation-report.md. Re-run build-verifier after fixes.`);
|
|
280
|
+
process.exit(0);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (status.state === 'completed' && status.retryAfterFix) {
|
|
284
|
+
const retry = status.retryAfterFix;
|
|
285
|
+
writeStatus({ currentAgent: retry, state: 'in_progress', retryAfterFix: null });
|
|
286
|
+
out(handoffForAgent(retry));
|
|
287
|
+
process.exit(0);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const idx = typeof status.pipelineIndex === 'number' ? status.pipelineIndex : 0;
|
|
291
|
+
const currentStep = steps[idx];
|
|
292
|
+
if (!currentStep) {
|
|
293
|
+
writeStatus({ phase: 'done', state: 'completed', currentAgent: null });
|
|
294
|
+
out(`Pipeline complete for "${slug}". Run /technical-retro ${slug}.`);
|
|
119
295
|
process.exit(0);
|
|
120
296
|
}
|
|
121
297
|
|
|
122
|
-
|
|
298
|
+
const completedAgent = status.currentAgent || getStepAgents(currentStep)[0];
|
|
299
|
+
const stepAgents = getStepAgents(currentStep);
|
|
300
|
+
|
|
301
|
+
if (currentStep.parallel && stepAgents.length > 1) {
|
|
302
|
+
const done = [...(status.parallelCompleted || [])];
|
|
303
|
+
if (completedAgent && !done.includes(completedAgent)) done.push(completedAgent);
|
|
304
|
+
writeStatus({ parallelCompleted: done });
|
|
305
|
+
if (stepAgents.filter((a) => !done.includes(a)).length > 0) {
|
|
306
|
+
process.stdout.write('{}');
|
|
307
|
+
process.exit(0);
|
|
308
|
+
}
|
|
309
|
+
writeStatus({ parallelCompleted: [] });
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (hasGateAfterStep(currentStep, pipeline.humanGates)) {
|
|
313
|
+
writeStatus({ awaitingHumanGate: true, state: 'awaiting_approval', currentAgent: completedAgent });
|
|
314
|
+
process.stdout.write('{}');
|
|
315
|
+
process.exit(0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const next = findNextExecutableStep(steps, idx + 1);
|
|
319
|
+
if (!next) {
|
|
320
|
+
writeStatus({ pipelineIndex: steps.length, phase: 'done', state: 'completed', currentAgent: null });
|
|
321
|
+
out(`Pipeline complete for "${slug}". Run /technical-retro ${slug}.`);
|
|
322
|
+
process.exit(0);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const { step: nextStep, index: nextIdx } = next;
|
|
326
|
+
const nextAgents = getStepAgents(nextStep);
|
|
327
|
+
|
|
328
|
+
writeStatus({
|
|
329
|
+
pipelineIndex: nextIdx,
|
|
330
|
+
currentAgent: nextAgents[0],
|
|
331
|
+
phase: 'executing',
|
|
332
|
+
state: 'in_progress',
|
|
333
|
+
awaitingHumanGate: false,
|
|
334
|
+
parallelCompleted: [],
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
if (nextStep.parallel && nextAgents.length > 1) {
|
|
338
|
+
out(handoffForParallelStep(nextStep));
|
|
339
|
+
} else {
|
|
340
|
+
out(handoffForAgent(nextAgents[0], nextStep.scope));
|
|
341
|
+
}
|
|
123
342
|
NODE
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Lightweight shell guard for Claude 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,54 +1,30 @@
|
|
|
1
1
|
# `.claude/rules` (preset next)
|
|
2
2
|
|
|
3
|
-
В Claude Code все `.md` под `rules/` **обнаруживаются рекурсивно**. Правила без YAML frontmatter загружаются **в начале сессии**; с `paths:` — **только при работе** с matching
|
|
3
|
+
В Claude Code все `.md` под `rules/` **обнаруживаются рекурсивно**. Правила без YAML frontmatter загружаются **в начале сессии**; с `paths:` — **только при работе** с matching-файлами.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Loading strategy
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
| `stack/` | Next.js, TS, навигация, JSDoc типов | core — session; `types-jsdoc.md` — `paths: app/src/types/**` |
|
|
11
|
-
| `api-and-data/` | HTTP, сервисы, store | `paths:` по каталогам слоя |
|
|
12
|
-
| `ui-and-accessibility/` | React UI, стили, a11y, пропсы | core — session; `react-ui.md` — `paths: app/src/ui/**` |
|
|
13
|
-
| `testing/` | unit, e2e, Playwright agents | `tests-unit.md`, `tests-e2e-structure.md` — `paths:`; `playwright-agents.md` — session start |
|
|
14
|
-
| `tooling-and-review/` | lint, package manager, качество, MR review | session start |
|
|
7
|
+
- **Session start (no `paths:`):** `next-app-core`, `post-change-lint`, `package-manager`, `agent-team-intake`, `code-quality`, orchestrator
|
|
8
|
+
- **`paths:` on-demand:** architecture, imports, UI, tests, feature-delivery-workflow, reference-features, next-app-router, react-a11y-coding
|
|
9
|
+
- **Skills:** long workflows (`feature-delivery`, `code-review`, …)
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
## С чего начать
|
|
17
12
|
|
|
18
|
-
|
|
13
|
+
- **`commands/task.md`** — router → `pipeline.json` → agents
|
|
14
|
+
- **`architecture/reference-features.md`** — заполнить TBD после init
|
|
15
|
+
- **`architecture/feature-delivery-workflow.md`** — порядок слоёв
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## Каталог правил
|
|
17
|
+
## Каталог (новые и ключевые)
|
|
23
18
|
|
|
24
19
|
| Файл | Назначение |
|
|
25
20
|
|------|------------|
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `architecture/feature-delivery-workflow.md` | Сквозной
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
| `architecture/types-public-imports.md` | Импорты только через barrel `@/types` |
|
|
37
|
-
| `architecture/api-public-imports.md` | Импорты только через barrel `@/api` |
|
|
38
|
-
| `architecture/layer-barrel-exports.md` | Двухуровневые barrel для слоёв с public API |
|
|
39
|
-
| `stack/types-jsdoc.md` | JSDoc для типов в `app/src/types` |
|
|
40
|
-
| `stack/no-type-assertion.md` | Ограничение `as`, `instanceof` для ошибок транспорта |
|
|
41
|
-
| `tooling-and-review/code-review-mr.md` | Чеклист ревью MR |
|
|
42
|
-
| `testing/tests-unit.md` | Unit‑тесты и behavior‑тесты HTTP‑клиента |
|
|
43
|
-
| `testing/playwright-agents.md`, `testing/tests-e2e-structure.md` | E2e |
|
|
44
|
-
| `ui-and-accessibility/react-ui.md` | React/Next UI: структура, `.data.ts` / `.utils.ts`, стили |
|
|
45
|
-
| `ui-and-accessibility/no-props-spread.md` | Без spread пропов в компонентах |
|
|
46
|
-
| `ui-and-accessibility/component-styles.md` | Колокация стилей, `Root` |
|
|
47
|
-
| `ui-and-accessibility/css-property-order.md` | Порядок CSS (Stylelint) |
|
|
48
|
-
| `stack/arrow-functions.md` | Стрелочные функции |
|
|
49
|
-
| `stack/navigation-router.md` | Навигация по стеку проекта |
|
|
50
|
-
| `tooling-and-review/code-quality.md` | Качество кода и рефакторинг |
|
|
51
|
-
|
|
52
|
-
**Коллизии:** импорт типов — **`architecture/types-public-imports.md`**; импорт API вне `app/src/api/**` — **`architecture/api-public-imports.md`**.
|
|
53
|
-
|
|
54
|
-
Задачи на **сеть, HTTP, эндпоинты**: **`api-and-data/http-client.md`** + **`api-and-data/api-services.md`** + **`api-and-data/store-rtk.md`**.
|
|
21
|
+
| `architecture/reference-features.md` | Эталонные пути UI/store/API |
|
|
22
|
+
| `stack/next-app-router.md` | App Router, RSC |
|
|
23
|
+
| `ui-and-accessibility/react-a11y-coding.md` | A11y при кодинге UI |
|
|
24
|
+
| `architecture/feature-delivery-workflow.md` | Сквозной чеклист (paths) |
|
|
25
|
+
| `tooling-and-review/agent-team-orchestrator.md` | Pipeline, build-verifier, parallel |
|
|
26
|
+
| `agents/build-verifier.md` | Validation gate agent |
|
|
27
|
+
|
|
28
|
+
Полный список — см. подпапки `architecture/`, `stack/`, `api-and-data/`, `ui-and-accessibility/`, `testing/`, `tooling-and-review/`.
|
|
29
|
+
|
|
30
|
+
**Коллизии:** импорт типов — `architecture/types-public-imports.md`; API вне `app/src/api/**` — `architecture/api-public-imports.md`.
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- app/src/**/*.ts
|
|
4
|
+
- app/src/**/*.tsx
|
|
5
|
+
---
|
|
6
|
+
|
|
1
7
|
# Импорты из `@/api`
|
|
2
8
|
|
|
3
9
|
- **Публичный API слоя API** — barrel `app/src/api/index.ts`. Для файлов **вне** `app/src/api/**` импортировать сервисы, клиенты, эндпоинты и публичные типы API **только** как `import … from '@/api'` (или `from '@/api/index'` при необходимости явного пути).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- app/src/**/*
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Эталонные фичи (reference features)
|
|
7
|
+
|
|
8
|
+
Перед реализацией найди фичу того же типа и **повтори её структуру**, не изобретая новую организацию файлов.
|
|
9
|
+
|
|
10
|
+
## Таблица эталонов
|
|
11
|
+
|
|
12
|
+
Замени **TBD** на реальные пути после договорённости в команде (или при `ai-rules init` в целевом репо):
|
|
13
|
+
|
|
14
|
+
| Слой | Эталон | Что копировать |
|
|
15
|
+
|------|--------|----------------|
|
|
16
|
+
| UI page | **TBD** `app/src/ui/pages/<Example>/` | `components/`, `*.data.ts`, `styles.ts`, barrel |
|
|
17
|
+
| Store slice | **TBD** `app/src/store/slices/<example>/` | slice, thunks, selectors, types |
|
|
18
|
+
| API service | **TBD** `app/src/api/services/<example>/` | service, mappers, barrel |
|
|
19
|
+
| Types module | **TBD** `app/src/types/<example>/` | domain types, JSDoc, barrel export |
|
|
20
|
+
| Unit tests | **TBD** рядом с эталонным mapper/service | `*.spec.ts`, describe/it naming |
|
|
21
|
+
| E2E area | **TBD** `app/__tests__/e2e/<Area>/` | `*.cases.md`, page objects, `_shared/` |
|
|
22
|
+
|
|
23
|
+
## Как использовать
|
|
24
|
+
|
|
25
|
+
1. Определи затронутые слои из `decomposition.md` или задачи.
|
|
26
|
+
2. Открой эталон из таблицы (после заполнения путей).
|
|
27
|
+
3. Зеркаль именование, порядок файлов, паттерны импортов и тестов.
|
|
28
|
+
4. Если эталона нет — выбери **самую близкую** существующую фичу того же слоя и зафиксируй выбор в handoff.
|
|
29
|
+
|
|
30
|
+
## Связанные правила
|
|
31
|
+
|
|
32
|
+
- `tooling-and-review/code-quality.md` — повторять паттерны, не deep-import.
|
|
33
|
+
- `architecture/feature-delivery-workflow.md` — порядок слоёв.
|
|
34
|
+
- skill `feature-delivery` — end-to-end сценарий.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- app/src/ui/**/*
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Навигация и роутинг: сначала стек проекта
|
|
2
7
|
|
|
3
8
|
**При любой задаче, связанной с навигацией, переходами между страницами, URL, редиректами, хлебными крошками, защищёнными маршрутами или программной сменой маршрута** — перед предложением кода или импортов **нельзя** опираться на «типичный React» по умолчанию. Нужно **явно свериться со стеком целевого репозитория** и использовать **один** согласованный с проектом механизм.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- app/src/app/**/*
|
|
4
|
+
- app/**/app/**/*
|
|
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
|
+
- Навигация — `stack/navigation-router.md` + 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/**` и повтори структуру (`architecture/reference-features.md`).
|