claude-code-templates 1.2.0 → 1.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.
Files changed (43) hide show
  1. package/package.json +10 -8
  2. package/src/command-scanner.js +1 -1
  3. package/src/file-operations.js +44 -3
  4. package/src/hook-scanner.js +229 -52
  5. package/src/index.js +23 -3
  6. package/src/prompts.js +68 -2
  7. package/src/templates.js +31 -8
  8. package/scripts/sync-templates.js +0 -182
  9. package/templates/common/.claude/commands/git-workflow.md +0 -239
  10. package/templates/common/.claude/commands/project-setup.md +0 -316
  11. package/templates/common/CLAUDE.md +0 -109
  12. package/templates/common/README.md +0 -96
  13. package/templates/go/README.md +0 -25
  14. package/templates/javascript-typescript/.claude/commands/api-endpoint.md +0 -51
  15. package/templates/javascript-typescript/.claude/commands/debug.md +0 -52
  16. package/templates/javascript-typescript/.claude/commands/lint.md +0 -48
  17. package/templates/javascript-typescript/.claude/commands/npm-scripts.md +0 -48
  18. package/templates/javascript-typescript/.claude/commands/refactor.md +0 -55
  19. package/templates/javascript-typescript/.claude/commands/test.md +0 -61
  20. package/templates/javascript-typescript/.claude/commands/typescript-migrate.md +0 -51
  21. package/templates/javascript-typescript/.claude/settings.json +0 -142
  22. package/templates/javascript-typescript/.mcp.json +0 -13
  23. package/templates/javascript-typescript/CLAUDE.md +0 -185
  24. package/templates/javascript-typescript/README.md +0 -259
  25. package/templates/javascript-typescript/examples/angular-app/.claude/commands/components.md +0 -63
  26. package/templates/javascript-typescript/examples/angular-app/.claude/commands/services.md +0 -62
  27. package/templates/javascript-typescript/examples/node-api/.claude/commands/api-endpoint.md +0 -46
  28. package/templates/javascript-typescript/examples/node-api/.claude/commands/database.md +0 -56
  29. package/templates/javascript-typescript/examples/node-api/.claude/commands/middleware.md +0 -61
  30. package/templates/javascript-typescript/examples/node-api/.claude/commands/route.md +0 -57
  31. package/templates/javascript-typescript/examples/node-api/CLAUDE.md +0 -102
  32. package/templates/javascript-typescript/examples/react-app/.claude/commands/component.md +0 -29
  33. package/templates/javascript-typescript/examples/react-app/.claude/commands/hooks.md +0 -44
  34. package/templates/javascript-typescript/examples/react-app/.claude/commands/state-management.md +0 -45
  35. package/templates/javascript-typescript/examples/react-app/CLAUDE.md +0 -81
  36. package/templates/javascript-typescript/examples/vue-app/.claude/commands/components.md +0 -46
  37. package/templates/javascript-typescript/examples/vue-app/.claude/commands/composables.md +0 -51
  38. package/templates/python/.claude/commands/django-model.md +0 -124
  39. package/templates/python/.claude/commands/flask-route.md +0 -217
  40. package/templates/python/.claude/commands/lint.md +0 -111
  41. package/templates/python/.claude/commands/test.md +0 -73
  42. package/templates/python/CLAUDE.md +0 -276
  43. package/templates/rust/README.md +0 -26
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.2.0",
4
- "description": "CLI tool to setup Claude Code configurations with selective automation hooks for different programming languages",
3
+ "version": "1.3.0",
4
+ "description": "CLI tool to setup Claude Code configurations with framework-specific commands and automation hooks for JavaScript/TypeScript and Python projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "create-claude-config": "bin/create-claude-config.js",
@@ -20,10 +20,7 @@
20
20
  "dev:link": "npm link",
21
21
  "dev:unlink": "npm unlink -g claude-code-templates",
