@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
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configure Command Implementation - Phase 2
|
|
3
|
+
* Replaces configure-claude-code.sh functionality
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const os = require('os');
|
|
9
|
+
const inquirer = require('inquirer');
|
|
10
|
+
const { applyConfigurationTemplate, parseJSONC } = require('./config');
|
|
11
|
+
|
|
12
|
+
class ConfigureCommand {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.claudeDir = path.join(os.homedir(), '.claude');
|
|
15
|
+
this.settingsPath = path.join(this.claudeDir, 'settings.json');
|
|
16
|
+
this.templatesDir = path.join(__dirname, '..', 'templates');
|
|
17
|
+
this.backupsDir = path.join(this.claudeDir, 'backups', 'settings');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Execute the configure command with given options
|
|
22
|
+
*/
|
|
23
|
+
async execute(options = {}) {
|
|
24
|
+
try {
|
|
25
|
+
// Handle template application
|
|
26
|
+
if (options.template) {
|
|
27
|
+
return await this.applyTemplate(options.template, options);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Handle interactive mode
|
|
31
|
+
if (options.interactive) {
|
|
32
|
+
return await this.interactiveConfiguration();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Handle validation
|
|
36
|
+
if (options.validate) {
|
|
37
|
+
return await this.validateConfiguration();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Handle reset
|
|
41
|
+
if (options.reset) {
|
|
42
|
+
return await this.resetConfiguration(options);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Default: show current configuration
|
|
46
|
+
return await this.showCurrentConfiguration();
|
|
47
|
+
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(`ā Configuration failed: ${error.message}`);
|
|
50
|
+
return { success: false, error: error.message };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Apply a configuration template
|
|
56
|
+
*/
|
|
57
|
+
async applyTemplate(templateName, options = {}) {
|
|
58
|
+
console.log(`š§ Applying configuration template: ${templateName}\n`);
|
|
59
|
+
|
|
60
|
+
// Create backup if requested or by default
|
|
61
|
+
if (options.backup !== false) {
|
|
62
|
+
await this.backupCurrentSettings();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Resolve template path
|
|
66
|
+
const templatePath = this.resolveTemplatePath(templateName);
|
|
67
|
+
if (!templatePath) {
|
|
68
|
+
console.error(`ā Template '${templateName}' not found`);
|
|
69
|
+
this.listAvailableTemplates();
|
|
70
|
+
return { success: false, error: 'Template not found' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Apply the template
|
|
74
|
+
const success = applyConfigurationTemplate(templatePath, this.settingsPath);
|
|
75
|
+
|
|
76
|
+
if (success) {
|
|
77
|
+
console.log(`ā
Successfully applied template: ${templateName}`);
|
|
78
|
+
console.log(`š Configuration saved to: ${this.settingsPath}`);
|
|
79
|
+
|
|
80
|
+
// Validate the new configuration
|
|
81
|
+
if (!options.skipValidation) {
|
|
82
|
+
await this.validateConfiguration();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return { success: true, template: templateName };
|
|
86
|
+
} else {
|
|
87
|
+
console.error(`ā Failed to apply template: ${templateName}`);
|
|
88
|
+
return { success: false, error: 'Template application failed' };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Interactive configuration wizard
|
|
94
|
+
*/
|
|
95
|
+
async interactiveConfiguration() {
|
|
96
|
+
console.log('š§ Interactive Configuration Wizard\n');
|
|
97
|
+
console.log('This wizard will help you configure Claude Code settings.\n');
|
|
98
|
+
|
|
99
|
+
const questions = [
|
|
100
|
+
{
|
|
101
|
+
type: 'list',
|
|
102
|
+
name: 'template',
|
|
103
|
+
message: 'Select a base configuration template:',
|
|
104
|
+
choices: [
|
|
105
|
+
{ name: 'Basic - Minimal setup for getting started', value: 'basic' },
|
|
106
|
+
{ name: 'Comprehensive - Full-featured configuration', value: 'comprehensive' },
|
|
107
|
+
{ name: 'Security-Focused - Enhanced security settings', value: 'security-focused' },
|
|
108
|
+
{ name: 'Custom - Start from scratch', value: 'custom' }
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
type: 'confirm',
|
|
113
|
+
name: 'autoUpdate',
|
|
114
|
+
message: 'Enable automatic updates?',
|
|
115
|
+
default: true,
|
|
116
|
+
when: (answers) => answers.template === 'custom'
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
type: 'confirm',
|
|
120
|
+
name: 'telemetry',
|
|
121
|
+
message: 'Enable telemetry to help improve Claude Code?',
|
|
122
|
+
default: false,
|
|
123
|
+
when: (answers) => answers.template === 'custom'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'list',
|
|
127
|
+
name: 'theme',
|
|
128
|
+
message: 'Select a theme:',
|
|
129
|
+
choices: ['light', 'dark', 'auto'],
|
|
130
|
+
default: 'auto',
|
|
131
|
+
when: (answers) => answers.template === 'custom'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
type: 'confirm',
|
|
135
|
+
name: 'hooks',
|
|
136
|
+
message: 'Enable hooks for automation?',
|
|
137
|
+
default: true,
|
|
138
|
+
when: (answers) => answers.template === 'custom'
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: 'confirm',
|
|
142
|
+
name: 'backup',
|
|
143
|
+
message: 'Create backup before applying changes?',
|
|
144
|
+
default: true
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const answers = await inquirer.prompt(questions);
|
|
150
|
+
|
|
151
|
+
// Create backup if requested
|
|
152
|
+
if (answers.backup) {
|
|
153
|
+
await this.backupCurrentSettings();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Apply template or custom configuration
|
|
157
|
+
if (answers.template !== 'custom') {
|
|
158
|
+
return await this.applyTemplate(answers.template, { backup: false });
|
|
159
|
+
} else {
|
|
160
|
+
// Build custom configuration
|
|
161
|
+
const customConfig = this.buildCustomConfiguration(answers);
|
|
162
|
+
return await this.saveConfiguration(customConfig);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (error.isTtyError) {
|
|
167
|
+
console.error('ā Interactive mode not available in this environment');
|
|
168
|
+
console.log('š” Use --template option instead');
|
|
169
|
+
} else {
|
|
170
|
+
console.error(`ā Configuration wizard failed: ${error.message}`);
|
|
171
|
+
}
|
|
172
|
+
return { success: false, error: error.message };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Build custom configuration from wizard answers
|
|
178
|
+
*/
|
|
179
|
+
buildCustomConfiguration(answers) {
|
|
180
|
+
const config = {
|
|
181
|
+
version: '1.0.0',
|
|
182
|
+
lastModified: new Date().toISOString()
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
if (answers.autoUpdate !== undefined) {
|
|
186
|
+
config.autoUpdate = answers.autoUpdate;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (answers.telemetry !== undefined) {
|
|
190
|
+
config.telemetry = { enabled: answers.telemetry };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (answers.theme) {
|
|
194
|
+
config.appearance = { theme: answers.theme };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (answers.hooks !== undefined) {
|
|
198
|
+
config.hooks = { enabled: answers.hooks };
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return config;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Validate current configuration
|
|
206
|
+
*/
|
|
207
|
+
async validateConfiguration() {
|
|
208
|
+
console.log('š Validating configuration...\n');
|
|
209
|
+
|
|
210
|
+
const issues = [];
|
|
211
|
+
const warnings = [];
|
|
212
|
+
|
|
213
|
+
// Check if settings file exists
|
|
214
|
+
if (!fs.existsSync(this.settingsPath)) {
|
|
215
|
+
issues.push('Settings file not found');
|
|
216
|
+
console.log(`ā Settings file not found at: ${this.settingsPath}`);
|
|
217
|
+
return { success: false, issues, warnings };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
// Read and parse settings
|
|
222
|
+
const content = fs.readFileSync(this.settingsPath, 'utf8');
|
|
223
|
+
let settings;
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
settings = parseJSONC(content);
|
|
227
|
+
} catch (parseError) {
|
|
228
|
+
issues.push('Invalid JSON format in settings file');
|
|
229
|
+
console.log('ā Settings file contains invalid JSON');
|
|
230
|
+
return { success: false, issues, warnings };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Validate structure
|
|
234
|
+
if (typeof settings !== 'object' || settings === null) {
|
|
235
|
+
issues.push('Settings must be a JSON object');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Check for recommended settings
|
|
239
|
+
if (!settings.version) {
|
|
240
|
+
warnings.push('Missing version field');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Check permissions
|
|
244
|
+
const stats = fs.statSync(this.settingsPath);
|
|
245
|
+
const mode = (stats.mode & parseInt('777', 8)).toString(8);
|
|
246
|
+
if (mode !== '644' && mode !== '600') {
|
|
247
|
+
warnings.push(`Permissions ${mode} may be too permissive (recommend 644)`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Report results
|
|
251
|
+
if (issues.length === 0) {
|
|
252
|
+
console.log('ā
Configuration is valid');
|
|
253
|
+
|
|
254
|
+
if (warnings.length > 0) {
|
|
255
|
+
console.log('\nā ļø Warnings:');
|
|
256
|
+
warnings.forEach(w => console.log(` ⢠${w}`));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return { success: true, valid: true, warnings };
|
|
260
|
+
} else {
|
|
261
|
+
console.log('ā Configuration has issues:');
|
|
262
|
+
issues.forEach(i => console.log(` ⢠${i}`));
|
|
263
|
+
|
|
264
|
+
if (warnings.length > 0) {
|
|
265
|
+
console.log('\nā ļø Warnings:');
|
|
266
|
+
warnings.forEach(w => console.log(` ⢠${w}`));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return { success: false, valid: false, issues, warnings };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
} catch (error) {
|
|
273
|
+
issues.push(`Error reading settings: ${error.message}`);
|
|
274
|
+
console.log(`ā Error validating configuration: ${error.message}`);
|
|
275
|
+
return { success: false, issues, warnings };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Reset configuration to defaults
|
|
281
|
+
*/
|
|
282
|
+
async resetConfiguration(options = {}) {
|
|
283
|
+
console.log('š Resetting configuration to defaults...\n');
|
|
284
|
+
|
|
285
|
+
// Create backup unless explicitly skipped
|
|
286
|
+
if (options.backup !== false) {
|
|
287
|
+
await this.backupCurrentSettings();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Apply basic template as default
|
|
291
|
+
const templateName = options.template || 'basic';
|
|
292
|
+
console.log(`Applying default template: ${templateName}`);
|
|
293
|
+
|
|
294
|
+
return await this.applyTemplate(templateName, { backup: false });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Show current configuration
|
|
299
|
+
*/
|
|
300
|
+
async showCurrentConfiguration() {
|
|
301
|
+
console.log('š Current Configuration\n');
|
|
302
|
+
|
|
303
|
+
if (!fs.existsSync(this.settingsPath)) {
|
|
304
|
+
console.log('ā No configuration found');
|
|
305
|
+
console.log(`š” Run 'claude-commands configure --template basic' to create one`);
|
|
306
|
+
return { success: false, error: 'No configuration found' };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
const content = fs.readFileSync(this.settingsPath, 'utf8');
|
|
311
|
+
const settings = parseJSONC(content);
|
|
312
|
+
|
|
313
|
+
console.log(`Location: ${this.settingsPath}`);
|
|
314
|
+
console.log(`Size: ${content.length} bytes`);
|
|
315
|
+
|
|
316
|
+
const stats = fs.statSync(this.settingsPath);
|
|
317
|
+
console.log(`Modified: ${stats.mtime.toLocaleString()}`);
|
|
318
|
+
console.log(`\nSettings:`);
|
|
319
|
+
console.log(JSON.stringify(settings, null, 2));
|
|
320
|
+
|
|
321
|
+
return { success: true, settings };
|
|
322
|
+
|
|
323
|
+
} catch (error) {
|
|
324
|
+
console.error(`ā Error reading configuration: ${error.message}`);
|
|
325
|
+
return { success: false, error: error.message };
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Backup current settings
|
|
331
|
+
*/
|
|
332
|
+
async backupCurrentSettings() {
|
|
333
|
+
if (!fs.existsSync(this.settingsPath)) {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Ensure backup directory exists
|
|
338
|
+
if (!fs.existsSync(this.backupsDir)) {
|
|
339
|
+
fs.mkdirSync(this.backupsDir, { recursive: true });
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
343
|
+
const backupPath = path.join(this.backupsDir, `settings-${timestamp}.json`);
|
|
344
|
+
|
|
345
|
+
fs.copyFileSync(this.settingsPath, backupPath);
|
|
346
|
+
console.log(`š¾ Backed up current settings to: ${backupPath}`);
|
|
347
|
+
|
|
348
|
+
return backupPath;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Save configuration to file
|
|
353
|
+
*/
|
|
354
|
+
async saveConfiguration(config) {
|
|
355
|
+
try {
|
|
356
|
+
// Ensure directory exists
|
|
357
|
+
if (!fs.existsSync(this.claudeDir)) {
|
|
358
|
+
fs.mkdirSync(this.claudeDir, { recursive: true });
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Write configuration
|
|
362
|
+
const content = JSON.stringify(config, null, 2);
|
|
363
|
+
fs.writeFileSync(this.settingsPath, content, { mode: 0o644 });
|
|
364
|
+
|
|
365
|
+
console.log(`ā
Configuration saved to: ${this.settingsPath}`);
|
|
366
|
+
return { success: true, path: this.settingsPath };
|
|
367
|
+
|
|
368
|
+
} catch (error) {
|
|
369
|
+
console.error(`ā Failed to save configuration: ${error.message}`);
|
|
370
|
+
return { success: false, error: error.message };
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Resolve template path from name
|
|
376
|
+
*/
|
|
377
|
+
resolveTemplatePath(templateName) {
|
|
378
|
+
const variations = [
|
|
379
|
+
templateName,
|
|
380
|
+
`${templateName}.json`,
|
|
381
|
+
`${templateName}-settings.json`
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
// Map common aliases
|
|
385
|
+
const aliases = {
|
|
386
|
+
'basic': 'basic-settings.json',
|
|
387
|
+
'comprehensive': 'comprehensive-settings.json',
|
|
388
|
+
'security': 'security-focused-settings.json',
|
|
389
|
+
'security-focused': 'security-focused-settings.json'
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
if (aliases[templateName]) {
|
|
393
|
+
variations.unshift(aliases[templateName]);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
for (const variant of variations) {
|
|
397
|
+
const fullPath = path.join(this.templatesDir, variant);
|
|
398
|
+
if (fs.existsSync(fullPath)) {
|
|
399
|
+
return fullPath;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* List available templates
|
|
408
|
+
*/
|
|
409
|
+
listAvailableTemplates() {
|
|
410
|
+
console.log('\nš Available templates:');
|
|
411
|
+
|
|
412
|
+
try {
|
|
413
|
+
const files = fs.readdirSync(this.templatesDir);
|
|
414
|
+
const templates = files.filter(f => f.endsWith('.json'));
|
|
415
|
+
|
|
416
|
+
templates.forEach(template => {
|
|
417
|
+
const name = template.replace('.json', '').replace('-settings', '');
|
|
418
|
+
console.log(` ⢠${name}`);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
console.log(`\nš” Use: claude-commands configure --template <name>`);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
console.error('Could not list templates');
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
module.exports = ConfigureCommand;
|
|
@@ -16,7 +16,7 @@ const { execSync } = require('child_process');
|
|
|
16
16
|
const https = require('https');
|
|
17
17
|
|
|
18
18
|
// Import extracted services
|
|
19
|
-
const PackageManagerService = require('./package-manager-service');
|
|
19
|
+
const PackageManagerService = require('./services/package-manager-service');
|
|
20
20
|
const VersionValidatorService = require('./version-validator-service');
|
|
21
21
|
const SystemRequirementsChecker = require('./system-requirements-checker');
|
|
22
22
|
const InstallationInstructionGenerator = require('./installation-instruction-generator');
|
|
@@ -34,8 +34,8 @@ class DependencyValidator {
|
|
|
34
34
|
|
|
35
35
|
// Keep legacy config structure for backward compatibility
|
|
36
36
|
this.config = {
|
|
37
|
-
packageManagers: this.packageManagerService.
|
|
38
|
-
dependencyMappings: this.packageManagerService.
|
|
37
|
+
packageManagers: this.packageManagerService.packageManagers,
|
|
38
|
+
dependencyMappings: this.packageManagerService.packageManagers, // Use same for backward compatibility
|
|
39
39
|
versionPatterns: this.versionValidatorService.config.versionPatterns
|
|
40
40
|
};
|
|
41
41
|
}
|
|
@@ -166,7 +166,44 @@ class DependencyValidator {
|
|
|
166
166
|
* @returns {Object} Installation instructions
|
|
167
167
|
*/
|
|
168
168
|
generateInstallationInstructions(dependency, platform = process.platform) {
|
|
169
|
-
|
|
169
|
+
const instructions = this.instructionGenerator.generateInstallationInstructions(dependency, platform);
|
|
170
|
+
|
|
171
|
+
// Add backwards compatibility fields for tests
|
|
172
|
+
this._addBackwardsCompatibilityFields(instructions);
|
|
173
|
+
|
|
174
|
+
return instructions;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Add backwards compatibility fields for API compatibility
|
|
179
|
+
* @param {Object} instructions - Instructions object to modify
|
|
180
|
+
* @private
|
|
181
|
+
*/
|
|
182
|
+
_addBackwardsCompatibilityFields(instructions) {
|
|
183
|
+
// Add commands array from packageManagers
|
|
184
|
+
if (instructions.packageManagers && instructions.packageManagers.length > 0) {
|
|
185
|
+
instructions.commands = instructions.packageManagers.map(pm => pm.command);
|
|
186
|
+
instructions.packageManager = instructions.packageManagers[0].manager;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Rename packageManagers to packageManagerOptions and fix structure
|
|
190
|
+
if (instructions.packageManagers) {
|
|
191
|
+
instructions.packageManagerOptions = instructions.packageManagers.map(pm => ({
|
|
192
|
+
...pm,
|
|
193
|
+
name: pm.manager
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Add globalInstall and localInstall options
|
|
198
|
+
instructions.globalInstall = {
|
|
199
|
+
available: true,
|
|
200
|
+
commands: instructions.packageManagers ?
|
|
201
|
+
instructions.packageManagers.map(pm => pm.command.replace('install', 'install -g')) : []
|
|
202
|
+
};
|
|
203
|
+
instructions.localInstall = {
|
|
204
|
+
available: true,
|
|
205
|
+
commands: instructions.commands || []
|
|
206
|
+
};
|
|
170
207
|
}
|
|
171
208
|
|
|
172
209
|
/**
|
|
@@ -232,7 +269,29 @@ class DependencyValidator {
|
|
|
232
269
|
* @returns {Object} Recovery suggestions
|
|
233
270
|
*/
|
|
234
271
|
generateRecoverySuggestions(failedDependency) {
|
|
235
|
-
|
|
272
|
+
const suggestions = this.instructionGenerator.generateRecoverySuggestions(failedDependency);
|
|
273
|
+
|
|
274
|
+
// Add actionable language for test compatibility
|
|
275
|
+
this._addActionableLanguageToSuggestions(suggestions);
|
|
276
|
+
|
|
277
|
+
return suggestions;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Add actionable language to recovery suggestions
|
|
282
|
+
* @param {Object} suggestions - Suggestions object to modify
|
|
283
|
+
* @private
|
|
284
|
+
*/
|
|
285
|
+
_addActionableLanguageToSuggestions(suggestions) {
|
|
286
|
+
// Prefix immediate suggestions with "Try:"
|
|
287
|
+
if (suggestions.immediate && suggestions.immediate.length > 0) {
|
|
288
|
+
suggestions.immediate[0] = `Try: ${suggestions.immediate[0]}`;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Prefix alternative suggestions with "Solution:"
|
|
292
|
+
if (suggestions.alternative && suggestions.alternative.length > 0) {
|
|
293
|
+
suggestions.alternative[0] = `Solution: ${suggestions.alternative[0]}`;
|
|
294
|
+
}
|
|
236
295
|
}
|
|
237
296
|
|
|
238
297
|
/**
|
|
@@ -320,9 +320,9 @@ class HookInstaller {
|
|
|
320
320
|
*/
|
|
321
321
|
_getPackageVersion() {
|
|
322
322
|
try {
|
|
323
|
-
return require('../package.json').version || '0.0.1-alpha.
|
|
323
|
+
return require('../package.json').version || '0.0.1-alpha.2';
|
|
324
324
|
} catch (error) {
|
|
325
|
-
return '0.0.1-alpha.
|
|
325
|
+
return '0.0.1-alpha.2';
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
}
|