@paulduvall/claude-dev-toolkit 0.0.1-alpha.11 → 0.0.1-alpha.13

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +7 -7
  3. package/bin/claude-commands +72 -9
  4. package/commands/active/xcontinue.md +92 -0
  5. package/commands/active/xexplore.md +94 -0
  6. package/commands/active/xverify.md +80 -0
  7. package/commands/experiments/xdevcontainer.md +238 -0
  8. package/commands/experiments/xnew.md +5 -0
  9. package/hooks/README.md +32 -0
  10. package/hooks/file-logger.sh +4 -2
  11. package/hooks/lib/argument-parser.sh +7 -2
  12. package/hooks/lib/config-constants.sh +4 -4
  13. package/hooks/lib/context-manager.sh +19 -8
  14. package/hooks/lib/error-handler.sh +21 -10
  15. package/hooks/lib/execution-engine.sh +11 -194
  16. package/hooks/lib/execution-results.sh +113 -0
  17. package/hooks/lib/execution-simulation.sh +114 -0
  18. package/hooks/lib/field-validators.sh +104 -0
  19. package/hooks/lib/file-utils.sh +49 -26
  20. package/hooks/lib/subagent-discovery.sh +9 -6
  21. package/hooks/lib/subagent-validator.sh +19 -209
  22. package/hooks/lib/validation-reporter.sh +134 -0
  23. package/hooks/on-error-debug.sh +16 -11
  24. package/hooks/pre-commit-test-runner.sh +132 -0
  25. package/hooks/pre-write-security.sh +14 -6
  26. package/hooks/prevent-credential-exposure.sh +55 -45
  27. package/hooks/subagent-trigger-simple.sh +17 -8
  28. package/hooks/verify-before-edit.sh +135 -0
  29. package/lib/oidc-command.js +385 -8
  30. package/lib/setup-wizard.js +155 -262
  31. package/lib/uninstall-command.js +100 -0
  32. package/package.json +2 -2
  33. package/scripts/postinstall.js +168 -171
  34. package/subagents/debug-specialist.md +6 -0
  35. package/templates/README.md +15 -0
  36. package/templates/basic-settings.json +33 -19
  37. package/templates/comprehensive-settings.json +68 -171
  38. package/templates/global-claude.md +344 -0
  39. package/templates/security-focused-settings.json +58 -41
  40. package/lib/installation-instruction-generator-backup.js +0 -579
  41. package/lib/package-manager-service.js +0 -270
  42. package/subagents/debug-context.md +0 -197
@@ -3,198 +3,195 @@
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
- const { execSync } = require('child_process');
7
6
 
8
- // Check for skip flag
9
- const skipSetup = process.env.CLAUDE_SKIP_SETUP === 'true' ||
10
- process.argv.includes('--skip-setup');
7
+ const skipSetup = process.env.CLAUDE_SKIP_SETUP === 'true' ||
8
+ process.argv.includes('--skip-setup');
11
9
 
12
- console.log('šŸš€ Setting up Claude Custom Commands...');
10
+ console.log('Setting up Claude Custom Commands...');
13
11
 
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
- copyCommandsFlat(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
- }
12
+ // --- Directory helpers ---
13
+
14
+ function ensureDir(dirPath, label) {
15
+ if (fs.existsSync(dirPath)) return;
16
+ fs.mkdirSync(dirPath, { recursive: true });
17
+ console.log(` Created ${label}`);
18
+ }
19
+
20
+ function getClaudeDirs() {
21
+ const homeDir = os.homedir();
22
+ const claudeDir = path.join(homeDir, '.claude');
23
+ return {
24
+ claudeDir,
25
+ commandsDir: path.join(claudeDir, 'commands'),
26
+ hooksDir: path.join(claudeDir, 'hooks')
27
+ };
113
28
  }
