@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,270 @@
1
+ /**
2
+ * Package Manager Service
3
+ *
4
+ * Handles cross-platform package manager operations and configurations.
5
+ * Extracted from DependencyValidator as part of Phase 1 bloater refactoring.
6
+ *
7
+ * Features:
8
+ * - Multi-platform package manager support
9
+ * - Package name mapping across different managers
10
+ * - Command generation for install/check operations
11
+ * - Platform-specific package manager detection
12
+ */
13
+
14
+ const { execSync } = require('child_process');
15
+ const PlatformUtils = require('./platform-utils');
16
+
17
+ class PackageManagerService {
18
+ constructor() {
19
+ this.platformUtils = new PlatformUtils();
20
+ this.config = {
21
+ packageManagers: this._createPackageManagersConfig(),
22
+ dependencyMappings: this._createDependencyMappings()
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Create package managers configuration by platform
28
+ * @returns {Object} Package managers by platform
29
+ * @private
30
+ */
31
+ _createPackageManagersConfig() {
32
+ return {
33
+ linux: [
34
+ { name: 'apt', install: 'sudo apt-get install {package}', check: 'dpkg -l {package}' },
35
+ { name: 'yum', install: 'sudo yum install {package}', check: 'rpm -q {package}' },
36
+ { name: 'dnf', install: 'sudo dnf install {package}', check: 'rpm -q {package}' },
37
+ { name: 'pacman', install: 'sudo pacman -S {package}', check: 'pacman -Q {package}' },
38
+ { name: 'snap', install: 'sudo snap install {package}', check: 'snap list {package}' }
39
+ ],
40
+ darwin: [
41
+ { name: 'brew', install: 'brew install {package}', check: 'brew list {package}' },
42
+ { name: 'port', install: 'sudo port install {package}', check: 'port installed {package}' },
43
+ { name: 'npm', install: 'npm install -g {package}', check: 'npm list -g {package}' }
44
+ ],
45
+ win32: [
46
+ { name: 'chocolatey', install: 'choco install {package}', check: 'choco list --local-only {package}' },
47
+ { name: 'winget', install: 'winget install {package}', check: 'winget list {package}' },
48
+ { name: 'npm', install: 'npm install -g {package}', check: 'npm list -g {package}' },
49
+ { name: 'scoop', install: 'scoop install {package}', check: 'scoop list {package}' }
50
+ ]
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Create dependency mappings for package managers
56
+ * @returns {Object} Dependency mappings by tool and platform
57
+ * @private
58
+ */
59
+ _createDependencyMappings() {
60
+ return {
61
+ git: {
62
+ linux: { apt: 'git', yum: 'git', dnf: 'git', pacman: 'git' },
63
+ darwin: { brew: 'git' },
64
+ win32: { chocolatey: 'git', winget: 'Git.Git' }
65
+ },
66
+ python: {
67
+ linux: { apt: 'python3', yum: 'python3', dnf: 'python3' },
68
+ darwin: { brew: 'python@3.11' },
69
+ win32: { chocolatey: 'python', winget: 'Python.Python.3' }
70
+ },
71
+ docker: {
72
+ linux: { apt: 'docker.io', snap: 'docker' },
73
+ darwin: { brew: 'docker' },
74
+ win32: { chocolatey: 'docker-desktop' }
75
+ }
76
+ };
77
+ }
78
+
79
+ /**
80
+ * Get package managers for a specific platform
81
+ * @param {string} platform - Platform identifier (optional, defaults to current)
82
+ * @returns {Array<Object>} List of package managers for the platform
83
+ */
84
+ getPackageManagersForPlatform(platform = this.platformUtils.getCurrentPlatform()) {
85
+ return this.config.packageManagers[platform] || [];
86
+ }
87
+
88
+ /**
89
+ * Get package name for a specific dependency and package manager
90
+ * @param {string} dependencyName - Name of the dependency
91
+ * @param {string} packageManagerName - Name of the package manager
92
+ * @param {string} platform - Platform identifier (optional, defaults to current)
93
+ * @returns {string} Mapped package name or original dependency name
94
+ */
95
+ getPackageName(dependencyName, packageManagerName, platform = this.platformUtils.getCurrentPlatform()) {
96
+ const dependencyMapping = this.config.dependencyMappings[dependencyName];
97
+
98
+ if (dependencyMapping && dependencyMapping[platform] && dependencyMapping[platform][packageManagerName]) {
99
+ return dependencyMapping[platform][packageManagerName];
100
+ }
101
+
102
+ return dependencyName;
103
+ }
104
+
105
+ /**
106
+ * Generate install command for a package
107
+ * @param {string} dependencyName - Name of the dependency
108
+ * @param {string} packageManagerName - Name of the package manager
109
+ * @param {string} platform - Platform identifier (optional, defaults to current)
110
+ * @returns {string|null} Install command or null if package manager not found
111
+ */
112
+ generateInstallCommand(dependencyName, packageManagerName, platform = this.platformUtils.getCurrentPlatform()) {
113
+ const packageManagers = this.getPackageManagersForPlatform(platform);
114
+ const packageManager = packageManagers.find(pm => pm.name === packageManagerName);
115
+
116
+ if (!packageManager) {
117
+ return null;
118
+ }
119
+
120
+ const packageName = this.getPackageName(dependencyName, packageManagerName, platform);
121
+ return packageManager.install.replace('{package}', packageName);
122
+ }
123
+
124
+ /**
125
+ * Generate check command for a package
126
+ * @param {string} dependencyName - Name of the dependency
127
+ * @param {string} packageManagerName - Name of the package manager
128
+ * @param {string} platform - Platform identifier (optional, defaults to current)
129
+ * @returns {string|null} Check command or null if package manager not found
130
+ */
131
+ generateCheckCommand(dependencyName, packageManagerName, platform = this.platformUtils.getCurrentPlatform()) {
132
+ const packageManagers = this.getPackageManagersForPlatform(platform);
133
+ const packageManager = packageManagers.find(pm => pm.name === packageManagerName);
134
+
135
+ if (!packageManager) {
136
+ return null;
137
+ }
138
+
139
+ const packageName = this.getPackageName(dependencyName, packageManagerName, platform);
140
+ return packageManager.check.replace('{package}', packageName);
141
+ }
142
+
143
+ /**
144
+ * Check if a package manager is available on the system
145
+ * @param {string} packageManagerName - Name of the package manager
146
+ * @returns {boolean} True if package manager is available
147
+ */
148
+ isPackageManagerAvailable(packageManagerName) {
149
+ try {
150
+ const command = this.platformUtils.getPathCommand();
151
+ execSync(`${command} ${packageManagerName}`, {
152
+ encoding: 'utf8',
153
+ timeout: 3000,
154
+ stdio: 'pipe'
155
+ });
156
+ return true;
157
+ } catch (error) {
158
+ return false;
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Get available package managers for the current platform
164
+ * @param {string} platform - Platform identifier (optional, defaults to current)
165
+ * @returns {Array<Object>} List of available package managers
166
+ */
167
+ getAvailablePackageManagers(platform = this.platformUtils.getCurrentPlatform()) {
168
+ const allManagers = this.getPackageManagersForPlatform(platform);
169
+ return allManagers.filter(pm => this.isPackageManagerAvailable(pm.name));
170
+ }
171
+
172
+ /**
173
+ * Get the best available package manager for a platform
174
+ * @param {string} platform - Platform identifier (optional, defaults to current)
175
+ * @returns {Object|null} Best available package manager or null
176
+ */
177
+ getBestAvailablePackageManager(platform = this.platformUtils.getCurrentPlatform()) {
178
+ const availableManagers = this.getAvailablePackageManagers(platform);
179
+
180
+ // Return the first available manager (they're ordered by preference)
181
+ return availableManagers.length > 0 ? availableManagers[0] : null;
182
+ }
183
+
184
+ /**
185
+ * Generate package manager options for installation instructions
186
+ * @param {string} dependencyName - Name of the dependency
187
+ * @param {string} platform - Platform identifier (optional, defaults to current)
188
+ * @returns {Array<Object>} List of package manager options
189
+ */
190
+ generatePackageManagerOptions(dependencyName, platform = this.platformUtils.getCurrentPlatform()) {
191
+ const packageManagers = this.getPackageManagersForPlatform(platform);
192
+ const options = [];
193
+
194
+ for (const pm of packageManagers) {
195
+ const packageName = this.getPackageName(dependencyName, pm.name, platform);
196
+ const installCommand = pm.install.replace('{package}', packageName);
197
+ const checkCommand = pm.check.replace('{package}', packageName);
198
+
199
+ options.push({
200
+ name: pm.name,
201
+ command: installCommand,
202
+ check: checkCommand,
203
+ packageName: packageName,
204
+ available: this.isPackageManagerAvailable(pm.name)
205
+ });
206
+ }
207
+
208
+ return options;
209
+ }
210
+
211
+ /**
212
+ * Check if a specific package is installed
213
+ * @param {string} dependencyName - Name of the dependency
214
+ * @param {string} packageManagerName - Name of the package manager
215
+ * @param {string} platform - Platform identifier (optional, defaults to current)
216
+ * @returns {boolean} True if package is installed
217
+ */
218
+ isPackageInstalled(dependencyName, packageManagerName, platform = this.platformUtils.getCurrentPlatform()) {
219
+ const checkCommand = this.generateCheckCommand(dependencyName, packageManagerName, platform);
220
+
221
+ if (!checkCommand) {
222
+ return false;
223
+ }
224
+
225
+ try {
226
+ execSync(checkCommand, {
227
+ encoding: 'utf8',
228
+ timeout: 5000,
229
+ stdio: 'pipe'
230
+ });
231
+ return true;
232
+ } catch (error) {
233
+ return false;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Execute a package manager command safely
239
+ * @param {string} command - Command to execute
240
+ * @param {Object} options - Execution options
241
+ * @returns {Object} Execution result
242
+ */
243
+ executePackageManagerCommand(command, options = {}) {
244
+ const defaultOptions = {
245
+ encoding: 'utf8',
246
+ timeout: 30000, // 30 seconds for package operations
247
+ stdio: 'pipe'
248
+ };
249
+
250
+ const execOptions = { ...defaultOptions, ...options };
251
+
252
+ try {
253
+ const output = execSync(command, execOptions);
254
+ return {
255
+ success: true,
256
+ output: output.toString(),
257
+ command: command
258
+ };
259
+ } catch (error) {
260
+ return {
261
+ success: false,
262
+ error: error.message,
263
+ command: command,
264
+ exitCode: error.status
265
+ };
266
+ }
267
+ }
268
+ }
269
+
270
+ module.exports = PackageManagerService;