@paulduvall/claude-dev-toolkit 0.0.1-alpha.2 → 0.0.1-alpha.21

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 (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -37
  3. package/bin/claude-commands +307 -65
  4. package/commands/active/xarchitecture.md +393 -0
  5. package/commands/active/xconfig.md +127 -0
  6. package/commands/active/xcontinue.md +92 -0
  7. package/commands/active/xdebug.md +130 -0
  8. package/commands/active/xdocs.md +178 -0
  9. package/commands/active/xexplore.md +94 -0
  10. package/commands/active/xgit.md +149 -0
  11. package/commands/active/xpipeline.md +152 -0
  12. package/commands/active/xquality.md +96 -0
  13. package/commands/active/xrefactor.md +198 -0
  14. package/commands/active/xrelease.md +142 -0
  15. package/commands/active/xsecurity.md +92 -0
  16. package/commands/active/xspec.md +174 -0
  17. package/commands/active/xtdd.md +151 -0
  18. package/commands/active/xtest.md +89 -0
  19. package/commands/active/xverify.md +80 -0
  20. package/commands/experiments/xact.md +742 -0
  21. package/commands/experiments/xanalytics.md +113 -0
  22. package/commands/experiments/xanalyze.md +70 -0
  23. package/commands/experiments/xapi.md +161 -0
  24. package/commands/experiments/xatomic.md +112 -0
  25. package/commands/experiments/xaws.md +85 -0
  26. package/commands/experiments/xcicd.md +337 -0
  27. package/commands/experiments/xcommit.md +122 -0
  28. package/commands/experiments/xcompliance.md +182 -0
  29. package/commands/experiments/xconstraints.md +89 -0
  30. package/commands/experiments/xcoverage.md +90 -0
  31. package/commands/experiments/xdb.md +102 -0
  32. package/commands/experiments/xdesign.md +121 -0
  33. package/commands/experiments/xdevcontainer.md +238 -0
  34. package/commands/experiments/xevaluate.md +111 -0
  35. package/commands/experiments/xfootnote.md +12 -0
  36. package/commands/experiments/xgenerate.md +117 -0
  37. package/commands/experiments/xgovernance.md +149 -0
  38. package/commands/experiments/xgreen.md +66 -0
  39. package/commands/experiments/xiac.md +118 -0
  40. package/commands/experiments/xincident.md +137 -0
  41. package/commands/experiments/xinfra.md +115 -0
  42. package/commands/experiments/xknowledge.md +115 -0
  43. package/commands/experiments/xmaturity.md +120 -0
  44. package/commands/experiments/xmetrics.md +118 -0
  45. package/commands/experiments/xmonitoring.md +128 -0
  46. package/commands/experiments/xnew.md +903 -0
  47. package/commands/experiments/xobservable.md +114 -0
  48. package/commands/experiments/xoidc.md +165 -0
  49. package/commands/experiments/xoptimize.md +115 -0
  50. package/commands/experiments/xperformance.md +112 -0
  51. package/commands/experiments/xplanning.md +131 -0
  52. package/commands/experiments/xpolicy.md +115 -0
  53. package/commands/experiments/xproduct.md +98 -0
  54. package/commands/experiments/xreadiness.md +75 -0
  55. package/commands/experiments/xred.md +55 -0
  56. package/commands/experiments/xrisk.md +128 -0
  57. package/commands/experiments/xrules.md +124 -0
  58. package/commands/experiments/xsandbox.md +120 -0
  59. package/commands/experiments/xscan.md +102 -0
  60. package/commands/experiments/xsetup.md +123 -0
  61. package/commands/experiments/xtemplate.md +116 -0
  62. package/commands/experiments/xtrace.md +212 -0
  63. package/commands/experiments/xux.md +171 -0
  64. package/commands/experiments/xvalidate.md +104 -0
  65. package/commands/experiments/xworkflow.md +113 -0
  66. package/hooks/.smellrc.example.json +19 -0
  67. package/hooks/README.md +263 -0
  68. package/hooks/check-commit-signing.py +127 -0
  69. package/hooks/check-complexity.py +38 -0
  70. package/hooks/check-security.py +37 -0
  71. package/hooks/claude-wrapper.sh +29 -0
  72. package/hooks/config.py +110 -0
  73. package/hooks/file-logger.sh +100 -0
  74. package/hooks/lib/argument-parser.sh +427 -0
  75. package/hooks/lib/config-constants.sh +230 -0
  76. package/hooks/lib/context-manager.sh +560 -0
  77. package/hooks/lib/error-handler.sh +423 -0
  78. package/hooks/lib/execution-engine.sh +444 -0
  79. package/hooks/lib/execution-results.sh +113 -0
  80. package/hooks/lib/execution-simulation.sh +114 -0
  81. package/hooks/lib/field-validators.sh +104 -0
  82. package/hooks/lib/file-utils.sh +398 -0
  83. package/hooks/lib/subagent-discovery.sh +468 -0
  84. package/hooks/lib/subagent-validator.sh +407 -0
  85. package/hooks/lib/validation-reporter.sh +134 -0
  86. package/hooks/on-error-debug.sh +226 -0
  87. package/hooks/pre-commit-quality.sh +204 -0
  88. package/hooks/pre-commit-test-runner.sh +132 -0
  89. package/hooks/pre-write-security.sh +115 -0
  90. package/hooks/prevent-credential-exposure.sh +279 -0
  91. package/hooks/security_bandit.py +177 -0
  92. package/hooks/security_checks.py +97 -0
  93. package/hooks/security_secrets.py +81 -0
  94. package/hooks/security_trojan.py +61 -0
  95. package/hooks/settings.example.json +52 -0
  96. package/hooks/smell_checks.py +238 -0
  97. package/hooks/smell_javascript.py +231 -0
  98. package/hooks/smell_python.py +110 -0
  99. package/hooks/smell_ruff.py +70 -0
  100. package/hooks/smell_types.py +72 -0
  101. package/hooks/subagent-trigger-simple.sh +202 -0
  102. package/hooks/subagent-trigger.sh +253 -0
  103. package/hooks/suppression.py +82 -0
  104. package/hooks/tab-color.sh +70 -0
  105. package/hooks/verify-before-edit.sh +135 -0
  106. package/lib/backup-restore-command.js +140 -0
  107. package/lib/base/base-command.js +252 -0
  108. package/lib/base/command-result.js +184 -0
  109. package/lib/config/constants.js +255 -0
  110. package/lib/config.js +48 -6
  111. package/lib/configure-command.js +428 -0
  112. package/lib/dependency-validator.js +64 -5
  113. package/lib/hook-installer-core.js +2 -2
  114. package/lib/installation-instruction-generator.js +213 -495
  115. package/lib/installer.js +134 -56
  116. package/lib/oidc-command.js +740 -0
  117. package/lib/services/backup-list-service.js +226 -0
  118. package/lib/services/backup-service.js +230 -0
  119. package/lib/services/command-installer-service.js +217 -0
  120. package/lib/services/logger-service.js +201 -0
  121. package/lib/services/package-manager-service.js +319 -0
  122. package/lib/services/platform-instruction-service.js +294 -0
  123. package/lib/services/recovery-instruction-service.js +348 -0
  124. package/lib/services/restore-service.js +221 -0
  125. package/lib/setup-command.js +359 -0
  126. package/lib/setup-wizard.js +155 -262
  127. package/lib/uninstall-command.js +100 -0
  128. package/lib/utils/claude-path-config.js +184 -0
  129. package/lib/utils/file-system-utils.js +152 -0
  130. package/lib/utils.js +8 -4
  131. package/lib/verify-command.js +430 -0
  132. package/package.json +7 -3
  133. package/scripts/postinstall.js +172 -157
  134. package/subagents/debug-specialist.md +7 -0
  135. package/templates/README.md +115 -0
  136. package/templates/basic-settings.json +30 -0
  137. package/templates/comprehensive-settings.json +57 -0
  138. package/templates/global-claude.md +344 -0
  139. package/templates/hybrid-hook-config.yaml +132 -0
  140. package/templates/security-focused-settings.json +62 -0
  141. package/templates/subagent-hooks.yaml +188 -0
  142. package/lib/package-manager-service.js +0 -270
  143. package/subagents/debug-context.md +0 -197
@@ -0,0 +1,221 @@
1
+ /**
2
+ * Restore Service
3
+ * Focused service for restoring Claude Code configuration from backups
4
+ */
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+ const FileSystemUtils = require('../utils/file-system-utils');
9
+ const ClaudePathConfig = require('../utils/claude-path-config');
10
+
11
+ class RestoreService {
12
+ constructor(config = null) {
13
+ this.config = config || new ClaudePathConfig();
14
+ this.restoredCount = 0;
15
+ }
16
+
17
+ /**
18
+ * Restore from a backup
19
+ */
20
+ async restore(backupName) {
21
+ // Find backup path
22
+ const backupPath = this.findBackupPath(backupName);
23
+ if (!backupPath) {
24
+ throw new Error(`Backup '${backupName}' not found`);
25
+ }
26
+
27
+ // Read metadata if available
28
+ const metadata = await this.readMetadata(backupPath);
29
+ if (metadata) {
30
+ console.log(`📋 Backup created: ${new Date(metadata.timestamp).toLocaleString()}`);
31
+ }
32
+
33
+ // Reset counter
34
+ this.restoredCount = 0;
35
+
36
+ // Restore components
37
+ const results = {};
38
+
39
+ // Restore settings
40
+ results.settings = await this.restoreSettings(backupPath);
41
+
42
+ // Restore commands
43
+ results.commands = await this.restoreCommands(backupPath);
44
+
45
+ // Restore hooks
46
+ results.hooks = await this.restoreHooks(backupPath);
47
+
48
+ return {
49
+ backupName,
50
+ backupPath,
51
+ restoredCount: this.restoredCount,
52
+ results,
53
+ metadata
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Find backup path (compressed or directory)
59
+ */
60
+ findBackupPath(backupName) {
61
+ // Try compressed backup first
62
+ const compressedPath = path.join(this.config.backupsDir, `${backupName}.tar.gz`);
63
+ if (fs.existsSync(compressedPath)) {
64
+ // Would need to extract here in a real implementation
65
+ // For now, look for directory version
66
+ }
67
+
68
+ // Try directory backup
69
+ const directoryPath = path.join(this.config.backupsDir, backupName);
70
+ if (fs.existsSync(directoryPath)) {
71
+ return directoryPath;
72
+ }
73
+
74
+ return null;
75
+ }
76
+
77
+ /**
78
+ * Read backup metadata
79
+ */
80
+ async readMetadata(backupPath) {
81
+ const metadataPath = path.join(backupPath, 'backup-metadata.json');
82
+
83
+ if (!FileSystemUtils.isReadable(metadataPath)) {
84
+ return null;
85
+ }
86
+
87
+ try {
88
+ const content = FileSystemUtils.readFile(metadataPath);
89
+ return JSON.parse(content);
90
+ } catch (error) {
91
+ console.warn(`⚠️ Warning: Could not read backup metadata - ${error.message}`);
92
+ return null;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Restore settings.json
98
+ */
99
+ async restoreSettings(backupPath) {
100
+ const backupSettingsPath = path.join(backupPath, 'settings.json');
101
+
102
+ if (!FileSystemUtils.isReadable(backupSettingsPath)) {
103
+ return { restored: false, reason: 'No settings file in backup' };
104
+ }
105
+
106
+ // Ensure directory exists
107
+ FileSystemUtils.ensureDirectory(this.config.claudeDir);
108
+
109
+ // Copy settings file
110
+ const success = FileSystemUtils.copyFile(backupSettingsPath, this.config.settingsPath);
111
+
112
+ if (success) {
113
+ this.restoredCount++;
114
+ console.log('✅ Restored settings.json');
115
+ return { restored: true };
116
+ } else {
117
+ return { restored: false, reason: 'Failed to copy settings file' };
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Restore commands directory
123
+ */
124
+ async restoreCommands(backupPath) {
125
+ const backupCommandsDir = path.join(backupPath, 'commands');
126
+
127
+ if (!fs.existsSync(backupCommandsDir)) {
128
+ return { restored: false, reason: 'No commands in backup', count: 0 };
129
+ }
130
+
131
+ // Ensure commands directory exists
132
+ FileSystemUtils.ensureDirectory(this.config.commandsDir);
133
+
134
+ // Clear existing commands (backup should be created by caller)
135
+ try {
136
+ const existingCommands = fs.readdirSync(this.config.commandsDir);
137
+ existingCommands.forEach(file => {
138
+ if (file.endsWith('.md')) {
139
+ const filePath = path.join(this.config.commandsDir, file);
140
+ FileSystemUtils.remove(filePath);
141
+ }
142
+ });
143
+ } catch (error) {
144
+ console.warn(`⚠️ Warning: Could not clear existing commands - ${error.message}`);
145
+ }
146
+
147
+ // Restore commands
148
+ let restoredCount = 0;
149
+
150
+ try {
151
+ const commandFiles = fs.readdirSync(backupCommandsDir);
152
+
153
+ for (const file of commandFiles) {
154
+ if (file.endsWith('.md')) {
155
+ const sourcePath = path.join(backupCommandsDir, file);
156
+ const destPath = path.join(this.config.commandsDir, file);
157
+
158
+ if (FileSystemUtils.copyFile(sourcePath, destPath)) {
159
+ restoredCount++;
160
+ this.restoredCount++;
161
+ }
162
+ }
163
+ }
164
+
165
+ if (restoredCount > 0) {
166
+ console.log(`✅ Restored ${restoredCount} commands`);
167
+ }
168
+
169
+ return { restored: true, count: restoredCount };
170
+ } catch (error) {
171
+ return { restored: false, reason: error.message, count: 0 };
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Restore hooks directory
177
+ */
178
+ async restoreHooks(backupPath) {
179
+ const backupHooksDir = path.join(backupPath, 'hooks');
180
+
181
+ if (!fs.existsSync(backupHooksDir)) {
182
+ return { restored: false, reason: 'No hooks in backup', count: 0 };
183
+ }
184
+
185
+ // Ensure hooks directory exists
186
+ FileSystemUtils.ensureDirectory(this.config.hooksDir);
187
+
188
+ let restoredCount = 0;
189
+
190
+ try {
191
+ const hookFiles = fs.readdirSync(backupHooksDir);
192
+
193
+ for (const file of hookFiles) {
194
+ const sourcePath = path.join(backupHooksDir, file);
195
+ const destPath = path.join(this.config.hooksDir, file);
196
+
197
+ // Set appropriate permissions for hooks
198
+ let mode = 0o644;
199
+ if (file.endsWith('.sh')) {
200
+ mode = 0o755; // Executable for shell scripts
201
+ }
202
+
203
+ if (FileSystemUtils.copyFile(sourcePath, destPath)) {
204
+ fs.chmodSync(destPath, mode);
205
+ restoredCount++;
206
+ this.restoredCount++;
207
+ }
208
+ }
209
+
210
+ if (restoredCount > 0) {
211
+ console.log(`✅ Restored ${restoredCount} hooks`);
212
+ }
213
+
214
+ return { restored: true, count: restoredCount };
215
+ } catch (error) {
216
+ return { restored: false, reason: error.message, count: 0 };
217
+ }
218
+ }
219
+ }
220
+
221
+ module.exports = RestoreService;
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Setup Command Implementation
5
+ * Replaces setup.sh functionality with npm package equivalent
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+ const { execSync } = require('child_process');
12
+
13
+ class SetupCommand {
14
+ constructor() {
15
+ this.homeDir = process.env.TEST_HOME || os.homedir();
16
+ this.claudeDir = path.join(this.homeDir, '.claude');
17
+ this.commandsDir = path.join(this.claudeDir, 'commands');
18
+ this.settingsFile = path.join(this.claudeDir, 'settings.json');
19
+ }
20
+
21
+ /**
22
+ * Execute setup with options
23
+ */
24
+ async execute(options = {}) {
25
+ console.log('🚀 Claude Dev Toolkit Setup\n');
26
+
27
+ const {
28
+ type = 'basic',
29
+ commands = 'active',
30
+ skipConfigure = false,
31
+ skipHooks = false,
32
+ force = false,
33
+ dryRun = false
34
+ } = options;
35
+
36
+ if (dryRun) {
37
+ return this.showDryRun(options);
38
+ }
39
+
40
+ try {
41
+ // 1. Verify Claude Code availability (optional check)
42
+ this.checkClaudeCode();
43
+
44
+ // 2. Create directory structure
45
+ await this.createDirectoryStructure(force);
46
+
47
+ // 3. Install commands
48
+ if (commands !== 'none') {
49
+ await this.installCommands(commands);
50
+ }
51
+
52
+ // 4. Apply configuration template
53
+ if (!skipConfigure) {
54
+ await this.applyConfigurationTemplate(type);
55
+ }
56
+
57
+ // 5. Install hooks (if requested)
58
+ if (!skipHooks) {
59
+ await this.installHooks();
60
+ }
61
+
62
+ // 6. Verify installation
63
+ await this.verifySetup();
64
+
65
+ console.log('\n✅ Setup completed successfully!');
66
+ console.log('\n💡 Next steps:');
67
+ console.log(' • Run: claude-commands verify');
68
+ console.log(' • Try: /xhelp in Claude Code to see all commands');
69
+
70
+ return { success: true, message: 'Setup completed successfully' };
71
+
72
+ } catch (error) {
73
+ console.error(`\n❌ Setup failed: ${error.message}`);
74
+ return { success: false, error: error.message };
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Show dry run preview
80
+ */
81
+ showDryRun(options) {
82
+ console.log('🔍 Dry Run - Preview of setup actions:\n');
83
+
84
+ console.log('📁 Directory Structure:');
85
+ console.log(` • Create: ${this.claudeDir}`);
86
+ console.log(` • Create: ${this.commandsDir}`);
87
+
88
+ if (!options.skipConfigure) {
89
+ console.log('\n⚙️ Configuration:');
90
+ console.log(` • Apply template: ${options.type || 'basic'}`);
91
+ console.log(` • Create: ${this.settingsFile}`);
92
+ }
93
+
94
+ console.log('\n📦 Commands Installation:');
95
+ const commandSet = options.commands || 'active';
96
+ console.log(` • Install: ${commandSet} command set`);
97
+
98
+ if (!options.skipHooks) {
99
+ console.log('\n🎣 Hooks:');
100
+ console.log(' • Install security hooks');
101
+ console.log(' • Configure file logging');
102
+ }
103
+
104
+ console.log('\n🔍 Verification:');
105
+ console.log(' • Check installation completeness');
106
+ console.log(' • Validate configuration');
107
+
108
+ console.log('\n💡 This was a dry run - no changes were made');
109
+ console.log(' Run without --dry-run to execute setup');
110
+
111
+ return { success: true, dryRun: true };
112
+ }
113
+
114
+ /**
115
+ * Check Claude Code availability
116
+ */
117
+ checkClaudeCode() {
118
+ console.log('🔍 Checking Claude Code availability...');
119
+
120
+ try {
121
+ execSync('claude --version', { stdio: 'pipe' });
122
+ console.log(' ✅ Claude Code detected');
123
+ } catch (error) {
124
+ console.log(' ⚠️ Claude Code not detected (optional)');
125
+ console.log(' 💡 Install with: npm install -g @anthropic-ai/claude-code');
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Create directory structure
131
+ */
132
+ async createDirectoryStructure(force) {
133
+ console.log('📁 Creating directory structure...');
134
+
135
+ // Check if directories already exist
136
+ if (fs.existsSync(this.claudeDir) && !force) {
137
+ console.log(' ✅ ~/.claude directory already exists');
138
+ } else {
139
+ fs.mkdirSync(this.claudeDir, { recursive: true });
140
+ console.log(` ✅ Created: ${this.claudeDir}`);
141
+ }
142
+
143
+ if (!fs.existsSync(this.commandsDir)) {
144
+ fs.mkdirSync(this.commandsDir, { recursive: true });
145
+ console.log(` ✅ Created: ${this.commandsDir}`);
146
+ } else {
147
+ console.log(' ✅ Commands directory already exists');
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Install commands
153
+ */
154
+ async installCommands(commandSet) {
155
+ console.log(`📦 Installing ${commandSet} commands...`);
156
+
157
+ try {
158
+ const installer = require('./installer');
159
+ const options = {};
160
+
161
+ switch (commandSet) {
162
+ case 'active':
163
+ options.active = true;
164
+ break;
165
+ case 'experiments':
166
+ options.experiments = true;
167
+ break;
168
+ case 'all':
169
+ options.all = true;
170
+ break;
171
+ default:
172
+ options.active = true;
173
+ }
174
+
175
+ await installer.install(options);
176
+ console.log(' ✅ Commands installed successfully');
177
+ } catch (error) {
178
+ throw new Error(`Command installation failed: ${error.message}`);
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Apply configuration template
184
+ */
185
+ async applyConfigurationTemplate(templateName) {
186
+ console.log(`⚙️ Applying ${templateName} configuration template...`);
187
+
188
+ try {
189
+ const config = require('./config');
190
+ await config.applyTemplate(templateName);
191
+ console.log(' ✅ Configuration template applied');
192
+ } catch (error) {
193
+ console.log(` ⚠️ Configuration template application failed: ${error.message}`);
194
+ // Don't fail setup for configuration issues
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Install hooks and their lib/ dependencies to ~/.claude/hooks/
200
+ */
201
+ async installHooks() {
202
+ console.log('🎣 Installing hooks...');
203
+
204
+ try {
205
+ const hooksInstaller = require('./hook-installer');
206
+ const targetHooksDir = path.join(this.claudeDir, 'hooks');
207
+ const availableHooks = hooksInstaller.getAvailableHooks();
208
+ const hookNames = availableHooks.map(h => h.name);
209
+
210
+ const result = hooksInstaller.installSecurityHooks(
211
+ targetHooksDir,
212
+ hookNames,
213
+ { force: true, backup: true }
214
+ );
215
+
216
+ if (result.success) {
217
+ console.log(` ✅ ${result.installed.length} hooks installed`);
218
+ } else {
219
+ console.log(` ⚠️ Hook installation had issues: ${result.errors.join(', ')}`);
220
+ }
221
+
222
+ // Copy lib/ directory (shared modules required by most hooks)
223
+ this._installHookLibs(targetHooksDir);
224
+
225
+ } catch (error) {
226
+ console.log(` ⚠️ Hooks installation skipped: ${error.message}`);
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Copy hooks/lib/ modules to target directory
232
+ */
233
+ _installHookLibs(targetHooksDir) {
234
+ const sourceLibDir = path.join(__dirname, '..', 'hooks', 'lib');
235
+ const targetLibDir = path.join(targetHooksDir, 'lib');
236
+
237
+ if (!fs.existsSync(sourceLibDir)) {
238
+ return;
239
+ }
240
+
241
+ fs.mkdirSync(targetLibDir, { recursive: true });
242
+
243
+ const libFiles = fs.readdirSync(sourceLibDir).filter(f => f.endsWith('.sh'));
244
+ for (const file of libFiles) {
245
+ const content = fs.readFileSync(path.join(sourceLibDir, file), 'utf8');
246
+ fs.writeFileSync(path.join(targetLibDir, file), content, { mode: 0o755 });
247
+ }
248
+
249
+ console.log(` ✅ ${libFiles.length} lib modules installed`);
250
+ }
251
+
252
+ /**
253
+ * Verify setup completion
254
+ */
255
+ async verifySetup() {
256
+ console.log('🔍 Verifying setup...');
257
+
258
+ const issues = [];
259
+
260
+ // Check directory structure
261
+ if (!fs.existsSync(this.claudeDir)) {
262
+ issues.push('Claude directory not found');
263
+ }
264
+
265
+ if (!fs.existsSync(this.commandsDir)) {
266
+ issues.push('Commands directory not found');
267
+ }
268
+
269
+ // Check command installation
270
+ try {
271
+ const commands = fs.readdirSync(this.commandsDir).filter(f => f.endsWith('.md'));
272
+ if (commands.length === 0) {
273
+ issues.push('No commands installed');
274
+ } else {
275
+ console.log(` ✅ ${commands.length} commands installed`);
276
+ }
277
+ } catch (error) {
278
+ issues.push('Cannot read commands directory');
279
+ }
280
+
281
+ // Check hooks installation
282
+ const hooksDir = path.join(this.claudeDir, 'hooks');
283
+ if (fs.existsSync(hooksDir)) {
284
+ const hooks = fs.readdirSync(hooksDir).filter(f => f.endsWith('.sh'));
285
+ if (hooks.length > 0) {
286
+ console.log(` ✅ ${hooks.length} hooks installed`);
287
+ } else {
288
+ issues.push('Hooks directory exists but no hooks found');
289
+ }
290
+ } else {
291
+ issues.push('Hooks directory not found');
292
+ }
293
+
294
+ // Check configuration
295
+ if (fs.existsSync(this.settingsFile)) {
296
+ console.log(' ✅ Configuration file present');
297
+ } else {
298
+ console.log(' ⚠️ No configuration file (will use defaults)');
299
+ }
300
+
301
+ if (issues.length > 0) {
302
+ console.log(' ⚠️ Issues detected:');
303
+ issues.forEach(issue => console.log(` • ${issue}`));
304
+ throw new Error(`Setup verification failed: ${issues.join(', ')}`);
305
+ }
306
+
307
+ console.log(' ✅ Setup verification passed');
308
+ }
309
+
310
+ /**
311
+ * Get available templates
312
+ */
313
+ getAvailableTemplates() {
314
+ const templatesDir = path.join(__dirname, '..', 'templates');
315
+ try {
316
+ return fs.readdirSync(templatesDir)
317
+ .filter(f => f.endsWith('.json'))
318
+ .map(f => f.replace('.json', ''));
319
+ } catch (error) {
320
+ return ['basic', 'comprehensive', 'security-focused'];
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Get help text for setup command
326
+ */
327
+ getHelpText() {
328
+ return `
329
+ Setup the Claude Dev Toolkit with custom commands and configuration.
330
+
331
+ This command replaces the functionality of setup.sh script, providing
332
+ a complete installation and configuration of the Claude Code toolkit.
333
+
334
+ Usage:
335
+ claude-commands setup [options]
336
+
337
+ Options:
338
+ --type <template> Configuration template to apply
339
+ (basic, comprehensive, security-focused)
340
+ --commands <set> Command set to install
341
+ (active, experiments, all, none)
342
+ --skip-configure Skip configuration step
343
+ --skip-hooks Skip hooks installation
344
+ --force Overwrite existing installation
345
+ --dry-run Preview actions without executing
346
+
347
+ Examples:
348
+ claude-commands setup
349
+ claude-commands setup --type comprehensive --commands all
350
+ claude-commands setup --dry-run
351
+ claude-commands setup --type security-focused --skip-hooks
352
+
353
+ This command performs the equivalent of running setup.sh with intelligent
354
+ defaults and enhanced error handling.
355
+ `.trim();
356
+ }
357
+ }
358
+
359
+ module.exports = SetupCommand;