114
29
 
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
-
120
- if (fs.statSync(sourcePath).isDirectory()) {
121
- // For subdirectories, copy their contents directly to targetDir (flat structure)
122
- copyAllCommands(sourcePath, targetDir);
30
+ // --- Command copying ---
31
+
32
+ function copyCommandsFlat(sourceDir, targetDir) {
33
+ if (!fs.existsSync(sourceDir)) return;
34
+ for (const item of fs.readdirSync(sourceDir)) {
35
+ const src = path.join(sourceDir, item);
36
+ if (fs.statSync(src).isDirectory()) {
37
+ copyCommandsFlat(src, targetDir);
123
38
  } else if (item.endsWith('.md')) {
124
- // Copy .md files directly to target directory
125
- const targetPath = path.join(targetDir, item);
126
- fs.copyFileSync(sourcePath, targetPath);
39
+ fs.copyFileSync(src, path.join(targetDir, item));
40
+ console.log(` Installed command: ${item}`);
127
41
  }
128
42
  }
129
43
  }
130
44
 
45
+ function copyCommandSubdir(sourceDir, subdir, targetDir) {
46
+ const sub = path.join(sourceDir, subdir);
47
+ if (fs.existsSync(sub)) copyCommandsFlat(sub, targetDir);
48
+ }
49
+
50
+ function shouldCopyActive(type, sets) {
51
+ return type === 'standard' || sets.includes('development');
52
+ }
53
+
54
+ function shouldCopyExperimental(type, sets) {
55
+ return type === 'full' || sets.includes('experimental');
56
+ }
57
+
131
58
  function copySelectedCommands(sourceDir, targetDir, config) {
132
- // Based on installation type, copy appropriate commands
133
- const installationType = config.installationType || 'standard';
134
-
135
- if (installationType === 'full' || !config.commandSets) {
136
- // Copy all commands in flat structure
59
+ const type = config.installationType || 'standard';
60
+ if (type === 'full' || !config.commandSets) {
137
61
  copyCommandsFlat(sourceDir, targetDir);
138
- } else {
139
- // Copy selected command sets
140
- const commandSets = config.commandSets || [];
141
-
142
- // Always copy active commands for standard installation (flat structure)
143
- if (installationType === 'standard' || commandSets.includes('development')) {
144
- const activeSource = path.join(sourceDir, 'active');
145
- if (fs.existsSync(activeSource)) {
146
- copyCommandsFlat(activeSource, targetDir);
147
- }
148
- }
149
-
150
- // Copy experimental if selected (flat structure to avoid namespace)
151
- if (commandSets.includes('experimental') || installationType === 'full') {
152
- const expSource = path.join(sourceDir, 'experiments');
153
- if (fs.existsSync(expSource)) {
154
- copyCommandsFlat(expSource, targetDir);
155
- }
156
- }
62
+ return;
157
63
  }
64
+ const sets = config.commandSets || [];
65
+ if (shouldCopyActive(type, sets)) copyCommandSubdir(sourceDir, 'active', targetDir);
66
+ if (shouldCopyExperimental(type, sets)) copyCommandSubdir(sourceDir, 'experiments', targetDir);
158
67
  }
159
68
 
160
- function copyCommandsFlat(sourceDir, targetDir) {
161
- // Copy all .md files from sourceDir and subdirectories directly to targetDir (flat structure)
162
- if (!fs.existsSync(sourceDir)) return;
163
-
164
- const items = fs.readdirSync(sourceDir);
165
- for (const item of items) {
166
- const sourcePath = path.join(sourceDir, item);
167
-
168
- if (fs.statSync(sourcePath).isDirectory()) {
169
- // Recursively copy from subdirectories but maintain flat structure
170
- copyCommandsFlat(sourcePath, targetDir);
171
- } else if (item.endsWith('.md')) {
172
- const targetPath = path.join(targetDir, item);
173
- fs.copyFileSync(sourcePath, targetPath);
174
- console.log(`āœ… Installed command: ${item}`);
69
+ // --- Hook copying ---
70
+
71
+ function copyHookFile(src, dest, label) {
72
+ fs.copyFileSync(src, dest);
73
+ if (label.endsWith('.sh')) fs.chmodSync(dest, '755');
74
+ console.log(` Installed hook: ${label}`);
75
+ }
76
+
77
+ function copyHooksLibDir(sourceDir, targetDir) {
78
+ const libSrc = path.join(sourceDir, 'lib');
79
+ if (!fs.existsSync(libSrc)) return;
80
+ const libDest = path.join(targetDir, 'lib');
81
+ ensureDir(libDest, 'hooks/lib');
82
+ for (const f of fs.readdirSync(libSrc)) {
83
+ const src = path.join(libSrc, f);
84
+ if (fs.statSync(src).isFile()) {
85
+ copyHookFile(src, path.join(libDest, f), `lib/${f}`);
175
86
  }
176
87
  }
177
88
  }
178
89
 
179
90
  function copySelectedHooks(sourceDir, targetDir, selectedHooks) {
180
- const items = fs.readdirSync(sourceDir);
181
- for (const item of items) {
182
- const sourcePath = path.join(sourceDir, item);
183
-
184
- // Copy hook if it's selected or if no specific selection (copy all)
185
- if (selectedHooks.length === 0 || selectedHooks.some(h => item.includes(h))) {
186
- const targetPath = path.join(targetDir, item);
187
- fs.copyFileSync(sourcePath, targetPath);
188
-
189
- // Make shell scripts executable
190
- if (item.endsWith('.sh')) {
191
- fs.chmodSync(targetPath, '755');
192
- }
193
-
194
- console.log(`āœ… Installed hook: ${item}`);
91
+ for (const item of fs.readdirSync(sourceDir)) {
92
+ const src = path.join(sourceDir, item);
93
+ if (fs.statSync(src).isDirectory()) continue;
94
+ const match = selectedHooks.length === 0 || selectedHooks.some(h => item.includes(h));
95
+ if (match) copyHookFile(src, path.join(targetDir, item), item);
96
+ }
97
+ copyHooksLibDir(sourceDir, targetDir);
98
+ }
99
+
100
+ // --- Template application ---
101
+
102
+ function applyTemplate(packageDir, claudeDir, templateName) {
103
+ const src = path.join(packageDir, 'templates', `${templateName}-settings.json`);
104
+ if (!fs.existsSync(src)) return;
105
+ const dest = path.join(claudeDir, 'settings.json');
106
+ fs.copyFileSync(src, dest);
107
+ console.log(` Applied ${templateName} configuration template`);
108
+ }
109
+
110
+ // --- Interactive setup ---
111
+
112
+ function installFromConfig(packageDir, dirs, config) {
113
+ const cmdSrc = path.join(packageDir, 'commands');
114
+ if (fs.existsSync(cmdSrc)) copySelectedCommands(cmdSrc, dirs.commandsDir, config);
115
+ if (config.securityHooks) {
116
+ const hookSrc = path.join(packageDir, 'hooks');
117
+ if (fs.existsSync(hookSrc)) copySelectedHooks(hookSrc, dirs.hooksDir, config.selectedHooks || []);
118
+ }
119
+ if (config.template) applyTemplate(packageDir, dirs.claudeDir, config.template);
120
+ }
121
+
122
+ async function runInteractiveInstall(packageDir, dirs) {
123
+ console.log('\nStarting Interactive Setup Wizard...');
124
+ console.log('(Use --skip-setup or set CLAUDE_SKIP_SETUP=true to skip)\n');
125
+ const Wizard = require('../lib/setup-wizard');
126
+ const wizard = new Wizard(dirs.claudeDir);
127
+ const envCheck = wizard.validateEnvironment();
128
+ if (!envCheck.valid) {
129
+ console.error('Environment validation failed:', envCheck.message);
130
+ console.error('\nTroubleshooting:');
131
+ console.error(' - Ensure Node.js >= 18 is installed');
132
+ console.error(' - Check write permissions on ~/.claude/');
133
+ console.error(' - Try: claude-commands setup --dry-run');
134
+ process.exit(1);
135
+ }
136
+ const result = await wizard.runInteractiveSetup();
137
+ if (!result.completed) return;
138
+ installFromConfig(packageDir, dirs, result.configuration);
139
+ }
140
+
141
+ // --- Non-interactive setup ---
142
+
143
+ function runNonInteractiveInstall(packageDir, dirs) {
144
+ console.log('Running non-interactive installation...');
145
+ const cmdSrc = path.join(packageDir, 'commands');
146
+ if (fs.existsSync(cmdSrc)) copyCommandsFlat(cmdSrc, dirs.commandsDir);
147
+ }
148
+
149
+ // --- Main ---
150
+
151
+ function printSummary(commandsDir) {
152
+ if (fs.existsSync(commandsDir)) {
153
+ const count = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md')).length;
154
+ console.log(`\nInstalled ${count} commands`);
155
+ }
156
+ console.log('\nInstallation complete!');
157
+ console.log('\nNext steps:');
158
+ console.log('1. Run: claude-commands list');
159
+ console.log('2. Try: claude-commands --help');
160
+ console.log('3. Configure: claude-commands config');
161
+ console.log('4. Explore commands in Claude Code using /xhelp\n');
162
+ }
163
+
164
+ function printInstallError(error) {
165
+ console.error('Installation failed:', error.message);
166
+ console.error('\nTroubleshooting:');
167
+ console.error(' - Check write permissions: ls -la ~/.claude/');
168
+ console.error(' - Try manual install: claude-commands install --all');
169
+ console.error(' - Report issues: https://github.com/PaulDuvall/claude-code/issues');
170
+ }
171
+
172
+ function initDirs() {
173
+ const dirs = getClaudeDirs();
174
+ ensureDir(dirs.claudeDir, '.claude');
175
+ ensureDir(dirs.commandsDir, '.claude/commands');
176
+ ensureDir(dirs.hooksDir, '.claude/hooks');
177
+ return dirs;
178
+ }
179
+
180
+ async function runSetup() {
181
+ try {
182
+ const dirs = initDirs();
183
+ const packageDir = path.dirname(__dirname);
184
+
185
+ if (!skipSetup && process.stdin.isTTY) {
186
+ await runInteractiveInstall(packageDir, dirs);
187
+ } else {
188
+ runNonInteractiveInstall(packageDir, dirs);
195
189
  }
190
+ printSummary(dirs.commandsDir);
191
+ } catch (error) {
192
+ printInstallError(error);
193
+ process.exit(1);
196
194
  }
197
195
  }
198
196
 
199
- // Run the setup
200
- runSetup();
197
+ runSetup();
@@ -1,3 +1,9 @@
1
+ ---
2
+ description: "Specialized debugging assistant with expertise in root cause analysis, error interpretation, and systematic troubleshooting"
3
+ tags: ["debugging", "error-analysis", "troubleshooting", "performance"]
4
+ tools: ["Read", "Bash", "Grep", "Edit", "Glob"]
5
+ ---
6
+
1
7
  # Debug Specialist Sub-Agent
2
8
 
3
9
  ## Agent Description
@@ -59,6 +59,21 @@ cp templates/comprehensive-settings.json ~/.claude/settings.json
59
59
  # Configure webhooks and organizational settings
60
60
  ```
61
61
 
62
+ ### 4. `global-claude.md`
63
+ **Use case**: Universal development standards for all projects
64
+ **Features**:
65
+ - Verification-before-action rules (prevent fabricated references)
66
+ - Zero-error test policy
67
+ - Platform-specific formatting guidelines (LinkedIn, Slack, GitHub, email)
68
+ - Code structure limits (function length, nesting, complexity)
69
+ - Security checklist (no hardcoded secrets, parameterized SQL, input validation)
70
+ - Session management and failure protocols
71
+
72
+ **To use**:
73
+ ```bash
74
+ cp templates/global-claude.md ~/.claude/CLAUDE.md
75
+ ```
76
+
62
77
  ## Configuration Notes
63
78
 
64
79
  ### Settings Hierarchy
@@ -1,30 +1,44 @@
1
1
  {
2
2
  "// Basic Claude Code settings.json template": "Copy to ~/.claude/settings.json",
3
- "// This provides minimal configuration for custom commands to work": "",
3
+ "// Based on official Claude Code documentation": "https://docs.anthropic.com/en/docs/claude-code/settings",
4
4
 
5
- "allowedTools": [
6
- "Edit",
7
- "Bash",
8
- "Read",
9
- "Write"
10
- ],
5
+ "// Core tool permissions (replaces invalid 'allowedTools')": "",
6
+ "permissions": {
7
+ "allow": [
8
+ "Edit(*)",
9
+ "Bash(*)",
10
+ "Read(*)",
11
+ "Write(*)",
12
+ "MultiEdit(*)",
13
+ "Glob(*)",
14
+ "Grep(*)",
15
+ "LS(*)"
16
+ ]
17
+ },
11
18
 
12
19
  "// Basic hooks configuration": "",
13
20
  "hooks": {
14
- "PreToolUse": [],
15
- "PostToolUse": []
21
+ "PreToolUse": [
22
+ {
23
+ "matcher": "*",
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "command": "echo 'Tool execution logged at $(date)' >> ~/.claude/logs/tool-usage.log"
28
+ }
29
+ ]
30
+ }
31
+ ]
16
32
  },
17
33
 
18
- "// Trust and onboarding settings": "",
19
- "hasTrustDialogAccepted": true,
20
- "hasCompletedProjectOnboarding": true,
34
+ "// Standard Claude Code environment variables": "",
35
+ "env": {
36
+ "DISABLE_TELEMETRY": "1"
37
+ },
21
38
 
22
- "// Performance optimization": "",
23
- "parallelTasksCount": 3,
39
+ "// Optional: Include Claude co-authorship in git commits": "",
40
+ "includeCoAuthoredBy": true,
24
41
 
25
- "// Optional: Environment variables": "",
26
- "env": {
27
- "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "true",
28
- "BASH_DEFAULT_TIMEOUT_MS": "120000"
29
- }
42
+ "// Optional: Custom retention for chat transcripts (days)": "",
43
+ "cleanupPeriodDays": 30
30
44
  }