agentic-team-templates 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +280 -0
- package/bin/cli.js +5 -0
- package/package.json +47 -0
- package/src/index.js +521 -0
- package/templates/_shared/code-quality.md +162 -0
- package/templates/_shared/communication.md +114 -0
- package/templates/_shared/core-principles.md +62 -0
- package/templates/_shared/git-workflow.md +165 -0
- package/templates/_shared/security-fundamentals.md +173 -0
- package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
- package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
- package/templates/blockchain/.cursorrules/overview.md +130 -0
- package/templates/blockchain/.cursorrules/security.md +318 -0
- package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
- package/templates/blockchain/.cursorrules/testing.md +415 -0
- package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
- package/templates/blockchain/CLAUDE.md +389 -0
- package/templates/cli-tools/.cursorrules/architecture.md +412 -0
- package/templates/cli-tools/.cursorrules/arguments.md +406 -0
- package/templates/cli-tools/.cursorrules/distribution.md +546 -0
- package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
- package/templates/cli-tools/.cursorrules/overview.md +136 -0
- package/templates/cli-tools/.cursorrules/testing.md +537 -0
- package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
- package/templates/cli-tools/CLAUDE.md +356 -0
- package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
- package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
- package/templates/data-engineering/.cursorrules/overview.md +85 -0
- package/templates/data-engineering/.cursorrules/performance.md +339 -0
- package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
- package/templates/data-engineering/.cursorrules/security.md +460 -0
- package/templates/data-engineering/.cursorrules/testing.md +452 -0
- package/templates/data-engineering/CLAUDE.md +974 -0
- package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
- package/templates/devops-sre/.cursorrules/change-management.md +584 -0
- package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
- package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
- package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
- package/templates/devops-sre/.cursorrules/observability.md +714 -0
- package/templates/devops-sre/.cursorrules/overview.md +230 -0
- package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
- package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
- package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
- package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
- package/templates/devops-sre/CLAUDE.md +1007 -0
- package/templates/documentation/.cursorrules/adr.md +277 -0
- package/templates/documentation/.cursorrules/api-documentation.md +411 -0
- package/templates/documentation/.cursorrules/code-comments.md +253 -0
- package/templates/documentation/.cursorrules/maintenance.md +260 -0
- package/templates/documentation/.cursorrules/overview.md +82 -0
- package/templates/documentation/.cursorrules/readme-standards.md +306 -0
- package/templates/documentation/CLAUDE.md +120 -0
- package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
- package/templates/fullstack/.cursorrules/architecture.md +298 -0
- package/templates/fullstack/.cursorrules/overview.md +109 -0
- package/templates/fullstack/.cursorrules/shared-types.md +348 -0
- package/templates/fullstack/.cursorrules/testing.md +386 -0
- package/templates/fullstack/CLAUDE.md +349 -0
- package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
- package/templates/ml-ai/.cursorrules/deployment.md +601 -0
- package/templates/ml-ai/.cursorrules/model-development.md +538 -0
- package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
- package/templates/ml-ai/.cursorrules/overview.md +131 -0
- package/templates/ml-ai/.cursorrules/security.md +637 -0
- package/templates/ml-ai/.cursorrules/testing.md +678 -0
- package/templates/ml-ai/CLAUDE.md +1136 -0
- package/templates/mobile/.cursorrules/navigation.md +246 -0
- package/templates/mobile/.cursorrules/offline-first.md +302 -0
- package/templates/mobile/.cursorrules/overview.md +71 -0
- package/templates/mobile/.cursorrules/performance.md +345 -0
- package/templates/mobile/.cursorrules/testing.md +339 -0
- package/templates/mobile/CLAUDE.md +233 -0
- package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
- package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
- package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
- package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
- package/templates/platform-engineering/.cursorrules/observability.md +747 -0
- package/templates/platform-engineering/.cursorrules/overview.md +215 -0
- package/templates/platform-engineering/.cursorrules/security.md +855 -0
- package/templates/platform-engineering/.cursorrules/testing.md +878 -0
- package/templates/platform-engineering/CLAUDE.md +850 -0
- package/templates/utility-agent/.cursorrules/action-control.md +284 -0
- package/templates/utility-agent/.cursorrules/context-management.md +186 -0
- package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
- package/templates/utility-agent/.cursorrules/overview.md +78 -0
- package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
- package/templates/utility-agent/CLAUDE.md +513 -0
- package/templates/web-backend/.cursorrules/api-design.md +255 -0
- package/templates/web-backend/.cursorrules/authentication.md +309 -0
- package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
- package/templates/web-backend/.cursorrules/error-handling.md +366 -0
- package/templates/web-backend/.cursorrules/overview.md +69 -0
- package/templates/web-backend/.cursorrules/security.md +358 -0
- package/templates/web-backend/.cursorrules/testing.md +395 -0
- package/templates/web-backend/CLAUDE.md +366 -0
- package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
- package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
- package/templates/web-frontend/.cursorrules/overview.md +72 -0
- package/templates/web-frontend/.cursorrules/performance.md +325 -0
- package/templates/web-frontend/.cursorrules/state-management.md +227 -0
- package/templates/web-frontend/.cursorrules/styling.md +271 -0
- package/templates/web-frontend/.cursorrules/testing.md +311 -0
- package/templates/web-frontend/CLAUDE.md +399 -0
package/src/index.js
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
8
|
+
|
|
9
|
+
// Available templates
|
|
10
|
+
const TEMPLATES = {
|
|
11
|
+
'blockchain': {
|
|
12
|
+
description: 'Smart contracts, DeFi protocols, and Web3 applications (Solidity, Foundry, Viem)',
|
|
13
|
+
rules: ['defi-patterns.md', 'gas-optimization.md', 'overview.md', 'security.md', 'smart-contracts.md', 'testing.md', 'web3-integration.md']
|
|
14
|
+
},
|
|
15
|
+
'cli-tools': {
|
|
16
|
+
description: 'Command-line applications and developer tools (Cobra, Commander, Click)',
|
|
17
|
+
rules: ['architecture.md', 'arguments.md', 'distribution.md', 'error-handling.md', 'overview.md', 'testing.md', 'user-experience.md']
|
|
18
|
+
},
|
|
19
|
+
'documentation': {
|
|
20
|
+
description: 'Technical documentation standards (READMEs, API docs, ADRs, code comments)',
|
|
21
|
+
rules: ['adr.md', 'api-documentation.md', 'code-comments.md', 'maintenance.md', 'overview.md', 'readme-standards.md']
|
|
22
|
+
},
|
|
23
|
+
'fullstack': {
|
|
24
|
+
description: 'Full-stack web applications (Next.js, Nuxt, SvelteKit, Remix)',
|
|
25
|
+
rules: ['api-contracts.md', 'architecture.md', 'overview.md', 'shared-types.md', 'testing.md']
|
|
26
|
+
},
|
|
27
|
+
'mobile': {
|
|
28
|
+
description: 'Mobile applications (React Native, Flutter, native iOS/Android)',
|
|
29
|
+
rules: ['navigation.md', 'offline-first.md', 'overview.md', 'performance.md', 'testing.md']
|
|
30
|
+
},
|
|
31
|
+
'utility-agent': {
|
|
32
|
+
description: 'AI agent utilities with context management and hallucination prevention',
|
|
33
|
+
rules: ['action-control.md', 'context-management.md', 'hallucination-prevention.md', 'overview.md', 'token-optimization.md']
|
|
34
|
+
},
|
|
35
|
+
'web-backend': {
|
|
36
|
+
description: 'Backend APIs and services (REST, GraphQL, microservices)',
|
|
37
|
+
rules: ['api-design.md', 'authentication.md', 'database-patterns.md', 'error-handling.md', 'overview.md', 'security.md', 'testing.md']
|
|
38
|
+
},
|
|
39
|
+
'web-frontend': {
|
|
40
|
+
description: 'Frontend web applications (SPAs, SSR, static sites, PWAs)',
|
|
41
|
+
rules: ['accessibility.md', 'component-patterns.md', 'overview.md', 'performance.md', 'state-management.md', 'styling.md', 'testing.md']
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const SHARED_RULES = [
|
|
46
|
+
'code-quality.md',
|
|
47
|
+
'communication.md',
|
|
48
|
+
'core-principles.md',
|
|
49
|
+
'git-workflow.md',
|
|
50
|
+
'security-fundamentals.md'
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// Colors
|
|
54
|
+
const colors = {
|
|
55
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
56
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
57
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
58
|
+
blue: (s) => `\x1b[34m${s}\x1b[0m`,
|
|
59
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function printBanner() {
|
|
63
|
+
console.log(colors.blue(`
|
|
64
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
65
|
+
║ Cursor Templates Installer ║
|
|
66
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
67
|
+
`));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function printHelp() {
|
|
71
|
+
console.log(`${colors.yellow('Usage:')}
|
|
72
|
+
npx cursor-templates <templates...>
|
|
73
|
+
|
|
74
|
+
${colors.yellow('Options:')}
|
|
75
|
+
--list, -l List available templates
|
|
76
|
+
--help, -h Show this help message
|
|
77
|
+
--dry-run Show what would be installed
|
|
78
|
+
--force, -f Overwrite existing files (default: skip)
|
|
79
|
+
|
|
80
|
+
${colors.yellow('Examples:')}
|
|
81
|
+
npx cursor-templates web-frontend
|
|
82
|
+
npx cursor-templates web-frontend web-backend
|
|
83
|
+
npx cursor-templates fullstack
|
|
84
|
+
npx cursor-templates mobile utility-agent
|
|
85
|
+
npx cursor-templates web-backend --force
|
|
86
|
+
|
|
87
|
+
${colors.dim('Shared rules (code-quality, security, git-workflow, etc.) are always included.')}
|
|
88
|
+
${colors.dim('Identical files are skipped. Modified files are preserved; ours saved as *-1.md.')}
|
|
89
|
+
`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function printTemplates() {
|
|
93
|
+
console.log(colors.yellow('Available Templates:\n'));
|
|
94
|
+
|
|
95
|
+
for (const [name, info] of Object.entries(TEMPLATES)) {
|
|
96
|
+
console.log(` ${colors.green(name)}`);
|
|
97
|
+
console.log(` ${info.description}\n`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log(colors.blue('Shared rules (always included):'));
|
|
101
|
+
for (const rule of SHARED_RULES) {
|
|
102
|
+
console.log(` - ${rule.replace('.md', '')}`);
|
|
103
|
+
}
|
|
104
|
+
console.log();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if two files have identical content
|
|
109
|
+
*/
|
|
110
|
+
function filesMatch(file1, file2) {
|
|
111
|
+
try {
|
|
112
|
+
const content1 = fs.readFileSync(file1, 'utf8');
|
|
113
|
+
const content2 = fs.readFileSync(file2, 'utf8');
|
|
114
|
+
return content1 === content2;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get alternate filename with -1 suffix (e.g., code-quality.md -> code-quality-1.md)
|
|
122
|
+
*/
|
|
123
|
+
function getAlternateFilename(filepath) {
|
|
124
|
+
const dir = path.dirname(filepath);
|
|
125
|
+
const ext = path.extname(filepath);
|
|
126
|
+
const base = path.basename(filepath, ext);
|
|
127
|
+
return path.join(dir, `${base}-1${ext}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Copy file, handling existing files intelligently
|
|
132
|
+
* @returns {{ status: string, destFile: string }}
|
|
133
|
+
* status: 'copied' | 'skipped' | 'renamed' | 'updated'
|
|
134
|
+
* destFile: actual destination path (may differ if renamed)
|
|
135
|
+
*/
|
|
136
|
+
function copyFile(src, dest, force = false) {
|
|
137
|
+
const destDir = path.dirname(dest);
|
|
138
|
+
if (!fs.existsSync(destDir)) {
|
|
139
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const exists = fs.existsSync(dest);
|
|
143
|
+
|
|
144
|
+
if (!exists) {
|
|
145
|
+
// File doesn't exist - copy normally
|
|
146
|
+
fs.copyFileSync(src, dest);
|
|
147
|
+
return { status: 'copied', destFile: dest };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (force) {
|
|
151
|
+
// Force mode - overwrite
|
|
152
|
+
fs.copyFileSync(src, dest);
|
|
153
|
+
return { status: 'updated', destFile: dest };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// File exists - check if it matches our template
|
|
157
|
+
if (filesMatch(src, dest)) {
|
|
158
|
+
// Same content - skip
|
|
159
|
+
return { status: 'skipped', destFile: dest };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Different content - save ours alongside with -1 suffix
|
|
163
|
+
const altDest = getAlternateFilename(dest);
|
|
164
|
+
fs.copyFileSync(src, altDest);
|
|
165
|
+
return { status: 'renamed', destFile: altDest };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function generateClaudeMdContent(installedTemplates) {
|
|
169
|
+
const templateList = installedTemplates
|
|
170
|
+
.map(t => `- **${t}**: ${TEMPLATES[t].description}`)
|
|
171
|
+
.join('\n');
|
|
172
|
+
|
|
173
|
+
const templateRuleTables = installedTemplates.map(template => {
|
|
174
|
+
const rules = TEMPLATES[template].rules
|
|
175
|
+
.map(rule => `| \`${template}-${rule}\` | ${rule.replace('.md', '').replace(/-/g, ' ')} guidelines |`)
|
|
176
|
+
.join('\n');
|
|
177
|
+
|
|
178
|
+
return `
|
|
179
|
+
#### ${template.charAt(0).toUpperCase() + template.slice(1)} Rules
|
|
180
|
+
|
|
181
|
+
| Rule | Purpose |
|
|
182
|
+
|------|---------|
|
|
183
|
+
${rules}`;
|
|
184
|
+
}).join('\n');
|
|
185
|
+
|
|
186
|
+
return `# CLAUDE.md - Development Guide
|
|
187
|
+
|
|
188
|
+
This project uses AI-assisted development with Cursor. The rules in \`.cursorrules/\` provide domain-specific guidance for the AI assistant.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Quick Reference
|
|
193
|
+
|
|
194
|
+
### Installed Templates
|
|
195
|
+
|
|
196
|
+
- **Shared** (always included): Core principles, code quality, security, git workflow, communication
|
|
197
|
+
${templateList}
|
|
198
|
+
|
|
199
|
+
### Rule Files
|
|
200
|
+
|
|
201
|
+
All rules are in \`.cursorrules/\`. The AI assistant automatically reads these when working on your project.
|
|
202
|
+
|
|
203
|
+
#### Shared Rules (Apply to All Code)
|
|
204
|
+
|
|
205
|
+
| Rule | Purpose |
|
|
206
|
+
|------|---------|
|
|
207
|
+
| \`core-principles.md\` | Honesty, simplicity, testing requirements |
|
|
208
|
+
| \`code-quality.md\` | SOLID, DRY, clean code patterns |
|
|
209
|
+
| \`security-fundamentals.md\` | Zero trust, input validation, secrets |
|
|
210
|
+
| \`git-workflow.md\` | Commits, branches, PRs, safety |
|
|
211
|
+
| \`communication.md\` | Direct, objective, professional |
|
|
212
|
+
${templateRuleTables}
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Development Principles
|
|
217
|
+
|
|
218
|
+
### 1. Honesty Over Output
|
|
219
|
+
|
|
220
|
+
- If something doesn't work, say it doesn't work
|
|
221
|
+
- If you don't know, say you don't know
|
|
222
|
+
- Never hide errors or suppress warnings
|
|
223
|
+
- Admit mistakes early
|
|
224
|
+
|
|
225
|
+
### 2. Security First
|
|
226
|
+
|
|
227
|
+
- Zero trust: Every input is hostile until proven otherwise
|
|
228
|
+
- Validate and sanitize all inputs
|
|
229
|
+
- No secrets in code or logs
|
|
230
|
+
- Least privilege principle
|
|
231
|
+
|
|
232
|
+
### 3. Tests Are Required
|
|
233
|
+
|
|
234
|
+
- No feature is complete without tests
|
|
235
|
+
- Green CI or it didn't happen
|
|
236
|
+
- Test behavior, not implementation
|
|
237
|
+
|
|
238
|
+
### 4. Code Quality
|
|
239
|
+
|
|
240
|
+
- SOLID principles
|
|
241
|
+
- DRY (Don't Repeat Yourself)
|
|
242
|
+
- Functional programming bias
|
|
243
|
+
- Explicit over implicit
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Definition of Done
|
|
248
|
+
|
|
249
|
+
A feature is complete when:
|
|
250
|
+
|
|
251
|
+
- [ ] Code written and reviewed
|
|
252
|
+
- [ ] Tests written and passing
|
|
253
|
+
- [ ] No linting errors
|
|
254
|
+
- [ ] Security reviewed
|
|
255
|
+
- [ ] Documentation updated
|
|
256
|
+
- [ ] Committed with conventional commit message
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Customization
|
|
261
|
+
|
|
262
|
+
### Adding Project-Specific Rules
|
|
263
|
+
|
|
264
|
+
1. Create new \`.md\` files in \`.cursorrules/\`
|
|
265
|
+
2. Follow the existing naming convention
|
|
266
|
+
3. Include clear examples and anti-patterns
|
|
267
|
+
|
|
268
|
+
### Modifying Existing Rules
|
|
269
|
+
|
|
270
|
+
Edit files directly in \`.cursorrules/\`. Changes take effect immediately.
|
|
271
|
+
|
|
272
|
+
### Updating Templates
|
|
273
|
+
|
|
274
|
+
Re-run the installer to update (will overwrite existing rules):
|
|
275
|
+
|
|
276
|
+
\`\`\`bash
|
|
277
|
+
npx cursor-templates ${installedTemplates.join(' ')}
|
|
278
|
+
\`\`\`
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Resources
|
|
283
|
+
|
|
284
|
+
- [Cursor Documentation](https://cursor.sh/docs)
|
|
285
|
+
`;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function generateClaudeMd(targetDir, installedTemplates) {
|
|
289
|
+
const content = generateClaudeMdContent(installedTemplates);
|
|
290
|
+
fs.writeFileSync(path.join(targetDir, 'CLAUDE.md'), content);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function generateClaudeMdToPath(targetDir, installedTemplates, destPath) {
|
|
294
|
+
const content = generateClaudeMdContent(installedTemplates);
|
|
295
|
+
fs.writeFileSync(destPath, content);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function install(targetDir, templates, dryRun = false, force = false) {
|
|
299
|
+
const cursorrules = path.join(targetDir, '.cursorrules');
|
|
300
|
+
|
|
301
|
+
if (!dryRun && !fs.existsSync(cursorrules)) {
|
|
302
|
+
fs.mkdirSync(cursorrules, { recursive: true });
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
console.log(`${colors.blue('Installing to:')} ${targetDir}`);
|
|
306
|
+
if (!force) {
|
|
307
|
+
console.log(colors.dim('(identical files skipped, modified files preserved with ours saved as *-1.md)'));
|
|
308
|
+
}
|
|
309
|
+
console.log();
|
|
310
|
+
|
|
311
|
+
const stats = { copied: 0, skipped: 0, updated: 0, renamed: 0 };
|
|
312
|
+
const renamedFiles = [];
|
|
313
|
+
|
|
314
|
+
// 1. Install shared rules
|
|
315
|
+
console.log(colors.green('► Installing shared rules...'));
|
|
316
|
+
for (const rule of SHARED_RULES) {
|
|
317
|
+
const src = path.join(TEMPLATES_DIR, '_shared', rule);
|
|
318
|
+
const dest = path.join(cursorrules, rule);
|
|
319
|
+
|
|
320
|
+
if (dryRun) {
|
|
321
|
+
const exists = fs.existsSync(dest);
|
|
322
|
+
if (!exists) {
|
|
323
|
+
console.log(` ${colors.dim('[copy]')} ${rule}`);
|
|
324
|
+
} else if (force) {
|
|
325
|
+
console.log(` ${colors.dim('[update]')} ${rule}`);
|
|
326
|
+
} else if (filesMatch(src, dest)) {
|
|
327
|
+
console.log(` ${colors.yellow('[skip]')} ${rule} (identical)`);
|
|
328
|
+
} else {
|
|
329
|
+
const altName = path.basename(getAlternateFilename(dest));
|
|
330
|
+
console.log(` ${colors.blue('[rename]')} ${rule} → ${altName}`);
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
const result = copyFile(src, dest, force);
|
|
334
|
+
stats[result.status]++;
|
|
335
|
+
if (result.status === 'skipped') {
|
|
336
|
+
console.log(` ${colors.yellow('[skip]')} ${rule} (identical)`);
|
|
337
|
+
} else if (result.status === 'renamed') {
|
|
338
|
+
const altName = path.basename(result.destFile);
|
|
339
|
+
renamedFiles.push({ original: rule, renamed: altName });
|
|
340
|
+
console.log(` ${colors.blue('[rename]')} ${rule} → ${altName}`);
|
|
341
|
+
} else {
|
|
342
|
+
console.log(` ${colors.dim(`[${result.status}]`)} ${rule}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
console.log();
|
|
347
|
+
|
|
348
|
+
// 2. Install template-specific rules
|
|
349
|
+
for (const template of templates) {
|
|
350
|
+
console.log(colors.green(`► Installing ${template} template...`));
|
|
351
|
+
|
|
352
|
+
for (const rule of TEMPLATES[template].rules) {
|
|
353
|
+
const src = path.join(TEMPLATES_DIR, template, '.cursorrules', rule);
|
|
354
|
+
const dest = path.join(cursorrules, `${template}-${rule}`);
|
|
355
|
+
const destName = `${template}-${rule}`;
|
|
356
|
+
|
|
357
|
+
if (dryRun) {
|
|
358
|
+
const exists = fs.existsSync(dest);
|
|
359
|
+
if (!exists) {
|
|
360
|
+
console.log(` ${colors.dim('[copy]')} ${destName}`);
|
|
361
|
+
} else if (force) {
|
|
362
|
+
console.log(` ${colors.dim('[update]')} ${destName}`);
|
|
363
|
+
} else if (filesMatch(src, dest)) {
|
|
364
|
+
console.log(` ${colors.yellow('[skip]')} ${destName} (identical)`);
|
|
365
|
+
} else {
|
|
366
|
+
const altName = path.basename(getAlternateFilename(dest));
|
|
367
|
+
console.log(` ${colors.blue('[rename]')} ${destName} → ${altName}`);
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
const result = copyFile(src, dest, force);
|
|
371
|
+
stats[result.status]++;
|
|
372
|
+
if (result.status === 'skipped') {
|
|
373
|
+
console.log(` ${colors.yellow('[skip]')} ${destName} (identical)`);
|
|
374
|
+
} else if (result.status === 'renamed') {
|
|
375
|
+
const altName = path.basename(result.destFile);
|
|
376
|
+
renamedFiles.push({ original: destName, renamed: altName });
|
|
377
|
+
console.log(` ${colors.blue('[rename]')} ${destName} → ${altName}`);
|
|
378
|
+
} else {
|
|
379
|
+
console.log(` ${colors.dim(`[${result.status}]`)} ${destName}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
console.log();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 3. Generate CLAUDE.md
|
|
387
|
+
const claudePath = path.join(targetDir, 'CLAUDE.md');
|
|
388
|
+
const claudeExists = fs.existsSync(claudePath);
|
|
389
|
+
|
|
390
|
+
console.log(colors.green('► Generating CLAUDE.md...'));
|
|
391
|
+
if (dryRun) {
|
|
392
|
+
if (!claudeExists) {
|
|
393
|
+
console.log(` ${colors.dim('[copy]')} CLAUDE.md`);
|
|
394
|
+
} else if (force) {
|
|
395
|
+
console.log(` ${colors.dim('[update]')} CLAUDE.md`);
|
|
396
|
+
} else {
|
|
397
|
+
console.log(` ${colors.blue('[rename]')} CLAUDE.md → CLAUDE-1.md`);
|
|
398
|
+
}
|
|
399
|
+
} else if (!claudeExists) {
|
|
400
|
+
generateClaudeMd(targetDir, templates);
|
|
401
|
+
console.log(` ${colors.dim('[copied]')} CLAUDE.md`);
|
|
402
|
+
stats.copied++;
|
|
403
|
+
} else if (force) {
|
|
404
|
+
generateClaudeMd(targetDir, templates);
|
|
405
|
+
console.log(` ${colors.dim('[updated]')} CLAUDE.md`);
|
|
406
|
+
stats.updated++;
|
|
407
|
+
} else {
|
|
408
|
+
// Save ours as CLAUDE-1.md
|
|
409
|
+
const altClaudePath = path.join(targetDir, 'CLAUDE-1.md');
|
|
410
|
+
generateClaudeMdToPath(targetDir, templates, altClaudePath);
|
|
411
|
+
renamedFiles.push({ original: 'CLAUDE.md', renamed: 'CLAUDE-1.md' });
|
|
412
|
+
console.log(` ${colors.blue('[rename]')} CLAUDE.md → CLAUDE-1.md`);
|
|
413
|
+
stats.renamed++;
|
|
414
|
+
}
|
|
415
|
+
console.log();
|
|
416
|
+
|
|
417
|
+
// Summary
|
|
418
|
+
console.log(colors.green('════════════════════════════════════════════════════════════'));
|
|
419
|
+
console.log(colors.green('✓ Installation complete!\n'));
|
|
420
|
+
|
|
421
|
+
console.log(colors.yellow('Summary:'));
|
|
422
|
+
console.log(` - ${stats.copied} files created`);
|
|
423
|
+
if (stats.updated > 0) {
|
|
424
|
+
console.log(` - ${stats.updated} files updated`);
|
|
425
|
+
}
|
|
426
|
+
if (stats.skipped > 0) {
|
|
427
|
+
console.log(` - ${stats.skipped} files skipped (identical to template)`);
|
|
428
|
+
}
|
|
429
|
+
if (stats.renamed > 0) {
|
|
430
|
+
console.log(` - ${colors.blue(`${stats.renamed} files saved as *-1.md`)} (yours preserved)`);
|
|
431
|
+
}
|
|
432
|
+
console.log();
|
|
433
|
+
|
|
434
|
+
console.log(colors.yellow('Templates installed:'));
|
|
435
|
+
console.log(' - _shared (always included)');
|
|
436
|
+
for (const template of templates) {
|
|
437
|
+
console.log(` - ${template}`);
|
|
438
|
+
}
|
|
439
|
+
console.log();
|
|
440
|
+
|
|
441
|
+
if (renamedFiles.length > 0) {
|
|
442
|
+
console.log(colors.blue('Files saved alongside existing (your files preserved):'));
|
|
443
|
+
for (const { original, renamed } of renamedFiles) {
|
|
444
|
+
console.log(` - ${original} → ${renamed}`);
|
|
445
|
+
}
|
|
446
|
+
console.log(colors.dim('\nReview the -1 files and merge changes as needed.'));
|
|
447
|
+
console.log(colors.dim('Use --force to overwrite existing files instead.'));
|
|
448
|
+
console.log();
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
console.log(colors.blue('Next steps:'));
|
|
452
|
+
console.log(' 1. Review CLAUDE.md for any customization');
|
|
453
|
+
console.log(' 2. Commit the new files to your repository');
|
|
454
|
+
console.log();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function run(args) {
|
|
458
|
+
const templates = [];
|
|
459
|
+
let dryRun = false;
|
|
460
|
+
let force = false;
|
|
461
|
+
|
|
462
|
+
// Parse arguments
|
|
463
|
+
for (const arg of args) {
|
|
464
|
+
switch (arg) {
|
|
465
|
+
case '--list':
|
|
466
|
+
case '-l':
|
|
467
|
+
printBanner();
|
|
468
|
+
printTemplates();
|
|
469
|
+
process.exit(0);
|
|
470
|
+
break;
|
|
471
|
+
case '--help':
|
|
472
|
+
case '-h':
|
|
473
|
+
printBanner();
|
|
474
|
+
printHelp();
|
|
475
|
+
process.exit(0);
|
|
476
|
+
break;
|
|
477
|
+
case '--dry-run':
|
|
478
|
+
dryRun = true;
|
|
479
|
+
break;
|
|
480
|
+
case '--force':
|
|
481
|
+
case '-f':
|
|
482
|
+
force = true;
|
|
483
|
+
break;
|
|
484
|
+
default:
|
|
485
|
+
if (arg.startsWith('-')) {
|
|
486
|
+
console.error(colors.red(`Error: Unknown option '${arg}'`));
|
|
487
|
+
printHelp();
|
|
488
|
+
process.exit(1);
|
|
489
|
+
}
|
|
490
|
+
templates.push(arg);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
printBanner();
|
|
495
|
+
|
|
496
|
+
// Validate
|
|
497
|
+
if (templates.length === 0) {
|
|
498
|
+
console.error(colors.red('Error: No templates specified\n'));
|
|
499
|
+
printHelp();
|
|
500
|
+
process.exit(1);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
for (const template of templates) {
|
|
504
|
+
if (!TEMPLATES[template]) {
|
|
505
|
+
console.error(colors.red(`Error: Unknown template '${template}'\n`));
|
|
506
|
+
printTemplates();
|
|
507
|
+
process.exit(1);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (dryRun) {
|
|
512
|
+
console.log(colors.yellow('DRY RUN - No changes will be made\n'));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (force) {
|
|
516
|
+
console.log(colors.yellow('FORCE MODE - Existing files will be overwritten\n'));
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Install to current directory
|
|
520
|
+
install(process.cwd(), templates, dryRun, force);
|
|
521
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Code Quality Standards
|
|
2
|
+
|
|
3
|
+
Universal code quality principles applicable across all languages and frameworks.
|
|
4
|
+
|
|
5
|
+
## SOLID Principles
|
|
6
|
+
|
|
7
|
+
### Single Responsibility (S)
|
|
8
|
+
One function, one job. One class, one purpose.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
// Good
|
|
12
|
+
function validateEmail(email: string): boolean { ... }
|
|
13
|
+
function sendEmail(email: string, body: string): void { ... }
|
|
14
|
+
|
|
15
|
+
// Bad
|
|
16
|
+
function validateAndSendEmail(email: string, body: string): boolean { ... }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Open/Closed (O)
|
|
20
|
+
Extend via composition, not modification.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
// Good: Extend behavior through composition
|
|
24
|
+
const enhancedLogger = compose(addTimestamp, addContext)(baseLogger);
|
|
25
|
+
|
|
26
|
+
// Bad: Modify existing code to add features
|
|
27
|
+
function logger(msg) {
|
|
28
|
+
if (config.addTimestamp) { ... } // Adding more conditionals over time
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Liskov Substitution (L)
|
|
33
|
+
Subtypes must be substitutable for their base types.
|
|
34
|
+
|
|
35
|
+
### Interface Segregation (I)
|
|
36
|
+
Small, focused interfaces over large, general ones.
|
|
37
|
+
|
|
38
|
+
### Dependency Inversion (D)
|
|
39
|
+
Depend on abstractions, not concrete implementations.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
// Good: Inject dependencies
|
|
43
|
+
function processOrder(orderRepo: OrderRepository) { ... }
|
|
44
|
+
|
|
45
|
+
// Bad: Import concrete implementations
|
|
46
|
+
import { MySQLOrderRepo } from './mysql-repo';
|
|
47
|
+
function processOrder() { const repo = new MySQLOrderRepo(); ... }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## DRY (Don't Repeat Yourself)
|
|
51
|
+
|
|
52
|
+
- Abstract repeated patterns into utilities
|
|
53
|
+
- Create reusable components/functions
|
|
54
|
+
- One source of truth for validation logic, constants, configurations
|
|
55
|
+
- BUT: Don't over-abstract. Three similar lines is often better than a premature abstraction.
|
|
56
|
+
|
|
57
|
+
## Clean Code Practices
|
|
58
|
+
|
|
59
|
+
### Naming
|
|
60
|
+
- Use intention-revealing names
|
|
61
|
+
- Avoid abbreviations unless universally understood
|
|
62
|
+
- Be consistent with naming conventions
|
|
63
|
+
- Names should be searchable
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
// Good
|
|
67
|
+
const maxConnectionRetries = 3;
|
|
68
|
+
const userEmailAddress = getEmail(user);
|
|
69
|
+
|
|
70
|
+
// Bad
|
|
71
|
+
const max = 3;
|
|
72
|
+
const e = getE(u);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Functions
|
|
76
|
+
- Keep functions small (ideally < 20 lines)
|
|
77
|
+
- Functions should do one thing
|
|
78
|
+
- Minimize arguments (0-3 is ideal)
|
|
79
|
+
- Avoid side effects when possible
|
|
80
|
+
- Return early to reduce nesting
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
// Good: Return early
|
|
84
|
+
function getDiscount(user) {
|
|
85
|
+
if (!user) return 0;
|
|
86
|
+
if (!user.isPremium) return 0;
|
|
87
|
+
return user.discountRate;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Bad: Deep nesting
|
|
91
|
+
function getDiscount(user) {
|
|
92
|
+
if (user) {
|
|
93
|
+
if (user.isPremium) {
|
|
94
|
+
return user.discountRate;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Comments
|
|
102
|
+
- Code should be self-documenting
|
|
103
|
+
- Comments explain *why*, not *what*
|
|
104
|
+
- Delete commented-out code (that's what git is for)
|
|
105
|
+
- Keep comments up-to-date or delete them
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
// Good: Explains why
|
|
109
|
+
// Using retry logic because the external API is flaky during peak hours
|
|
110
|
+
await retryWithBackoff(apiCall, 3);
|
|
111
|
+
|
|
112
|
+
// Bad: Explains what (obvious from code)
|
|
113
|
+
// Increment counter by 1
|
|
114
|
+
counter++;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Error Handling
|
|
118
|
+
|
|
119
|
+
- Never swallow errors silently
|
|
120
|
+
- Provide meaningful error messages
|
|
121
|
+
- Fail fast with clear diagnostics
|
|
122
|
+
- Handle errors at the appropriate level
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
// Good
|
|
126
|
+
function parseConfig(path: string): Result<Config, ConfigError> {
|
|
127
|
+
const content = readFile(path);
|
|
128
|
+
if (!content.ok) {
|
|
129
|
+
return err(new ConfigError(`Failed to read config at ${path}: ${content.error}`));
|
|
130
|
+
}
|
|
131
|
+
// ...
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Bad
|
|
135
|
+
function parseConfig(path: string): Config | null {
|
|
136
|
+
try {
|
|
137
|
+
// ...
|
|
138
|
+
} catch (e) {
|
|
139
|
+
return null; // Caller has no idea what went wrong
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Immutability
|
|
145
|
+
|
|
146
|
+
Prefer immutable data structures and pure functions.
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
// Good: Immutable update
|
|
150
|
+
const updatedUser = { ...user, name: newName };
|
|
151
|
+
|
|
152
|
+
// Bad: Mutation
|
|
153
|
+
user.name = newName;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Avoid Over-Engineering
|
|
157
|
+
|
|
158
|
+
- Only make changes that are directly requested or clearly necessary
|
|
159
|
+
- Don't add features, refactor code, or make "improvements" beyond what was asked
|
|
160
|
+
- Don't add error handling for scenarios that can't happen
|
|
161
|
+
- Don't create helpers or abstractions for one-time operations
|
|
162
|
+
- Don't design for hypothetical future requirements
|