@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/README.md +254 -0
- package/bin/claude-commands +132 -0
- package/lib/claude-code-compatibility.js +545 -0
- package/lib/command-selector.js +245 -0
- package/lib/config.js +182 -0
- package/lib/context-utils.js +80 -0
- package/lib/dependency-validator.js +354 -0
- package/lib/error-factory.js +394 -0
- package/lib/error-handler-utils.js +432 -0
- package/lib/error-recovery-system.js +563 -0
- package/lib/failure-recovery-installer.js +370 -0
- package/lib/hook-installer-core.js +330 -0
- package/lib/hook-installer.js +187 -0
- package/lib/hook-metadata-service.js +352 -0
- package/lib/hook-validator.js +358 -0
- package/lib/installation-configuration.js +380 -0
- package/lib/installation-instruction-generator.js +564 -0
- package/lib/installer.js +68 -0
- package/lib/package-manager-service.js +270 -0
- package/lib/permission-error-handler.js +543 -0
- package/lib/platform-utils.js +491 -0
- package/lib/setup-wizard-ui.js +245 -0
- package/lib/setup-wizard.js +355 -0
- package/lib/system-requirements-checker.js +558 -0
- package/lib/utils.js +15 -0
- package/lib/validation-utils.js +320 -0
- package/lib/version-validator-service.js +326 -0
- package/package.json +73 -0
- package/scripts/postinstall.js +182 -0
- package/scripts/validate.js +94 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
const readline = require('readline');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles user interface interactions for the setup wizard
|
|
5
|
+
* Extracted from InteractiveSetupWizard for better separation of concerns
|
|
6
|
+
*/
|
|
7
|
+
class SetupWizardUI {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.rl = null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create readline interface
|
|
14
|
+
*/
|
|
15
|
+
createInterface() {
|
|
16
|
+
this.rl = readline.createInterface({
|
|
17
|
+
input: process.stdin,
|
|
18
|
+
output: process.stdout
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Close readline interface
|
|
24
|
+
*/
|
|
25
|
+
closeInterface() {
|
|
26
|
+
if (this.rl) {
|
|
27
|
+
this.rl.close();
|
|
28
|
+
this.rl = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Display welcome message
|
|
34
|
+
*/
|
|
35
|
+
showWelcome() {
|
|
36
|
+
console.log('\nš Claude Code Custom Commands Setup Wizard');
|
|
37
|
+
console.log('='.repeat(50));
|
|
38
|
+
console.log('Welcome to the interactive setup wizard!');
|
|
39
|
+
console.log('This will guide you through configuring your Claude Code toolkit.\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Display installation types menu
|
|
44
|
+
* @param {Array} installationTypes - Available installation types
|
|
45
|
+
*/
|
|
46
|
+
showInstallationTypes(installationTypes) {
|
|
47
|
+
console.log('š¦ Installation Types:');
|
|
48
|
+
console.log('-'.repeat(25));
|
|
49
|
+
installationTypes.forEach(type => {
|
|
50
|
+
console.log(`${type.id}. ${type.name}`);
|
|
51
|
+
console.log(` ${type.description}`);
|
|
52
|
+
console.log('');
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Display command categories
|
|
58
|
+
* @param {Object} commandCategories - Available command categories
|
|
59
|
+
*/
|
|
60
|
+
showCommandCategories(commandCategories) {
|
|
61
|
+
console.log('\nš Available Command Categories:');
|
|
62
|
+
console.log('-'.repeat(35));
|
|
63
|
+
Object.entries(commandCategories).forEach(([category, commands], index) => {
|
|
64
|
+
console.log(`${index + 1}. ${category.charAt(0).toUpperCase() + category.slice(1)} (${commands.length} commands)`);
|
|
65
|
+
console.log(` Commands: ${commands.join(', ')}`);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Display available hooks
|
|
71
|
+
* @param {Array} availableHooks - Available security hooks
|
|
72
|
+
*/
|
|
73
|
+
showAvailableHooks(availableHooks) {
|
|
74
|
+
console.log('\nš Available Security Hooks:');
|
|
75
|
+
console.log('-'.repeat(30));
|
|
76
|
+
availableHooks.forEach((hook, index) => {
|
|
77
|
+
console.log(`${index + 1}. ${hook.name}`);
|
|
78
|
+
if (hook.description) {
|
|
79
|
+
console.log(` ${hook.description}`);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Display configuration templates
|
|
86
|
+
* @param {Array} templates - Available configuration templates
|
|
87
|
+
*/
|
|
88
|
+
showConfigurationTemplates(templates) {
|
|
89
|
+
console.log('\nāļø Configuration Templates:');
|
|
90
|
+
console.log('-'.repeat(28));
|
|
91
|
+
templates.forEach((template, index) => {
|
|
92
|
+
console.log(`${index + 1}. ${template.name}`);
|
|
93
|
+
console.log(` ${template.description}`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Prompt user for input
|
|
99
|
+
* @param {string} question - Question to ask
|
|
100
|
+
* @returns {Promise<string>} User's response
|
|
101
|
+
*/
|
|
102
|
+
prompt(question) {
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
this.rl.question(question, (answer) => {
|
|
105
|
+
resolve(answer.trim());
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Prompt for yes/no confirmation
|
|
112
|
+
* @param {string} question - Question to ask
|
|
113
|
+
* @param {boolean} defaultValue - Default value if user just presses enter
|
|
114
|
+
* @returns {Promise<boolean>} User's confirmation
|
|
115
|
+
*/
|
|
116
|
+
async confirmPrompt(question, defaultValue = false) {
|
|
117
|
+
const defaultText = defaultValue ? '[Y/n]' : '[y/N]';
|
|
118
|
+
const answer = await this.prompt(`${question} ${defaultText}: `);
|
|
119
|
+
|
|
120
|
+
if (answer === '') {
|
|
121
|
+
return defaultValue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return answer.toLowerCase().startsWith('y');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Prompt for numeric choice
|
|
129
|
+
* @param {string} question - Question to ask
|
|
130
|
+
* @param {number} min - Minimum valid number
|
|
131
|
+
* @param {number} max - Maximum valid number
|
|
132
|
+
* @returns {Promise<number>} User's choice
|
|
133
|
+
*/
|
|
134
|
+
async numericPrompt(question, min = 1, max = 10) {
|
|
135
|
+
while (true) {
|
|
136
|
+
const answer = await this.prompt(question);
|
|
137
|
+
const num = parseInt(answer);
|
|
138
|
+
|
|
139
|
+
if (!isNaN(num) && num >= min && num <= max) {
|
|
140
|
+
return num;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(`ā Please enter a number between ${min} and ${max}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Prompt for multiple choices
|
|
149
|
+
* @param {string} question - Question to ask
|
|
150
|
+
* @param {Array} choices - Available choices
|
|
151
|
+
* @returns {Promise<Array<number>>} User's choices
|
|
152
|
+
*/
|
|
153
|
+
async multipleChoicePrompt(question, choices) {
|
|
154
|
+
const answer = await this.prompt(`${question} (comma-separated numbers, or 'all'): `);
|
|
155
|
+
|
|
156
|
+
if (answer.toLowerCase() === 'all') {
|
|
157
|
+
return choices.map((_, index) => index + 1);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const selected = answer.split(',')
|
|
161
|
+
.map(s => parseInt(s.trim()))
|
|
162
|
+
.filter(n => !isNaN(n) && n >= 1 && n <= choices.length);
|
|
163
|
+
|
|
164
|
+
return selected.length > 0 ? selected : [1]; // Default to first choice
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Display setup summary
|
|
169
|
+
* @param {Object} config - Setup configuration
|
|
170
|
+
*/
|
|
171
|
+
showSetupSummary(config) {
|
|
172
|
+
console.log('\nš Setup Summary:');
|
|
173
|
+
console.log('='.repeat(20));
|
|
174
|
+
console.log(`Installation Type: ${config.installationType}`);
|
|
175
|
+
console.log(`Commands: ${config.selectedCommands.length} selected`);
|
|
176
|
+
console.log(`Security Hooks: ${config.securityHooks ? 'Yes' : 'No'}`);
|
|
177
|
+
console.log(`Configuration Template: ${config.configTemplate || 'None'}`);
|
|
178
|
+
console.log('');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Display progress indicator
|
|
183
|
+
* @param {string} step - Current step
|
|
184
|
+
* @param {number} current - Current step number
|
|
185
|
+
* @param {number} total - Total steps
|
|
186
|
+
*/
|
|
187
|
+
showProgress(step, current, total) {
|
|
188
|
+
const progress = 'ā'.repeat(Math.floor((current / total) * 20));
|
|
189
|
+
const empty = 'ā'.repeat(20 - progress.length);
|
|
190
|
+
console.log(`\n[${progress}${empty}] Step ${current}/${total}: ${step}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Display completion message
|
|
195
|
+
* @param {Object} result - Setup result
|
|
196
|
+
*/
|
|
197
|
+
showCompletion(result) {
|
|
198
|
+
console.log('\nš Setup Complete!');
|
|
199
|
+
console.log('='.repeat(20));
|
|
200
|
+
|
|
201
|
+
if (result.success) {
|
|
202
|
+
console.log('ā
Claude Code toolkit has been successfully configured!');
|
|
203
|
+
console.log(`š¦ Installed ${result.installedCount} commands`);
|
|
204
|
+
if (result.hooksInstalled) {
|
|
205
|
+
console.log('š Security hooks installed');
|
|
206
|
+
}
|
|
207
|
+
if (result.configApplied) {
|
|
208
|
+
console.log('āļø Configuration template applied');
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
console.log('ā Setup encountered issues:');
|
|
212
|
+
result.errors.forEach(error => console.log(` ⢠${error}`));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Display error message
|
|
218
|
+
* @param {string} message - Error message
|
|
219
|
+
* @param {Error} error - Optional error object
|
|
220
|
+
*/
|
|
221
|
+
showError(message, error = null) {
|
|
222
|
+
console.log(`\nā Error: ${message}`);
|
|
223
|
+
if (error && error.message) {
|
|
224
|
+
console.log(` Details: ${error.message}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Display warning message
|
|
230
|
+
* @param {string} message - Warning message
|
|
231
|
+
*/
|
|
232
|
+
showWarning(message) {
|
|
233
|
+
console.log(`\nā ļø Warning: ${message}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Display info message
|
|
238
|
+
* @param {string} message - Info message
|
|
239
|
+
*/
|
|
240
|
+
showInfo(message) {
|
|
241
|
+
console.log(`\nā¹ļø ${message}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = SetupWizardUI;
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Interactive Setup Wizard for REQ-007
|
|
5
|
+
* GREEN phase - Minimal implementation to pass tests
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
|
|
12
|
+
// Import extracted classes for better separation of concerns
|
|
13
|
+
const SetupWizardUI = require('./setup-wizard-ui');
|
|
14
|
+
const InstallationConfiguration = require('./installation-configuration');
|
|
15
|
+
const CommandSelector = require('./command-selector');
|
|
16
|
+
|
|
17
|
+
class InteractiveSetupWizard {
|
|
18
|
+
constructor(packageRoot) {
|
|
19
|
+
this.packageRoot = packageRoot;
|
|
20
|
+
|
|
21
|
+
// Import config module for template application
|
|
22
|
+
const config = require('./config');
|
|
23
|
+
this.applyConfigurationTemplate = config.applyConfigurationTemplate;
|
|
24
|
+
|
|
25
|
+
// Import hook installer for security hooks
|
|
26
|
+
const hookInstaller = require('./hook-installer');
|
|
27
|
+
this.installSecurityHooks = hookInstaller.installSecurityHooks;
|
|
28
|
+
this.getAvailableHooks = hookInstaller.getAvailableHooks;
|
|
29
|
+
|
|
30
|
+
// Initialize extracted components
|
|
31
|
+
this.ui = new SetupWizardUI();
|
|
32
|
+
this.config = new InstallationConfiguration(packageRoot);
|
|
33
|
+
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
|
+
];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
validateEnvironment() {
|
|
53
|
+
try {
|
|
54
|
+
// Check write permissions
|
|
55
|
+
const testFile = path.join(this.packageRoot, '.test');
|
|
56
|
+
fs.writeFileSync(testFile, 'test');
|
|
57
|
+
fs.unlinkSync(testFile);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
valid: true,
|
|
61
|
+
message: 'Environment validation passed'
|
|
62
|
+
};
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return {
|
|
65
|
+
valid: false,
|
|
66
|
+
message: `Environment validation failed: ${error.message}`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getInstallationTypes() {
|
|
72
|
+
return this.config.getInstallationTypes();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
selectInstallationType(optionId) {
|
|
76
|
+
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;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getCommandCategories() {
|
|
88
|
+
return this.commandSelector.getCommandCategories();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
selectCommandSets(categories) {
|
|
92
|
+
return this.commandSelector.selectCommandSets(categories);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getSecurityHooks() {
|
|
96
|
+
return this.securityHooks;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
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
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
getConfigurationTemplates() {
|
|
111
|
+
return this.config.getConfigurationTemplates();
|
|
112
|
+
}
|
|
113
|
+
|
|
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;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
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
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
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
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
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
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
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
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
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
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
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
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
applyPreset(presetName) {
|
|
219
|
+
return this.commandSelector.applyPreset(presetName);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
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
|
+
|
|
232
|
+
console.log('\nš Claude Dev Toolkit Interactive Setup Wizard');
|
|
233
|
+
console.log('=' .repeat(50));
|
|
234
|
+
|
|
235
|
+
const config = {};
|
|
236
|
+
|
|
237
|
+
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
|
+
|
|
317
|
+
console.log('\nā
Setup completed successfully!');
|
|
318
|
+
console.log(`Configuration saved to: ${this.configFile}`);
|
|
319
|
+
|
|
320
|
+
rl.close();
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
completed: true,
|
|
324
|
+
configuration: config
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
} catch (error) {
|
|
328
|
+
rl.close();
|
|
329
|
+
return {
|
|
330
|
+
completed: false,
|
|
331
|
+
error: error.message
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Support for PostInstaller integration
|
|
338
|
+
class PostInstaller {
|
|
339
|
+
constructor() {
|
|
340
|
+
this.packageRoot = path.join(require('os').homedir(), '.claude');
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
runSetupWizard(options = {}) {
|
|
344
|
+
if (options.skipSetup) {
|
|
345
|
+
return { skipped: true };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const wizard = new InteractiveSetupWizard(this.packageRoot);
|
|
349
|
+
return wizard.runNonInteractiveSetup();
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Export both classes
|
|
354
|
+
module.exports = InteractiveSetupWizard;
|
|
355
|
+
module.exports.PostInstaller = PostInstaller;
|