claude-code-templates 1.14.1 → 1.14.2
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/bin/create-claude-config.js +3 -2
- package/package.json +1 -2
- package/src/file-operations.js +217 -81
- package/src/index.js +56 -72
- package/components/agents/api-security-audit.md +0 -92
- package/components/agents/database-optimization.md +0 -94
- package/components/agents/react-performance-optimization.md +0 -64
- package/components/commands/check-file.md +0 -53
- package/components/commands/generate-tests.md +0 -68
- package/components/mcps/deepgraph-nextjs.json +0 -12
- package/components/mcps/deepgraph-react.json +0 -12
- package/components/mcps/deepgraph-typescript.json +0 -12
- package/components/mcps/deepgraph-vue.json +0 -12
- package/components/mcps/filesystem-access.json +0 -12
- package/components/mcps/github-integration.json +0 -11
- package/components/mcps/memory-integration.json +0 -8
- package/components/mcps/mysql-integration.json +0 -11
- package/components/mcps/postgresql-integration.json +0 -11
- package/components/mcps/web-fetch.json +0 -8
|
@@ -43,8 +43,9 @@ program
|
|
|
43
43
|
.name('create-claude-config')
|
|
44
44
|
.description('Setup Claude Code configurations for different programming languages')
|
|
45
45
|
.version(require('../package.json').version)
|
|
46
|
-
.option('-l, --language <language>', 'specify programming language')
|
|
47
|
-
.option('-f, --framework <framework>', 'specify framework')
|
|
46
|
+
.option('-l, --language <language>', 'specify programming language (deprecated, use --template)')
|
|
47
|
+
.option('-f, --framework <framework>', 'specify framework (deprecated, use --template)')
|
|
48
|
+
.option('-t, --template <template>', 'specify template (e.g., common, javascript-typescript, python, ruby)')
|
|
48
49
|
.option('-d, --directory <directory>', 'target directory (default: current directory)')
|
|
49
50
|
.option('-y, --yes', 'skip prompts and use defaults')
|
|
50
51
|
.option('--dry-run', 'show what would be copied without actually copying')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.2",
|
|
4
4
|
"description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"bin/",
|
|
87
87
|
"src/",
|
|
88
88
|
"templates/",
|
|
89
|
-
"components/",
|
|
90
89
|
"README.md"
|
|
91
90
|
],
|
|
92
91
|
"devDependencies": {
|
package/src/file-operations.js
CHANGED
|
@@ -4,6 +4,152 @@ const chalk = require('chalk');
|
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
5
|
const { getHooksForLanguage, filterHooksBySelection, getMCPsForLanguage, filterMCPsBySelection } = require('./hook-scanner');
|
|
6
6
|
|
|
7
|
+
// GitHub configuration for downloading templates
|
|
8
|
+
const GITHUB_CONFIG = {
|
|
9
|
+
owner: 'davila7',
|
|
10
|
+
repo: 'claude-code-templates',
|
|
11
|
+
branch: 'main',
|
|
12
|
+
templatesPath: 'cli-tool/templates'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// Cache for downloaded files to avoid repeated downloads
|
|
16
|
+
const downloadCache = new Map();
|
|
17
|
+
|
|
18
|
+
async function downloadFileFromGitHub(filePath) {
|
|
19
|
+
// Check cache first
|
|
20
|
+
if (downloadCache.has(filePath)) {
|
|
21
|
+
return downloadCache.get(filePath);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const githubUrl = `https://raw.githubusercontent.com/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/${GITHUB_CONFIG.branch}/${GITHUB_CONFIG.templatesPath}/${filePath}`;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch(githubUrl);
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`Failed to download ${filePath}: ${response.status} ${response.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const content = await response.text();
|
|
33
|
+
downloadCache.set(filePath, content);
|
|
34
|
+
return content;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(chalk.red(`❌ Error downloading ${filePath} from GitHub:`), error.message);
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function downloadDirectoryFromGitHub(dirPath) {
|
|
42
|
+
// For directories, we need to get the list of files first
|
|
43
|
+
// GitHub API endpoint to get directory contents
|
|
44
|
+
const apiUrl = `https://api.github.com/repos/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/contents/${GITHUB_CONFIG.templatesPath}/${dirPath}?ref=${GITHUB_CONFIG.branch}`;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetch(apiUrl);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`Failed to get directory listing for ${dirPath}: ${response.status} ${response.statusText}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const items = await response.json();
|
|
53
|
+
const files = {};
|
|
54
|
+
|
|
55
|
+
for (const item of items) {
|
|
56
|
+
if (item.type === 'file') {
|
|
57
|
+
const relativePath = path.relative(GITHUB_CONFIG.templatesPath, item.path);
|
|
58
|
+
const content = await downloadFileFromGitHub(relativePath);
|
|
59
|
+
files[item.name] = content;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return files;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error(chalk.red(`❌ Error downloading directory ${dirPath} from GitHub:`), error.message);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Helper functions for processing downloaded content
|
|
71
|
+
async function processSettingsFileFromContent(settingsContent, destPath, templateConfig) {
|
|
72
|
+
const settings = JSON.parse(settingsContent);
|
|
73
|
+
|
|
74
|
+
// Filter hooks based on selection
|
|
75
|
+
if (templateConfig.selectedHooks && settings.hooks) {
|
|
76
|
+
settings.hooks = filterHooksBySelection(settings.hooks, templateConfig.selectedHooks);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const destDir = path.dirname(destPath);
|
|
80
|
+
await fs.ensureDir(destDir);
|
|
81
|
+
await fs.writeJson(destPath, settings, { spaces: 2 });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function mergeSettingsFileFromContent(settingsContent, destPath, templateConfig) {
|
|
85
|
+
const newSettings = JSON.parse(settingsContent);
|
|
86
|
+
let existingSettings = {};
|
|
87
|
+
|
|
88
|
+
if (await fs.pathExists(destPath)) {
|
|
89
|
+
existingSettings = await fs.readJson(destPath);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Filter hooks based on selection
|
|
93
|
+
if (templateConfig.selectedHooks && newSettings.hooks) {
|
|
94
|
+
newSettings.hooks = filterHooksBySelection(newSettings.hooks, templateConfig.selectedHooks);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Merge settings
|
|
98
|
+
const mergedSettings = {
|
|
99
|
+
...existingSettings,
|
|
100
|
+
...newSettings,
|
|
101
|
+
hooks: {
|
|
102
|
+
...existingSettings.hooks,
|
|
103
|
+
...newSettings.hooks
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const destDir = path.dirname(destPath);
|
|
108
|
+
await fs.ensureDir(destDir);
|
|
109
|
+
await fs.writeJson(destPath, mergedSettings, { spaces: 2 });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function processMCPFileFromContent(mcpContent, destPath, templateConfig) {
|
|
113
|
+
const mcpConfig = JSON.parse(mcpContent);
|
|
114
|
+
|
|
115
|
+
// Filter MCPs based on selection
|
|
116
|
+
if (templateConfig.selectedMCPs && mcpConfig.mcpServers) {
|
|
117
|
+
mcpConfig.mcpServers = filterMCPsBySelection(mcpConfig.mcpServers, templateConfig.selectedMCPs);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const destDir = path.dirname(destPath);
|
|
121
|
+
await fs.ensureDir(destDir);
|
|
122
|
+
await fs.writeJson(destPath, mcpConfig, { spaces: 2 });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function mergeMCPFileFromContent(mcpContent, destPath, templateConfig) {
|
|
126
|
+
const newMcpConfig = JSON.parse(mcpContent);
|
|
127
|
+
let existingMcpConfig = {};
|
|
128
|
+
|
|
129
|
+
if (await fs.pathExists(destPath)) {
|
|
130
|
+
existingMcpConfig = await fs.readJson(destPath);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Filter MCPs based on selection
|
|
134
|
+
if (templateConfig.selectedMCPs && newMcpConfig.mcpServers) {
|
|
135
|
+
newMcpConfig.mcpServers = filterMCPsBySelection(newMcpConfig.mcpServers, templateConfig.selectedMCPs);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Merge MCP configurations
|
|
139
|
+
const mergedMcpConfig = {
|
|
140
|
+
...existingMcpConfig,
|
|
141
|
+
...newMcpConfig,
|
|
142
|
+
mcpServers: {
|
|
143
|
+
...existingMcpConfig.mcpServers,
|
|
144
|
+
...newMcpConfig.mcpServers
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const destDir = path.dirname(destPath);
|
|
149
|
+
await fs.ensureDir(destDir);
|
|
150
|
+
await fs.writeJson(destPath, mergedMcpConfig, { spaces: 2 });
|
|
151
|
+
}
|
|
152
|
+
|
|
7
153
|
async function checkExistingFiles(targetDir, templateConfig) {
|
|
8
154
|
const existingFiles = [];
|
|
9
155
|
|
|
@@ -86,7 +232,7 @@ async function createBackups(existingFiles, targetDir) {
|
|
|
86
232
|
}
|
|
87
233
|
|
|
88
234
|
async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
|
|
89
|
-
|
|
235
|
+
console.log(chalk.gray(`📥 Downloading templates from GitHub (${GITHUB_CONFIG.branch} branch)...`));
|
|
90
236
|
|
|
91
237
|
// Check for existing files and get user preference
|
|
92
238
|
const existingFiles = await checkExistingFiles(targetDir, templateConfig);
|
|
@@ -114,7 +260,6 @@ async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
|
|
|
114
260
|
|
|
115
261
|
// Copy base files and framework-specific files
|
|
116
262
|
for (const file of templateConfig.files) {
|
|
117
|
-
const sourcePath = path.join(templateDir, file.source);
|
|
118
263
|
const destPath = path.join(targetDir, file.destination);
|
|
119
264
|
|
|
120
265
|
try {
|
|
@@ -123,94 +268,115 @@ async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
|
|
|
123
268
|
// This is a framework-specific commands directory - merge with existing commands
|
|
124
269
|
await fs.ensureDir(destPath);
|
|
125
270
|
|
|
126
|
-
//
|
|
127
|
-
const frameworkFiles = await
|
|
128
|
-
for (const
|
|
129
|
-
const
|
|
130
|
-
const destFile = path.join(destPath, frameworkFile);
|
|
271
|
+
// Download framework-specific commands from GitHub
|
|
272
|
+
const frameworkFiles = await downloadDirectoryFromGitHub(file.source);
|
|
273
|
+
for (const [frameworkFileName, content] of Object.entries(frameworkFiles)) {
|
|
274
|
+
const destFile = path.join(destPath, frameworkFileName);
|
|
131
275
|
|
|
132
276
|
// In merge mode, skip if file already exists
|
|
133
277
|
if (userAction === 'merge' && await fs.pathExists(destFile)) {
|
|
134
|
-
console.log(chalk.blue(`⏭️ Skipped ${
|
|
278
|
+
console.log(chalk.blue(`⏭️ Skipped ${frameworkFileName} (already exists)`));
|
|
135
279
|
continue;
|
|
136
280
|
}
|
|
137
281
|
|
|
138
|
-
await fs.
|
|
282
|
+
await fs.writeFile(destFile, content, 'utf8');
|
|
139
283
|
}
|
|
140
284
|
|
|
141
|
-
console.log(chalk.green(`✓
|
|
285
|
+
console.log(chalk.green(`✓ Downloaded framework commands ${file.source} → ${file.destination}`));
|
|
142
286
|
} else if (file.source.includes('.claude') && !file.source.includes('examples/')) {
|
|
143
|
-
// This is base .claude directory -
|
|
144
|
-
await fs.
|
|
145
|
-
overwrite: shouldOverwrite,
|
|
146
|
-
filter: (src) => {
|
|
147
|
-
// Skip the commands directory itself - we'll handle it separately
|
|
148
|
-
return !src.endsWith('.claude/commands');
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Now handle base commands specifically
|
|
153
|
-
const baseCommandsPath = path.join(sourcePath, 'commands');
|
|
154
|
-
const destCommandsPath = path.join(destPath, 'commands');
|
|
287
|
+
// This is base .claude directory - download it but handle commands specially
|
|
288
|
+
await fs.ensureDir(destPath);
|
|
155
289
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
// Copy base commands, but exclude framework-specific ones that were moved
|
|
160
|
-
const baseCommands = await fs.readdir(baseCommandsPath);
|
|
161
|
-
const excludeCommands = ['react-component.md', 'route.md', 'api-endpoint.md']; // Commands moved to framework dirs
|
|
290
|
+
// Download base .claude directory structure from GitHub
|
|
291
|
+
try {
|
|
292
|
+
const baseClaudeFiles = await downloadDirectoryFromGitHub(file.source);
|
|
162
293
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const destFile = path.join(
|
|
294
|
+
// Write non-command files first
|
|
295
|
+
for (const [fileName, content] of Object.entries(baseClaudeFiles)) {
|
|
296
|
+
if (fileName !== 'commands') { // Skip commands directory, handle separately
|
|
297
|
+
const destFile = path.join(destPath, fileName);
|
|
167
298
|
|
|
168
299
|
// In merge mode, skip if file already exists
|
|
169
300
|
if (userAction === 'merge' && await fs.pathExists(destFile)) {
|
|
170
|
-
console.log(chalk.blue(`⏭️ Skipped ${
|
|
301
|
+
console.log(chalk.blue(`⏭️ Skipped ${fileName} (already exists)`));
|
|
171
302
|
continue;
|
|
172
303
|
}
|
|
173
304
|
|
|
174
|
-
await fs.
|
|
305
|
+
await fs.writeFile(destFile, content, 'utf8');
|
|
175
306
|
}
|
|
176
307
|
}
|
|
308
|
+
|
|
309
|
+
// Now handle base commands specifically
|
|
310
|
+
const destCommandsPath = path.join(destPath, 'commands');
|
|
311
|
+
await fs.ensureDir(destCommandsPath);
|
|
312
|
+
|
|
313
|
+
// Download base commands from GitHub
|
|
314
|
+
const baseCommandsDir = `${file.source}/commands`;
|
|
315
|
+
try {
|
|
316
|
+
const baseCommands = await downloadDirectoryFromGitHub(baseCommandsDir);
|
|
317
|
+
const excludeCommands = ['react-component.md', 'route.md', 'api-endpoint.md']; // Commands moved to framework dirs
|
|
318
|
+
|
|
319
|
+
for (const [baseCommandName, commandContent] of Object.entries(baseCommands)) {
|
|
320
|
+
if (!excludeCommands.includes(baseCommandName)) {
|
|
321
|
+
const destFile = path.join(destCommandsPath, baseCommandName);
|
|
322
|
+
|
|
323
|
+
// In merge mode, skip if file already exists
|
|
324
|
+
if (userAction === 'merge' && await fs.pathExists(destFile)) {
|
|
325
|
+
console.log(chalk.blue(`⏭️ Skipped ${baseCommandName} (already exists)`));
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
await fs.writeFile(destFile, commandContent, 'utf8');
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
} catch (error) {
|
|
333
|
+
// Commands directory might not exist for some templates, that's ok
|
|
334
|
+
console.log(chalk.yellow(`⚠️ No commands directory found for ${baseCommandsDir}`));
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error(chalk.red(`❌ Error downloading .claude directory: ${error.message}`));
|
|
339
|
+
throw error;
|
|
177
340
|
}
|
|
178
341
|
|
|
179
|
-
console.log(chalk.green(`✓
|
|
342
|
+
console.log(chalk.green(`✓ Downloaded base configuration and commands ${file.source} → ${file.destination}`));
|
|
180
343
|
} else if (file.source.includes('settings.json') && templateConfig.selectedHooks) {
|
|
344
|
+
// Download and process settings.json with hooks
|
|
345
|
+
const settingsContent = await downloadFileFromGitHub(file.source);
|
|
346
|
+
|
|
181
347
|
// In merge mode, merge settings instead of overwriting
|
|
182
348
|
if (userAction === 'merge') {
|
|
183
|
-
await
|
|
349
|
+
await mergeSettingsFileFromContent(settingsContent, destPath, templateConfig);
|
|
184
350
|
console.log(chalk.green(`✓ Merged ${file.source} → ${file.destination} (with selected hooks)`));
|
|
185
351
|
} else {
|
|
186
|
-
await
|
|
187
|
-
console.log(chalk.green(`✓
|
|
352
|
+
await processSettingsFileFromContent(settingsContent, destPath, templateConfig);
|
|
353
|
+
console.log(chalk.green(`✓ Downloaded ${file.source} → ${file.destination} (with selected hooks)`));
|
|
188
354
|
}
|
|
189
355
|
} else if (file.source.includes('.mcp.json') && templateConfig.selectedMCPs) {
|
|
356
|
+
// Download and process MCP config with selected MCPs
|
|
357
|
+
const mcpContent = await downloadFileFromGitHub(file.source);
|
|
358
|
+
|
|
190
359
|
// In merge mode, merge MCP config instead of overwriting
|
|
191
360
|
if (userAction === 'merge') {
|
|
192
|
-
await
|
|
361
|
+
await mergeMCPFileFromContent(mcpContent, destPath, templateConfig);
|
|
193
362
|
console.log(chalk.green(`✓ Merged ${file.source} → ${file.destination} (with selected MCPs)`));
|
|
194
363
|
} else {
|
|
195
|
-
await
|
|
196
|
-
console.log(chalk.green(`✓
|
|
364
|
+
await processMCPFileFromContent(mcpContent, destPath, templateConfig);
|
|
365
|
+
console.log(chalk.green(`✓ Downloaded ${file.source} → ${file.destination} (with selected MCPs)`));
|
|
197
366
|
}
|
|
198
367
|
} else {
|
|
199
|
-
//
|
|
368
|
+
// Download regular files (CLAUDE.md, etc.)
|
|
200
369
|
// In merge mode, skip if file already exists
|
|
201
370
|
if (userAction === 'merge' && await fs.pathExists(destPath)) {
|
|
202
371
|
console.log(chalk.blue(`⏭️ Skipped ${file.destination} (already exists)`));
|
|
203
372
|
continue;
|
|
204
373
|
}
|
|
205
374
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
console.log(chalk.green(`✓ Copied ${file.source} → ${file.destination}`));
|
|
375
|
+
const fileContent = await downloadFileFromGitHub(file.source);
|
|
376
|
+
const destDir = path.dirname(destPath);
|
|
377
|
+
await fs.ensureDir(destDir);
|
|
378
|
+
await fs.writeFile(destPath, fileContent, 'utf8');
|
|
379
|
+
console.log(chalk.green(`✓ Downloaded ${file.source} → ${file.destination}`));
|
|
214
380
|
}
|
|
215
381
|
} catch (error) {
|
|
216
382
|
console.error(chalk.red(`✗ Failed to copy ${file.source}:`), error.message);
|
|
@@ -218,38 +384,8 @@ async function copyTemplateFiles(templateConfig, targetDir, options = {}) {
|
|
|
218
384
|
}
|
|
219
385
|
}
|
|
220
386
|
|
|
387
|
+
console.log(chalk.cyan(`📦 All templates downloaded from: https://github.com/${GITHUB_CONFIG.owner}/${GITHUB_CONFIG.repo}/tree/${GITHUB_CONFIG.branch}/${GITHUB_CONFIG.templatesPath}`));
|
|
221
388
|
return true; // Indicate successful completion
|
|
222
|
-
|
|
223
|
-
// Copy selected commands individually
|
|
224
|
-
if (templateConfig.selectedCommands && templateConfig.selectedCommands.length > 0) {
|
|
225
|
-
const commandsDir = path.join(targetDir, '.claude', 'commands');
|
|
226
|
-
await fs.ensureDir(commandsDir);
|
|
227
|
-
|
|
228
|
-
for (const command of templateConfig.selectedCommands) {
|
|
229
|
-
try {
|
|
230
|
-
const commandFileName = `${command.name}.md`;
|
|
231
|
-
const destPath = path.join(commandsDir, commandFileName);
|
|
232
|
-
|
|
233
|
-
await fs.copy(command.filePath, destPath);
|
|
234
|
-
console.log(chalk.green(`✓ Added command: ${command.displayName}`));
|
|
235
|
-
} catch (error) {
|
|
236
|
-
console.error(chalk.red(`✗ Failed to copy command ${command.name}:`), error.message);
|
|
237
|
-
// Don't throw - continue with other commands
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
console.log(chalk.cyan(`📋 Installed ${templateConfig.selectedCommands.length} commands`));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// Report hook selection
|
|
245
|
-
if (templateConfig.selectedHooks && templateConfig.selectedHooks.length > 0) {
|
|
246
|
-
console.log(chalk.magenta(`🔧 Installed ${templateConfig.selectedHooks.length} automation hooks`));
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Report MCP selection
|
|
250
|
-
if (templateConfig.selectedMCPs && templateConfig.selectedMCPs.length > 0) {
|
|
251
|
-
console.log(chalk.blue(`🔧 Installed ${templateConfig.selectedMCPs.length} MCP`));
|
|
252
|
-
}
|
|
253
389
|
}
|
|
254
390
|
|
|
255
391
|
async function runPostInstallationValidation(targetDir, templateConfig) {
|
package/src/index.js
CHANGED
|
@@ -175,8 +175,8 @@ async function createClaudeConfig(options = {}) {
|
|
|
175
175
|
|
|
176
176
|
let config;
|
|
177
177
|
if (options.yes) {
|
|
178
|
-
// Use defaults
|
|
179
|
-
const selectedLanguage = options.language || projectInfo.detectedLanguage || 'common';
|
|
178
|
+
// Use defaults - prioritize --template over --language for backward compatibility
|
|
179
|
+
const selectedLanguage = options.template || options.language || projectInfo.detectedLanguage || 'common';
|
|
180
180
|
|
|
181
181
|
// Check if selected language is coming soon
|
|
182
182
|
if (selectedLanguage && TEMPLATES_CONFIG[selectedLanguage] && TEMPLATES_CONFIG[selectedLanguage].comingSoon) {
|
|
@@ -305,53 +305,39 @@ async function installIndividualAgent(agentName, targetDir, options) {
|
|
|
305
305
|
console.log(chalk.blue(`🤖 Installing agent: ${agentName}`));
|
|
306
306
|
|
|
307
307
|
try {
|
|
308
|
-
//
|
|
309
|
-
const
|
|
310
|
-
|
|
308
|
+
// Download agent directly from GitHub
|
|
309
|
+
const githubUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/agents/${agentName}.md`;
|
|
310
|
+
console.log(chalk.gray(`📥 Downloading from GitHub (main branch)...`));
|
|
311
311
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const agents = await fs.readdir(componentsPath);
|
|
319
|
-
agents.filter(f => f.endsWith('.md')).forEach(agent => {
|
|
320
|
-
console.log(chalk.cyan(` - ${agent.replace('.md', '')}`));
|
|
321
|
-
});
|
|
312
|
+
const response = await fetch(githubUrl);
|
|
313
|
+
if (!response.ok) {
|
|
314
|
+
if (response.status === 404) {
|
|
315
|
+
console.log(chalk.red(`❌ Agent "${agentName}" not found`));
|
|
316
|
+
console.log(chalk.yellow('Available agents: api-security-audit, database-optimization, react-performance-optimization'));
|
|
317
|
+
return;
|
|
322
318
|
}
|
|
323
|
-
|
|
319
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
324
320
|
}
|
|
325
321
|
|
|
326
|
-
|
|
327
|
-
// the appropriate language/framework and install the complete template
|
|
328
|
-
const agentContent = await fs.readFile(agentFile, 'utf8');
|
|
329
|
-
const language = extractLanguageFromAgent(agentContent, agentName);
|
|
330
|
-
const framework = extractFrameworkFromAgent(agentContent, agentName);
|
|
322
|
+
const agentContent = await response.text();
|
|
331
323
|
|
|
332
|
-
|
|
333
|
-
|
|
324
|
+
// Create .claude/agents directory if it doesn't exist
|
|
325
|
+
const agentsDir = path.join(targetDir, '.claude', 'agents');
|
|
326
|
+
await fs.ensureDir(agentsDir);
|
|
334
327
|
|
|
335
|
-
//
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
language,
|
|
339
|
-
framework,
|
|
340
|
-
yes: true,
|
|
341
|
-
targetDirectory: targetDir,
|
|
342
|
-
agent: null // Remove agent to avoid recursion
|
|
343
|
-
};
|
|
344
|
-
delete setupOptions.agent;
|
|
345
|
-
await createClaudeConfig(setupOptions);
|
|
328
|
+
// Write the agent file
|
|
329
|
+
const targetFile = path.join(agentsDir, `${agentName}.md`);
|
|
330
|
+
await fs.writeFile(targetFile, agentContent, 'utf8');
|
|
346
331
|
|
|
347
332
|
console.log(chalk.green(`✅ Agent "${agentName}" installed successfully!`));
|
|
333
|
+
console.log(chalk.cyan(`📁 Installed to: ${path.relative(targetDir, targetFile)}`));
|
|
334
|
+
console.log(chalk.cyan(`📦 Downloaded from: ${githubUrl}`));
|
|
348
335
|
|
|
349
336
|
// Track successful agent installation
|
|
350
337
|
trackingService.trackDownload('agent', agentName, {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
template_installed: true
|
|
338
|
+
installation_type: 'individual_component',
|
|
339
|
+
target_directory: path.relative(process.cwd(), targetDir),
|
|
340
|
+
source: 'github_main'
|
|
355
341
|
});
|
|
356
342
|
|
|
357
343
|
} catch (error) {
|
|
@@ -363,39 +349,39 @@ async function installIndividualCommand(commandName, targetDir, options) {
|
|
|
363
349
|
console.log(chalk.blue(`⚡ Installing command: ${commandName}`));
|
|
364
350
|
|
|
365
351
|
try {
|
|
366
|
-
//
|
|
367
|
-
const
|
|
368
|
-
|
|
352
|
+
// Download command directly from GitHub
|
|
353
|
+
const githubUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/commands/${commandName}.md`;
|
|
354
|
+
console.log(chalk.gray(`📥 Downloading from GitHub (main branch)...`));
|
|
369
355
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const commands = await fs.readdir(componentsPath);
|
|
377
|
-
commands.filter(f => f.endsWith('.md')).forEach(command => {
|
|
378
|
-
console.log(chalk.cyan(` - ${command.replace('.md', '')}`));
|
|
379
|
-
});
|
|
356
|
+
const response = await fetch(githubUrl);
|
|
357
|
+
if (!response.ok) {
|
|
358
|
+
if (response.status === 404) {
|
|
359
|
+
console.log(chalk.red(`❌ Command "${commandName}" not found`));
|
|
360
|
+
console.log(chalk.yellow('Available commands: check-file, generate-tests'));
|
|
361
|
+
return;
|
|
380
362
|
}
|
|
381
|
-
|
|
363
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
382
364
|
}
|
|
383
365
|
|
|
366
|
+
const commandContent = await response.text();
|
|
367
|
+
|
|
384
368
|
// Create .claude/commands directory if it doesn't exist
|
|
385
369
|
const commandsDir = path.join(targetDir, '.claude', 'commands');
|
|
386
370
|
await fs.ensureDir(commandsDir);
|
|
387
371
|
|
|
388
|
-
//
|
|
372
|
+
// Write the command file
|
|
389
373
|
const targetFile = path.join(commandsDir, `${commandName}.md`);
|
|
390
|
-
await fs.
|
|
374
|
+
await fs.writeFile(targetFile, commandContent, 'utf8');
|
|
391
375
|
|
|
392
376
|
console.log(chalk.green(`✅ Command "${commandName}" installed successfully!`));
|
|
393
377
|
console.log(chalk.cyan(`📁 Installed to: ${path.relative(targetDir, targetFile)}`));
|
|
378
|
+
console.log(chalk.cyan(`📦 Downloaded from: ${githubUrl}`));
|
|
394
379
|
|
|
395
380
|
// Track successful command installation
|
|
396
381
|
trackingService.trackDownload('command', commandName, {
|
|
397
382
|
installation_type: 'individual_command',
|
|
398
|
-
target_directory: path.relative(process.cwd(), targetDir)
|
|
383
|
+
target_directory: path.relative(process.cwd(), targetDir),
|
|
384
|
+
source: 'github_main'
|
|
399
385
|
});
|
|
400
386
|
|
|
401
387
|
} catch (error) {
|
|
@@ -407,26 +393,22 @@ async function installIndividualMCP(mcpName, targetDir, options) {
|
|
|
407
393
|
console.log(chalk.blue(`🔌 Installing MCP: ${mcpName}`));
|
|
408
394
|
|
|
409
395
|
try {
|
|
410
|
-
//
|
|
411
|
-
const
|
|
412
|
-
|
|
396
|
+
// Download MCP directly from GitHub
|
|
397
|
+
const githubUrl = `https://raw.githubusercontent.com/davila7/claude-code-templates/main/cli-tool/components/mcps/${mcpName}.json`;
|
|
398
|
+
console.log(chalk.gray(`📥 Downloading from GitHub (main branch)...`));
|
|
413
399
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const mcps = await fs.readdir(componentsPath);
|
|
421
|
-
mcps.filter(f => f.endsWith('.json')).forEach(mcp => {
|
|
422
|
-
console.log(chalk.cyan(` - ${mcp.replace('.json', '')}`));
|
|
423
|
-
});
|
|
400
|
+
const response = await fetch(githubUrl);
|
|
401
|
+
if (!response.ok) {
|
|
402
|
+
if (response.status === 404) {
|
|
403
|
+
console.log(chalk.red(`❌ MCP "${mcpName}" not found`));
|
|
404
|
+
console.log(chalk.yellow('Available MCPs: web-fetch, filesystem-access, github-integration, memory-integration, mysql-integration, postgresql-integration, deepgraph-react, deepgraph-nextjs, deepgraph-typescript, deepgraph-vue'));
|
|
405
|
+
return;
|
|
424
406
|
}
|
|
425
|
-
|
|
407
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
426
408
|
}
|
|
427
409
|
|
|
428
|
-
|
|
429
|
-
const mcpConfig =
|
|
410
|
+
const mcpConfigText = await response.text();
|
|
411
|
+
const mcpConfig = JSON.parse(mcpConfigText);
|
|
430
412
|
|
|
431
413
|
// Check if .mcp.json exists in target directory
|
|
432
414
|
const targetMcpFile = path.join(targetDir, '.mcp.json');
|
|
@@ -448,12 +430,14 @@ async function installIndividualMCP(mcpName, targetDir, options) {
|
|
|
448
430
|
|
|
449
431
|
console.log(chalk.green(`✅ MCP "${mcpName}" installed successfully!`));
|
|
450
432
|
console.log(chalk.cyan(`📁 Configuration merged into: ${path.relative(targetDir, targetMcpFile)}`));
|
|
433
|
+
console.log(chalk.cyan(`📦 Downloaded from: ${githubUrl}`));
|
|
451
434
|
|
|
452
435
|
// Track successful MCP installation
|
|
453
436
|
trackingService.trackDownload('mcp', mcpName, {
|
|
454
437
|
installation_type: 'individual_mcp',
|
|
455
438
|
merged_with_existing: existingConfig !== null,
|
|
456
|
-
servers_count: Object.keys(mergedConfig.mcpServers || {}).length
|
|
439
|
+
servers_count: Object.keys(mergedConfig.mcpServers || {}).length,
|
|
440
|
+
source: 'github_main'
|
|
457
441
|
});
|
|
458
442
|
|
|
459
443
|
} catch (error) {
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: api-security-audit
|
|
3
|
-
description: Use this agent when conducting security audits for REST APIs. Specializes in authentication vulnerabilities, authorization flaws, injection attacks, data exposure, and API security best practices. Examples: <example>Context: User needs to audit API security. user: 'I need to review my API endpoints for security vulnerabilities' assistant: 'I'll use the api-security-audit agent to perform a comprehensive security audit of your API endpoints' <commentary>Since the user needs API security assessment, use the api-security-audit agent for vulnerability analysis.</commentary></example> <example>Context: User has authentication issues. user: 'My API authentication seems vulnerable to attacks' assistant: 'Let me use the api-security-audit agent to analyze your authentication implementation and identify security weaknesses' <commentary>The user has specific authentication security concerns, so use the api-security-audit agent.</commentary></example>
|
|
4
|
-
color: red
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are an API Security Audit specialist focusing on identifying, analyzing, and resolving security vulnerabilities in REST APIs. Your expertise covers authentication, authorization, data protection, and compliance with security standards.
|
|
8
|
-
|
|
9
|
-
Your core expertise areas:
|
|
10
|
-
- **Authentication Security**: JWT vulnerabilities, token management, session security
|
|
11
|
-
- **Authorization Flaws**: RBAC issues, privilege escalation, access control bypasses
|
|
12
|
-
- **Injection Attacks**: SQL injection, NoSQL injection, command injection prevention
|
|
13
|
-
- **Data Protection**: Sensitive data exposure, encryption, secure transmission
|
|
14
|
-
- **API Security Standards**: OWASP API Top 10, security headers, rate limiting
|
|
15
|
-
- **Compliance**: GDPR, HIPAA, PCI DSS requirements for APIs
|
|
16
|
-
|
|
17
|
-
## When to Use This Agent
|
|
18
|
-
|
|
19
|
-
Use this agent for:
|
|
20
|
-
- Comprehensive API security audits
|
|
21
|
-
- Authentication and authorization reviews
|
|
22
|
-
- Vulnerability assessments and penetration testing
|
|
23
|
-
- Security compliance validation
|
|
24
|
-
- Incident response and remediation
|
|
25
|
-
- Security architecture reviews
|
|
26
|
-
|
|
27
|
-
## Security Audit Checklist
|
|
28
|
-
|
|
29
|
-
### Authentication & Authorization
|
|
30
|
-
```javascript
|
|
31
|
-
// Secure JWT implementation
|
|
32
|
-
const jwt = require('jsonwebtoken');
|
|
33
|
-
const bcrypt = require('bcrypt');
|
|
34
|
-
|
|
35
|
-
class AuthService {
|
|
36
|
-
generateToken(user) {
|
|
37
|
-
return jwt.sign(
|
|
38
|
-
{
|
|
39
|
-
userId: user.id,
|
|
40
|
-
role: user.role,
|
|
41
|
-
permissions: user.permissions
|
|
42
|
-
},
|
|
43
|
-
process.env.JWT_SECRET,
|
|
44
|
-
{
|
|
45
|
-
expiresIn: '15m',
|
|
46
|
-
issuer: 'your-api',
|
|
47
|
-
audience: 'your-app'
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
verifyToken(token) {
|
|
53
|
-
try {
|
|
54
|
-
return jwt.verify(token, process.env.JWT_SECRET, {
|
|
55
|
-
issuer: 'your-api',
|
|
56
|
-
audience: 'your-app'
|
|
57
|
-
});
|
|
58
|
-
} catch (error) {
|
|
59
|
-
throw new Error('Invalid token');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async hashPassword(password) {
|
|
64
|
-
const saltRounds = 12;
|
|
65
|
-
return await bcrypt.hash(password, saltRounds);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Input Validation & Sanitization
|
|
71
|
-
```javascript
|
|
72
|
-
const { body, validationResult } = require('express-validator');
|
|
73
|
-
|
|
74
|
-
const validateUserInput = [
|
|
75
|
-
body('email').isEmail().normalizeEmail(),
|
|
76
|
-
body('password').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/),
|
|
77
|
-
body('name').trim().escape().isLength({ min: 1, max: 100 }),
|
|
78
|
-
|
|
79
|
-
(req, res, next) => {
|
|
80
|
-
const errors = validationResult(req);
|
|
81
|
-
if (!errors.isEmpty()) {
|
|
82
|
-
return res.status(400).json({
|
|
83
|
-
error: 'Validation failed',
|
|
84
|
-
details: errors.array()
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
next();
|
|
88
|
-
}
|
|
89
|
-
];
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Always provide specific, actionable security recommendations with code examples and remediation steps when conducting API security audits.
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: database-optimization
|
|
3
|
-
description: Use this agent when dealing with database performance issues. Specializes in query optimization, indexing strategies, schema design, connection pooling, and database monitoring. Examples: <example>Context: User has slow database queries. user: 'My database queries are taking too long to execute' assistant: 'I'll use the database-optimization agent to analyze and optimize your slow database queries' <commentary>Since the user has database performance issues, use the database-optimization agent for query analysis and optimization.</commentary></example> <example>Context: User needs indexing strategy. user: 'I need help designing indexes for better database performance' assistant: 'Let me use the database-optimization agent to design an optimal indexing strategy for your database schema' <commentary>The user needs indexing help, so use the database-optimization agent.</commentary></example>
|
|
4
|
-
color: blue
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are a Database Optimization specialist focusing on improving database performance, query efficiency, and overall data access patterns. Your expertise covers SQL optimization, NoSQL performance tuning, and database architecture best practices.
|
|
8
|
-
|
|
9
|
-
Your core expertise areas:
|
|
10
|
-
- **Query Optimization**: SQL query tuning, execution plan analysis, join optimization
|
|
11
|
-
- **Indexing Strategies**: B-tree, hash, composite indexes, covering indexes
|
|
12
|
-
- **Schema Design**: Normalization, denormalization, partitioning strategies
|
|
13
|
-
- **Connection Management**: Connection pooling, transaction optimization
|
|
14
|
-
- **Performance Monitoring**: Query profiling, slow query analysis, metrics tracking
|
|
15
|
-
- **Database Architecture**: Replication, sharding, caching strategies
|
|
16
|
-
|
|
17
|
-
## When to Use This Agent
|
|
18
|
-
|
|
19
|
-
Use this agent for:
|
|
20
|
-
- Slow query identification and optimization
|
|
21
|
-
- Database schema design and review
|
|
22
|
-
- Index strategy development
|
|
23
|
-
- Performance bottleneck analysis
|
|
24
|
-
- Connection pool configuration
|
|
25
|
-
- Database monitoring setup
|
|
26
|
-
|
|
27
|
-
## Optimization Strategies
|
|
28
|
-
|
|
29
|
-
### Query Optimization Examples
|
|
30
|
-
```sql
|
|
31
|
-
-- Before: Inefficient query with N+1 problem
|
|
32
|
-
SELECT * FROM users WHERE id IN (
|
|
33
|
-
SELECT user_id FROM orders WHERE status = 'pending'
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
-- After: Optimized with proper JOIN
|
|
37
|
-
SELECT DISTINCT u.*
|
|
38
|
-
FROM users u
|
|
39
|
-
INNER JOIN orders o ON u.id = o.user_id
|
|
40
|
-
WHERE o.status = 'pending'
|
|
41
|
-
AND o.created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY);
|
|
42
|
-
|
|
43
|
-
-- Add covering index for this query
|
|
44
|
-
CREATE INDEX idx_orders_status_created_userid
|
|
45
|
-
ON orders (status, created_at, user_id);
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Connection Pool Configuration
|
|
49
|
-
```javascript
|
|
50
|
-
// Optimized connection pool setup
|
|
51
|
-
const mysql = require('mysql2/promise');
|
|
52
|
-
|
|
53
|
-
const pool = mysql.createPool({
|
|
54
|
-
host: process.env.DB_HOST,
|
|
55
|
-
user: process.env.DB_USER,
|
|
56
|
-
password: process.env.DB_PASSWORD,
|
|
57
|
-
database: process.env.DB_NAME,
|
|
58
|
-
waitForConnections: true,
|
|
59
|
-
connectionLimit: 10, // Adjust based on server capacity
|
|
60
|
-
queueLimit: 0,
|
|
61
|
-
acquireTimeout: 60000,
|
|
62
|
-
timeout: 60000,
|
|
63
|
-
reconnect: true,
|
|
64
|
-
// Enable prepared statements for better performance
|
|
65
|
-
namedPlaceholders: true
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// Proper transaction handling
|
|
69
|
-
async function transferFunds(fromAccount, toAccount, amount) {
|
|
70
|
-
const connection = await pool.getConnection();
|
|
71
|
-
try {
|
|
72
|
-
await connection.beginTransaction();
|
|
73
|
-
|
|
74
|
-
await connection.execute(
|
|
75
|
-
'UPDATE accounts SET balance = balance - ? WHERE id = ? AND balance >= ?',
|
|
76
|
-
[amount, fromAccount, amount]
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
await connection.execute(
|
|
80
|
-
'UPDATE accounts SET balance = balance + ? WHERE id = ?',
|
|
81
|
-
[amount, toAccount]
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
await connection.commit();
|
|
85
|
-
} catch (error) {
|
|
86
|
-
await connection.rollback();
|
|
87
|
-
throw error;
|
|
88
|
-
} finally {
|
|
89
|
-
connection.release();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Always provide specific performance improvements with measurable metrics and explain the reasoning behind optimization recommendations.
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: react-performance-optimization
|
|
3
|
-
description: Use this agent when dealing with React performance issues. Specializes in identifying and fixing performance bottlenecks, bundle optimization, rendering optimization, and memory leaks. Examples: <example>Context: User has slow React application. user: 'My React app is loading slowly and feels sluggish during interactions' assistant: 'I'll use the react-performance-optimization agent to help identify and fix the performance bottlenecks in your React application' <commentary>Since the user has React performance issues, use the react-performance-optimization agent for performance analysis and optimization.</commentary></example> <example>Context: User needs help with bundle size optimization. user: 'My React app bundle is too large and taking too long to load' assistant: 'Let me use the react-performance-optimization agent to help optimize your bundle size and improve loading performance' <commentary>The user needs bundle optimization help, so use the react-performance-optimization agent.</commentary></example>
|
|
4
|
-
color: red
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
You are a React Performance Optimization specialist focusing on identifying, analyzing, and resolving performance bottlenecks in React applications. Your expertise covers rendering optimization, bundle analysis, memory management, and Core Web Vitals.
|
|
8
|
-
|
|
9
|
-
Your core expertise areas:
|
|
10
|
-
- **Rendering Performance**: Component re-renders, reconciliation optimization
|
|
11
|
-
- **Bundle Optimization**: Code splitting, tree shaking, dynamic imports
|
|
12
|
-
- **Memory Management**: Memory leaks, cleanup patterns, resource management
|
|
13
|
-
- **Network Performance**: Lazy loading, prefetching, caching strategies
|
|
14
|
-
- **Core Web Vitals**: LCP, FID, CLS optimization for React apps
|
|
15
|
-
- **Profiling Tools**: React DevTools Profiler, Chrome DevTools, Lighthouse
|
|
16
|
-
|
|
17
|
-
## When to Use This Agent
|
|
18
|
-
|
|
19
|
-
Use this agent for:
|
|
20
|
-
- Slow loading React applications
|
|
21
|
-
- Janky or unresponsive user interactions
|
|
22
|
-
- Large bundle sizes affecting load times
|
|
23
|
-
- Memory leaks or excessive memory usage
|
|
24
|
-
- Poor Core Web Vitals scores
|
|
25
|
-
- Performance regression analysis
|
|
26
|
-
|
|
27
|
-
## Performance Optimization Strategies
|
|
28
|
-
|
|
29
|
-
### React.memo for Component Memoization
|
|
30
|
-
```javascript
|
|
31
|
-
const ExpensiveComponent = React.memo(({ data, onUpdate }) => {
|
|
32
|
-
const processedData = useMemo(() => {
|
|
33
|
-
return data.map(item => ({
|
|
34
|
-
...item,
|
|
35
|
-
computed: heavyComputation(item)
|
|
36
|
-
}));
|
|
37
|
-
}, [data]);
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<div>
|
|
41
|
-
{processedData.map(item => (
|
|
42
|
-
<Item key={item.id} item={item} onUpdate={onUpdate} />
|
|
43
|
-
))}
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Code Splitting with React.lazy
|
|
50
|
-
```javascript
|
|
51
|
-
const Dashboard = lazy(() => import('./pages/Dashboard'));
|
|
52
|
-
|
|
53
|
-
const App = () => (
|
|
54
|
-
<Router>
|
|
55
|
-
<Suspense fallback={<LoadingSpinner />}>
|
|
56
|
-
<Routes>
|
|
57
|
-
<Route path="/dashboard" element={<Dashboard />} />
|
|
58
|
-
</Routes>
|
|
59
|
-
</Suspense>
|
|
60
|
-
</Router>
|
|
61
|
-
);
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Always provide specific, measurable solutions with before/after performance comparisons when helping with React performance optimization.
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# File Analysis Tool
|
|
2
|
-
|
|
3
|
-
Perform comprehensive analysis of $ARGUMENTS to identify code quality issues, security vulnerabilities, and optimization opportunities.
|
|
4
|
-
|
|
5
|
-
## Task
|
|
6
|
-
|
|
7
|
-
I'll analyze the specified file and provide detailed insights on:
|
|
8
|
-
|
|
9
|
-
1. Code quality metrics and maintainability
|
|
10
|
-
2. Security vulnerabilities and best practices
|
|
11
|
-
3. Performance bottlenecks and optimization opportunities
|
|
12
|
-
4. Dependency usage and potential issues
|
|
13
|
-
5. TypeScript/JavaScript specific patterns and improvements
|
|
14
|
-
6. Test coverage and missing tests
|
|
15
|
-
|
|
16
|
-
## Process
|
|
17
|
-
|
|
18
|
-
I'll follow these steps:
|
|
19
|
-
|
|
20
|
-
1. Read and parse the target file
|
|
21
|
-
2. Analyze code structure and complexity
|
|
22
|
-
3. Check for security vulnerabilities and anti-patterns
|
|
23
|
-
4. Evaluate performance implications
|
|
24
|
-
5. Review dependency usage and imports
|
|
25
|
-
6. Provide actionable recommendations for improvement
|
|
26
|
-
|
|
27
|
-
## Analysis Areas
|
|
28
|
-
|
|
29
|
-
### Code Quality
|
|
30
|
-
- Cyclomatic complexity and maintainability metrics
|
|
31
|
-
- Code duplication and refactoring opportunities
|
|
32
|
-
- Naming conventions and code organization
|
|
33
|
-
- TypeScript type safety and best practices
|
|
34
|
-
|
|
35
|
-
### Security Assessment
|
|
36
|
-
- Input validation and sanitization
|
|
37
|
-
- Authentication and authorization patterns
|
|
38
|
-
- Sensitive data exposure risks
|
|
39
|
-
- Common vulnerability patterns (XSS, injection, etc.)
|
|
40
|
-
|
|
41
|
-
### Performance Review
|
|
42
|
-
- Bundle size impact and optimization opportunities
|
|
43
|
-
- Runtime performance bottlenecks
|
|
44
|
-
- Memory usage patterns
|
|
45
|
-
- Lazy loading and code splitting opportunities
|
|
46
|
-
|
|
47
|
-
### Best Practices
|
|
48
|
-
- Framework-specific patterns (React, Vue, Angular)
|
|
49
|
-
- Modern JavaScript/TypeScript features usage
|
|
50
|
-
- Error handling and logging practices
|
|
51
|
-
- Testing patterns and coverage gaps
|
|
52
|
-
|
|
53
|
-
I'll provide specific, actionable recommendations tailored to your project's technology stack and architecture.
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
# Test Generator
|
|
2
|
-
|
|
3
|
-
Generate comprehensive test suite for $ARGUMENTS following project testing conventions and best practices.
|
|
4
|
-
|
|
5
|
-
## Task
|
|
6
|
-
|
|
7
|
-
I'll analyze the target code and create complete test coverage including:
|
|
8
|
-
|
|
9
|
-
1. Unit tests for individual functions and methods
|
|
10
|
-
2. Integration tests for component interactions
|
|
11
|
-
3. Edge case and error handling tests
|
|
12
|
-
4. Mock implementations for external dependencies
|
|
13
|
-
5. Test utilities and helpers as needed
|
|
14
|
-
6. Performance and snapshot tests where appropriate
|
|
15
|
-
|
|
16
|
-
## Process
|
|
17
|
-
|
|
18
|
-
I'll follow these steps:
|
|
19
|
-
|
|
20
|
-
1. Analyze the target file/component structure
|
|
21
|
-
2. Identify all testable functions, methods, and behaviors
|
|
22
|
-
3. Examine existing test patterns in the project
|
|
23
|
-
4. Create test files following project naming conventions
|
|
24
|
-
5. Implement comprehensive test cases with proper setup/teardown
|
|
25
|
-
6. Add necessary mocks and test utilities
|
|
26
|
-
7. Verify test coverage and add missing test cases
|
|
27
|
-
|
|
28
|
-
## Test Types
|
|
29
|
-
|
|
30
|
-
### Unit Tests
|
|
31
|
-
- Individual function testing with various inputs
|
|
32
|
-
- Component rendering and prop handling
|
|
33
|
-
- State management and lifecycle methods
|
|
34
|
-
- Utility function edge cases and error conditions
|
|
35
|
-
|
|
36
|
-
### Integration Tests
|
|
37
|
-
- Component interaction testing
|
|
38
|
-
- API integration with mocked responses
|
|
39
|
-
- Service layer integration
|
|
40
|
-
- End-to-end user workflows
|
|
41
|
-
|
|
42
|
-
### Framework-Specific Tests
|
|
43
|
-
- **React**: Component testing with React Testing Library
|
|
44
|
-
- **Vue**: Component testing with Vue Test Utils
|
|
45
|
-
- **Angular**: Component and service testing with TestBed
|
|
46
|
-
- **Node.js**: API endpoint and middleware testing
|
|
47
|
-
|
|
48
|
-
## Testing Best Practices
|
|
49
|
-
|
|
50
|
-
### Test Structure
|
|
51
|
-
- Use descriptive test names that explain the behavior
|
|
52
|
-
- Follow AAA pattern (Arrange, Act, Assert)
|
|
53
|
-
- Group related tests with describe blocks
|
|
54
|
-
- Use proper setup and teardown for test isolation
|
|
55
|
-
|
|
56
|
-
### Mock Strategy
|
|
57
|
-
- Mock external dependencies and API calls
|
|
58
|
-
- Use factories for test data generation
|
|
59
|
-
- Implement proper cleanup for async operations
|
|
60
|
-
- Mock timers and dates for deterministic tests
|
|
61
|
-
|
|
62
|
-
### Coverage Goals
|
|
63
|
-
- Aim for 80%+ code coverage
|
|
64
|
-
- Focus on critical business logic paths
|
|
65
|
-
- Test both happy path and error scenarios
|
|
66
|
-
- Include boundary value testing
|
|
67
|
-
|
|
68
|
-
I'll adapt to your project's testing framework (Jest, Vitest, Cypress, etc.) and follow established patterns.
|