@paulduvall/claude-dev-toolkit 0.0.1-alpha.6 → 0.0.1-alpha.8

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 (34) hide show
  1. package/README.md +12 -12
  2. package/bin/claude-commands +185 -64
  3. package/hooks/lib/argument-parser.sh +0 -0
  4. package/hooks/lib/config-constants.sh +0 -0
  5. package/hooks/lib/context-manager.sh +0 -0
  6. package/hooks/lib/error-handler.sh +0 -0
  7. package/hooks/lib/execution-engine.sh +0 -0
  8. package/hooks/lib/file-utils.sh +0 -0
  9. package/hooks/lib/subagent-discovery.sh +0 -0
  10. package/hooks/lib/subagent-validator.sh +0 -0
  11. package/lib/backup-restore-command.js +140 -0
  12. package/lib/base/base-command.js +252 -0
  13. package/lib/base/command-result.js +184 -0
  14. package/lib/config/constants.js +255 -0
  15. package/lib/config.js +48 -6
  16. package/lib/configure-command.js +428 -0
  17. package/lib/dependency-validator.js +64 -5
  18. package/lib/installation-instruction-generator-backup.js +579 -0
  19. package/lib/installation-instruction-generator.js +213 -495
  20. package/lib/installer.js +134 -56
  21. package/lib/services/backup-list-service.js +226 -0
  22. package/lib/services/backup-service.js +230 -0
  23. package/lib/services/command-installer-service.js +217 -0
  24. package/lib/services/logger-service.js +201 -0
  25. package/lib/services/package-manager-service.js +319 -0
  26. package/lib/services/platform-instruction-service.js +294 -0
  27. package/lib/services/recovery-instruction-service.js +348 -0
  28. package/lib/services/restore-service.js +221 -0
  29. package/lib/setup-command.js +309 -0
  30. package/lib/utils/claude-path-config.js +184 -0
  31. package/lib/utils/file-system-utils.js +152 -0
  32. package/lib/utils.js +8 -4
  33. package/lib/verify-command.js +430 -0
  34. package/package.json +1 -1
package/README.md CHANGED
@@ -41,7 +41,7 @@ npm install -g @paulduvall/claude-dev-toolkit
41
41
  ```bash
42
42
  # Install specific command sets
43
43
  claude-commands install --active # Install 13 production commands
44
- claude-commands install --experimental # Install 45 experimental commands
44
+ claude-commands install --experiments # Install 45 experimental commands
45
45
  claude-commands install --all # Install all 58 commands
46
46
  ```
47
47
 
@@ -89,7 +89,7 @@ Advanced commands for specialized workflows:
89
89
  claude-commands list # List all available commands
90
90
  claude-commands status # Show installation status
91
91
  claude-commands install --active # Install production commands
92
- claude-commands install --experimental # Install experimental commands
92
+ claude-commands install --experiments # Install experimental commands
93
93
  claude-commands install --all # Install all commands
94
94
 
95
95
  # Configuration Management
@@ -174,8 +174,8 @@ npm run lint # Code linting
174
174
  - **Configuration Tests**: Template and setup validation
175
175
 
176
176
  ### Architecture
177
- - **Symlink Consolidation**: Single source of truth with root directory
178
- - **JavaScript-Based**: Migrated from Python for better Node.js integration
177
+ - **Self-Contained Package**: No dependencies on repository cloning
178
+ - **JavaScript-Based**: Native Node.js integration with comprehensive testing
179
179
  - **Modular Design**: Separate installer, config, and validation modules
180
180
  - **Cross-Platform**: Works on macOS, Linux, and Windows
181
181
 
