@paulduvall/claude-dev-toolkit 0.0.1-alpha.1

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/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@paulduvall/claude-dev-toolkit",
3
+ "version": "0.0.1-alpha.1",
4
+ "description": "Custom commands toolkit for Claude Code - streamline your development workflow",
5
+ "author": "Paul Duvall",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "claude-code",
9
+ "claude",
10
+ "ai",
11
+ "development",
12
+ "automation",
13
+ "commands"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/PaulDuvall/claude-code.git"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/PaulDuvall/claude-code/issues"
21
+ },
22
+ "homepage": "https://github.com/PaulDuvall/claude-code#readme",
23
+ "bin": {
24
+ "claude-commands": "bin/claude-commands"
25
+ },
26
+ "scripts": {
27
+ "postinstall": "node scripts/postinstall.js",
28
+ "test": "node tests/test_all_suites.js",
29
+ "test:req007": "node tests/test_req_007_interactive_setup_wizard.js",
30
+ "test:req009": "node tests/test_req_009_configuration_template_application.js",
31
+ "test:req018": "node tests/test_req_018_security_hook_installation.js",
32
+ "test:req020": "node tests/test_req_020_installation_failure_recovery.js",
33
+ "test:commands": "node tests/test_command_validation.js",
34
+ "test:workflow": "node tests/test_core_workflow_commands.js",
35
+ "test:security": "node tests/test_security_commands.js",
36
+ "test:quality": "node tests/test_quality_commands.js",
37
+ "test:git": "node tests/test_git_commands.js",
38
+ "test:ux": "node tests/test_user_experience.js",
39
+ "test:validation": "node tests/test_validation_system.js",
40
+ "test:install": "scripts/publishing/test-package-install.sh",
41
+ "test:manual": "scripts/publishing/manual-test-suite.sh",
42
+ "publish:local": "scripts/publishing/setup-local-registry.sh",
43
+ "publish:private": "scripts/publishing/publish-private.sh",
44
+ "lint": "eslint lib/**/*.js bin/**/*.js",
45
+ "validate": "node scripts/validate.js"
46
+ },
47
+ "dependencies": {
48
+ "commander": "^9.0.0",
49
+ "inquirer": "^8.2.7",
50
+ "js-yaml": "^4.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "eslint": "^8.0.0",
54
+ "jest": "^29.0.0"
55
+ },
56
+ "engines": {
57
+ "node": ">=16.0.0"
58
+ },
59
+ "files": [
60
+ "bin/",
61
+ "lib/",
62
+ "commands/",
63
+ "templates/",
64
+ "hooks/",
65
+ "scripts/postinstall.js",
66
+ "scripts/validate.js",
67
+ "README.md",
68
+ "LICENSE"
69
+ ],
70
+ "publishConfig": {
71
+ "access": "public"
72
+ }
73
+ }
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const { execSync } = require('child_process');
7
+
8
+ // Check for skip flag
9
+ const skipSetup = process.env.CLAUDE_SKIP_SETUP === 'true' ||
10
+ process.argv.includes('--skip-setup');
11
+
12
+ console.log('🚀 Setting up Claude Custom Commands...');
13
+
14
+ async function runSetup() {
15
+ try {
16
+ // Get Claude Code directory
17
+ const homeDir = os.homedir();
18
+ const claudeDir = path.join(homeDir, '.claude');
19
+ const commandsDir = path.join(claudeDir, 'commands');
20
+ const hooksDir = path.join(claudeDir, 'hooks');
21
+
22
+ // Ensure Claude directories exist
23
+ if (!fs.existsSync(claudeDir)) {
24
+ fs.mkdirSync(claudeDir, { recursive: true });
25
+ console.log('✅ Created .claude directory');
26
+ }
27
+
28
+ if (!fs.existsSync(commandsDir)) {
29
+ fs.mkdirSync(commandsDir, { recursive: true });
30
+ console.log('✅ Created .claude/commands directory');
31
+ }
32
+
33
+ if (!fs.existsSync(hooksDir)) {
34
+ fs.mkdirSync(hooksDir, { recursive: true });
35
+ console.log('✅ Created .claude/hooks directory');
36
+ }
37
+
38
+ // Get package installation directory
39
+ const packageDir = __dirname.replace('/scripts', '');
40
+
41
+ // Check if we should run interactive setup
42
+ if (!skipSetup && process.stdin.isTTY) {
43
+ console.log('\n📋 Starting Interactive Setup Wizard...');
44
+ console.log('(Use --skip-setup or set CLAUDE_SKIP_SETUP=true to skip)\n');
45
+
46
+ const InteractiveSetupWizard = require('../lib/setup-wizard');
47
+ const wizard = new InteractiveSetupWizard(claudeDir);
48
+
49
+ // Validate environment first (REQ-006)
50
+ const envCheck = wizard.validateEnvironment();
51
+ if (!envCheck.valid) {
52
+ console.error('❌ Environment validation failed:', envCheck.message);
53
+ process.exit(1);
54
+ }
55
+
56
+ // Run interactive setup (REQ-007)
57
+ const setupResult = await wizard.runInteractiveSetup();
58
+
59
+ if (setupResult.completed) {
60
+ const config = setupResult.configuration;
61
+
62
+ // Install commands based on selection
63
+ const sourceCommandsDir = path.join(packageDir, 'commands');
64
+ if (fs.existsSync(sourceCommandsDir)) {
65
+ copySelectedCommands(sourceCommandsDir, commandsDir, config);
66
+ }
67
+
68
+ // Install security hooks if selected
69
+ if (config.securityHooks) {
70
+ const sourceHooksDir = path.join(packageDir, 'hooks');
71
+ if (fs.existsSync(sourceHooksDir)) {
72
+ copySelectedHooks(sourceHooksDir, hooksDir, config.selectedHooks || []);
73
+ }
74
+ }
75
+
76
+ // Apply configuration template
77
+ if (config.template) {
78
+ const templateFile = path.join(packageDir, 'templates', `${config.template}-settings.json`);
79
+ const targetFile = path.join(claudeDir, 'settings.json');
80
+ if (fs.existsSync(templateFile)) {
81
+ fs.copyFileSync(templateFile, targetFile);
82
+ console.log(`✅ Applied ${config.template} configuration template`);
83
+ }
84
+ }
85
+ }
86
+ } else {
87
+ // Non-interactive installation - install all commands by default
88
+ console.log('Running non-interactive installation...');
89
+
90
+ const sourceCommandsDir = path.join(packageDir, 'commands');
91
+ if (fs.existsSync(sourceCommandsDir)) {
92
+ copyAllCommands(sourceCommandsDir, commandsDir);
93
+ }
94
+ }
95
+
96
+ // Count installed commands (now in flat structure)
97
+ if (fs.existsSync(commandsDir)) {
98
+ const installedCommands = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md')).length;
99
+ console.log(`\n📦 Installed ${installedCommands} commands`);
100
+ }
101
+
102
+ console.log('\n🎉 Installation complete!');
103
+ console.log('\nNext steps:');
104
+ console.log('1. Run: claude-commands list');
105
+ console.log('2. Try: claude-commands --help');
106
+ console.log('3. Configure: claude-commands config');
107
+ console.log('4. Explore commands in Claude Code using /xhelp\n');
108
+
109
+ } catch (error) {
110
+ console.error('❌ Installation failed:', error.message);
111
+ process.exit(1);
112
+ }
113
+ }
114
+
115
+ function copyAllCommands(sourceDir, targetDir) {
116
+ const items = fs.readdirSync(sourceDir);
117
+ for (const item of items) {
118
+ const sourcePath = path.join(sourceDir, item);
119
+ const targetPath = path.join(targetDir, item);
120
+
121
+ if (fs.statSync(sourcePath).isDirectory()) {
122
+ if (!fs.existsSync(targetPath)) {
123
+ fs.mkdirSync(targetPath, { recursive: true });
124
+ }
125
+ copyAllCommands(sourcePath, targetPath);
126
+ } else if (item.endsWith('.md')) {
127
+ fs.copyFileSync(sourcePath, targetPath);
128
+ }
129
+ }
130
+ }
131
+
132
+ function copySelectedCommands(sourceDir, targetDir, config) {
133
+ // Based on installation type, copy appropriate commands
134
+ const installationType = config.installationType || 'standard';
135
+
136
+ if (installationType === 'full' || !config.commandSets) {
137
+ // Copy all commands
138
+ copyAllCommands(sourceDir, targetDir);
139
+ } else {
140
+ // Copy selected command sets
141
+ const commandSets = config.commandSets || [];
142
+
143
+ // Always copy active commands for standard installation (flat structure)
144
+ if (installationType === 'standard' || commandSets.includes('development')) {
145
+ const activeSource = path.join(sourceDir, 'active');
146
+ if (fs.existsSync(activeSource)) {
147
+ copyAllCommands(activeSource, targetDir); // Copy directly to targetDir, no subdirectory
148
+ }
149
+ }
150
+
151
+ // Copy experimental if selected (flat structure to avoid namespace)
152
+ if (commandSets.includes('experimental') || installationType === 'full') {
153
+ const expSource = path.join(sourceDir, 'experiments');
154
+ if (fs.existsSync(expSource)) {
155
+ copyAllCommands(expSource, targetDir); // Copy directly to targetDir, no subdirectory
156
+ }
157
+ }
158
+ }
159
+ }
160
+
161
+ function copySelectedHooks(sourceDir, targetDir, selectedHooks) {
162
+ const items = fs.readdirSync(sourceDir);
163
+ for (const item of items) {
164
+ const sourcePath = path.join(sourceDir, item);
165
+
166
+ // Copy hook if it's selected or if no specific selection (copy all)
167
+ if (selectedHooks.length === 0 || selectedHooks.some(h => item.includes(h))) {
168
+ const targetPath = path.join(targetDir, item);
169
+ fs.copyFileSync(sourcePath, targetPath);
170
+
171
+ // Make shell scripts executable
172
+ if (item.endsWith('.sh')) {
173
+ fs.chmodSync(targetPath, '755');
174
+ }
175
+
176
+ console.log(`✅ Installed hook: ${item}`);
177
+ }
178
+ }
179
+ }
180
+
181
+ // Run the setup
182
+ runSetup();
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ console.log('🔍 Validating Claude Custom Commands package...');
7
+
8
+ let errors = 0;
9
+ let warnings = 0;
10
+
11
+ const log = (level, message) => {
12
+ const prefix = level === 'error' ? '❌' : level === 'warn' ? '⚠️' : '✅';
13
+ console.log(`${prefix} ${message}`);
14
+ if (level === 'error') errors++;
15
+ if (level === 'warn') warnings++;
16
+ };
17
+
18
+ try {
19
+ const packageDir = __dirname.replace('/scripts', '');
20
+
21
+ // Check required directories
22
+ const requiredDirs = ['bin', 'lib', 'commands', 'commands/active', 'commands/experiments'];
23
+ requiredDirs.forEach(dir => {
24
+ const dirPath = path.join(packageDir, dir);
25
+ if (fs.existsSync(dirPath)) {
26
+ log('info', `Directory exists: ${dir}/`);
27
+ } else {
28
+ log('error', `Missing required directory: ${dir}/`);
29
+ }
30
+ });
31
+
32
+ // Check required files
33
+ const requiredFiles = [
34
+ 'package.json',
35
+ 'README.md',
36
+ 'bin/claude-commands',
37
+ 'lib/config.js',
38
+ 'lib/installer.js',
39
+ 'lib/utils.js'
40
+ ];
41
+
42
+ requiredFiles.forEach(file => {
43
+ const filePath = path.join(packageDir, file);
44
+ if (fs.existsSync(filePath)) {
45
+ log('info', `File exists: ${file}`);
46
+ } else {
47
+ log('error', `Missing required file: ${file}`);
48
+ }
49
+ });
50
+
51
+ // Check bin file permissions
52
+ const binFile = path.join(packageDir, 'bin/claude-commands');
53
+ if (fs.existsSync(binFile)) {
54
+ const stats = fs.statSync(binFile);
55
+ const mode = (stats.mode & parseInt('777', 8)).toString(8);
56
+ if (mode.includes('7') || mode.includes('5')) {
57
+ log('info', `Binary is executable (${mode})`);
58
+ } else {
59
+ log('warn', `Binary may not be executable (${mode})`);
60
+ }
61
+ }
62
+
63
+ // Count commands
64
+ const activeDir = path.join(packageDir, 'commands/active');
65
+ const experimentalDir = path.join(packageDir, 'commands/experiments');
66
+
67
+ if (fs.existsSync(activeDir)) {
68
+ const activeCount = fs.readdirSync(activeDir).filter(f => f.endsWith('.md')).length;
69
+ log('info', `Found ${activeCount} active commands`);
70
+ }
71
+
72
+ if (fs.existsSync(experimentalDir)) {
73
+ const expCount = fs.readdirSync(experimentalDir).filter(f => f.endsWith('.md')).length;
74
+ log('info', `Found ${expCount} experimental commands`);
75
+ }
76
+
77
+ console.log('');
78
+ console.log(`📊 Validation Summary:`);
79
+ console.log(` Errors: ${errors}`);
80
+ console.log(` Warnings: ${warnings}`);
81
+
82
+ if (errors > 0) {
83
+ console.log('');
84
+ console.log('❌ Package validation failed');
85
+ process.exit(1);
86
+ } else {
87
+ console.log('');
88
+ console.log('✅ Package validation passed');
89
+ }
90
+
91
+ } catch (error) {
92
+ console.error('❌ Validation failed:', error.message);
93
+ process.exit(1);
94
+ }