@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
@@ -2,354 +2,247 @@
2
2
 
3
3
  /**
4
4
  * Interactive Setup Wizard for REQ-007
5
- * GREEN phase - Minimal implementation to pass tests
6
5
  */
7
6
 
8
7
  const fs = require('fs');
9
8
  const path = require('path');
10
9
  const readline = require('readline');
11
10
 
12
- // Import extracted classes for better separation of concerns
13
11
  const SetupWizardUI = require('./setup-wizard-ui');
14
12
  const InstallationConfiguration = require('./installation-configuration');
15
13
  const CommandSelector = require('./command-selector');
16
14
 
15
+ function getDefaultConfig() {
16
+ return {
17
+ installationType: 'standard',
18
+ commandSets: ['development', 'planning'],
19
+ securityHooks: true,
20
+ selectedHooks: ['credential-protection'],
21
+ template: 'basic'
22
+ };
23
+ }
24
+
25
+ function buildConfigResult(success, configPath) {
26
+ return {
27
+ saved: success,
28
+ file: success ? configPath : null,
29
+ error: success ? null : 'Failed to save configuration'
30
+ };
31
+ }
32
+
33
+ function buildSecurityHooksList() {
34
+ return [
35
+ { id: 1, name: 'credential-protection', description: 'Prevents credential exposure in commits', file: 'prevent-credential-exposure.sh' },
36
+ { id: 2, name: 'file-logger', description: 'Logs file operations for audit trail', file: 'file-logger.sh' },
37
+ { id: 3, name: 'pre-commit-quality', description: 'Code quality checks before commits', file: 'pre-commit-quality.sh' },
38
+ { id: 4, name: 'pre-write-security', description: 'Security scan before file writes', file: 'pre-write-security.sh' },
39
+ { id: 5, name: 'pre-commit-test-runner', description: 'Auto-detects and runs project tests before commits', file: 'pre-commit-test-runner.sh' },
40
+ { id: 6, name: 'verify-before-edit', description: 'Warns about fabricated references in edits', file: 'verify-before-edit.sh' },
41
+ { id: 7, name: 'audit-bash-commands', description: 'Logs shell commands for security audit', file: 'audit-bash-commands.sh' },
42
+ { id: 8, name: 'log-all-operations', description: 'Audit trail for all tool usage', file: 'log-all-operations.sh' },
43
+ { id: 9, name: 'validate-changes', description: 'Post-edit validation of changes', file: 'validate-changes.sh' },
44
+ { id: 10, name: 'backup-before-edit', description: 'Preserves file state before modifications', file: 'backup-before-edit.sh' },
45
+ { id: 11, name: 'session-init', description: 'Validates environment at session start', file: 'session-init.sh' },
46
+ { id: 12, name: 'session-cleanup', description: 'End-of-session security cleanup', file: 'session-cleanup.sh' },
47
+ { id: 13, name: 'prompt-security-scan', description: 'Scans prompts for credential exposure risks', file: 'prompt-security-scan.sh' }
48
+ ];
49
+ }
50
+
51
+ function enhanceConfig(configData) {
52
+ return { timestamp: new Date().toISOString(), version: '1.0.0', ...configData };
53
+ }
54
+
17
55
  class InteractiveSetupWizard {
18
56
  constructor(packageRoot) {
19
57
  this.packageRoot = packageRoot;
20
-
21
- // Import config module for template application
58
+
22
59
  const config = require('./config');
23
60
  this.applyConfigurationTemplate = config.applyConfigurationTemplate;
24
-
25
- // Import hook installer for security hooks
61
+
26
62
  const hookInstaller = require('./hook-installer');
27
63
  this.installSecurityHooks = hookInstaller.installSecurityHooks;
28
64
  this.getAvailableHooks = hookInstaller.getAvailableHooks;
29
-
30
- // Initialize extracted components
65
+
31
66
  this.ui = new SetupWizardUI();
32
67
  this.config = new InstallationConfiguration(packageRoot);
33
68
  this.commandSelector = new CommandSelector();
34
-
35
- // Legacy data for backward compatibility
36
- this.securityHooks = [
37
- {
38
- id: 1,
39
- name: 'credential-protection',
40
- description: 'Prevents credential exposure in commits',
41
- file: 'prevent-credential-exposure.sh'
42
- },
43
- {
44
- id: 2,
45
- name: 'file-logger',
46
- description: 'Logs file operations for audit trail',
47
- file: 'file-logger.sh'
48
- }
49
- ];
69
+ this.securityHooks = buildSecurityHooksList();
50
70
  }
51
-
71
+
52
72
  validateEnvironment() {
53
73
  try {
54
- // Check write permissions
55
74
  const testFile = path.join(this.packageRoot, '.test');
56
75
  fs.writeFileSync(testFile, 'test');
57
76
  fs.unlinkSync(testFile);
58
-
59
- return {
60
- valid: true,
61
- message: 'Environment validation passed'
62
- };
77
+ return { valid: true, message: 'Environment validation passed' };
63
78
  } catch (error) {
64
- return {
65
- valid: false,
66
- message: `Environment validation failed: ${error.message}`
67
- };
79
+ return { valid: false, message: `Environment validation failed: ${error.message}` };
68
80
  }
69
81
  }
70
-
82
+
71
83
  getInstallationTypes() {
72
84
  return this.config.getInstallationTypes();
73
85
  }
74
-
86
+
75
87
  selectInstallationType(optionId) {
76
88
  const selected = this.config.getInstallationTypeById(optionId);
77
- if (selected) {
78
- return {
79
- type: selected.name.toLowerCase().split(' ')[0],
80
- description: selected.description,
81
- commands: selected.commands
82
- };
83
- }
84
- return null;
89
+ if (!selected) return null;
90
+ return { type: selected.name.toLowerCase().split(' ')[0], description: selected.description, commands: selected.commands };
85
91
  }
86
-
92
+
87
93
  getCommandCategories() {
88
94
  return this.commandSelector.getCommandCategories();
89
95
  }
90
-
96
+
91
97
  selectCommandSets(categories) {
92
98
  return this.commandSelector.selectCommandSets(categories);
93
99
  }
94
-
100
+
95
101
  getSecurityHooks() {
96
102
  return this.securityHooks;
97
103
  }
98
-
104
+
99
105
  selectSecurityHooks(hookIds) {
100
- const selected = hookIds.map(id =>
101
- this.securityHooks.find(h => h.id === id)
102
- ).filter(Boolean);
103
-
104
- return {
105
- enabled: selected.length > 0,
106
- selected: selected.map(h => h.name)
107
- };
106
+ const selected = hookIds.map(id => this.securityHooks.find(h => h.id === id)).filter(Boolean);
107
+ return { enabled: selected.length > 0, selected: selected.map(h => h.name) };
108
108
  }
109
-
109
+
110
110
  getConfigurationTemplates() {
111
111
  return this.config.getConfigurationTemplates();
112
112
  }
113
-
113
+
114
114
  selectConfigurationTemplate(templateName) {
115
- const templates = this.config.getConfigurationTemplates();
116
- const template = templates.find(t => t.name === templateName);
117
-
118
- if (template) {
119
- return {
120
- template: template.name,
121
- file: template.filename,
122
- description: template.description
123
- };
124
- }
125
- return null;
115
+ const template = this.config.getConfigurationTemplates().find(t => t.name === templateName);
116
+ if (!template) return null;
117
+ return { template: template.name, file: template.filename, description: template.description };
126
118
  }
127
-
119
+
128
120
  runNonInteractiveSetup() {
129
- const defaultConfig = {
130
- installationType: 'standard',
131
- commandSets: ['development', 'planning'],
132
- securityHooks: true,
133
- selectedHooks: ['credential-protection'],
134
- template: 'basic'
135
- };
136
-
137
- this.saveConfiguration(defaultConfig);
138
-
139
- return {
140
- completed: true,
141
- configuration: defaultConfig
142
- };
121
+ const cfg = getDefaultConfig();
122
+ this.saveConfiguration(cfg);
123
+ return { completed: true, configuration: cfg };
143
124
  }
144
-
125
+
145
126
  async runNonInteractiveSetupAsync() {
146
- const defaultConfig = {
147
- installationType: 'standard',
148
- commandSets: ['development', 'planning'],
149
- securityHooks: true,
150
- selectedHooks: ['credential-protection'],
151
- template: 'basic'
152
- };
153
-
154
- await this.saveConfigurationAsync(defaultConfig);
155
-
156
- return {
157
- completed: true,
158
- configuration: defaultConfig
159
- };
127
+ const cfg = getDefaultConfig();
128
+ await this.saveConfigurationAsync(cfg);
129
+ return { completed: true, configuration: cfg };
160
130
  }
161
-
131
+
162
132
  saveConfiguration(configData) {
163
- const enhancedConfig = {
164
- timestamp: new Date().toISOString(),
165
- version: '1.0.0',
166
- ...configData
167
- };
168
-
169
- const success = this.config.saveConfiguration(enhancedConfig);
170
- return {
171
- saved: success,
172
- file: success ? this.config.getConfigurationPath() : null,
173
- error: success ? null : 'Failed to save configuration'
174
- };
133
+ const success = this.config.saveConfiguration(enhanceConfig(configData));
134
+ return buildConfigResult(success, this.config.getConfigurationPath());
175
135
  }
176
-
136
+
177
137
  async saveConfigurationAsync(configData) {
178
- const enhancedConfig = {
179
- timestamp: new Date().toISOString(),
180
- version: '1.0.0',
181
- ...configData
182
- };
183
-
184
- const success = await this.config.saveConfigurationAsync(enhancedConfig);
185
- return {
186
- saved: success,
187
- file: success ? this.config.getConfigurationPath() : null,
188
- error: success ? null : 'Failed to save configuration'
189
- };
138
+ const success = await this.config.saveConfigurationAsync(enhanceConfig(configData));
139
+ return buildConfigResult(success, this.config.getConfigurationPath());
190
140
  }
191
-
141
+
192
142
  loadConfiguration() {
193
- const configData = this.config.loadConfiguration();
194
- if (configData) {
195
- return {
196
- found: true,
197
- config: configData
198
- };
199
- }
200
- return {
201
- found: false
202
- };
143
+ const data = this.config.loadConfiguration();
144
+ return data ? { found: true, config: data } : { found: false };
203
145
  }
204
-
146
+
205
147
  async loadConfigurationAsync() {
206
- const configData = await this.config.loadConfigurationAsync();
207
- if (configData) {
208
- return {
209
- found: true,
210
- config: configData
211
- };
212
- }
213
- return {
214
- found: false
215
- };
148
+ const data = await this.config.loadConfigurationAsync();
149
+ return data ? { found: true, config: data } : { found: false };
216
150
  }
217
-
151
+
218
152
  applyPreset(presetName) {
219
153
  return this.commandSelector.applyPreset(presetName);
220
154
  }
221
-
155
+
156
+ async promptInstallationType(ask) {
157
+ console.log('\n📦 Installation Type:');
158
+ this.installationTypes.forEach(t => console.log(`${t.id}. ${t.name}\n ${t.description}`));
159
+ const choice = await ask('\nSelect installation type (1-3): ');
160
+ return this.selectInstallationType(parseInt(choice));
161
+ }
162
+
163
+ async promptCommandSets(ask) {
164
+ console.log('\n🛠️ Command Sets:');
165
+ const cats = Object.keys(this.commandCategories);
166
+ cats.forEach((c, i) => console.log(`${i + 1}. ${c} (${this.commandCategories[c].length} commands)`));
167
+ const choice = await ask('\nSelect command sets (comma-separated numbers): ');
168
+ return choice.split(',').map(s => cats[parseInt(s.trim()) - 1]).filter(Boolean);
169
+ }
170
+
171
+ async promptSecurityHooks(ask, config) {
172
+ const enable = await ask('\n🔒 Enable security hooks? (y/n): ');
173
+ if (enable.toLowerCase() !== 'y') {
174
+ config.securityHooks = false;
175
+ config.selectedHooks = [];
176
+ return;
177
+ }
178
+ console.log('\nAvailable hooks:');
179
+ this.securityHooks.forEach(h => console.log(`${h.id}. ${h.name}\n ${h.description}`));
180
+ const choice = await ask('\nSelect hooks (comma-separated numbers): ');
181
+ const ids = choice.split(',').map(h => parseInt(h.trim()));
182
+ const selected = this.selectSecurityHooks(ids);
183
+ config.securityHooks = selected.enabled;
184
+ config.selectedHooks = selected.selected;
185
+ }
186
+
187
+ async promptAndApplyTemplate(ask, config) {
188
+ console.log('\n⚙️ Configuration Templates:');
189
+ this.configurationTemplates.forEach(t => console.log(`${t.id}. ${t.name}\n ${t.description}`));
190
+ const choice = await ask('\nSelect template (1-3): ');
191
+ const tpl = this.configurationTemplates.find(t => t.id === parseInt(choice));
192
+ if (!tpl) return;
193
+ config.template = tpl.name;
194
+ await this.saveConfigurationAsync(config);
195
+ const tplPath = path.join(this.packageRoot, 'templates', tpl.filename);
196
+ const settingsPath = path.join(require('os').homedir(), '.claude', 'settings.json');
197
+ console.log(`\n📋 Applying configuration template: ${tpl.name}`);
198
+ const applied = this.applyConfigurationTemplate(tplPath, settingsPath);
199
+ config.templateApplied = applied;
200
+ if (applied) {
201
+ config.settingsPath = settingsPath;
202
+ console.log(`✅ Template applied to: ${settingsPath}`);
203
+ } else {
204
+ console.log('⚠️ Template application failed, but setup will continue');
205
+ }
206
+ }
207
+
208
+ async collectSetupChoices(ask) {
209
+ const config = {};
210
+ const selectedType = await this.promptInstallationType(ask);
211
+ if (selectedType) config.installationType = selectedType.type;
212
+ config.commandSets = await this.promptCommandSets(ask);
213
+ await this.promptSecurityHooks(ask, config);
214
+ await this.promptAndApplyTemplate(ask, config);
215
+ return config;
216
+ }
217
+
222
218
  async runInteractiveSetup() {
223
- const rl = readline.createInterface({
224
- input: process.stdin,
225
- output: process.stdout
226
- });
227
-
228
- const question = (prompt) => new Promise((resolve) => {
229
- rl.question(prompt, resolve);
230
- });
231
-
219
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
220
+ const ask = (prompt) => new Promise((resolve) => rl.question(prompt, resolve));
232
221
  console.log('\n🚀 Claude Dev Toolkit Interactive Setup Wizard');
233
- console.log('=' .repeat(50));
234
-
235
- const config = {};
236
-
222
+ console.log('='.repeat(50));
237
223
  try {
238
- // Installation type
239
- console.log('\n📦 Installation Type:');
240
- this.installationTypes.forEach(type => {
241
- console.log(`${type.id}. ${type.name}`);
242
- console.log(` ${type.description}`);
243
- });
244
-
245
- const typeChoice = await question('\nSelect installation type (1-3): ');
246
- const selectedType = this.selectInstallationType(parseInt(typeChoice));
247
- if (selectedType) {
248
- config.installationType = selectedType.type;
249
- }
250
-
251
- // Command sets
252
- console.log('\n🛠️ Command Sets:');
253
- const categories = Object.keys(this.commandCategories);
254
- categories.forEach((cat, i) => {
255
- console.log(`${i + 1}. ${cat} (${this.commandCategories[cat].length} commands)`);
256
- });
257
-
258
- const setChoice = await question('\nSelect command sets (comma-separated numbers): ');
259
- const selectedIndices = setChoice.split(',').map(s => parseInt(s.trim()) - 1);
260
- const selectedSets = selectedIndices.map(i => categories[i]).filter(Boolean);
261
- config.commandSets = selectedSets;
262
-
263
- // Security hooks
264
- const enableHooks = await question('\n🔒 Enable security hooks? (y/n): ');
265
- if (enableHooks.toLowerCase() === 'y') {
266
- console.log('\nAvailable hooks:');
267
- this.securityHooks.forEach(hook => {
268
- console.log(`${hook.id}. ${hook.name}`);
269
- console.log(` ${hook.description}`);
270
- });
271
-
272
- const hookChoice = await question('\nSelect hooks (comma-separated numbers): ');
273
- const hookIds = hookChoice.split(',').map(h => parseInt(h.trim()));
274
- const selectedHooks = this.selectSecurityHooks(hookIds);
275
- config.securityHooks = selectedHooks.enabled;
276
- config.selectedHooks = selectedHooks.selected;
277
- } else {
278
- config.securityHooks = false;
279
- config.selectedHooks = [];
280
- }
281
-
282
- // Configuration template
283
- console.log('\n⚙️ Configuration Templates:');
284
- this.configurationTemplates.forEach(template => {
285
- console.log(`${template.id}. ${template.name}`);
286
- console.log(` ${template.description}`);
287
- });
288
-
289
- const templateChoice = await question('\nSelect template (1-3): ');
290
- const templateId = parseInt(templateChoice);
291
- const selectedTemplate = this.configurationTemplates.find(t => t.id === templateId);
292
- if (selectedTemplate) {
293
- config.template = selectedTemplate.name;
294
- }
295
-
296
- // Save configuration
297
- await this.saveConfigurationAsync(config);
298
-
299
- // Apply selected configuration template (REQ-009 integration)
300
- if (selectedTemplate) {
301
- const templatesDir = path.join(this.packageRoot, 'templates');
302
- const templatePath = path.join(templatesDir, selectedTemplate.filename);
303
- const settingsPath = path.join(require('os').homedir(), '.claude', 'settings.json');
304
-
305
- console.log(`\n📋 Applying configuration template: ${selectedTemplate.name}`);
306
- const applied = this.applyConfigurationTemplate(templatePath, settingsPath);
307
- if (applied) {
308
- console.log(`✅ Template applied to: ${settingsPath}`);
309
- config.templateApplied = true;
310
- config.settingsPath = settingsPath;
311
- } else {
312
- console.log('⚠️ Template application failed, but setup will continue');
313
- config.templateApplied = false;
314
- }
315
- }
316
-
224
+ const config = await this.collectSetupChoices(ask);
317
225
  console.log('\n✅ Setup completed successfully!');
318
- console.log(`Configuration saved to: ${this.configFile}`);
319
-
320
226
  rl.close();
321
-
322
- return {
323
- completed: true,
324
- configuration: config
325
- };
326
-
227
+ return { completed: true, configuration: config };
327
228
  } catch (error) {
328
229
  rl.close();
329
- return {
330
- completed: false,
331
- error: error.message
332
- };
230
+ return { completed: false, error: error.message };
333
231
  }
334
232
  }
335
233
  }