@@ -203,7 +203,7 @@ claude-commands install --active # Reinstall commands
203
203
  chmod 755 ~/.claude/commands/*.md # Fix permissions
204
204
 
205
205
  # Missing experimental commands?
206
- claude-commands install --experimental # Install experimental set
206
+ claude-commands install --experiments # Install experimental set
207
207
 
208
208
  # Test failures?
209
209
  npm test # Run full test suite
@@ -212,13 +212,13 @@ npm run validate # Validate package
212
212
 
213
213
  ### Validation Commands
214
214
  ```bash
215
- # Repository validation (from main repo)
216
- ./validate-commands.sh # JavaScript-based validation
217
- ./verify-setup.sh # Complete setup verification
218
-
219
215
  # Package validation
220
216
  npm run validate # Package structure validation
221
217
  npm test # Comprehensive test suite
218
+
219
+ # CLI validation
220
+ claude-commands verify # Complete setup verification
221
+ claude-commands list # Check installed commands
222
222
  ```
223
223
 
224
224
  ## 📚 Documentation
@@ -252,8 +252,8 @@ npm test
252
252
  ```
253
253
 
254
254
  ### Adding Commands
255
- 1. Create command files in root `slash-commands/active/` or `slash-commands/experiments/`
256
- 2. Commands automatically sync to NPM package via symlinks
255
+ 1. Create command files in repository `slash-commands/active/` or `slash-commands/experiments/`
256
+ 2. Commands are included in NPM package through build process
257
257
  3. Validate with `npm run test:commands`
258
258
  4. Follow existing patterns and security guidelines
259
259
 
@@ -264,7 +264,7 @@ npm test
264
264
 
265
265
  ## 🔄 Recent Updates
266
266
 
267
- ### Version 0.0.1-alpha.2
267
+ ### Version 0.0.1-alpha.7
268
268
  - ✅ **NPM Scoped Package**: Published as `@paulduvall/claude-dev-toolkit`
269
269
  - ✅ **Configuration Command**: Built-in `config` command for template management
270
270
  - ✅ **Workflow Reporting**: Comprehensive GitHub Actions reporting
@@ -20,64 +20,53 @@ program
20
20
  .command('list')
21
21
  .description('List all available commands')
22
22
  .option('-a, --active', 'Show only active commands')
23
- .option('-e, --experimental', 'Show only experimental commands')
23
+ .option('-e, --experiments', 'Show only experimental commands')
24
24
  .action((options) => {
25
25
  const claudeDir = path.join(os.homedir(), '.claude', 'commands');
26
- const activeDir = path.join(claudeDir, 'active');
27
- const experimentalDir = path.join(claudeDir, 'experiments');
28
26
 
29
27
  console.log('📦 Claude Custom Commands\n');
30
28
 
31
- if (!options.experimental) {
32
- console.log('🎯 Active Commands:');
33
- if (fs.existsSync(activeDir)) {
34
- const activeCommands = fs.readdirSync(activeDir)
35
- .filter(f => f.endsWith('.md'))
36
- .map(f => f.replace('.md', ''))
37
- .sort();
38
-
39
- if (activeCommands.length > 0) {
40
- activeCommands.forEach(cmd => console.log(` /${cmd}`));
41
- } else {
42
- console.log(' No active commands found');
43
- }
44
- } else {
45
- console.log(' Commands directory not found');
46
- }
47
- console.log('');
48
- }
49
-
50
- if (!options.active) {
51
- console.log('🧪 Experimental Commands:');
52
- if (fs.existsSync(experimentalDir)) {
53
- const expCommands = fs.readdirSync(experimentalDir)
54
- .filter(f => f.endsWith('.md'))
55
- .map(f => f.replace('.md', ''))
56
- .sort();
57
-
58
- if (expCommands.length > 0) {
59
- expCommands.forEach(cmd => console.log(` /${cmd}`));
60
- } else {
61
- console.log(' No experimental commands found');
62
- }
29
+ if (fs.existsSync(claudeDir)) {
30
+ const allCommands = fs.readdirSync(claudeDir)
31
+ .filter(f => f.endsWith('.md'))
32
+ .map(f => f.replace('.md', ''))
33
+ .sort();
34
+
35
+ if (allCommands.length > 0) {
36
+ console.log('🚀 Available Commands:');
37
+ allCommands.forEach(cmd => console.log(` /${cmd}`));
38
+ console.log(`\n📊 Total: ${allCommands.length} commands`);
63
39
  } else {
64
- console.log(' Commands directory not found');
40
+ console.log(' No commands found');
65
41
  }
66
- console.log('');
42
+ } else {
43
+ console.log(' Commands directory not found');
67
44
  }
68
45
 
69
- console.log('💡 Usage: Try /xhelp in Claude Code to see all commands');
46
+ console.log('\n💡 Usage: Try /xhelp in Claude Code to see all commands');
70
47
  });
71
48
 
72
49
  program
73
50
  .command('install')
74
- .description('Install command sets')
75
- .option('--active', 'Install active commands only')
76
- .option('--experimental', 'Install experimental commands')
77
- .option('--all', 'Install all commands')
78
- .action((options) => {
51
+ .description('Install command sets to ~/.claude/commands/')
52
+ .option('--active', 'Install production-ready commands (default)')
53
+ .option('--experiments', 'Install experimental commands only')
54
+ .option('--all', 'Install both active and experimental')
55
+ .option('--include <pattern>', 'Include specific commands matching pattern')
56
+ .option('--exclude <pattern>', 'Exclude commands matching pattern')
57
+ .option('--dry-run', 'Show what would be installed without making changes')
58
+ .option('--backup', 'Create backup before installation')
59
+ .action(async (options) => {
79
60
  const installer = require('../lib/installer');
80
- installer.install(options);
61
+ try {
62
+ const result = await installer.install(options);
63
+ if (!result.success && !result.dryRun) {
64
+ process.exit(1);
65
+ }
66
+ } catch (error) {
67
+ console.error(`Installation failed: ${error.message}`);
68
+ process.exit(1);
69
+ }
81
70
  });
82
71
 
83
72
  program
@@ -85,33 +74,22 @@ program
85
74
  .description('Show installation status')
86
75
  .action(() => {
87
76
  const claudeDir = path.join(os.homedir(), '.claude', 'commands');
88
- const activeDir = path.join(claudeDir, 'active');
89
- const experimentalDir = path.join(claudeDir, 'experiments');
90
77
 
91
78
  console.log('📊 Claude Dev Toolkit Status\n');
92
79
 
93
80
  // Check Claude directory
94
- console.log('📁 Installation Paths:');
95
- console.log(` Claude directory: ${fs.existsSync(claudeDir) ? '✅' : '❌'} ${claudeDir}`);
96
- console.log(` Active commands: ${fs.existsSync(activeDir) ? '✅' : '❌'} ${activeDir}`);
97
- console.log(` Experimental: ${fs.existsSync(experimentalDir) ? '✅' : '❌'} ${experimentalDir}\n`);
81
+ console.log('📁 Installation Path:');
82
+ console.log(` Commands directory: ${fs.existsSync(claudeDir) ? '✅' : '❌'} ${claudeDir}\n`);
98
83
 
99
84
  // Count commands
100
- let activeCount = 0;
101
- let expCount = 0;
102
-
103
- if (fs.existsSync(activeDir)) {
104
- activeCount = fs.readdirSync(activeDir).filter(f => f.endsWith('.md')).length;
105
- }
85
+ let totalCount = 0;
106
86
 
107
- if (fs.existsSync(experimentalDir)) {
108
- expCount = fs.readdirSync(experimentalDir).filter(f => f.endsWith('.md')).length;
87
+ if (fs.existsSync(claudeDir)) {
88
+ totalCount = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md')).length;
109
89
  }
110
90
 
111
91
  console.log('📦 Command Inventory:');
112
- console.log(` Active commands: ${activeCount}`);
113
- console.log(` Experimental commands: ${expCount}`);
114
- console.log(` Total commands: ${activeCount + expCount}\n`);
92
+ console.log(` Total commands: ${totalCount}\n`);
115
93
 
116
94
  // Package info
117
95
  console.log('📋 Package Information:');
@@ -119,13 +97,13 @@ program
119
97
  console.log(` CLI Location: ${process.argv[1]}\n`);
120
98
 
121
99
  // Quick health check
122
- const isHealthy = fs.existsSync(claudeDir) && (activeCount > 0 || expCount > 0);
100
+ const isHealthy = fs.existsSync(claudeDir) && totalCount > 0;
123
101
  console.log(`🔍 Overall Status: ${isHealthy ? '✅ Healthy' : '⚠️ Issues detected'}`);
124
102
 
125
103
  if (!isHealthy) {
126
104
  console.log('\n💡 Troubleshooting:');
127
- console.log(' • Try: npm install -g claude-dev-toolkit');
128
- console.log(' • Or reinstall to refresh commands');
105
+ console.log(' • Try: npm install -g @paulduvall/claude-dev-toolkit');
106
+ console.log(' • Or reinstall: claude-commands install --all');
129
107
  }
130
108
  });
131
109
 
@@ -149,4 +127,147 @@ program
149
127
  config.handleCommand(options);
150
128
  });
151
129
 
130
+ program
131
+ .command('configure')
132
+ .description('Configure Claude Code settings (replaces configure-claude-code.sh)')
133
+ .option('--template <name>', 'Apply named template')
134
+ .option('--interactive', 'Launch interactive configuration wizard')
135
+ .option('--validate', 'Validate current configuration')
136
+ .option('--reset', 'Reset to default configuration')
137
+ .option('--backup', 'Create backup before changes (default: true)')
138
+ .option('--no-backup', 'Skip backup creation')
139
+ .action(async (options) => {
140
+ const ConfigureCommand = require('../lib/configure-command');
141
+ const configureCmd = new ConfigureCommand();
142
+ try {
143
+ const result = await configureCmd.execute(options);
144
+ if (!result.success) {
145
+ process.exit(1);
146
+ }
147
+ } catch (error) {
148
+ console.error(`Configuration failed: ${error.message}`);
149
+ process.exit(1);
150
+ }
151
+ });
152
+
153
+ program
154
+ .command('setup')
155
+ .description('Setup the Claude Dev Toolkit with custom commands and configuration')
156
+ .option('--type <template>', 'Configuration template to apply (basic, comprehensive, security-focused)')
157
+ .option('--commands <set>', 'Command set to install (active, experiments, all, none)')
158
+ .option('--skip-configure', 'Skip configuration step')
159
+ .option('--skip-hooks', 'Skip hooks installation')
160
+ .option('--force', 'Overwrite existing installation')
161
+ .option('--dry-run', 'Preview actions without executing')
162
+ .action(async (options) => {
163
+ const SetupCommand = require('../lib/setup-command');
164
+ const setupCmd = new SetupCommand();
165
+ try {
166
+ const result = await setupCmd.execute(options);
167
+ if (!result.success && !result.dryRun) {
168
+ process.exit(1);
169
+ }
170
+ } catch (error) {
171
+ console.error(`Setup failed: ${error.message}`);
172
+ process.exit(1);
173
+ }
174
+ });
175
+
176
+ program
177
+ .command('verify')
178
+ .description('Verify the Claude Dev Toolkit installation status and health')
179
+ .option('--verbose', 'Show detailed verification information')
180
+ .option('--fix', 'Attempt to fix detected issues automatically')
181
+ .action(async (options) => {
182
+ const VerifyCommand = require('../lib/verify-command');
183
+ const verifyCmd = new VerifyCommand();
184
+ try {
185
+ const result = await verifyCmd.execute(options);
186
+ // Set exit code based on health status
187
+ if (result.overall === 'critical') {
188
+ process.exit(2);
189
+ } else if (result.overall === 'warning') {
190
+ process.exit(1);
191
+ }
192
+ // Exit 0 for healthy
193
+ } catch (error) {
194
+ console.error(`Verification failed: ${error.message}`);
195
+ process.exit(2);
196
+ }
197
+ });
198
+
199
+ program
200
+ .command('backup [name]')
201
+ .description('Create named backup of Claude Code configuration')
202
+ .action(async (name) => {
203
+ const BackupRestoreCommand = require('../lib/backup-restore-command');
204
+ const backupCmd = new BackupRestoreCommand();
205
+ try {
206
+ const result = await backupCmd.backup(name);
207
+ if (!result.success) {
208
+ process.exit(1);
209
+ }
210
+ } catch (error) {
211
+ console.error(`Backup failed: ${error.message}`);
212
+ process.exit(1);
213
+ }
214
+ });
215
+
216
+ program
217
+ .command('restore <name>')
218
+ .description('Restore from a named backup')
219
+ .action(async (name) => {
220
+ const BackupRestoreCommand = require('../lib/backup-restore-command');
221
+ const restoreCmd = new BackupRestoreCommand();
222
+ try {
223
+ const result = await restoreCmd.restore(name);
224
+ if (!result.success) {
225
+ process.exit(1);
226
+ }
227
+ } catch (error) {
228
+ console.error(`Restore failed: ${error.message}`);
229
+ process.exit(1);
230
+ }
231
+ });
232
+
233
+ program
234
+ .command('update')
235
+ .description('Check for package updates')
236
+ .action(async () => {
237
+ const { version } = require('../package.json');
238
+ console.log('🔍 Checking for updates...\n');
239
+ console.log(`Current version: ${version}`);
240
+
241
+ try {
242
+ const { execSync } = require('child_process');
243
+ const output = execSync('npm view @paulduvall/claude-dev-toolkit version', {
244
+ encoding: 'utf8',
245
+ stdio: 'pipe'
246
+ }).trim();
247
+
248
+ console.log(`Latest version: ${output}`);
249
+
250
+ if (output !== version) {
251
+ console.log('\n🆕 Update available!');
252
+ console.log('\nTo update, run:');
253
+ console.log(' npm update -g @paulduvall/claude-dev-toolkit');
254
+
255
+ // Check for breaking changes in major version
256
+ const currentMajor = parseInt(version.split('.')[0]);
257
+ const latestMajor = parseInt(output.split('.')[0]);
258
+
259
+ if (latestMajor > currentMajor) {
260
+ console.log('\n⚠️ Major version update - may contain breaking changes');
261
+ console.log(' Review release notes before updating');
262
+ }
263
+ } else {
264
+ console.log('\n✅ You are using the latest version');
265
+ }
266
+ } catch (error) {
267
+ console.error('❌ Could not check for updates');
268
+ console.log(' Please check your internet connection');
269
+ process.exit(1);
270
+ }
271
+ });
272
+
152
273
  program.parse(process.argv);
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Backup and Restore Commands Implementation - Refactored
3
+ * Orchestrator for backup and restore operations using focused services
4
+ */
5
+
6
+ const BackupService = require('./services/backup-service');
7
+ const RestoreService = require('./services/restore-service');
8
+ const BackupListService = require('./services/backup-list-service');
9
+ const BaseCommand = require('./base/base-command');
10
+ const FileSystemUtils = require('./utils/file-system-utils');
11
+ const { execSync } = require('child_process');
12
+
13
+ class BackupRestoreCommand extends BaseCommand {
14
+ constructor(config = null) {
15
+ super(config);
16
+ this.backupService = new BackupService(this.config);
17
+ this.restoreService = new RestoreService(this.config);
18
+ this.listService = new BackupListService(this.config);
19
+ }
20
+
21
+ /**
22
+ * Create a backup of the entire .claude directory
23
+ */
24
+ async backup(name = null) {
25
+ this.logger.step('Creating backup of Claude Code configuration', { backupName: name });
26
+
27
+ try {
28
+ const result = await this.backupService.create(name);
29
+
30
+ // Try to compress the backup
31
+ const compressed = await this.compressBackup(result.path);
32
+
33
+ this.logger.complete(`Backup '${result.name}' created successfully`, {
34
+ files: result.totalFiles,
35
+ size: FileSystemUtils.formatSize(result.totalSize),
36
+ compressed: !!compressed
37
+ });
38
+
39
+ if (compressed) {
40
+ this.logger.info(`Backup compressed and stored at: ${compressed.path}`, {
41
+ compressionRatio: compressed.size / result.totalSize
42
+ });
43
+ } else {
44
+ this.logger.info(`Backup stored at: ${result.path}`);
45
+ }
46
+
47
+ return {
48
+ success: true,
49
+ name: result.name,
50
+ path: compressed ? compressed.path : result.path,
51
+ metadata: result.metadata
52
+ };
53
+
54
+ } catch (error) {
55
+ return this.handleError(error);
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Try to compress a backup using tar
61
+ */
62
+ async compressBackup(backupPath) {
63
+ try {
64
+ const backupName = require('path').basename(backupPath);
65
+ const tarPath = `${backupPath}.tar.gz`;
66
+
67
+ execSync(`tar -czf "${tarPath}" -C "${this.config.backupsDir}" "${backupName}"`, {
68
+ encoding: 'utf8',
69
+ stdio: 'pipe'
70
+ });
71
+
72
+ // Remove uncompressed backup
73
+ FileSystemUtils.remove(backupPath);
74
+
75
+ const compressedSize = FileSystemUtils.getStats(tarPath).size;
76
+ return {
77
+ path: tarPath,
78
+ size: compressedSize
79
+ };
80
+ } catch (error) {
81
+ // Compression failed, keep uncompressed backup
82
+ return null;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Restore from a backup
88
+ */
89
+ async restore(backupName) {
90
+ this.logger.step(`Restoring from backup: ${backupName}`, { backupName });
91
+
92
+ try {
93
+ // Create undo backup first
94
+ this.logger.info('Creating undo backup for safety');
95
+ const undoBackup = await this.backup('undo-before-restore');
96
+
97
+ if (!undoBackup.success) {
98
+ this.logger.warn('Could not create undo backup, continuing anyway', {
99
+ risk: 'restore cannot be undone'
100
+ });
101
+ }
102
+
103
+ // Perform restore using service
104
+ const result = await this.restoreService.restore(backupName);
105
+
106
+ this.logger.complete(`Restore completed successfully`, {
107
+ restoredCount: result.restoredCount,
108
+ hasUndo: undoBackup.success
109
+ });
110
+
111
+ if (undoBackup.success) {
112
+ this.logger.info(`To undo this restore, run: claude-commands restore ${undoBackup.name}`, {
113
+ undoCommand: `claude-commands restore ${undoBackup.name}`
114
+ });
115
+ }
116
+
117
+ return {
118
+ success: true,
119
+ restoredCount: result.restoredCount,
120
+ undoBackup: undoBackup.success ? undoBackup.name : null
121
+ };
122
+
123
+ } catch (error) {
124
+ return this.handleError(error);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * List available backups
130
+ */
131
+ async listBackups() {
132
+ try {
133
+ return await this.listService.display();
134
+ } catch (error) {
135
+ return this.handleError(error);
136
+ }
137
+ }
138
+ }
139
+
140
+ module.exports = BackupRestoreCommand;