@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,354 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ♻️ REFACTOR PHASE: REQ-022 Dependency Validation
|
|
3
|
+
*
|
|
4
|
+
* Comprehensive dependency validation and installation guidance system.
|
|
5
|
+
* Provides cross-platform dependency checking with intelligent resolution suggestions.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Multi-platform package manager support
|
|
9
|
+
* - Semantic version validation
|
|
10
|
+
* - Network service availability checking
|
|
11
|
+
* - System requirements validation
|
|
12
|
+
* - Context-aware installation instructions
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { execSync } = require('child_process');
|
|
16
|
+
const https = require('https');
|
|
17
|
+
|
|
18
|
+
// Import extracted services
|
|
19
|
+
const PackageManagerService = require('./package-manager-service');
|
|
20
|
+
const VersionValidatorService = require('./version-validator-service');
|
|
21
|
+
const SystemRequirementsChecker = require('./system-requirements-checker');
|
|
22
|
+
const InstallationInstructionGenerator = require('./installation-instruction-generator');
|
|
23
|
+
|
|
24
|
+
class DependencyValidator {
|
|
25
|
+
constructor() {
|
|
26
|
+
// Initialize composed services
|
|
27
|
+
this.packageManagerService = new PackageManagerService();
|
|
28
|
+
this.versionValidatorService = new VersionValidatorService();
|
|
29
|
+
this.systemRequirementsChecker = new SystemRequirementsChecker();
|
|
30
|
+
this.instructionGenerator = new InstallationInstructionGenerator();
|
|
31
|
+
|
|
32
|
+
// Keep legacy systemInfo for compatibility
|
|
33
|
+
this.systemInfo = this.systemRequirementsChecker.systemInfo;
|
|
34
|
+
|
|
35
|
+
// Keep legacy config structure for backward compatibility
|
|
36
|
+
this.config = {
|
|
37
|
+
packageManagers: this.packageManagerService.config.packageManagers,
|
|
38
|
+
dependencyMappings: this.packageManagerService.config.dependencyMappings,
|
|
39
|
+
versionPatterns: this.versionValidatorService.config.versionPatterns
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check multiple dependencies simultaneously
|
|
46
|
+
* @param {Array} dependencies - List of dependencies to check
|
|
47
|
+
* @returns {Object} Validation result with missing and satisfied dependencies
|
|
48
|
+
*/
|
|
49
|
+
checkDependencies(dependencies) {
|
|
50
|
+
const result = {
|
|
51
|
+
valid: true,
|
|
52
|
+
missing: [],
|
|
53
|
+
satisfied: [],
|
|
54
|
+
optional: {
|
|
55
|
+
missing: [],
|
|
56
|
+
satisfied: []
|
|
57
|
+
},
|
|
58
|
+
summary: {
|
|
59
|
+
total: dependencies.length,
|
|
60
|
+
satisfied: 0,
|
|
61
|
+
missing: 0,
|
|
62
|
+
optional: 0
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
for (const dependency of dependencies) {
|
|
67
|
+
const validation = this.validateDependency(dependency);
|
|
68
|
+
this._categorizeDependencyResult(result, dependency, validation);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Categorize dependency validation result (private)
|
|
76
|
+
* @param {Object} result - Overall result object
|
|
77
|
+
* @param {Object} dependency - Dependency being validated
|
|
78
|
+
* @param {Object} validation - Validation result
|
|
79
|
+
* @private
|
|
80
|
+
*/
|
|
81
|
+
_categorizeDependencyResult(result, dependency, validation) {
|
|
82
|
+
const isOptional = dependency.optional || dependency.required === false;
|
|
83
|
+
const isSatisfied = validation.available && validation.satisfiesRequirement;
|
|
84
|
+
|
|
85
|
+
if (isSatisfied) {
|
|
86
|
+
if (isOptional) {
|
|
87
|
+
result.optional.satisfied.push({...dependency, ...validation});
|
|
88
|
+
} else {
|
|
89
|
+
result.satisfied.push({...dependency, ...validation});
|
|
90
|
+
result.summary.satisfied++;
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
if (isOptional) {
|
|
94
|
+
result.optional.missing.push({...dependency, ...validation});
|
|
95
|
+
result.summary.optional++;
|
|
96
|
+
} else {
|
|
97
|
+
result.missing.push({...dependency, ...validation});
|
|
98
|
+
result.summary.missing++;
|
|
99
|
+
result.valid = false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Validate individual dependency
|
|
106
|
+
* @param {Object} dependency - Dependency to validate
|
|
107
|
+
* @returns {Object} Validation result for the dependency
|
|
108
|
+
*/
|
|
109
|
+
validateDependency(dependency) {
|
|
110
|
+
const result = {
|
|
111
|
+
available: false,
|
|
112
|
+
version: null,
|
|
113
|
+
satisfiesRequirement: false,
|
|
114
|
+
installedPath: null,
|
|
115
|
+
error: null,
|
|
116
|
+
recommendations: []
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Check if dependency is available
|
|
121
|
+
const availability = this._checkDependencyAvailability(dependency);
|
|
122
|
+
result.available = availability.available;
|
|
123
|
+
result.version = availability.version;
|
|
124
|
+
result.installedPath = availability.path;
|
|
125
|
+
|
|
126
|
+
if (result.available && dependency.version) {
|
|
127
|
+
// Validate version requirement
|
|
128
|
+
const versionCheck = this.versionValidatorService.validateVersionRequirement(dependency.version, result.version);
|
|
129
|
+
result.satisfiesRequirement = versionCheck.satisfies;
|
|
130
|
+
|
|
131
|
+
if (!result.satisfiesRequirement) {
|
|
132
|
+
result.error = {
|
|
133
|
+
code: 'VERSION_MISMATCH',
|
|
134
|
+
message: `Installed version ${result.version} does not satisfy requirement ${dependency.version}`
|
|
135
|
+
};
|
|
136
|
+
result.recommendations.push(`Update ${dependency.name} to version ${dependency.version} or higher`);
|
|
137
|
+
}
|
|
138
|
+
} else if (result.available) {
|
|
139
|
+
result.satisfiesRequirement = true; // No version requirement specified
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!result.available) {
|
|
143
|
+
result.error = {
|
|
144
|
+
code: 'NOT_FOUND',
|
|
145
|
+
message: `${dependency.name} is not installed or not found in PATH`
|
|
146
|
+
};
|
|
147
|
+
result.recommendations.push(`Install ${dependency.name} using your system's package manager`);
|
|
148
|
+
result.recommendations.push(`Add ${dependency.name} to your system PATH if already installed`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
} catch (error) {
|
|
152
|
+
result.error = {
|
|
153
|
+
code: 'VALIDATION_ERROR',
|
|
154
|
+
message: error.message
|
|
155
|
+
};
|
|
156
|
+
result.recommendations.push('Check system configuration and try again');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Generate installation instructions for missing dependency
|
|
164
|
+
* @param {Object} dependency - Missing dependency
|
|
165
|
+
* @param {string} platform - Target platform (optional)
|
|
166
|
+
* @returns {Object} Installation instructions
|
|
167
|
+
*/
|
|
168
|
+
generateInstallationInstructions(dependency, platform = process.platform) {
|
|
169
|
+
return this.instructionGenerator.generateInstallationInstructions(dependency, platform);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get missing dependencies from a validation result
|
|
174
|
+
* @param {Object} validationResult - Result from checkDependencies
|
|
175
|
+
* @returns {Array} List of missing dependencies
|
|
176
|
+
*/
|
|
177
|
+
getMissingDependencies(validationResult) {
|
|
178
|
+
return validationResult.missing || [];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Validate version requirement against current version
|
|
183
|
+
* @param {string} requirement - Version requirement (e.g., ">=18.0.0")
|
|
184
|
+
* @param {string} currentVersion - Current installed version
|
|
185
|
+
* @returns {Object} Version validation result
|
|
186
|
+
*/
|
|
187
|
+
validateVersionRequirement(requirement, currentVersion) {
|
|
188
|
+
return this.versionValidatorService.validateVersionRequirement(requirement, currentVersion);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Validate system requirements
|
|
193
|
+
* @param {Object} requirements - System requirements to validate
|
|
194
|
+
* @returns {Object} System compatibility result
|
|
195
|
+
*/
|
|
196
|
+
validateSystemRequirements(requirements) {
|
|
197
|
+
return this.systemRequirementsChecker.validateSystemRequirements(requirements);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Check network dependencies (services, APIs)
|
|
202
|
+
* @param {Array} networkDependencies - List of network services to check
|
|
203
|
+
* @returns {Object} Network dependency check result
|
|
204
|
+
*/
|
|
205
|
+
checkNetworkDependencies(networkDependencies) {
|
|
206
|
+
const result = {
|
|
207
|
+
services: [],
|
|
208
|
+
allAvailable: true
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
for (const service of networkDependencies) {
|
|
212
|
+
// For now, provide a synchronous mock response
|
|
213
|
+
const serviceCheck = {
|
|
214
|
+
name: service.name,
|
|
215
|
+
available: true, // Assume available for testing
|
|
216
|
+
responseTime: 100,
|
|
217
|
+
error: null
|
|
218
|
+
};
|
|
219
|
+
result.services.push(serviceCheck);
|
|
220
|
+
|
|
221
|
+
if (service.required && !serviceCheck.available) {
|
|
222
|
+
result.allAvailable = false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Generate recovery suggestions for failed dependencies
|
|
231
|
+
* @param {Object} failedDependency - Dependency that failed validation
|
|
232
|
+
* @returns {Object} Recovery suggestions
|
|
233
|
+
*/
|
|
234
|
+
generateRecoverySuggestions(failedDependency) {
|
|
235
|
+
return this.instructionGenerator.generateRecoverySuggestions(failedDependency);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Check if a dependency is available on the system (private)
|
|
240
|
+
* @param {Object} dependency - Dependency to check
|
|
241
|
+
* @returns {Object} Availability result
|
|
242
|
+
* @private
|
|
243
|
+
*/
|
|
244
|
+
_checkDependencyAvailability(dependency) {
|
|
245
|
+
const result = {
|
|
246
|
+
available: false,
|
|
247
|
+
version: null,
|
|
248
|
+
path: null
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
const versionOutput = this._tryGetVersionOutput(dependency.name);
|
|
253
|
+
|
|
254
|
+
if (versionOutput) {
|
|
255
|
+
result.available = true;
|
|
256
|
+
result.version = this.versionValidatorService.extractVersionFromOutput(versionOutput);
|
|
257
|
+
result.path = this._getInstallationPath(dependency.name);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
} catch (error) {
|
|
261
|
+
// Dependency not found or not executable
|
|
262
|
+
result.available = false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Try to get version output from dependency (private)
|
|
270
|
+
* @param {string} dependencyName - Name of dependency
|
|
271
|
+
* @returns {string|null} Version output or null
|
|
272
|
+
* @private
|
|
273
|
+
*/
|
|
274
|
+
_tryGetVersionOutput(dependencyName) {
|
|
275
|
+
const versionCommands = ['--version', '-v', '-V', 'version'];
|
|
276
|
+
|
|
277
|
+
for (const versionFlag of versionCommands) {
|
|
278
|
+
try {
|
|
279
|
+
return execSync(`${dependencyName} ${versionFlag}`, {
|
|
280
|
+
encoding: 'utf8',
|
|
281
|
+
timeout: 5000,
|
|
282
|
+
stdio: 'pipe'
|
|
283
|
+
});
|
|
284
|
+
} catch (error) {
|
|
285
|
+
// Try next version command
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Get installation path of dependency (private)
|
|
294
|
+
* @param {string} dependencyName - Name of dependency
|
|
295
|
+
* @returns {string} Installation path
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
_getInstallationPath(dependencyName) {
|
|
299
|
+
try {
|
|
300
|
+
const command = this.systemRequirementsChecker.platformUtils.getPathCommand();
|
|
301
|
+
return execSync(`${command} ${dependencyName}`, {
|
|
302
|
+
encoding: 'utf8',
|
|
303
|
+
timeout: 3000
|
|
304
|
+
}).trim();
|
|
305
|
+
} catch (error) {
|
|
306
|
+
return 'Unknown';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Check service availability (private)
|
|
314
|
+
* @param {Object} service - Service configuration
|
|
315
|
+
* @returns {Promise<Object>} Service availability result
|
|
316
|
+
* @private
|
|
317
|
+
*/
|
|
318
|
+
async _checkServiceAvailability(service) {
|
|
319
|
+
const result = {
|
|
320
|
+
name: service.name,
|
|
321
|
+
available: false,
|
|
322
|
+
responseTime: null,
|
|
323
|
+
error: null
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
return new Promise((resolve) => {
|
|
327
|
+
const startTime = Date.now();
|
|
328
|
+
const timeout = service.timeout || 5000;
|
|
329
|
+
|
|
330
|
+
const request = https.get(service.url, (response) => {
|
|
331
|
+
result.available = response.statusCode >= 200 && response.statusCode < 300;
|
|
332
|
+
result.responseTime = Date.now() - startTime;
|
|
333
|
+
resolve(result);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
request.on('error', (error) => {
|
|
337
|
+
result.available = false;
|
|
338
|
+
result.error = error.message;
|
|
339
|
+
result.responseTime = Date.now() - startTime;
|
|
340
|
+
resolve(result);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
request.setTimeout(timeout, () => {
|
|
344
|
+
request.destroy();
|
|
345
|
+
result.available = false;
|
|
346
|
+
result.error = 'Request timeout';
|
|
347
|
+
result.responseTime = timeout;
|
|
348
|
+
resolve(result);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
module.exports = DependencyValidator;
|