@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,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized Logger Service
|
|
3
|
+
* Provides consistent logging across the entire application with context support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class LoggerService {
|
|
7
|
+
constructor(options = {}) {
|
|
8
|
+
this.options = {
|
|
9
|
+
timestamp: options.timestamp ?? true,
|
|
10
|
+
context: options.context ?? true,
|
|
11
|
+
colors: options.colors ?? true,
|
|
12
|
+
level: options.level ?? 'info' // debug, info, warn, error
|
|
13
|
+
};
|
|
14
|
+
this.contextData = {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set persistent context data for all log messages
|
|
19
|
+
*/
|
|
20
|
+
setContext(context) {
|
|
21
|
+
this.contextData = { ...this.contextData, ...context };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Clear all context data
|
|
26
|
+
*/
|
|
27
|
+
clearContext() {
|
|
28
|
+
this.contextData = {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Success message logging
|
|
33
|
+
*/
|
|
34
|
+
success(message, context = {}) {
|
|
35
|
+
this._log('success', '✅', message, context);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Information message logging
|
|
40
|
+
*/
|
|
41
|
+
info(message, context = {}) {
|
|
42
|
+
this._log('info', 'ℹ️', message, context);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Warning message logging
|
|
47
|
+
*/
|
|
48
|
+
warn(message, context = {}) {
|
|
49
|
+
this._log('warn', '⚠️', message, context);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Error message logging
|
|
54
|
+
*/
|
|
55
|
+
error(message, error = null, context = {}) {
|
|
56
|
+
const errorContext = error ? { error: this._serializeError(error), ...context } : context;
|
|
57
|
+
this._log('error', '❌', message, errorContext);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Debug message logging
|
|
62
|
+
*/
|
|
63
|
+
debug(message, context = {}) {
|
|
64
|
+
if (this.options.level === 'debug') {
|
|
65
|
+
this._log('debug', '🔍', message, context);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Step progress logging
|
|
71
|
+
*/
|
|
72
|
+
step(message, context = {}) {
|
|
73
|
+
this._log('step', '🔄', message, context);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Completion logging
|
|
78
|
+
*/
|
|
79
|
+
complete(message, context = {}) {
|
|
80
|
+
this._log('complete', '🎉', message, context);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Progress logging with metrics
|
|
85
|
+
*/
|
|
86
|
+
progress(message, current, total, context = {}) {
|
|
87
|
+
const progressContext = { current, total, percentage: Math.round((current / total) * 100), ...context };
|
|
88
|
+
this._log('progress', '📊', message, progressContext);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Internal logging method
|
|
93
|
+
*/
|
|
94
|
+
_log(level, icon, message, context = {}) {
|
|
95
|
+
const timestamp = this.options.timestamp ? `[${new Date().toISOString()}]` : '';
|
|
96
|
+
const fullContext = { ...this.contextData, ...context };
|
|
97
|
+
|
|
98
|
+
let logMessage = `${timestamp} ${icon} ${message}`;
|
|
99
|
+
|
|
100
|
+
// Add context if enabled and present
|
|
101
|
+
if (this.options.context && Object.keys(fullContext).length > 0) {
|
|
102
|
+
const contextStr = this._formatContext(fullContext);
|
|
103
|
+
if (contextStr) {
|
|
104
|
+
logMessage += ` ${contextStr}`;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Route to appropriate console method
|
|
109
|
+
switch (level) {
|
|
110
|
+
case 'error':
|
|
111
|
+
console.error(logMessage);
|
|
112
|
+
break;
|
|
113
|
+
case 'warn':
|
|
114
|
+
console.warn(logMessage);
|
|
115
|
+
break;
|
|
116
|
+
case 'debug':
|
|
117
|
+
console.debug(logMessage);
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
console.log(logMessage);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Format context data for display
|
|
126
|
+
*/
|
|
127
|
+
_formatContext(context) {
|
|
128
|
+
try {
|
|
129
|
+
// Filter out complex objects and functions
|
|
130
|
+
const filteredContext = {};
|
|
131
|
+
for (const [key, value] of Object.entries(context)) {
|
|
132
|
+
if (value !== null && value !== undefined) {
|
|
133
|
+
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
134
|
+
// Include only simple object properties
|
|
135
|
+
if (Object.keys(value).length < 5) {
|
|
136
|
+
filteredContext[key] = value;
|
|
137
|
+
} else {
|
|
138
|
+
filteredContext[key] = `[Object with ${Object.keys(value).length} keys]`;
|
|
139
|
+
}
|
|
140
|
+
} else if (typeof value !== 'function') {
|
|
141
|
+
filteredContext[key] = value;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (Object.keys(filteredContext).length === 0) {
|
|
147
|
+
return '';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return JSON.stringify(filteredContext);
|
|
151
|
+
} catch (error) {
|
|
152
|
+
return `[Context formatting error: ${error.message}]`;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Serialize error objects for logging
|
|
158
|
+
*/
|
|
159
|
+
_serializeError(error) {
|
|
160
|
+
if (!error) return null;
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
name: error.name,
|
|
164
|
+
message: error.message,
|
|
165
|
+
code: error.code,
|
|
166
|
+
stack: error.stack?.split('\n').slice(0, 3).join('\n') // First 3 lines of stack
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Create a scoped logger with persistent context
|
|
172
|
+
*/
|
|
173
|
+
scope(scopeName, context = {}) {
|
|
174
|
+
const scopedLogger = new LoggerService(this.options);
|
|
175
|
+
scopedLogger.setContext({ scope: scopeName, ...this.contextData, ...context });
|
|
176
|
+
return scopedLogger;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Performance timing utilities
|
|
181
|
+
*/
|
|
182
|
+
time(label) {
|
|
183
|
+
console.time(`⏱️ ${label}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
timeEnd(label) {
|
|
187
|
+
console.timeEnd(`⏱️ ${label}`);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Table logging for structured data
|
|
192
|
+
*/
|
|
193
|
+
table(data, message = '') {
|
|
194
|
+
if (message) {
|
|
195
|
+
this.info(message);
|
|
196
|
+
}
|
|
197
|
+
console.table(data);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = LoggerService;
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package Manager Service
|
|
3
|
+
* Handles package manager detection, validation, and instruction generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const { PACKAGE_MANAGERS } = require('../config/constants');
|
|
8
|
+
|
|
9
|
+
class PackageManagerService {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.packageManagers = PACKAGE_MANAGERS;
|
|
12
|
+
this.detectedManagers = null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Detect available package managers on the system
|
|
17
|
+
* @returns {Array} Available package managers
|
|
18
|
+
*/
|
|
19
|
+
detectAvailablePackageManagers() {
|
|
20
|
+
if (this.detectedManagers) {
|
|
21
|
+
return this.detectedManagers;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const available = [];
|
|
25
|
+
|
|
26
|
+
Object.keys(this.packageManagers).forEach(manager => {
|
|
27
|
+
if (this.isPackageManagerAvailable(manager)) {
|
|
28
|
+
const managerInfo = this.packageManagers[manager];
|
|
29
|
+
available.push({
|
|
30
|
+
name: manager,
|
|
31
|
+
displayName: managerInfo.name,
|
|
32
|
+
version: this.getPackageManagerVersion(manager),
|
|
33
|
+
installCommand: managerInfo.install,
|
|
34
|
+
globalInstallCommand: managerInfo.globalInstall,
|
|
35
|
+
updateCommand: managerInfo.update
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
this.detectedManagers = available;
|
|
41
|
+
return available;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if a package manager is available on the system
|
|
46
|
+
* @param {string} manager - Package manager name
|
|
47
|
+
* @returns {boolean} Is available
|
|
48
|
+
*/
|
|
49
|
+
isPackageManagerAvailable(manager) {
|
|
50
|
+
const managerInfo = this.packageManagers[manager];
|
|
51
|
+
if (!managerInfo || !managerInfo.checkCommand) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check platform compatibility
|
|
56
|
+
if (managerInfo.platforms && !managerInfo.platforms.includes(process.platform)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
execSync(managerInfo.checkCommand, {
|
|
62
|
+
stdio: 'pipe',
|
|
63
|
+
timeout: 5000,
|
|
64
|
+
encoding: 'utf8'
|
|
65
|
+
});
|
|
66
|
+
return true;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get version of a package manager
|
|
74
|
+
* @param {string} manager - Package manager name
|
|
75
|
+
* @returns {string|null} Version string or null if not available
|
|
76
|
+
*/
|
|
77
|
+
getPackageManagerVersion(manager) {
|
|
78
|
+
const managerInfo = this.packageManagers[manager];
|
|
79
|
+
if (!managerInfo || !managerInfo.checkCommand) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const output = execSync(managerInfo.checkCommand, {
|
|
85
|
+
stdio: 'pipe',
|
|
86
|
+
timeout: 5000,
|
|
87
|
+
encoding: 'utf8'
|
|
88
|
+
});
|
|
89
|
+
return output.trim();
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get recommended package manager for platform
|
|
97
|
+
* @param {string} platform - Target platform
|
|
98
|
+
* @returns {string} Recommended package manager name
|
|
99
|
+
*/
|
|
100
|
+
getRecommendedPackageManager(platform = process.platform) {
|
|
101
|
+
const platformRecommendations = {
|
|
102
|
+
linux: 'apt',
|
|
103
|
+
darwin: 'brew',
|
|
104
|
+
win32: 'npm'
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const recommended = platformRecommendations[platform] || 'npm';
|
|
108
|
+
|
|
109
|
+
// Check if recommended manager is available
|
|
110
|
+
if (this.isPackageManagerAvailable(recommended)) {
|
|
111
|
+
return recommended;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Fall back to any available manager
|
|
115
|
+
const available = this.detectAvailablePackageManagers();
|
|
116
|
+
return available.length > 0 ? available[0].name : 'npm';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Generate installation instructions for multiple package managers
|
|
121
|
+
* @param {string} packageName - Package to install
|
|
122
|
+
* @param {Object} options - Installation options
|
|
123
|
+
* @returns {Array} Installation instructions for different package managers
|
|
124
|
+
*/
|
|
125
|
+
generateInstallationInstructions(packageName, options = {}) {
|
|
126
|
+
const instructions = [];
|
|
127
|
+
const availableManagers = this.detectAvailablePackageManagers();
|
|
128
|
+
|
|
129
|
+
if (availableManagers.length === 0) {
|
|
130
|
+
return [{
|
|
131
|
+
manager: 'none',
|
|
132
|
+
error: 'No package managers detected on this system',
|
|
133
|
+
installUrl: this.packageManagers.npm.installUrl
|
|
134
|
+
}];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
availableManagers.forEach(manager => {
|
|
138
|
+
const instruction = this._generateManagerInstruction(manager, packageName, options);
|
|
139
|
+
if (instruction) {
|
|
140
|
+
instructions.push(instruction);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Sort by recommendation (recommended first)
|
|
145
|
+
const recommended = this.getRecommendedPackageManager();
|
|
146
|
+
instructions.sort((a, b) => {
|
|
147
|
+
if (a.manager === recommended) return -1;
|
|
148
|
+
if (b.manager === recommended) return 1;
|
|
149
|
+
return 0;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return instructions;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate instruction for specific package manager
|
|
157
|
+
* @param {Object} manager - Manager information
|
|
158
|
+
* @param {string} packageName - Package to install
|
|
159
|
+
* @param {Object} options - Installation options
|
|
160
|
+
* @returns {Object} Installation instruction
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
_generateManagerInstruction(manager, packageName, options) {
|
|
164
|
+
const command = options.global ?
|
|
165
|
+
manager.globalInstallCommand || manager.installCommand :
|
|
166
|
+
manager.installCommand;
|
|
167
|
+
|
|
168
|
+
const version = options.version ? `@${options.version}` : '';
|
|
169
|
+
const fullPackageName = `${packageName}${version}`;
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
manager: manager.name,
|
|
173
|
+
displayName: manager.displayName,
|
|
174
|
+
command: `${command} ${fullPackageName}`,
|
|
175
|
+
version: manager.version,
|
|
176
|
+
global: options.global || false,
|
|
177
|
+
recommended: manager.name === this.getRecommendedPackageManager(),
|
|
178
|
+
notes: this._getManagerSpecificNotes(manager.name, options)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Get manager-specific installation notes
|
|
184
|
+
* @param {string} managerName - Package manager name
|
|
185
|
+
* @param {Object} options - Installation options
|
|
186
|
+
* @returns {Array} Installation notes
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
_getManagerSpecificNotes(managerName, options) {
|
|
190
|
+
const notes = [];
|
|
191
|
+
|
|
192
|
+
switch (managerName) {
|
|
193
|
+
case 'npm':
|
|
194
|
+
if (options.global) {
|
|
195
|
+
notes.push('Global installation may require administrator privileges');
|
|
196
|
+
}
|
|
197
|
+
notes.push('Use "npm list" to verify installation');
|
|
198
|
+
break;
|
|
199
|
+
|
|
200
|
+
case 'yarn':
|
|
201
|
+
if (options.global) {
|
|
202
|
+
notes.push('Yarn global installation location may not be in PATH');
|
|
203
|
+
}
|
|
204
|
+
notes.push('Yarn provides faster and more reliable dependency resolution');
|
|
205
|
+
break;
|
|
206
|
+
|
|
207
|
+
case 'pnpm':
|
|
208
|
+
notes.push('pnpm saves disk space by using a content-addressable store');
|
|
209
|
+
if (options.global) {
|
|
210
|
+
notes.push('pnpm global packages are stored in a separate location');
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
|
|
214
|
+
case 'brew':
|
|
215
|
+
notes.push('Homebrew automatically handles dependencies');
|
|
216
|
+
notes.push('Update Homebrew regularly: brew update && brew upgrade');
|
|
217
|
+
break;
|
|
218
|
+
|
|
219
|
+
case 'apt':
|
|
220
|
+
notes.push('May require "sudo" for system-wide installation');
|
|
221
|
+
notes.push('Update package lists first: sudo apt update');
|
|
222
|
+
break;
|
|
223
|
+
|
|
224
|
+
case 'chocolatey':
|
|
225
|
+
notes.push('Run PowerShell as Administrator');
|
|
226
|
+
notes.push('Chocolatey packages are community maintained');
|
|
227
|
+
break;
|
|
228
|
+
|
|
229
|
+
case 'winget':
|
|
230
|
+
notes.push('winget is the official Windows package manager');
|
|
231
|
+
notes.push('Available on Windows 10 1709+ and Windows 11');
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return notes;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Validate package manager installation
|
|
240
|
+
* @param {string} manager - Package manager name
|
|
241
|
+
* @returns {Object} Validation result
|
|
242
|
+
*/
|
|
243
|
+
validatePackageManager(manager) {
|
|
244
|
+
const managerInfo = this.packageManagers[manager];
|
|
245
|
+
|
|
246
|
+
if (!managerInfo) {
|
|
247
|
+
return {
|
|
248
|
+
valid: false,
|
|
249
|
+
error: `Unknown package manager: ${manager}`,
|
|
250
|
+
suggestions: ['Use npm, yarn, or pnpm for Node.js packages']
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Check platform compatibility
|
|
255
|
+
if (managerInfo.platforms && !managerInfo.platforms.includes(process.platform)) {
|
|
256
|
+
return {
|
|
257
|
+
valid: false,
|
|
258
|
+
error: `${managerInfo.name} is not available on ${process.platform}`,
|
|
259
|
+
suggestions: [
|
|
260
|
+
`Try ${this.getRecommendedPackageManager()} instead`,
|
|
261
|
+
`Install ${managerInfo.name} from ${managerInfo.installUrl || 'official website'}`
|
|
262
|
+
]
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Check if manager is available
|
|
267
|
+
if (!this.isPackageManagerAvailable(manager)) {
|
|
268
|
+
return {
|
|
269
|
+
valid: false,
|
|
270
|
+
error: `${managerInfo.name} is not installed or not in PATH`,
|
|
271
|
+
installUrl: managerInfo.installUrl,
|
|
272
|
+
suggestions: [
|
|
273
|
+
`Install ${managerInfo.name} from ${managerInfo.installUrl || 'official website'}`,
|
|
274
|
+
`Add ${managerInfo.name} to your system PATH`,
|
|
275
|
+
`Use alternative package manager: ${this.getRecommendedPackageManager()}`
|
|
276
|
+
]
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
valid: true,
|
|
282
|
+
manager: managerInfo.name,
|
|
283
|
+
version: this.getPackageManagerVersion(manager),
|
|
284
|
+
commands: {
|
|
285
|
+
install: managerInfo.install,
|
|
286
|
+
globalInstall: managerInfo.globalInstall,
|
|
287
|
+
update: managerInfo.update
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Get installation command for specific package and manager
|
|
294
|
+
* @param {string} manager - Package manager name
|
|
295
|
+
* @param {string} packageName - Package to install
|
|
296
|
+
* @param {Object} options - Installation options
|
|
297
|
+
* @returns {string|null} Installation command
|
|
298
|
+
*/
|
|
299
|
+
getInstallCommand(manager, packageName, options = {}) {
|
|
300
|
+
const managerInfo = this.packageManagers[manager];
|
|
301
|
+
if (!managerInfo) return null;
|
|
302
|
+
|
|
303
|
+
const baseCommand = options.global ?
|
|
304
|
+
managerInfo.globalInstall || managerInfo.install :
|
|
305
|
+
managerInfo.install;
|
|
306
|
+
|
|
307
|
+
const version = options.version ? `@${options.version}` : '';
|
|
308
|
+
return `${baseCommand} ${packageName}${version}`;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Clear detected managers cache
|
|
313
|
+
*/
|
|
314
|
+
clearCache() {
|
|
315
|
+
this.detectedManagers = null;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = PackageManagerService;
|