22
22
  "pretest": "npm run dev:link",
23
- "sync": "node scripts/sync-templates.js",
24
- "presync": "echo \"🔄 Starting template synchronization...\"",
25
- "postsync": "echo \"✅ Synchronization completed. Ready to publish!\"",
26
- "prepublishOnly": "npm run sync && npm run test"
23
+ "prepublishOnly": "npm run test"
27
24
  },
28
25
  "keywords": [
29
26
  "claude",
@@ -37,7 +34,14 @@
37
34
  "automation",
38
35
  "javascript",
39
36
  "typescript",
37
+ "react",
38
+ "vue",
39
+ "angular",
40
+ "nodejs",
40
41
  "python",
42
+ "django",
43
+ "flask",
44
+ "fastapi",
41
45
  "rust",
42
46
  "go"
43
47
  ],
@@ -65,8 +69,6 @@
65
69
  "files": [
66
70
  "bin/",
67
71
  "src/",
68
- "scripts/",
69
- "templates/",
70
72
  "README.md"
71
73
  ]
72
74
  }
@@ -7,7 +7,7 @@ const path = require('path');
7
7
  * @returns {Array} Array of available commands with metadata
8
8
  */
9
9
  function getAvailableCommands(language) {
10
- const templatesDir = path.join(__dirname, '..', 'templates');
10
+ const templatesDir = path.join(__dirname, '../../');
11
11
  const languageDir = path.join(templatesDir, language);
12
12
 
13
13
  // Check if language directory exists
@@ -1,10 +1,10 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
- const { getHooksForLanguage, filterHooksBySelection } = require('./hook-scanner');
4
+ const { getHooksForLanguage, filterHooksBySelection, getMCPsForLanguage, filterMCPsBySelection } = require('./hook-scanner');
5
5
 
6
6
  async function copyTemplateFiles(templateConfig, targetDir) {
7
- const templateDir = path.join(__dirname, '../templates');
7
+ const templateDir = path.join(__dirname, '../../');
8
8
 
9
9
  // Check if CLAUDE.md already exists
10
10
  const claudeFile = path.join(targetDir, 'CLAUDE.md');
@@ -79,6 +79,10 @@ async function copyTemplateFiles(templateConfig, targetDir) {
79
79
  // Handle settings.json with hook filtering
80
80
  await processSettingsFile(sourcePath, destPath, templateConfig);
81
81
  console.log(chalk.green(`✓ Copied ${file.source} → ${file.destination} (with selected hooks)`));
82
+ } else if (file.source.includes('.mcp.json') && templateConfig.selectedMCPs) {
83
+ // Handle .mcp.json with MCP filtering
84
+ await processMCPFile(sourcePath, destPath, templateConfig);
85
+ console.log(chalk.green(`✓ Copied ${file.source} → ${file.destination} (with selected MCPs)`));
82
86
  } else {
83
87
  // Copy regular files (CLAUDE.md, settings.json, etc.)
84
88
  await fs.copy(sourcePath, destPath, {
@@ -121,6 +125,11 @@ async function copyTemplateFiles(templateConfig, targetDir) {
121
125
  if (templateConfig.selectedHooks && templateConfig.selectedHooks.length > 0) {
122
126
  console.log(chalk.magenta(`🔧 Installed ${templateConfig.selectedHooks.length} automation hooks`));
123
127
  }
128
+
129
+ // Report MCP selection
130
+ if (templateConfig.selectedMCPs && templateConfig.selectedMCPs.length > 0) {
131
+ console.log(chalk.blue(`🔧 Installed ${templateConfig.selectedMCPs.length} MCP`));
132
+ }
124
133
  }
125
134
 
126
135
  async function processSettingsFile(sourcePath, destPath, templateConfig) {
@@ -155,6 +164,37 @@ async function processSettingsFile(sourcePath, destPath, templateConfig) {
155
164
  }
156
165
  }
157
166
 
167
+ async function processMCPFile(sourcePath, destPath, templateConfig) {
168
+ try {
169
+ // Read the original MCP file
170
+ const originalMCPData = JSON.parse(await fs.readFile(sourcePath, 'utf8'));
171
+
172
+ // If MCPs are selected, filter them
173
+ if (templateConfig.selectedMCPs && templateConfig.selectedMCPs.length > 0) {
174
+ const availableMCPs = getMCPsForLanguage(templateConfig.language);
175
+ const filteredMCPData = filterMCPsBySelection(
176
+ originalMCPData,
177
+ templateConfig.selectedMCPs,
178
+ availableMCPs
179
+ );
180
+
181
+ // Write the filtered MCP data
182
+ await fs.ensureDir(path.dirname(destPath));
183
+ await fs.writeFile(destPath, JSON.stringify(filteredMCPData, null, 2));
184
+ } else {
185
+ // No MCPs selected, create empty MCP file
186
+ const emptyMCPData = { mcpServers: {} };
187
+
188
+ await fs.ensureDir(path.dirname(destPath));
189
+ await fs.writeFile(destPath, JSON.stringify(emptyMCPData, null, 2));
190
+ }
191
+ } catch (error) {
192
+ console.error(chalk.red(`Failed to process MCP file: ${error.message}`));
193
+ // Fallback to copying original file
194
+ await fs.copy(sourcePath, destPath);
195
+ }
196
+ }
197
+
158
198
  async function ensureDirectoryExists(dirPath) {
159
199
  try {
160
200
  await fs.ensureDir(dirPath);
@@ -180,5 +220,6 @@ module.exports = {
180
220
  copyTemplateFiles,
181
221
  ensureDirectoryExists,
182
222
  checkWritePermissions,
183
- processSettingsFile
223
+ processSettingsFile,
224
+ processMCPFile
184
225
  };
@@ -110,56 +110,129 @@ function getHooksFromSettings(settingsPath) {
110
110
  function getHookDescription(hook, matcher, type) {
111
111
  const command = hook.command || '';
112
112
 
113
- // Pre-defined descriptions for common hooks
114
- const descriptions = {
115
- // PreToolUse hooks
116
- 'jq -r': 'Log Bash commands to ~/.claude/bash-command-log.txt',
117
- 'console\\.log': 'Block files containing console.log statements',
118
- 'print(': 'Block Python files containing print statements',
119
- 'fmt.Print': 'Block Go files containing fmt.Print statements',
120
- 'println!': 'Block Rust files containing println! statements',
121
- 'npm audit': 'Check for vulnerable dependencies when modifying package.json',
122
- 'pip-audit': 'Check for vulnerable Python dependencies',
123
- 'cargo audit': 'Check for vulnerable Rust dependencies',
124
- 'go list': 'Check Go dependencies',
125
-
126
- // PostToolUse hooks
127
- 'prettier --write': 'Auto-format JavaScript/TypeScript files with Prettier',
128
- 'black': 'Auto-format Python files with Black',
129
- 'isort': 'Sort Python imports with isort',
130
- 'gofmt': 'Auto-format Go files with gofmt',
131
- 'goimports': 'Auto-format Go imports with goimports',
132
- 'rustfmt': 'Auto-format Rust files with rustfmt',
133
- 'tsc --noEmit': 'Run TypeScript type checking after edits',
134
- 'flake8': 'Run Python code quality checks with flake8',
135
- 'mypy': 'Run Python type checking with mypy',
136
- 'go vet': 'Run Go code analysis with go vet',
137
- 'cargo check': 'Run Rust code checking with cargo check',
138
- 'cargo clippy': 'Run Rust linting with clippy',
139
- 'import \\* from': 'Warn about wildcard imports (bad for tree-shaking)',
140
- 'npx jest': 'Run JavaScript/TypeScript tests automatically',
141
- 'pytest': 'Run Python tests automatically',
142
- 'go test': 'Run Go tests automatically',
143
- 'cargo test': 'Run Rust tests automatically',
144
-
145
- // Stop hooks
146
- 'eslint': 'Run ESLint on changed files before stopping',
147
- 'flake8.*git diff': 'Run Python linting on changed files',
148
- 'bandit': 'Run Python security analysis',
149
- 'go vet.*git diff': 'Run Go analysis on changed files',
150
- 'staticcheck': 'Run Go static analysis',
151
- 'cargo clippy.*git diff': 'Run Rust linting on changed files',
152
- 'bundlesize': 'Analyze bundle size impact of changes',
153
-
154
- // Notification hooks
155
- 'notifications.log': 'Log Claude Code notifications'
156
- };
157
-
158
- // Try to match command with known descriptions
159
- for (const [pattern, description] of Object.entries(descriptions)) {
160
- if (command.includes(pattern)) {
161
- return description;
162
- }
113
+ // Extract key patterns for more specific descriptions
114
+ if (command.includes('jq -r') && command.includes('bash-command-log')) {
115
+ return 'Log all Bash commands for debugging';
116
+ }
117
+
118
+ if (command.includes('console\\.log')) {
119
+ return 'Block console.log statements in JS/TS files';
120
+ }
121
+
122
+ if (command.includes('print(') && command.includes('py$')) {
123
+ return 'Block print() statements in Python files';
124
+ }
125
+
126
+ if (command.includes('fmt.Print') && command.includes('go$')) {
127
+ return 'Block fmt.Print statements in Go files';
128
+ }
129
+
130
+ if (command.includes('println!') && command.includes('rs$')) {
131
+ return 'Block println! macros in Rust files';
132
+ }
133
+
134
+ if (command.includes('npm audit') || command.includes('pip-audit') || command.includes('cargo audit')) {
135
+ return 'Security audit for dependencies';
136
+ }
137
+
138
+ if (command.includes('prettier --write')) {
139
+ return 'Auto-format JS/TS files with Prettier';
140
+ }
141
+
142
+ if (command.includes('black') && command.includes('py$')) {
143
+ return 'Auto-format Python files with Black';
144
+ }
145
+
146
+ if (command.includes('isort') && command.includes('py$')) {
147
+ return 'Auto-sort Python imports with isort';
148
+ }
149
+
150
+ if (command.includes('gofmt') && command.includes('go$')) {
151
+ return 'Auto-format Go files with gofmt';
152
+ }
153
+
154
+ if (command.includes('goimports')) {
155
+ return 'Auto-format Go imports with goimports';
156
+ }
157
+
158
+ if (command.includes('rustfmt') && command.includes('rs$')) {
159
+ return 'Auto-format Rust files with rustfmt';
160
+ }
161
+
162
+ if (command.includes('tsc --noEmit')) {
163
+ return 'Run TypeScript type checking';
164
+ }
165
+
166
+ if (command.includes('flake8') && !command.includes('git diff')) {
167
+ return 'Run Python linting with flake8';
168
+ }
169
+
170
+ if (command.includes('mypy')) {
171
+ return 'Run Python type checking with mypy';
172
+ }
173
+
174
+ if (command.includes('go vet') && !command.includes('git diff')) {
175
+ return 'Run Go static analysis with go vet';
176
+ }
177
+
178
+ if (command.includes('cargo check')) {
179
+ return 'Run Rust compilation checks';
180
+ }
181
+
182
+ if (command.includes('cargo clippy') && !command.includes('git diff')) {
183
+ return 'Run Rust linting with clippy';
184
+ }
185
+
186
+ if (command.includes('import \\* from')) {
187
+ return 'Warn about wildcard imports';
188
+ }
189
+
190
+ if (command.includes('jest') || command.includes('vitest')) {
191
+ return 'Auto-run tests for modified files';
192
+ }
193
+
194
+ if (command.includes('pytest')) {
195
+ return 'Auto-run Python tests for modified files';
196
+ }
197
+
198
+ if (command.includes('go test')) {
199
+ return 'Auto-run Go tests for modified files';
200
+ }
201
+
202
+ if (command.includes('cargo test')) {
203
+ return 'Auto-run Rust tests for modified files';
204
+ }
205
+
206
+ if (command.includes('eslint') && command.includes('git diff')) {
207
+ return 'Run ESLint on changed files';
208
+ }
209
+
210
+ if (command.includes('flake8') && command.includes('git diff')) {
211
+ return 'Run Python linting on changed files';
212
+ }
213
+
214
+ if (command.includes('bandit')) {
215
+ return 'Run Python security analysis';
216
+ }
217
+
218
+ if (command.includes('go vet') && command.includes('git diff')) {
219
+ return 'Run Go analysis on changed files';
220
+ }
221
+
222
+ if (command.includes('staticcheck')) {
223
+ return 'Run Go static analysis on changed files';
224
+ }
225
+
226
+ if (command.includes('cargo clippy') && command.includes('git diff')) {
227
+ return 'Run Rust linting on changed files';
228
+ }
229
+
230
+ if (command.includes('bundlesize') || command.includes('webpack-bundle-analyzer')) {
231
+ return 'Analyze bundle size impact';
232
+ }
233
+
234
+ if (command.includes('notifications.log')) {
235
+ return 'Log Claude Code notifications';
163
236
  }
164
237
 
165
238
  // Generate description based on command analysis
@@ -194,7 +267,7 @@ function getHookDescription(hook, matcher, type) {
194
267
  * @returns {Array} Array of available hooks for the language
195
268
  */
196
269
  function getHooksForLanguage(language) {
197
- const templateDir = path.join(__dirname, '..', 'templates', language);
270
+ const templateDir = path.join(__dirname, '../../', language);
198
271
  const settingsPath = path.join(templateDir, '.claude', 'settings.json');
199
272
 
200
273
  return getHooksFromSettings(settingsPath);
@@ -263,9 +336,113 @@ function filterHooksBySelection(originalSettings, selectedHookIds, availableHook
263
336
  return filteredSettings;
264
337
  }
265
338
 
339
+ /**
340
+ * Extracts and describes MCPs from a .mcp.json file
341
+ * @param {string} mcpPath - Path to the .mcp.json file
342
+ * @returns {Array} Array of MCP descriptions
343
+ */
344
+ function getMCPsFromFile(mcpPath) {
345
+ if (!fs.existsSync(mcpPath)) {
346
+ return [];
347
+ }
348
+
349
+ try {
350
+ const mcpData = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
351
+ const mcps = [];
352
+
353
+ if (mcpData.mcpServers) {
354
+ Object.keys(mcpData.mcpServers).forEach((serverId) => {
355
+ const server = mcpData.mcpServers[serverId];
356
+ mcps.push({
357
+ id: serverId,
358
+ name: server.name || serverId,
359
+ description: server.description || 'No description available',
360
+ command: server.command,
361
+ args: server.args || [],
362
+ env: server.env || {},
363
+ originalServer: server,
364
+ checked: getDefaultMCPSelection(serverId) // Default selection logic
365
+ });
366
+ });
367
+ }
368
+
369
+ return mcps;
370
+ } catch (error) {
371
+ console.error(`Error parsing MCP file ${mcpPath}:`, error.message);
372
+ return [];
373
+ }
374
+ }
375
+
376
+ /**
377
+ * Determines default selection for MCP servers
378
+ * @param {string} serverId - The MCP server ID
379
+ * @returns {boolean} Whether the MCP should be selected by default
380
+ */
381
+ function getDefaultMCPSelection(serverId) {
382
+ // Default to checked for commonly useful MCPs
383
+ const defaultSelected = [
384
+ 'filesystem',
385
+ 'memory-bank',
386
+ 'sequential-thinking',
387
+ 'typescript-sdk',
388
+ 'python-sdk',
389
+ 'rust-sdk',
390
+ 'go-sdk'
391
+ ];
392
+
393
+ return defaultSelected.includes(serverId);
394
+ }
395
+
396
+ /**
397
+ * Gets MCPs for a specific language
398
+ * @param {string} language - The programming language
399
+ * @returns {Array} Array of available MCPs for the language
400
+ */
401
+ function getMCPsForLanguage(language) {
402
+ const templateDir = path.join(__dirname, '../../', language);
403
+ const mcpPath = path.join(templateDir, '.mcp.json');
404
+
405
+ return getMCPsFromFile(mcpPath);
406
+ }
407
+
408
+ /**
409
+ * Filters MCPs based on user selection
410
+ * @param {Object} originalMCPData - Original MCP data object
411
+ * @param {Array} selectedMCPIds - Array of selected MCP IDs
412
+ * @param {Array} availableMCPs - Array of available MCPs
413
+ * @returns {Object} Filtered MCP data object
414
+ */
415
+ function filterMCPsBySelection(originalMCPData, selectedMCPIds, availableMCPs) {
416
+ if (!originalMCPData.mcpServers) {
417
+ return originalMCPData;
418
+ }
419
+
420
+ const filteredMCPData = {
421
+ mcpServers: {}
422
+ };
423
+
424
+ // Create a map of selected MCPs for quick lookup
425
+ const selectedMCPs = new Map();
426
+ availableMCPs.forEach(mcp => {
427
+ if (selectedMCPIds.includes(mcp.id)) {
428
+ selectedMCPs.set(mcp.id, mcp);
429
+ }
430
+ });
431
+
432
+ // Add selected MCPs to filtered data
433
+ selectedMCPs.forEach((mcp, mcpId) => {
434
+ filteredMCPData.mcpServers[mcpId] = mcp.originalServer;
435
+ });
436
+
437
+ return filteredMCPData;
438
+ }
439
+
266
440
  module.exports = {
267
441
  getHooksFromSettings,
268
442
  getHooksForLanguage,
269
443
  filterHooksBySelection,
270
- getHookDescription
444
+ getHookDescription,
445
+ getMCPsFromFile,
446
+ getMCPsForLanguage,
447
+ filterMCPsBySelection
271
448
  };
package/src/index.js CHANGED
@@ -4,10 +4,10 @@ const fs = require('fs-extra');
4
4
  const path = require('path');
5
5
  const ora = require('ora');
6
6
  const { detectProject } = require('./utils');
7
- const { getTemplateConfig } = require('./templates');
7
+ const { getTemplateConfig, TEMPLATES_CONFIG } = require('./templates');
8
8
  const { createPrompts, interactivePrompts } = require('./prompts');
9
9
  const { copyTemplateFiles } = require('./file-operations');
10
- const { getHooksForLanguage } = require('./hook-scanner');
10
+ const { getHooksForLanguage, getMCPsForLanguage } = require('./hook-scanner');
11
11
 
12
12
  async function createClaudeConfig(options = {}) {
13
13
  const targetDir = options.directory || process.cwd();
@@ -24,14 +24,24 @@ async function createClaudeConfig(options = {}) {
24
24
  if (options.yes) {
25
25
  // Use defaults
26
26
  const selectedLanguage = options.language || projectInfo.detectedLanguage || 'common';
27
+
28
+ // Check if selected language is coming soon
29
+ if (selectedLanguage && TEMPLATES_CONFIG[selectedLanguage] && TEMPLATES_CONFIG[selectedLanguage].comingSoon) {
30
+ console.log(chalk.red(`❌ ${selectedLanguage} is not available yet. Coming soon!`));
31
+ console.log(chalk.yellow('Available languages: common, javascript-typescript, python'));
32
+ return;
33
+ }
27
34
  const availableHooks = getHooksForLanguage(selectedLanguage);
28
35
  const defaultHooks = availableHooks.filter(hook => hook.checked).map(hook => hook.id);
36
+ const availableMCPs = getMCPsForLanguage(selectedLanguage);
37
+ const defaultMCPs = availableMCPs.filter(mcp => mcp.checked).map(mcp => mcp.id);
29
38
 
30
39
  config = {
31
40
  language: selectedLanguage,
32
41
  framework: options.framework || projectInfo.detectedFramework || 'none',
33
42
  features: [],
34
- hooks: defaultHooks
43
+ hooks: defaultHooks,
44
+ mcps: defaultMCPs
35
45
  };
36
46
  } else {
37
47
  // Interactive prompts with back navigation
@@ -53,6 +63,12 @@ async function createClaudeConfig(options = {}) {
53
63
  templateConfig.language = config.language; // Ensure language is available for hook filtering
54
64
  }
55
65
 
66
+ // Add selected MCPs to template config
67
+ if (config.mcps) {
68
+ templateConfig.selectedMCPs = config.mcps;
69
+ templateConfig.language = config.language; // Ensure language is available for MCP filtering
70
+ }
71
+
56
72
  if (options.dryRun) {
57
73
  console.log(chalk.yellow('🔍 Dry run - showing what would be copied:'));
58
74
  templateConfig.files.forEach(file => {
@@ -89,6 +105,10 @@ async function createClaudeConfig(options = {}) {
89
105
  if (config.hooks && config.hooks.length > 0) {
90
106
  console.log(chalk.magenta(`🔧 ${config.hooks.length} automation hooks have been configured`));
91
107
  }
108
+
109
+ if (config.mcps && config.mcps.length > 0) {
110
+ console.log(chalk.blue(`🔧 ${config.mcps.length} MCP servers have been configured`));
111
+ }
92
112
  }
93
113
 
94
114
  module.exports = createClaudeConfig;
package/src/prompts.js CHANGED
@@ -13,7 +13,7 @@ class CustomCheckboxPrompt extends inquirer.prompt.prompts.checkbox {
13
13
  inquirer.registerPrompt('checkbox', CustomCheckboxPrompt);
14
14
  const { getAvailableLanguages, getFrameworksForLanguage } = require('./templates');
15
15
  const { getCommandsForLanguageAndFramework } = require('./command-scanner');
16
- const { getHooksForLanguage } = require('./hook-scanner');
16
+ const { getHooksForLanguage, getMCPsForLanguage } = require('./hook-scanner');
17
17
 
18
18
  async function interactivePrompts(projectInfo, options = {}) {
19
19
  const state = {
@@ -25,7 +25,7 @@ async function interactivePrompts(projectInfo, options = {}) {
25
25
  // Build steps array based on options
26
26
  if (!options.language) state.steps.push('language');
27
27
  if (!options.framework) state.steps.push('framework');
28
- state.steps.push('commands', 'hooks', 'confirm');
28
+ state.steps.push('commands', 'hooks', 'mcps', 'confirm');
29
29
 
30
30
  while (state.currentStep < state.steps.length) {
31
31
  const stepName = state.steps[state.currentStep];
@@ -170,11 +170,38 @@ function getStepConfig(stepName, currentAnswers, projectInfo, options) {
170
170
  pageSize: 15
171
171
  };
172
172
 
173
+ case 'mcps':
174
+ const mcpLanguage = currentAnswers.language || options.language;
175
+
176
+ if (!mcpLanguage) {
177
+ return null; // Skip if no language selected
178
+ }
179
+
180
+ const availableMCPs = getMCPsForLanguage(mcpLanguage);
181
+
182
+ if (availableMCPs.length === 0) {
183
+ return null; // Skip if no MCPs available
184
+ }
185
+
186
+ return {
187
+ type: 'checkbox',
188
+ name: 'mcps',
189
+ message: 'Select MCP servers to include (use space to select):',
190
+ choices: availableMCPs.map(mcp => ({
191
+ value: mcp.id,
192
+ name: `${mcp.name} - ${mcp.description}`,
193
+ checked: mcp.checked
194
+ })),
195
+ prefix: chalk.blue('🔧'),
196
+ pageSize: 15
197
+ };
198
+
173
199
  case 'confirm':
174
200
  const confirmLanguage = currentAnswers.language || options.language || 'common';
175
201
  const confirmFramework = currentAnswers.framework || options.framework || 'none';
176
202
  const commandCount = currentAnswers.commands ? currentAnswers.commands.length : 0;
177
203
  const hookCount = currentAnswers.hooks ? currentAnswers.hooks.length : 0;
204
+ const mcpCount = currentAnswers.mcps ? currentAnswers.mcps.length : 0;
178
205
 
179
206
  let message = `Setup Claude Code for ${chalk.cyan(confirmLanguage)}`;
180
207
  if (confirmFramework !== 'none') {
@@ -186,6 +213,9 @@ function getStepConfig(stepName, currentAnswers, projectInfo, options) {
186
213
  if (hookCount > 0) {
187
214
  message += ` (${chalk.magenta(hookCount)} hooks)`;
188
215
  }
216
+ if (mcpCount > 0) {
217
+ message += ` (${chalk.blue(mcpCount)} MCP)`;
218
+ }
189
219
  message += '?';
190
220
 
191
221
  return {
@@ -312,6 +342,38 @@ function createPrompts(projectInfo, options = {}) {
312
342
  return availableHooks.length > 0;
313
343
  }
314
344
  });
345
+
346
+ // MCP selection
347
+ prompts.push({
348
+ type: 'checkbox',
349
+ name: 'mcps',
350
+ message: 'Select MCP servers to include (use space to select):',
351
+ choices: (answers) => {
352
+ const selectedLanguage = answers.language || options.language;
353
+
354
+ if (!selectedLanguage) {
355
+ return [];
356
+ }
357
+
358
+ const availableMCPs = getMCPsForLanguage(selectedLanguage);
359
+
360
+ return availableMCPs.map(mcp => ({
361
+ value: mcp.id,
362
+ name: `${mcp.name} - ${mcp.description}`,
363
+ checked: mcp.checked
364
+ }));
365
+ },
366
+ prefix: chalk.blue('🔧'),
367
+ pageSize: 15,
368
+ when: (answers) => {
369
+ const selectedLanguage = answers.language || options.language;
370
+ if (!selectedLanguage) {
371
+ return false;
372
+ }
373
+ const availableMCPs = getMCPsForLanguage(selectedLanguage);
374
+ return availableMCPs.length > 0;
375
+ }
376
+ });
315
377
 
316
378
  // Confirmation
317
379
  prompts.push({
@@ -322,6 +384,7 @@ function createPrompts(projectInfo, options = {}) {
322
384
  const framework = answers.framework || options.framework || 'none';
323
385
  const commandCount = answers.commands ? answers.commands.length : 0;
324
386
  const hookCount = answers.hooks ? answers.hooks.length : 0;
387
+ const mcpCount = answers.mcps ? answers.mcps.length : 0;
325
388
 
326
389
  let message = `Setup Claude Code for ${chalk.cyan(language)}`;
327
390
  if (framework !== 'none') {
@@ -333,6 +396,9 @@ function createPrompts(projectInfo, options = {}) {
333
396
  if (hookCount > 0) {
334
397
  message += ` (${chalk.magenta(hookCount)} hooks)`;
335
398
  }
399
+ if (mcpCount > 0) {
400
+ message += ` (${chalk.blue(mcpCount)} MCP)`;
401
+ }
336
402
  message += '?';
337
403
 
338
404
  return message;