@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.
@@ -0,0 +1,564 @@
1
+ /**
2
+ * Installation Instruction Generator
3
+ *
4
+ * Generates platform-specific installation instructions and recovery guidance.
5
+ * Extracted from DependencyValidator as part of Phase 1 bloater refactoring.
6
+ *
7
+ * Features:
8
+ * - Cross-platform installation instructions
9
+ * - Package manager integration
10
+ * - Download link management
11
+ * - Alternative installation methods
12
+ * - Recovery and troubleshooting guidance
13
+ */
14
+
15
+ const PackageManagerService = require('./package-manager-service');
16
+ const PlatformUtils = require('./platform-utils');
17
+
18
+ class InstallationInstructionGenerator {
19
+ constructor() {
20
+ this.packageManagerService = new PackageManagerService();
21
+ this.platformUtils = new PlatformUtils();
22
+ this.config = {
23
+ downloadLinks: this._createDownloadLinks()
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Create download links for common tools
29
+ * @returns {Object} Download links by tool and platform
30
+ * @private
31
+ */
32
+ _createDownloadLinks() {
33
+ return {
34
+ git: {
35
+ linux: 'https://git-scm.com/download/linux',
36
+ darwin: 'https://git-scm.com/download/mac',
37
+ win32: 'https://git-scm.com/download/win'
38
+ },
39
+ node: {
40
+ all: 'https://nodejs.org/en/download/'
41
+ },
42
+ python: {
43
+ all: 'https://www.python.org/downloads/'
44
+ },
45
+ docker: {
46
+ linux: 'https://docs.docker.com/engine/install/',
47
+ darwin: 'https://docs.docker.com/desktop/install/mac-install/',
48
+ win32: 'https://docs.docker.com/desktop/install/windows-install/'
49
+ }
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Generate installation instructions for missing dependency
55
+ * @param {Object} dependency - Missing dependency
56
+ * @param {string} platform - Target platform (optional)
57
+ * @returns {Object} Installation instructions
58
+ */
59
+ generateInstallationInstructions(dependency, platform = process.platform) {
60
+ const context = this._createInstructionContext(dependency, platform);
61
+ const instructions = this._initializeInstructions(platform);
62
+
63
+ this._addPlatformPackageManagers(instructions, context);
64
+ this._setDefaultPackageManager(instructions);
65
+ this._handleNpmPackageSpecific(instructions, context);
66
+ this._addAlternativeInstallationMethods(instructions, dependency, platform);
67
+
68
+ return instructions;
69
+ }
70
+
71
+ /**
72
+ * Generate recovery suggestions for failed dependencies
73
+ * @param {Object} failedDependency - Dependency that failed validation
74
+ * @returns {Object} Recovery suggestions
75
+ */
76
+ generateRecoverySuggestions(failedDependency) {
77
+ const suggestions = {
78
+ immediate: [],
79
+ alternative: [],
80
+ troubleshooting: []
81
+ };
82
+
83
+ if (failedDependency.error) {
84
+ switch (failedDependency.error.code) {
85
+ case 'NOT_FOUND':
86
+ suggestions.immediate.push(`Try: Install ${failedDependency.name} using your package manager`);
87
+ suggestions.immediate.push(`Solution: Add ${failedDependency.name} to your system PATH`);
88
+ suggestions.alternative.push(`Use portable version of ${failedDependency.name}`);
89
+ suggestions.alternative.push(`Install via different package manager`);
90
+ break;
91
+
92
+ case 'VERSION_MISMATCH':
93
+ suggestions.immediate.push(`Try: Update ${failedDependency.name} to newer version`);
94
+ suggestions.immediate.push(`Solution: Use version manager to install required version`);
95
+ suggestions.alternative.push(`Install specific version manually`);
96
+ break;
97
+
98
+ default:
99
+ suggestions.immediate.push(`Try: Reinstall ${failedDependency.name}`);
100
+ suggestions.immediate.push(`Solution: Check system configuration`);
101
+ }
102
+ }
103
+
104
+ // Add general troubleshooting guidance
105
+ suggestions.troubleshooting = [
106
+ 'Next steps for troubleshooting: Check system logs and package manager status',
107
+ 'Verify internet connectivity for downloads',
108
+ 'Try running commands with elevated privileges',
109
+ 'Check for conflicting software installations'
110
+ ];
111
+
112
+ return suggestions;
113
+ }
114
+
115
+ /**
116
+ * Generate installation instructions for multiple dependencies
117
+ * @param {Array} dependencies - List of dependencies to install
118
+ * @param {string} platform - Target platform
119
+ * @returns {Object} Batch installation instructions
120
+ */
121
+ generateBatchInstallationInstructions(dependencies, platform = process.platform) {
122
+ const batchInstructions = {
123
+ platform: platform,
124
+ dependencies: dependencies.map(dep => dep.name),
125
+ packageManagerOptions: [],
126
+ bulkCommands: [],
127
+ individualInstructions: []
128
+ };
129
+
130
+ // Generate individual instructions
131
+ for (const dependency of dependencies) {
132
+ const individualInstructions = this.generateInstallationInstructions(dependency, platform);
133
+ batchInstructions.individualInstructions.push({
134
+ dependency: dependency.name,
135
+ instructions: individualInstructions
136
+ });
137
+ }
138
+
139
+ // Generate bulk installation commands
140
+ const packageManagers = this.packageManagerService.getPackageManagersForPlatform(platform);
141
+ for (const pm of packageManagers) {
142
+ const packages = dependencies.map(dep =>
143
+ this.packageManagerService.getPackageName(dep.name, pm.name, platform)
144
+ );
145
+
146
+ if (packages.length > 0) {
147
+ const bulkCommand = this._generateBulkInstallCommand(pm, packages);
148
+ batchInstructions.bulkCommands.push({
149
+ packageManager: pm.name,
150
+ command: bulkCommand,
151
+ packages: packages
152
+ });
153
+ }
154
+ }
155
+
156
+ return batchInstructions;
157
+ }
158
+
159
+ /**
160
+ * Generate upgrade instructions for outdated dependencies
161
+ * @param {Object} dependency - Dependency to upgrade
162
+ * @param {string} currentVersion - Current version
163
+ * @param {string} targetVersion - Target version
164
+ * @param {string} platform - Target platform
165
+ * @returns {Object} Upgrade instructions
166
+ */
167
+ generateUpgradeInstructions(dependency, currentVersion, targetVersion, platform = process.platform) {
168
+ const upgradeInstructions = {
169
+ dependency: dependency.name,
170
+ currentVersion: currentVersion,
171
+ targetVersion: targetVersion,
172
+ platform: platform,
173
+ upgradeSteps: [],
174
+ verificationSteps: [],
175
+ backupRecommendations: [],
176
+ troubleshootingTips: []
177
+ };
178
+
179
+ // Add backup recommendations
180
+ upgradeInstructions.backupRecommendations = [
181
+ `Backup current ${dependency.name} configuration if applicable`,
182
+ 'Document current working setup before upgrading',
183
+ 'Ensure you can rollback if needed'
184
+ ];
185
+
186
+ // Generate upgrade commands
187
+ const packageManagers = this.packageManagerService.getAvailablePackageManagers(platform);
188
+ for (const pm of packageManagers) {
189
+ const upgradeCommand = this._generateUpgradeCommand(pm, dependency.name, platform);
190
+ if (upgradeCommand) {
191
+ upgradeInstructions.upgradeSteps.push({
192
+ packageManager: pm.name,
193
+ command: upgradeCommand,
194
+ description: `Upgrade ${dependency.name} using ${pm.name}`
195
+ });
196
+ }
197
+ }
198
+
199
+ // Add verification steps
200
+ upgradeInstructions.verificationSteps = [
201
+ `Run: ${dependency.name} --version`,
202
+ `Verify version shows ${targetVersion} or higher`,
203
+ 'Test basic functionality to ensure upgrade was successful'
204
+ ];
205
+
206
+ // Add troubleshooting tips
207
+ upgradeInstructions.troubleshootingTips = [
208
+ 'Clear package manager cache if upgrade fails',
209
+ 'Check for dependency conflicts',
210
+ 'Restart terminal/shell after upgrade',
211
+ 'Verify PATH environment variable is correct'
212
+ ];
213
+
214
+ return upgradeInstructions;
215
+ }
216
+
217
+ /**
218
+ * Generate platform-specific installation guidance
219
+ * @param {string} platform - Target platform
220
+ * @returns {Object} Platform-specific guidance
221
+ */
222
+ generatePlatformGuidance(platform) {
223
+ const guidance = {
224
+ platform: platform,
225
+ platformName: this.platformUtils.getPlatformName(platform),
226
+ packageManagers: [],
227
+ commonIssues: [],
228
+ bestPractices: [],
229
+ systemRequirements: {}
230
+ };
231
+
232
+ // Get package managers for platform
233
+ guidance.packageManagers = this.packageManagerService.getPackageManagersForPlatform(platform)
234
+ .map(pm => ({
235
+ name: pm.name,
236
+ description: this._getPackageManagerDescription(pm.name),
237
+ installationUrl: this._getPackageManagerInstallUrl(pm.name, platform)
238
+ }));
239
+
240
+ // Platform-specific guidance
241
+ switch (platform) {
242
+ case 'win32':
243
+ guidance.commonIssues = [
244
+ 'PATH environment variable not updated',
245
+ 'PowerShell execution policy restrictions',
246
+ 'Windows Defender blocking downloads',
247
+ 'Missing Visual C++ redistributables'
248
+ ];
249
+ guidance.bestPractices = [
250
+ 'Run commands as Administrator when necessary',
251
+ 'Use PowerShell instead of Command Prompt',
252
+ 'Install package manager first (Chocolatey, Winget)',
253
+ 'Check Windows version compatibility'
254
+ ];
255
+ break;
256
+
257
+ case 'darwin':
258
+ guidance.commonIssues = [
259
+ 'Xcode Command Line Tools missing',
260
+ 'System Integrity Protection (SIP) restrictions',
261
+ 'Homebrew not installed or outdated',
262
+ 'Architecture mismatch (Intel vs Apple Silicon)'
263
+ ];
264
+ guidance.bestPractices = [
265
+ 'Install Xcode Command Line Tools first',
266
+ 'Use Homebrew for package management',
267
+ 'Check architecture compatibility (x86_64 vs arm64)',
268
+ 'Update shell profile (.zshrc) for PATH changes'
269
+ ];
270
+ break;
271
+
272
+ case 'linux':
273
+ guidance.commonIssues = [
274
+ 'Missing package repositories',
275
+ 'Insufficient permissions',
276
+ 'Outdated package lists',
277
+ 'Missing dependencies'
278
+ ];
279
+ guidance.bestPractices = [
280
+ 'Update package lists before installing',
281
+ 'Use distribution-specific package manager',
282
+ 'Install development tools if compiling from source',
283
+ 'Check distribution version compatibility'
284
+ ];
285
+ break;
286
+ }
287
+
288
+ return guidance;
289
+ }
290
+
291
+ /**
292
+ * Create instruction generation context
293
+ * @param {Object} dependency - Dependency information
294
+ * @param {string} platform - Target platform
295
+ * @returns {Object} Instruction context
296
+ * @private
297
+ */
298
+ _createInstructionContext(dependency, platform) {
299
+ return {
300
+ dependency,
301
+ platform,
302
+ platformManagers: this.packageManagerService.getPackageManagersForPlatform(platform),
303
+ dependencyMapping: this.packageManagerService.config.dependencyMappings[dependency.name]
304
+ };
305
+ }
306
+
307
+ /**
308
+ * Initialize empty instructions object
309
+ * @param {string} platform - Target platform
310
+ * @returns {Object} Empty instructions object
311
+ * @private
312
+ */
313
+ _initializeInstructions(platform) {
314
+ return {
315
+ platform: platform,
316
+ packageManager: null,
317
+ commands: [],
318
+ packageManagerOptions: [],
319
+ globalInstall: null,
320
+ localInstall: null,
321
+ alternativeOptions: []
322
+ };
323
+ }
324
+
325
+ /**
326
+ * Add platform-specific package managers to instructions
327
+ * @param {Object} instructions - Instructions object to modify
328
+ * @param {Object} context - Instruction context
329
+ * @private
330
+ */
331
+ _addPlatformPackageManagers(instructions, context) {
332
+ for (const pm of context.platformManagers) {
333
+ const packageName = this._resolvePackageName(pm, context);
334
+ const packageManagerOption = this._createPackageManagerOption(pm, packageName);
335
+ instructions.packageManagerOptions.push(packageManagerOption);
336
+ }
337
+ }
338
+
339
+ /**
340
+ * Resolve package name for specific package manager
341
+ * @param {Object} pm - Package manager configuration
342
+ * @param {Object} context - Instruction context
343
+ * @returns {string} Resolved package name
344
+ * @private
345
+ */
346
+ _resolvePackageName(pm, context) {
347
+ const { dependency, platform, dependencyMapping } = context;
348
+
349
+ if (dependencyMapping && dependencyMapping[platform] && dependencyMapping[platform][pm.name]) {
350
+ return dependencyMapping[platform][pm.name];
351
+ }
352
+
353
+ return dependency.name;
354
+ }
355
+
356
+ /**
357
+ * Create package manager option object
358
+ * @param {Object} pm - Package manager configuration
359
+ * @param {string} packageName - Resolved package name
360
+ * @returns {Object} Package manager option
361
+ * @private
362
+ */
363
+ _createPackageManagerOption(pm, packageName) {
364
+ return {
365
+ name: pm.name,
366
+ command: pm.install.replace('{package}', packageName),
367
+ check: pm.check.replace('{package}', packageName),
368
+ packageName: packageName
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Set default package manager from available options
374
+ * @param {Object} instructions - Instructions object to modify
375
+ * @private
376
+ */
377
+ _setDefaultPackageManager(instructions) {
378
+ if (instructions.packageManagerOptions.length > 0) {
379
+ const defaultPM = instructions.packageManagerOptions[0];
380
+ instructions.packageManager = defaultPM.name;
381
+ instructions.commands.push(defaultPM.command);
382
+ }
383
+ }
384
+
385
+ /**
386
+ * Handle npm package-specific instructions
387
+ * @param {Object} instructions - Instructions object to modify
388
+ * @param {Object} context - Instruction context
389
+ * @private
390
+ */
391
+ _handleNpmPackageSpecific(instructions, context) {
392
+ if (context.dependency.type !== 'npm_package') return;
393
+
394
+ this._addNpmInstallOptions(instructions, context.dependency.name);
395
+ this._ensureNpmInOptions(instructions, context.dependency.name);
396
+ this._addNpmAlternatives(instructions, context.dependency.name);
397
+ }
398
+
399
+ /**
400
+ * Add npm install options (global/local)
401
+ * @param {Object} instructions - Instructions object to modify
402
+ * @param {string} packageName - Package name
403
+ * @private
404
+ */
405
+ _addNpmInstallOptions(instructions, packageName) {
406
+ instructions.globalInstall = `npm install -g ${packageName}`;
407
+ instructions.localInstall = `npm install ${packageName}`;
408
+ }
409
+
410
+ /**
411
+ * Ensure npm is in package manager options
412
+ * @param {Object} instructions - Instructions object to modify
413
+ * @param {string} packageName - Package name
414
+ * @private
415
+ */
416
+ _ensureNpmInOptions(instructions, packageName) {
417
+ const hasNpm = instructions.packageManagerOptions.some(pm => pm.name === 'npm');
418
+ if (!hasNpm) {
419
+ instructions.packageManagerOptions.unshift({
420
+ name: 'npm',
421
+ command: `npm install -g ${packageName}`
422
+ });
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Add npm alternatives (yarn, pnpm)
428
+ * @param {Object} instructions - Instructions object to modify
429
+ * @param {string} packageName - Package name
430
+ * @private
431
+ */
432
+ _addNpmAlternatives(instructions, packageName) {
433
+ instructions.packageManagerOptions.push(
434
+ { name: 'yarn', command: `yarn global add ${packageName}` },
435
+ { name: 'pnpm', command: `pnpm add -g ${packageName}` }
436
+ );
437
+ }
438
+
439
+ /**
440
+ * Add alternative installation methods (private)
441
+ * @param {Object} instructions - Instructions to enhance
442
+ * @param {Object} dependency - Dependency information
443
+ * @param {string} platform - Target platform
444
+ * @private
445
+ */
446
+ _addAlternativeInstallationMethods(instructions, dependency, platform) {
447
+ this._addDownloadLinks(instructions, dependency, platform);
448
+ this._addDockerAlternative(instructions, dependency);
449
+ }
450
+
451
+ /**
452
+ * Add download links for dependencies (private)
453
+ * @param {Object} instructions - Instructions to enhance
454
+ * @param {Object} dependency - Dependency information
455
+ * @param {string} platform - Target platform
456
+ * @private
457
+ */
458
+ _addDownloadLinks(instructions, dependency, platform) {
459
+ const links = this.config.downloadLinks[dependency.name];
460
+ if (!links) return;
461
+
462
+ if (links.all) {
463
+ instructions.alternativeOptions.push(`Download from: ${links.all}`);
464
+ } else if (links[platform]) {
465
+ instructions.alternativeOptions.push(`Download from: ${links[platform]}`);
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Add Docker alternative for tools (private)
471
+ * @param {Object} instructions - Instructions to enhance
472
+ * @param {Object} dependency - Dependency information
473
+ * @private
474
+ */
475
+ _addDockerAlternative(instructions, dependency) {
476
+ if (dependency.type === 'tool') {
477
+ instructions.alternativeOptions.push(`Use Docker container with ${dependency.name} pre-installed`);
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Generate bulk install command for multiple packages
483
+ * @param {Object} packageManager - Package manager configuration
484
+ * @param {Array<string>} packages - List of packages
485
+ * @returns {string} Bulk install command
486
+ * @private
487
+ */
488
+ _generateBulkInstallCommand(packageManager, packages) {
489
+ const packageList = packages.join(' ');
490
+ return packageManager.install.replace('{package}', packageList);
491
+ }
492
+
493
+ /**
494
+ * Generate upgrade command for a specific package
495
+ * @param {Object} packageManager - Package manager configuration
496
+ * @param {string} packageName - Package to upgrade
497
+ * @param {string} platform - Target platform
498
+ * @returns {string} Upgrade command
499
+ * @private
500
+ */
501
+ _generateUpgradeCommand(packageManager, packageName, platform) {
502
+ const resolvedName = this.packageManagerService.getPackageName(packageName, packageManager.name, platform);
503
+
504
+ // Map package manager to upgrade commands
505
+ const upgradeCommands = {
506
+ 'apt': `sudo apt-get update && sudo apt-get upgrade ${resolvedName}`,
507
+ 'yum': `sudo yum update ${resolvedName}`,
508
+ 'dnf': `sudo dnf update ${resolvedName}`,
509
+ 'pacman': `sudo pacman -S ${resolvedName}`,
510
+ 'brew': `brew upgrade ${resolvedName}`,
511
+ 'chocolatey': `choco upgrade ${resolvedName}`,
512
+ 'winget': `winget upgrade ${resolvedName}`,
513
+ 'npm': `npm update -g ${resolvedName}`,
514
+ 'yarn': `yarn global upgrade ${resolvedName}`,
515
+ 'pnpm': `pnpm update -g ${resolvedName}`
516
+ };
517
+
518
+ return upgradeCommands[packageManager.name] || null;
519
+ }
520
+
521
+
522
+ /**
523
+ * Get package manager description
524
+ * @param {string} packageManagerName - Package manager name
525
+ * @returns {string} Description
526
+ * @private
527
+ */
528
+ _getPackageManagerDescription(packageManagerName) {
529
+ const descriptions = {
530
+ 'apt': 'Advanced Package Tool - Debian/Ubuntu package manager',
531
+ 'yum': 'Yellowdog Updater Modified - Red Hat package manager',
532
+ 'dnf': 'Dandified YUM - Modern Red Hat package manager',
533
+ 'pacman': 'Package Manager - Arch Linux package manager',
534
+ 'brew': 'Homebrew - macOS package manager',
535
+ 'chocolatey': 'Chocolatey - Windows package manager',
536
+ 'winget': 'Windows Package Manager - Microsoft package manager',
537
+ 'npm': 'Node Package Manager - JavaScript package manager',
538
+ 'yarn': 'Yarn - Fast JavaScript package manager',
539
+ 'pnpm': 'pnpm - Efficient JavaScript package manager'
540
+ };
541
+ return descriptions[packageManagerName] || `${packageManagerName} package manager`;
542
+ }
543
+
544
+ /**
545
+ * Get package manager installation URL
546
+ * @param {string} packageManagerName - Package manager name
547
+ * @param {string} platform - Target platform
548
+ * @returns {string} Installation URL
549
+ * @private
550
+ */
551
+ _getPackageManagerInstallUrl(packageManagerName, platform) {
552
+ const installUrls = {
553
+ 'brew': 'https://brew.sh/',
554
+ 'chocolatey': 'https://chocolatey.org/install',
555
+ 'winget': 'https://docs.microsoft.com/en-us/windows/package-manager/winget/',
556
+ 'npm': 'https://nodejs.org/en/download/',
557
+ 'yarn': 'https://yarnpkg.com/getting-started/install',
558
+ 'pnpm': 'https://pnpm.io/installation'
559
+ };
560
+ return installUrls[packageManagerName] || null;
561
+ }
562
+ }
563
+
564
+ module.exports = InstallationInstructionGenerator;
@@ -0,0 +1,68 @@
1
+ // Installation logic for Claude Dev Toolkit
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { ensureDirectory } = require('./utils');
6
+
7
+ module.exports = {
8
+ install: async (options = {}) => {
9
+ const claudeDir = path.join(os.homedir(), '.claude', 'commands');
10
+ const packageDir = path.join(__dirname, '..');
11
+
12
+ console.log('šŸš€ Installing Claude Custom Commands...\n');
13
+
14
+ // Ensure directories exist
15
+ ensureDirectory(claudeDir);
16
+ ensureDirectory(path.join(claudeDir, 'active'));
17
+ ensureDirectory(path.join(claudeDir, 'experimental'));
18
+
19
+ let installedCount = 0;
20
+
21
+ // Install active commands
22
+ if (options.active || options.all || (!options.active && !options.experimental)) {
23
+ const activeSource = path.join(packageDir, 'commands', 'active');
24
+ const activeTarget = path.join(claudeDir, 'active');
25
+
26
+ if (fs.existsSync(activeSource)) {
27
+ const activeFiles = fs.readdirSync(activeSource).filter(f => f.endsWith('.md'));
28
+ activeFiles.forEach(file => {
29
+ fs.copyFileSync(
30
+ path.join(activeSource, file),
31
+ path.join(activeTarget, file)
32
+ );
33
+ });
34
+ installedCount += activeFiles.length;
35
+ console.log(`āœ… Installed ${activeFiles.length} active commands`);
36
+ }
37
+ }
38
+
39
+ // Install experimental commands
40
+ if (options.experimental || options.all) {
41
+ const expSource = path.join(packageDir, 'commands', 'experiments');
42
+ const expTarget = path.join(claudeDir, 'experiments');
43
+
44
+ if (fs.existsSync(expSource)) {
45
+ const expFiles = fs.readdirSync(expSource).filter(f => f.endsWith('.md'));
46
+ expFiles.forEach(file => {
47
+ fs.copyFileSync(
48
+ path.join(expSource, file),
49
+ path.join(expTarget, file)
50
+ );
51
+ });
52
+ installedCount += expFiles.length;
53
+ console.log(`āœ… Installed ${expFiles.length} experimental commands`);
54
+ }
55
+ }
56
+
57
+ console.log(`\nšŸŽ‰ Installation complete! ${installedCount} commands installed.`);
58
+ console.log('\nNext steps:');
59
+ console.log('• Try: claude-commands list');
60
+ console.log('• Use commands in Claude Code: /xhelp');
61
+
62
+ return {
63
+ success: true,
64
+ installedPath: claudeDir,
65
+ commandsInstalled: installedCount
66
+ };
67
+ }
68
+ };