agentic-team-templates 0.13.2 → 0.15.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 +6 -1
- package/package.json +1 -1
- package/src/index.js +91 -13
- package/src/index.test.js +95 -1
- package/templates/cpp-expert/.cursorrules/concurrency.md +211 -0
- package/templates/cpp-expert/.cursorrules/error-handling.md +170 -0
- package/templates/cpp-expert/.cursorrules/memory-and-ownership.md +220 -0
- package/templates/cpp-expert/.cursorrules/modern-cpp.md +211 -0
- package/templates/cpp-expert/.cursorrules/overview.md +87 -0
- package/templates/cpp-expert/.cursorrules/performance.md +223 -0
- package/templates/cpp-expert/.cursorrules/testing.md +230 -0
- package/templates/cpp-expert/.cursorrules/tooling.md +312 -0
- package/templates/cpp-expert/CLAUDE.md +242 -0
- package/templates/csharp-expert/.cursorrules/aspnet-core.md +311 -0
- package/templates/csharp-expert/.cursorrules/async-patterns.md +206 -0
- package/templates/csharp-expert/.cursorrules/dependency-injection.md +206 -0
- package/templates/csharp-expert/.cursorrules/error-handling.md +235 -0
- package/templates/csharp-expert/.cursorrules/language-features.md +204 -0
- package/templates/csharp-expert/.cursorrules/overview.md +92 -0
- package/templates/csharp-expert/.cursorrules/performance.md +251 -0
- package/templates/csharp-expert/.cursorrules/testing.md +282 -0
- package/templates/csharp-expert/.cursorrules/tooling.md +254 -0
- package/templates/csharp-expert/CLAUDE.md +360 -0
- package/templates/java-expert/.cursorrules/concurrency.md +209 -0
- package/templates/java-expert/.cursorrules/error-handling.md +205 -0
- package/templates/java-expert/.cursorrules/modern-java.md +216 -0
- package/templates/java-expert/.cursorrules/overview.md +81 -0
- package/templates/java-expert/.cursorrules/performance.md +239 -0
- package/templates/java-expert/.cursorrules/persistence.md +262 -0
- package/templates/java-expert/.cursorrules/spring-boot.md +262 -0
- package/templates/java-expert/.cursorrules/testing.md +272 -0
- package/templates/java-expert/.cursorrules/tooling.md +301 -0
- package/templates/java-expert/CLAUDE.md +325 -0
- package/templates/javascript-expert/.cursorrules/overview.md +5 -3
- package/templates/javascript-expert/.cursorrules/typescript-deep-dive.md +348 -0
- package/templates/javascript-expert/CLAUDE.md +34 -3
- package/templates/kotlin-expert/.cursorrules/coroutines.md +237 -0
- package/templates/kotlin-expert/.cursorrules/error-handling.md +149 -0
- package/templates/kotlin-expert/.cursorrules/frameworks.md +227 -0
- package/templates/kotlin-expert/.cursorrules/language-features.md +231 -0
- package/templates/kotlin-expert/.cursorrules/overview.md +77 -0
- package/templates/kotlin-expert/.cursorrules/performance.md +185 -0
- package/templates/kotlin-expert/.cursorrules/testing.md +213 -0
- package/templates/kotlin-expert/.cursorrules/tooling.md +258 -0
- package/templates/kotlin-expert/CLAUDE.md +276 -0
- package/templates/swift-expert/.cursorrules/concurrency.md +230 -0
- package/templates/swift-expert/.cursorrules/error-handling.md +213 -0
- package/templates/swift-expert/.cursorrules/language-features.md +246 -0
- package/templates/swift-expert/.cursorrules/overview.md +88 -0
- package/templates/swift-expert/.cursorrules/performance.md +260 -0
- package/templates/swift-expert/.cursorrules/swiftui.md +260 -0
- package/templates/swift-expert/.cursorrules/testing.md +286 -0
- package/templates/swift-expert/.cursorrules/tooling.md +285 -0
- package/templates/swift-expert/CLAUDE.md +275 -0
package/README.md
CHANGED
|
@@ -148,13 +148,17 @@ npx agentic-team-templates --reset --force
|
|
|
148
148
|
| Template | Description |
|
|
149
149
|
|----------|-------------|
|
|
150
150
|
| `blockchain` | Smart contracts, DeFi protocols, and Web3 applications (Solidity, Foundry, Viem) |
|
|
151
|
+
| `cpp-expert` | Principal-level C++ engineering (modern C++, RAII, concurrency, templates, performance) |
|
|
152
|
+
| `csharp-expert` | Principal-level C# engineering (async, DI, EF Core, ASP.NET Core, testing) |
|
|
151
153
|
| `cli-tools` | Command-line applications and developer tools (Cobra, Commander, Click) |
|
|
152
154
|
| `data-engineering` | Data platforms and pipelines (ETL, data modeling, data quality) |
|
|
153
155
|
| `devops-sre` | DevOps and SRE practices (incident management, observability, SLOs, chaos engineering) |
|
|
154
156
|
| `documentation` | Technical documentation standards (READMEs, API docs, ADRs, code comments) |
|
|
155
157
|
| `fullstack` | Full-stack web applications (Next.js, Nuxt, SvelteKit, Remix) |
|
|
156
158
|
| `golang-expert` | Principal-level Go engineering (concurrency, stdlib, production patterns, testing) |
|
|
157
|
-
| `
|
|
159
|
+
| `kotlin-expert` | Principal-level Kotlin engineering (coroutines, multiplatform, Ktor, Spring Boot, testing) |
|
|
160
|
+
| `javascript-expert` | Principal-level JavaScript & TypeScript engineering (Node.js, React, type system, testing) |
|
|
161
|
+
| `java-expert` | Principal-level Java engineering (JVM, Spring Boot, concurrency, JPA, testing) |
|
|
158
162
|
| `ml-ai` | Machine learning and AI systems (model development, deployment, monitoring) |
|
|
159
163
|
| `mobile` | Mobile applications (React Native, Flutter, native iOS/Android) |
|
|
160
164
|
| `platform-engineering` | Internal developer platforms, infrastructure automation, reliability engineering |
|
|
@@ -162,6 +166,7 @@ npx agentic-team-templates --reset --force
|
|
|
162
166
|
| `python-expert` | Principal-level Python engineering (type system, async, testing, FastAPI, Django) |
|
|
163
167
|
| `qa-engineering` | Quality assurance programs for confident, rapid software delivery |
|
|
164
168
|
| `rust-expert` | Principal-level Rust engineering (ownership, concurrency, unsafe, traits, async) |
|
|
169
|
+
| `swift-expert` | Principal-level Swift engineering (concurrency, SwiftUI, protocols, testing, Apple platforms) |
|
|
165
170
|
| `testing` | Comprehensive testing practices (TDD, test design, CI/CD integration, performance testing) |
|
|
166
171
|
| `utility-agent` | AI agent utilities with context management and hallucination prevention |
|
|
167
172
|
| `web-backend` | Backend APIs and services (REST, GraphQL, microservices) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-team-templates",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "AI coding assistant templates for Cursor IDE. Pre-configured rules and guidelines that help AI assistants write better code. - use at your own risk",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cursor",
|
package/src/index.js
CHANGED
|
@@ -24,6 +24,14 @@ const TEMPLATES = {
|
|
|
24
24
|
description: 'Smart contracts, DeFi protocols, and Web3 applications (Solidity, Foundry, Viem)',
|
|
25
25
|
rules: ['defi-patterns.md', 'gas-optimization.md', 'overview.md', 'security.md', 'smart-contracts.md', 'testing.md', 'web3-integration.md']
|
|
26
26
|
},
|
|
27
|
+
'cpp-expert': {
|
|
28
|
+
description: 'Principal-level C++ engineering (modern C++, RAII, concurrency, templates, performance)',
|
|
29
|
+
rules: ['concurrency.md', 'error-handling.md', 'memory-and-ownership.md', 'modern-cpp.md', 'overview.md', 'performance.md', 'testing.md', 'tooling.md']
|
|
30
|
+
},
|
|
31
|
+
'csharp-expert': {
|
|
32
|
+
description: 'Principal-level C# engineering (async, DI, EF Core, ASP.NET Core, testing)',
|
|
33
|
+
rules: ['aspnet-core.md', 'async-patterns.md', 'dependency-injection.md', 'error-handling.md', 'language-features.md', 'overview.md', 'performance.md', 'testing.md', 'tooling.md']
|
|
34
|
+
},
|
|
27
35
|
'cli-tools': {
|
|
28
36
|
description: 'Command-line applications and developer tools (Cobra, Commander, Click)',
|
|
29
37
|
rules: ['architecture.md', 'arguments.md', 'distribution.md', 'error-handling.md', 'overview.md', 'testing.md', 'user-experience.md']
|
|
@@ -48,9 +56,17 @@ const TEMPLATES = {
|
|
|
48
56
|
description: 'Principal-level Go engineering (concurrency, stdlib, production patterns, testing)',
|
|
49
57
|
rules: ['concurrency.md', 'error-handling.md', 'interfaces-and-types.md', 'overview.md', 'performance.md', 'production-patterns.md', 'stdlib-and-tooling.md', 'testing.md']
|
|
50
58
|
},
|
|
59
|
+
'java-expert': {
|
|
60
|
+
description: 'Principal-level Java engineering (JVM, Spring Boot, concurrency, JPA, testing)',
|
|
61
|
+
rules: ['concurrency.md', 'error-handling.md', 'modern-java.md', 'overview.md', 'performance.md', 'persistence.md', 'spring-boot.md', 'testing.md', 'tooling.md']
|
|
62
|
+
},
|
|
51
63
|
'javascript-expert': {
|
|
52
|
-
description: 'Principal-level JavaScript engineering
|
|
53
|
-
rules: ['language-deep-dive.md', 'node-patterns.md', 'overview.md', 'performance.md', 'react-patterns.md', 'testing.md', 'tooling.md']
|
|
64
|
+
description: 'Principal-level JavaScript & TypeScript engineering (Node.js, React, type system, testing)',
|
|
65
|
+
rules: ['language-deep-dive.md', 'node-patterns.md', 'overview.md', 'performance.md', 'react-patterns.md', 'testing.md', 'tooling.md', 'typescript-deep-dive.md']
|
|
66
|
+
},
|
|
67
|
+
'kotlin-expert': {
|
|
68
|
+
description: 'Principal-level Kotlin engineering (coroutines, multiplatform, Ktor, Spring Boot, testing)',
|
|
69
|
+
rules: ['coroutines.md', 'error-handling.md', 'frameworks.md', 'language-features.md', 'overview.md', 'performance.md', 'testing.md', 'tooling.md']
|
|
54
70
|
},
|
|
55
71
|
'ml-ai': {
|
|
56
72
|
description: 'Machine learning and AI systems (model development, deployment, monitoring)',
|
|
@@ -80,6 +96,10 @@ const TEMPLATES = {
|
|
|
80
96
|
description: 'Principal-level Rust engineering (ownership, concurrency, unsafe, traits, async)',
|
|
81
97
|
rules: ['concurrency.md', 'ecosystem-and-tooling.md', 'error-handling.md', 'overview.md', 'ownership-and-borrowing.md', 'performance-and-unsafe.md', 'testing.md', 'traits-and-generics.md']
|
|
82
98
|
},
|
|
99
|
+
'swift-expert': {
|
|
100
|
+
description: 'Principal-level Swift engineering (concurrency, SwiftUI, protocols, testing, Apple platforms)',
|
|
101
|
+
rules: ['concurrency.md', 'error-handling.md', 'language-features.md', 'overview.md', 'performance.md', 'swiftui.md', 'testing.md', 'tooling.md']
|
|
102
|
+
},
|
|
83
103
|
'testing': {
|
|
84
104
|
description: 'Comprehensive testing practices (TDD, test design, CI/CD integration, performance testing)',
|
|
85
105
|
rules: ['advanced-techniques.md', 'ci-cd-integration.md', 'overview.md', 'performance-testing.md', 'quality-metrics.md', 'reliability.md', 'tdd-methodology.md', 'test-data.md', 'test-design.md', 'test-types.md']
|
|
@@ -98,6 +118,36 @@ const TEMPLATES = {
|
|
|
98
118
|
}
|
|
99
119
|
};
|
|
100
120
|
|
|
121
|
+
// Shorthand aliases for language expert templates
|
|
122
|
+
const TEMPLATE_ALIASES = {
|
|
123
|
+
'js': 'javascript-expert',
|
|
124
|
+
'javascript': 'javascript-expert',
|
|
125
|
+
'ts': 'javascript-expert',
|
|
126
|
+
'typescript': 'javascript-expert',
|
|
127
|
+
'go': 'golang-expert',
|
|
128
|
+
'golang': 'golang-expert',
|
|
129
|
+
'py': 'python-expert',
|
|
130
|
+
'python': 'python-expert',
|
|
131
|
+
'rs': 'rust-expert',
|
|
132
|
+
'rust': 'rust-expert',
|
|
133
|
+
'swift': 'swift-expert',
|
|
134
|
+
'kotlin': 'kotlin-expert',
|
|
135
|
+
'kt': 'kotlin-expert',
|
|
136
|
+
'java': 'java-expert',
|
|
137
|
+
'cpp': 'cpp-expert',
|
|
138
|
+
'csharp': 'csharp-expert',
|
|
139
|
+
'cs': 'csharp-expert',
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resolve a template alias to its canonical name
|
|
144
|
+
* @param {string} name - Template name or alias
|
|
145
|
+
* @returns {string} Canonical template name
|
|
146
|
+
*/
|
|
147
|
+
function resolveTemplateAlias(name) {
|
|
148
|
+
return TEMPLATE_ALIASES[name] || name;
|
|
149
|
+
}
|
|
150
|
+
|
|
101
151
|
const SHARED_RULES = [
|
|
102
152
|
'code-quality.md',
|
|
103
153
|
'communication.md',
|
|
@@ -195,7 +245,19 @@ ${colors.yellow('IDE Targets:')}
|
|
|
195
245
|
claude CLAUDE.md file (Claude Code, Cursor with Claude)
|
|
196
246
|
codex .github/copilot-instructions.md (GitHub Copilot)
|
|
197
247
|
|
|
248
|
+
${colors.yellow('Shorthand Aliases:')}
|
|
249
|
+
js, ts, javascript, typescript → javascript-expert
|
|
250
|
+
go, golang → golang-expert
|
|
251
|
+
py, python → python-expert
|
|
252
|
+
rs, rust → rust-expert
|
|
253
|
+
swift → swift-expert
|
|
254
|
+
kotlin, kt → kotlin-expert
|
|
255
|
+
java → java-expert
|
|
256
|
+
cpp → cpp-expert
|
|
257
|
+
csharp, cs → csharp-expert
|
|
258
|
+
|
|
198
259
|
${colors.yellow('Examples:')}
|
|
260
|
+
npx cursor-templates js
|
|
199
261
|
npx cursor-templates web-frontend
|
|
200
262
|
npx cursor-templates web-frontend --ide=cursor
|
|
201
263
|
npx cursor-templates web-frontend --ide=claude --ide=codex
|
|
@@ -217,13 +279,24 @@ ${colors.dim('CLAUDE.md: missing sections are intelligently merged (not overwrit
|
|
|
217
279
|
}
|
|
218
280
|
|
|
219
281
|
function printTemplates() {
|
|
282
|
+
// Build reverse map: canonical name -> list of aliases
|
|
283
|
+
const aliasesByTemplate = {};
|
|
284
|
+
for (const [alias, canonical] of Object.entries(TEMPLATE_ALIASES)) {
|
|
285
|
+
if (!aliasesByTemplate[canonical]) {
|
|
286
|
+
aliasesByTemplate[canonical] = [];
|
|
287
|
+
}
|
|
288
|
+
aliasesByTemplate[canonical].push(alias);
|
|
289
|
+
}
|
|
290
|
+
|
|
220
291
|
console.log(colors.yellow('Available Templates:\n'));
|
|
221
|
-
|
|
292
|
+
|
|
222
293
|
for (const [name, info] of Object.entries(TEMPLATES)) {
|
|
223
|
-
|
|
294
|
+
const aliases = aliasesByTemplate[name];
|
|
295
|
+
const aliasSuffix = aliases ? ` ${colors.dim(`(aliases: ${aliases.join(', ')})`)}` : '';
|
|
296
|
+
console.log(` ${colors.green(name)}${aliasSuffix}`);
|
|
224
297
|
console.log(` ${info.description}\n`);
|
|
225
298
|
}
|
|
226
|
-
|
|
299
|
+
|
|
227
300
|
console.log(colors.blue('Shared rules (always included):'));
|
|
228
301
|
for (const rule of SHARED_RULES) {
|
|
229
302
|
console.log(` - ${rule.replace('.md', '')}`);
|
|
@@ -1358,10 +1431,13 @@ export async function run(args) {
|
|
|
1358
1431
|
}
|
|
1359
1432
|
|
|
1360
1433
|
printBanner();
|
|
1361
|
-
|
|
1434
|
+
|
|
1362
1435
|
// Check for updates (non-blocking, fails silently)
|
|
1363
1436
|
await checkForUpdates();
|
|
1364
1437
|
|
|
1438
|
+
// Resolve template aliases to canonical names
|
|
1439
|
+
const resolvedTemplates = templates.map(resolveTemplateAlias);
|
|
1440
|
+
|
|
1365
1441
|
// Use default IDEs if none specified
|
|
1366
1442
|
const targetIdes = ides.length > 0 ? ides : DEFAULT_IDES;
|
|
1367
1443
|
|
|
@@ -1371,7 +1447,7 @@ export async function run(args) {
|
|
|
1371
1447
|
console.error(colors.red('Error: Cannot use --remove and --reset together\n'));
|
|
1372
1448
|
process.exit(1);
|
|
1373
1449
|
}
|
|
1374
|
-
if (
|
|
1450
|
+
if (resolvedTemplates.length > 0) {
|
|
1375
1451
|
console.error(colors.red('Error: --reset does not accept template arguments\n'));
|
|
1376
1452
|
console.error(colors.dim('Use --remove <templates...> to remove specific templates.\n'));
|
|
1377
1453
|
process.exit(1);
|
|
@@ -1390,14 +1466,14 @@ export async function run(args) {
|
|
|
1390
1466
|
|
|
1391
1467
|
// Handle remove mode
|
|
1392
1468
|
if (removeMode) {
|
|
1393
|
-
if (
|
|
1469
|
+
if (resolvedTemplates.length === 0) {
|
|
1394
1470
|
console.error(colors.red('Error: No templates specified for removal\n'));
|
|
1395
1471
|
console.error(colors.dim('Usage: npx cursor-templates --remove <templates...>\n'));
|
|
1396
1472
|
printTemplates();
|
|
1397
1473
|
process.exit(1);
|
|
1398
1474
|
}
|
|
1399
1475
|
|
|
1400
|
-
for (const template of
|
|
1476
|
+
for (const template of resolvedTemplates) {
|
|
1401
1477
|
if (!TEMPLATES[template]) {
|
|
1402
1478
|
console.error(colors.red(`Error: Unknown template '${template}'\n`));
|
|
1403
1479
|
printTemplates();
|
|
@@ -1412,18 +1488,18 @@ export async function run(args) {
|
|
|
1412
1488
|
console.log(colors.yellow('FORCE MODE - Modified files will be removed\n'));
|
|
1413
1489
|
}
|
|
1414
1490
|
|
|
1415
|
-
await remove(process.cwd(),
|
|
1491
|
+
await remove(process.cwd(), resolvedTemplates, dryRun, force, skipConfirm, targetIdes);
|
|
1416
1492
|
return;
|
|
1417
1493
|
}
|
|
1418
1494
|
|
|
1419
1495
|
// Install mode (default)
|
|
1420
|
-
if (
|
|
1496
|
+
if (resolvedTemplates.length === 0) {
|
|
1421
1497
|
console.error(colors.red('Error: No templates specified\n'));
|
|
1422
1498
|
printHelp();
|
|
1423
1499
|
process.exit(1);
|
|
1424
1500
|
}
|
|
1425
1501
|
|
|
1426
|
-
for (const template of
|
|
1502
|
+
for (const template of resolvedTemplates) {
|
|
1427
1503
|
if (!TEMPLATES[template]) {
|
|
1428
1504
|
console.error(colors.red(`Error: Unknown template '${template}'\n`));
|
|
1429
1505
|
printTemplates();
|
|
@@ -1440,7 +1516,7 @@ export async function run(args) {
|
|
|
1440
1516
|
}
|
|
1441
1517
|
|
|
1442
1518
|
// Install to current directory
|
|
1443
|
-
install(process.cwd(),
|
|
1519
|
+
install(process.cwd(), resolvedTemplates, dryRun, force, targetIdes);
|
|
1444
1520
|
}
|
|
1445
1521
|
|
|
1446
1522
|
// Export internals for testing
|
|
@@ -1450,11 +1526,13 @@ export const _internals = {
|
|
|
1450
1526
|
REPO_URL,
|
|
1451
1527
|
CHANGELOG_URL,
|
|
1452
1528
|
TEMPLATES,
|
|
1529
|
+
TEMPLATE_ALIASES,
|
|
1453
1530
|
SHARED_RULES,
|
|
1454
1531
|
SUPPORTED_IDES,
|
|
1455
1532
|
DEFAULT_IDES,
|
|
1456
1533
|
compareVersions,
|
|
1457
1534
|
checkForUpdates,
|
|
1535
|
+
resolveTemplateAlias,
|
|
1458
1536
|
filesMatch,
|
|
1459
1537
|
parseMarkdownSections,
|
|
1460
1538
|
generateSectionSignature,
|
package/src/index.test.js
CHANGED
|
@@ -8,10 +8,12 @@ const {
|
|
|
8
8
|
PACKAGE_NAME,
|
|
9
9
|
CURRENT_VERSION,
|
|
10
10
|
TEMPLATES,
|
|
11
|
+
TEMPLATE_ALIASES,
|
|
11
12
|
SHARED_RULES,
|
|
12
13
|
SUPPORTED_IDES,
|
|
13
14
|
DEFAULT_IDES,
|
|
14
15
|
compareVersions,
|
|
16
|
+
resolveTemplateAlias,
|
|
15
17
|
filesMatch,
|
|
16
18
|
parseMarkdownSections,
|
|
17
19
|
generateSectionSignature,
|
|
@@ -74,13 +76,17 @@ describe('Constants', () => {
|
|
|
74
76
|
it('should have all expected templates', () => {
|
|
75
77
|
const expectedTemplates = [
|
|
76
78
|
'blockchain',
|
|
79
|
+
'cpp-expert',
|
|
80
|
+
'csharp-expert',
|
|
77
81
|
'cli-tools',
|
|
78
82
|
'data-engineering',
|
|
79
83
|
'devops-sre',
|
|
80
84
|
'documentation',
|
|
81
85
|
'fullstack',
|
|
82
86
|
'golang-expert',
|
|
87
|
+
'java-expert',
|
|
83
88
|
'javascript-expert',
|
|
89
|
+
'kotlin-expert',
|
|
84
90
|
'ml-ai',
|
|
85
91
|
'mobile',
|
|
86
92
|
'platform-engineering',
|
|
@@ -88,6 +94,7 @@ describe('Constants', () => {
|
|
|
88
94
|
'python-expert',
|
|
89
95
|
'qa-engineering',
|
|
90
96
|
'rust-expert',
|
|
97
|
+
'swift-expert',
|
|
91
98
|
'testing',
|
|
92
99
|
'utility-agent',
|
|
93
100
|
'web-backend',
|
|
@@ -145,6 +152,50 @@ describe('Constants', () => {
|
|
|
145
152
|
expect(DEFAULT_IDES).toEqual(SUPPORTED_IDES);
|
|
146
153
|
});
|
|
147
154
|
});
|
|
155
|
+
|
|
156
|
+
describe('TEMPLATE_ALIASES', () => {
|
|
157
|
+
it('all alias values should be valid TEMPLATES keys', () => {
|
|
158
|
+
for (const [alias, canonical] of Object.entries(TEMPLATE_ALIASES)) {
|
|
159
|
+
expect(TEMPLATES).toHaveProperty(canonical,
|
|
160
|
+
expect.anything(),
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should include expected shorthand aliases', () => {
|
|
166
|
+
expect(TEMPLATE_ALIASES['js']).toBe('javascript-expert');
|
|
167
|
+
expect(TEMPLATE_ALIASES['ts']).toBe('javascript-expert');
|
|
168
|
+
expect(TEMPLATE_ALIASES['go']).toBe('golang-expert');
|
|
169
|
+
expect(TEMPLATE_ALIASES['py']).toBe('python-expert');
|
|
170
|
+
expect(TEMPLATE_ALIASES['rs']).toBe('rust-expert');
|
|
171
|
+
expect(TEMPLATE_ALIASES['kt']).toBe('kotlin-expert');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe('resolveTemplateAlias', () => {
|
|
176
|
+
it('should resolve known aliases to canonical names', () => {
|
|
177
|
+
expect(resolveTemplateAlias('js')).toBe('javascript-expert');
|
|
178
|
+
expect(resolveTemplateAlias('typescript')).toBe('javascript-expert');
|
|
179
|
+
expect(resolveTemplateAlias('go')).toBe('golang-expert');
|
|
180
|
+
expect(resolveTemplateAlias('golang')).toBe('golang-expert');
|
|
181
|
+
expect(resolveTemplateAlias('py')).toBe('python-expert');
|
|
182
|
+
expect(resolveTemplateAlias('rs')).toBe('rust-expert');
|
|
183
|
+
expect(resolveTemplateAlias('kotlin')).toBe('kotlin-expert');
|
|
184
|
+
expect(resolveTemplateAlias('kt')).toBe('kotlin-expert');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should pass through unknown names unchanged', () => {
|
|
188
|
+
expect(resolveTemplateAlias('web-frontend')).toBe('web-frontend');
|
|
189
|
+
expect(resolveTemplateAlias('blockchain')).toBe('blockchain');
|
|
190
|
+
expect(resolveTemplateAlias('nonexistent')).toBe('nonexistent');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should pass through canonical template names unchanged', () => {
|
|
194
|
+
expect(resolveTemplateAlias('javascript-expert')).toBe('javascript-expert');
|
|
195
|
+
expect(resolveTemplateAlias('golang-expert')).toBe('golang-expert');
|
|
196
|
+
expect(resolveTemplateAlias('python-expert')).toBe('python-expert');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
148
199
|
});
|
|
149
200
|
|
|
150
201
|
// ============================================================================
|
|
@@ -1014,7 +1065,50 @@ describe('CLI Argument Parsing', () => {
|
|
|
1014
1065
|
it('should accept -y shorthand for yes', async () => {
|
|
1015
1066
|
await run(['web-frontend']);
|
|
1016
1067
|
await run(['--reset', '-y']);
|
|
1017
|
-
|
|
1068
|
+
|
|
1069
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
it('should resolve shorthand alias "js" to javascript-expert', async () => {
|
|
1073
|
+
await run(['js', '--dry-run']);
|
|
1074
|
+
|
|
1075
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1078
|
+
it('should resolve shorthand alias "go" to golang-expert', async () => {
|
|
1079
|
+
await run(['go', '--dry-run']);
|
|
1080
|
+
|
|
1081
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1082
|
+
});
|
|
1083
|
+
|
|
1084
|
+
it('should resolve shorthand alias "py" to python-expert', async () => {
|
|
1085
|
+
await run(['py', '--dry-run']);
|
|
1086
|
+
|
|
1087
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
it('should resolve shorthand alias "rs" to rust-expert', async () => {
|
|
1091
|
+
await run(['rs', '--dry-run']);
|
|
1092
|
+
|
|
1093
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
it('should resolve shorthand alias "kt" to kotlin-expert', async () => {
|
|
1097
|
+
await run(['kt', '--dry-run']);
|
|
1098
|
+
|
|
1099
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
it('should resolve aliases in --remove mode', async () => {
|
|
1103
|
+
await run(['go']);
|
|
1104
|
+
await run(['--remove', 'go', '--yes']);
|
|
1105
|
+
|
|
1106
|
+
expect(exitSpy).not.toHaveBeenCalled();
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
it('should still accept canonical template names', async () => {
|
|
1110
|
+
await run(['javascript-expert', '--dry-run']);
|
|
1111
|
+
|
|
1018
1112
|
expect(exitSpy).not.toHaveBeenCalled();
|
|
1019
1113
|
});
|
|
1020
1114
|
});
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# C++ Concurrency
|
|
2
|
+
|
|
3
|
+
The C++ memory model is the law. Every concurrent access must be explicitly synchronized.
|
|
4
|
+
|
|
5
|
+
## std::thread and std::jthread
|
|
6
|
+
|
|
7
|
+
```cpp
|
|
8
|
+
// std::jthread (C++20) — automatically joins on destruction
|
|
9
|
+
void process_data(std::stop_token stop, std::span<const Item> items) {
|
|
10
|
+
for (const auto& item : items) {
|
|
11
|
+
if (stop.stop_requested()) return;
|
|
12
|
+
process(item);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
auto worker = std::jthread(process_data, data);
|
|
17
|
+
// Automatically joins when worker goes out of scope
|
|
18
|
+
// Can request stop: worker.request_stop();
|
|
19
|
+
|
|
20
|
+
// Never use std::thread without join/detach — it calls std::terminate
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Mutex and Locking
|
|
24
|
+
|
|
25
|
+
```cpp
|
|
26
|
+
// RAII locking — always
|
|
27
|
+
class ThreadSafeCounter {
|
|
28
|
+
mutable std::mutex mutex_;
|
|
29
|
+
int count_ = 0;
|
|
30
|
+
|
|
31
|
+
public:
|
|
32
|
+
void increment() {
|
|
33
|
+
std::lock_guard lock(mutex_);
|
|
34
|
+
++count_;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
int get() const {
|
|
38
|
+
std::lock_guard lock(mutex_);
|
|
39
|
+
return count_;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Multiple mutexes — use std::scoped_lock to avoid deadlock
|
|
44
|
+
void transfer(Account& from, Account& to, int amount) {
|
|
45
|
+
std::scoped_lock lock(from.mutex_, to.mutex_); // Deadlock-free
|
|
46
|
+
from.balance_ -= amount;
|
|
47
|
+
to.balance_ += amount;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Read-heavy workloads — use shared_mutex
|
|
51
|
+
class Cache {
|
|
52
|
+
mutable std::shared_mutex mutex_;
|
|
53
|
+
std::unordered_map<std::string, Value> data_;
|
|
54
|
+
|
|
55
|
+
public:
|
|
56
|
+
auto get(const std::string& key) const -> std::optional<Value> {
|
|
57
|
+
std::shared_lock lock(mutex_); // Multiple readers OK
|
|
58
|
+
auto it = data_.find(key);
|
|
59
|
+
return it != data_.end() ? std::optional{it->second} : std::nullopt;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void set(const std::string& key, Value value) {
|
|
63
|
+
std::unique_lock lock(mutex_); // Exclusive write
|
|
64
|
+
data_[key] = std::move(value);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Atomics
|
|
70
|
+
|
|
71
|
+
```cpp
|
|
72
|
+
// Lock-free operations for simple types
|
|
73
|
+
std::atomic<int> counter{0};
|
|
74
|
+
counter.fetch_add(1, std::memory_order_relaxed); // Fastest for counters
|
|
75
|
+
|
|
76
|
+
// Flags
|
|
77
|
+
std::atomic<bool> ready{false};
|
|
78
|
+
// Producer:
|
|
79
|
+
data = prepare();
|
|
80
|
+
ready.store(true, std::memory_order_release);
|
|
81
|
+
// Consumer:
|
|
82
|
+
while (!ready.load(std::memory_order_acquire)) { /* spin or yield */ }
|
|
83
|
+
use(data); // Guaranteed to see prepared data
|
|
84
|
+
|
|
85
|
+
// std::atomic_ref (C++20) for non-atomic variables
|
|
86
|
+
int value = 0;
|
|
87
|
+
std::atomic_ref ref{value};
|
|
88
|
+
ref.fetch_add(1);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Condition Variables
|
|
92
|
+
|
|
93
|
+
```cpp
|
|
94
|
+
template <typename T>
|
|
95
|
+
class BoundedQueue {
|
|
96
|
+
std::queue<T> queue_;
|
|
97
|
+
mutable std::mutex mutex_;
|
|
98
|
+
std::condition_variable not_empty_;
|
|
99
|
+
std::condition_variable not_full_;
|
|
100
|
+
size_t max_size_;
|
|
101
|
+
|
|
102
|
+
public:
|
|
103
|
+
explicit BoundedQueue(size_t max_size) : max_size_{max_size} {}
|
|
104
|
+
|
|
105
|
+
void push(T item) {
|
|
106
|
+
std::unique_lock lock(mutex_);
|
|
107
|
+
not_full_.wait(lock, [this] { return queue_.size() < max_size_; });
|
|
108
|
+
queue_.push(std::move(item));
|
|
109
|
+
not_empty_.notify_one();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
auto pop() -> T {
|
|
113
|
+
std::unique_lock lock(mutex_);
|
|
114
|
+
not_empty_.wait(lock, [this] { return !queue_.empty(); });
|
|
115
|
+
auto item = std::move(queue_.front());
|
|
116
|
+
queue_.pop();
|
|
117
|
+
not_full_.notify_one();
|
|
118
|
+
return item;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
auto try_pop(std::chrono::milliseconds timeout) -> std::optional<T> {
|
|
122
|
+
std::unique_lock lock(mutex_);
|
|
123
|
+
if (!not_empty_.wait_for(lock, timeout, [this] { return !queue_.empty(); })) {
|
|
124
|
+
return std::nullopt;
|
|
125
|
+
}
|
|
126
|
+
auto item = std::move(queue_.front());
|
|
127
|
+
queue_.pop();
|
|
128
|
+
not_full_.notify_one();
|
|
129
|
+
return item;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Async and Futures
|
|
135
|
+
|
|
136
|
+
```cpp
|
|
137
|
+
// std::async for fire-and-forget parallel work
|
|
138
|
+
auto future = std::async(std::launch::async, [] {
|
|
139
|
+
return expensive_computation();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
auto result = future.get(); // Blocks until ready
|
|
143
|
+
|
|
144
|
+
// Parallel independent work
|
|
145
|
+
auto user_future = std::async(std::launch::async, [&] { return fetch_user(id); });
|
|
146
|
+
auto orders_future = std::async(std::launch::async, [&] { return fetch_orders(id); });
|
|
147
|
+
|
|
148
|
+
auto user = user_future.get();
|
|
149
|
+
auto orders = orders_future.get();
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Parallel Algorithms (C++17)
|
|
153
|
+
|
|
154
|
+
```cpp
|
|
155
|
+
#include <execution>
|
|
156
|
+
|
|
157
|
+
// Parallel sort
|
|
158
|
+
std::sort(std::execution::par, data.begin(), data.end());
|
|
159
|
+
|
|
160
|
+
// Parallel transform-reduce
|
|
161
|
+
auto total = std::transform_reduce(
|
|
162
|
+
std::execution::par,
|
|
163
|
+
orders.begin(), orders.end(),
|
|
164
|
+
0.0, // Initial value
|
|
165
|
+
std::plus<>{}, // Reduce
|
|
166
|
+
[](const Order& o) { return o.total(); } // Transform
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Parallel for_each
|
|
170
|
+
std::for_each(std::execution::par_unseq, items.begin(), items.end(),
|
|
171
|
+
[](auto& item) { item.process(); });
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Thread Safety Rules
|
|
175
|
+
|
|
176
|
+
1. **Immutable data is thread-safe** — share freely via `const` references
|
|
177
|
+
2. **Every mutable shared state needs synchronization** — no exceptions
|
|
178
|
+
3. **Prefer lock-free data structures** when correctness is provable
|
|
179
|
+
4. **Hold locks for the minimum time** — compute outside the critical section
|
|
180
|
+
5. **Never hold two locks simultaneously** unless using `std::scoped_lock`
|
|
181
|
+
6. **Use `std::atomic` for single variables**, mutex for compound operations
|
|
182
|
+
|
|
183
|
+
## Anti-Patterns
|
|
184
|
+
|
|
185
|
+
```cpp
|
|
186
|
+
// Never: lock and forget
|
|
187
|
+
mutex_.lock();
|
|
188
|
+
do_work(); // If this throws, mutex stays locked forever
|
|
189
|
+
mutex_.unlock();
|
|
190
|
+
// Use: std::lock_guard or std::unique_lock (RAII)
|
|
191
|
+
|
|
192
|
+
// Never: double-checked locking without atomics
|
|
193
|
+
if (!instance) {
|
|
194
|
+
std::lock_guard lock(mutex);
|
|
195
|
+
if (!instance) instance = new Singleton(); // Data race!
|
|
196
|
+
}
|
|
197
|
+
// Use: std::call_once or static local (Meyers singleton)
|
|
198
|
+
|
|
199
|
+
static Singleton& instance() {
|
|
200
|
+
static Singleton s; // Thread-safe in C++11+
|
|
201
|
+
return s;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Never: volatile for synchronization
|
|
205
|
+
volatile int flag; // volatile != atomic in C++
|
|
206
|
+
// Use: std::atomic<int> flag;
|
|
207
|
+
|
|
208
|
+
// Never: busy-waiting without yield
|
|
209
|
+
while (!ready.load()) {} // Burns CPU
|
|
210
|
+
// Use: condition_variable, or at least std::this_thread::yield()
|
|
211
|
+
```
|