336
234
 
337
- // Support for PostInstaller integration
338
235
  class PostInstaller {
339
236
  constructor() {
340
237
  this.packageRoot = path.join(require('os').homedir(), '.claude');
341
238
  }
342
-
239
+
343
240
  runSetupWizard(options = {}) {
344
- if (options.skipSetup) {
345
- return { skipped: true };
346
- }
347
-
241
+ if (options.skipSetup) return { skipped: true };
348
242
  const wizard = new InteractiveSetupWizard(this.packageRoot);
349
243
  return wizard.runNonInteractiveSetup();
350
244
  }
351
245
  }
352
246
 
353
- // Export both classes
354
247
  module.exports = InteractiveSetupWizard;
355
- module.exports.PostInstaller = PostInstaller;
248
+ module.exports.PostInstaller = PostInstaller;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Uninstall Command
3
+ *
4
+ * Removes all files installed by claude-dev-toolkit:
5
+ * - ~/.claude/commands/*.md (slash commands)
6
+ * - ~/.claude/hooks/*.sh (hook scripts)
7
+ * - ~/.claude/sub-agents/*.md (subagent definitions)
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const os = require('os');
13
+
14
+ const CLAUDE_DIR = path.join(os.homedir(), '.claude');
15
+
16
+ const TARGETS = [
17
+ { dir: path.join(CLAUDE_DIR, 'commands'), pattern: /\.md$/, label: 'commands' },
18
+ { dir: path.join(CLAUDE_DIR, 'hooks'), pattern: /\.sh$/, label: 'hooks' },
19
+ { dir: path.join(CLAUDE_DIR, 'sub-agents'), pattern: /\.md$/, label: 'subagents' },
20
+ ];
21
+
22
+ function listFiles(dir, pattern) {
23
+ if (!fs.existsSync(dir)) return [];
24
+ return fs.readdirSync(dir)
25
+ .filter(f => pattern.test(f))
26
+ .map(f => path.join(dir, f));
27
+ }
28
+
29
+ function removeFiles(files, dryRun) {
30
+ let removed = 0;
31
+ for (const file of files) {
32
+ if (dryRun) {
33
+ console.log(` Would remove: ${file}`);
34
+ } else {
35
+ fs.unlinkSync(file);
36
+ }
37
+ removed++;
38
+ }
39
+ return removed;
40
+ }
41
+
42
+ function removeAllTargets(dryRun) {
43
+ const prefix = dryRun ? '[DRY RUN] ' : '';
44
+ let totalRemoved = 0;
45
+
46
+ for (const target of TARGETS) {
47
+ const files = listFiles(target.dir, target.pattern);
48
+ if (files.length === 0) continue;
49
+
50
+ console.log(`${prefix}Removing ${files.length} ${target.label}:`);
51
+ totalRemoved += removeFiles(files, dryRun);
52
+ console.log('');
53
+ }
54
+ return totalRemoved;
55
+ }
56
+
57
+ function execute(options = {}) {
58
+ const { dryRun, keepSettings } = options;
59
+ const prefix = dryRun ? '[DRY RUN] ' : '';
60
+
61
+ console.log(`${prefix}Uninstalling claude-dev-toolkit files...\n`);
62
+
63
+ const totalRemoved = removeAllTargets(dryRun);
64
+ if (!keepSettings) handleSettingsCleanup(dryRun, prefix);
65
+ printSummary(totalRemoved, dryRun);
66
+ }
67
+
68
+ function handleSettingsCleanup(dryRun, prefix) {
69
+ const settingsPath = path.join(CLAUDE_DIR, 'settings.json');
70
+ if (!fs.existsSync(settingsPath)) return;
71
+
72
+ console.log(`${prefix}Cleaning settings.json (removing sub_agents key)`);
73
+ if (dryRun) return;
74
+
75
+ try {
76
+ const raw = fs.readFileSync(settingsPath, 'utf8');
77
+ const settings = JSON.parse(raw);
78
+ delete settings.sub_agents;
79
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
80
+ } catch (err) {
81
+ console.log(` Warning: could not clean settings.json: ${err.message}`);
82
+ }
83
+ }
84
+
85
+ function printSummary(totalRemoved, dryRun) {
86
+ if (totalRemoved === 0) {
87
+ console.log('Nothing to remove. No installed files found.');
88
+ return;
89
+ }
90
+
91
+ const action = dryRun ? 'Would remove' : 'Removed';
92
+ console.log(`\n${action} ${totalRemoved} file(s).`);
93
+
94
+ if (!dryRun) {
95
+ console.log('\nTo fully uninstall the npm package:');
96
+ console.log(' npm uninstall -g @paulduvall/claude-dev-toolkit');
97
+ }
98
+ }
99
+
100
+ module.exports = { execute };