@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.
- package/LICENSE +21 -0
- package/README.md +88 -37
- package/bin/claude-commands +307 -65
- package/commands/active/xarchitecture.md +393 -0
- package/commands/active/xconfig.md +127 -0
- package/commands/active/xcontinue.md +92 -0
- package/commands/active/xdebug.md +130 -0
- package/commands/active/xdocs.md +178 -0
- package/commands/active/xexplore.md +94 -0
- package/commands/active/xgit.md +149 -0
- package/commands/active/xpipeline.md +152 -0
- package/commands/active/xquality.md +96 -0
- package/commands/active/xrefactor.md +198 -0
- package/commands/active/xrelease.md +142 -0
- package/commands/active/xsecurity.md +92 -0
- package/commands/active/xspec.md +174 -0
- package/commands/active/xtdd.md +151 -0
- package/commands/active/xtest.md +89 -0
- package/commands/active/xverify.md +80 -0
- package/commands/experiments/xact.md +742 -0
- package/commands/experiments/xanalytics.md +113 -0
- package/commands/experiments/xanalyze.md +70 -0
- package/commands/experiments/xapi.md +161 -0
- package/commands/experiments/xatomic.md +112 -0
- package/commands/experiments/xaws.md +85 -0
- package/commands/experiments/xcicd.md +337 -0
- package/commands/experiments/xcommit.md +122 -0
- package/commands/experiments/xcompliance.md +182 -0
- package/commands/experiments/xconstraints.md +89 -0
- package/commands/experiments/xcoverage.md +90 -0
- package/commands/experiments/xdb.md +102 -0
- package/commands/experiments/xdesign.md +121 -0
- package/commands/experiments/xdevcontainer.md +238 -0
- package/commands/experiments/xevaluate.md +111 -0
- package/commands/experiments/xfootnote.md +12 -0
- package/commands/experiments/xgenerate.md +117 -0
- package/commands/experiments/xgovernance.md +149 -0
- package/commands/experiments/xgreen.md +66 -0
- package/commands/experiments/xiac.md +118 -0
- package/commands/experiments/xincident.md +137 -0
- package/commands/experiments/xinfra.md +115 -0
- package/commands/experiments/xknowledge.md +115 -0
- package/commands/experiments/xmaturity.md +120 -0
- package/commands/experiments/xmetrics.md +118 -0
- package/commands/experiments/xmonitoring.md +128 -0
- package/commands/experiments/xnew.md +903 -0
- package/commands/experiments/xobservable.md +114 -0
- package/commands/experiments/xoidc.md +165 -0
- package/commands/experiments/xoptimize.md +115 -0
- package/commands/experiments/xperformance.md +112 -0
- package/commands/experiments/xplanning.md +131 -0
- package/commands/experiments/xpolicy.md +115 -0
- package/commands/experiments/xproduct.md +98 -0
- package/commands/experiments/xreadiness.md +75 -0
- package/commands/experiments/xred.md +55 -0
- package/commands/experiments/xrisk.md +128 -0
- package/commands/experiments/xrules.md +124 -0
- package/commands/experiments/xsandbox.md +120 -0
- package/commands/experiments/xscan.md +102 -0
- package/commands/experiments/xsetup.md +123 -0
- package/commands/experiments/xtemplate.md +116 -0
- package/commands/experiments/xtrace.md +212 -0
- package/commands/experiments/xux.md +171 -0
- package/commands/experiments/xvalidate.md +104 -0
- package/commands/experiments/xworkflow.md +113 -0
- package/hooks/.smellrc.example.json +19 -0
- package/hooks/README.md +263 -0
- package/hooks/check-commit-signing.py +127 -0
- package/hooks/check-complexity.py +38 -0
- package/hooks/check-security.py +37 -0
- package/hooks/claude-wrapper.sh +29 -0
- package/hooks/config.py +110 -0
- package/hooks/file-logger.sh +100 -0
- package/hooks/lib/argument-parser.sh +427 -0
- package/hooks/lib/config-constants.sh +230 -0
- package/hooks/lib/context-manager.sh +560 -0
- package/hooks/lib/error-handler.sh +423 -0
- package/hooks/lib/execution-engine.sh +444 -0
- package/hooks/lib/execution-results.sh +113 -0
- package/hooks/lib/execution-simulation.sh +114 -0
- package/hooks/lib/field-validators.sh +104 -0
- package/hooks/lib/file-utils.sh +398 -0
- package/hooks/lib/subagent-discovery.sh +468 -0
- package/hooks/lib/subagent-validator.sh +407 -0
- package/hooks/lib/validation-reporter.sh +134 -0
- package/hooks/on-error-debug.sh +226 -0
- package/hooks/pre-commit-quality.sh +204 -0
- package/hooks/pre-commit-test-runner.sh +132 -0
- package/hooks/pre-write-security.sh +115 -0
- package/hooks/prevent-credential-exposure.sh +279 -0
- package/hooks/security_bandit.py +177 -0
- package/hooks/security_checks.py +97 -0
- package/hooks/security_secrets.py +81 -0
- package/hooks/security_trojan.py +61 -0
- package/hooks/settings.example.json +52 -0
- package/hooks/smell_checks.py +238 -0
- package/hooks/smell_javascript.py +231 -0
- package/hooks/smell_python.py +110 -0
- package/hooks/smell_ruff.py +70 -0
- package/hooks/smell_types.py +72 -0
- package/hooks/subagent-trigger-simple.sh +202 -0
- package/hooks/subagent-trigger.sh +253 -0
- package/hooks/suppression.py +82 -0
- package/hooks/tab-color.sh +70 -0
- package/hooks/verify-before-edit.sh +135 -0
- package/lib/backup-restore-command.js +140 -0
- package/lib/base/base-command.js +252 -0
- package/lib/base/command-result.js +184 -0
- package/lib/config/constants.js +255 -0
- package/lib/config.js +48 -6
- package/lib/configure-command.js +428 -0
- package/lib/dependency-validator.js +64 -5
- package/lib/hook-installer-core.js +2 -2
- package/lib/installation-instruction-generator.js +213 -495
- package/lib/installer.js +134 -56
- package/lib/oidc-command.js +740 -0
- package/lib/services/backup-list-service.js +226 -0
- package/lib/services/backup-service.js +230 -0
- package/lib/services/command-installer-service.js +217 -0
- package/lib/services/logger-service.js +201 -0
- package/lib/services/package-manager-service.js +319 -0
- package/lib/services/platform-instruction-service.js +294 -0
- package/lib/services/recovery-instruction-service.js +348 -0
- package/lib/services/restore-service.js +221 -0
- package/lib/setup-command.js +359 -0
- package/lib/setup-wizard.js +155 -262
- package/lib/uninstall-command.js +100 -0
- package/lib/utils/claude-path-config.js +184 -0
- package/lib/utils/file-system-utils.js +152 -0
- package/lib/utils.js +8 -4
- package/lib/verify-command.js +430 -0
- package/package.json +7 -3
- package/scripts/postinstall.js +172 -157
- package/subagents/debug-specialist.md +7 -0
- package/templates/README.md +115 -0
- package/templates/basic-settings.json +30 -0
- package/templates/comprehensive-settings.json +57 -0
- package/templates/global-claude.md +344 -0
- package/templates/hybrid-hook-config.yaml +132 -0
- package/templates/security-focused-settings.json +62 -0
- package/templates/subagent-hooks.yaml +188 -0
- package/lib/package-manager-service.js +0 -270
- package/subagents/debug-context.md +0 -197
package/lib/setup-wizard.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
116
|
-
|
|
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
|
|
130
|
-
|
|
131
|
-
|
|
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
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
164
|
-
|
|
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
|
|
179
|
-
|
|
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
|
|
194
|
-
|
|
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
|
|
207
|
-
|
|
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
|
-
|
|
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('='
|
|
234
|
-
|
|
235
|
-
const config = {};
|
|
236
|
-
|
|
222
|
+
console.log('='.repeat(50));
|
|
237
223
|
try {
|
|
238
|
-
|
|
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 };
|