imcp 0.0.19 → 0.1.2
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/.roo/rules-code/rules.md +88 -0
- package/dist/cli/index.js +1 -45
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -5
- package/dist/core/installers/clients/BaseClientInstaller.js +40 -38
- package/dist/core/installers/clients/ClientInstaller.d.ts +9 -9
- package/dist/core/installers/clients/ClientInstaller.js +105 -99
- package/dist/core/installers/requirements/BaseInstaller.d.ts +9 -1
- package/dist/core/installers/requirements/CommandInstaller.d.ts +9 -1
- package/dist/core/installers/requirements/CommandInstaller.js +46 -12
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +11 -1
- package/dist/core/installers/requirements/GeneralInstaller.js +46 -10
- package/dist/core/installers/requirements/InstallerFactory.d.ts +3 -1
- package/dist/core/installers/requirements/InstallerFactory.js +3 -2
- package/dist/core/installers/requirements/NpmInstaller.d.ts +4 -2
- package/dist/core/installers/requirements/NpmInstaller.js +38 -22
- package/dist/core/installers/requirements/PipInstaller.d.ts +3 -1
- package/dist/core/installers/requirements/PipInstaller.js +58 -36
- package/dist/core/installers/requirements/RequirementInstaller.d.ts +4 -1
- package/dist/core/loaders/InstallOperationManager.d.ts +115 -0
- package/dist/core/loaders/InstallOperationManager.js +311 -0
- package/dist/core/loaders/SystemSettingsManager.d.ts +54 -0
- package/dist/core/loaders/SystemSettingsManager.js +257 -0
- package/dist/core/metadatas/constants.d.ts +7 -0
- package/dist/core/metadatas/constants.js +7 -0
- package/dist/core/metadatas/recordingConstants.d.ts +44 -0
- package/dist/core/metadatas/recordingConstants.js +45 -0
- package/dist/core/metadatas/types.d.ts +21 -0
- package/dist/core/onboard/FeedOnboardService.d.ts +7 -3
- package/dist/core/onboard/FeedOnboardService.js +52 -5
- package/dist/core/onboard/InstallOperationManager.d.ts +23 -0
- package/dist/core/onboard/InstallOperationManager.js +144 -0
- package/dist/core/onboard/OnboardStatusManager.js +2 -1
- package/dist/core/validators/StdioServerValidator.js +4 -3
- package/dist/services/InstallationService.d.ts +2 -37
- package/dist/services/InstallationService.js +45 -313
- package/dist/services/MCPManager.d.ts +1 -1
- package/dist/services/MCPManager.js +53 -47
- package/dist/services/RequirementService.d.ts +85 -12
- package/dist/services/RequirementService.js +488 -49
- package/dist/services/ServerService.d.ts +0 -6
- package/dist/services/ServerService.js +0 -74
- package/dist/services/TelemetryService.d.ts +15 -0
- package/dist/services/TelemetryService.js +54 -0
- package/dist/utils/adoUtils.js +6 -3
- package/dist/utils/githubAuth.js +65 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +78 -1
- package/dist/utils/macroExpressionUtils.js +3 -25
- package/dist/utils/osUtils.d.ts +22 -1
- package/dist/utils/osUtils.js +92 -1
- package/dist/utils/versionUtils.d.ts +20 -0
- package/dist/utils/versionUtils.js +76 -0
- package/dist/web/public/css/modal.css +292 -1
- package/dist/web/public/css/serverCategoryList.css +120 -0
- package/dist/web/public/css/serverDetails.css +14 -1
- package/dist/web/public/index.html +126 -21
- package/dist/web/public/js/flights/flights.js +1 -1
- package/dist/web/public/js/modal/index.js +8 -14
- package/dist/web/public/js/modal/installModal.js +3 -4
- package/dist/web/public/js/modal/installation.js +122 -137
- package/dist/web/public/js/modal/loadingModal.js +155 -25
- package/dist/web/public/js/modal/messageQueue.js +45 -101
- package/dist/web/public/js/modal/modalSetup.js +125 -43
- package/dist/web/public/js/modal/modalUtils.js +0 -12
- package/dist/web/public/js/modal.js +23 -10
- package/dist/web/public/js/onboard/formProcessor.js +18 -11
- package/dist/web/public/js/onboard/publishHandler.js +35 -3
- package/dist/web/public/js/onboard/templates.js +5 -1
- package/dist/web/public/js/onboard/uiHandlers.js +266 -39
- package/dist/web/public/js/onboard/validationHandlers.js +71 -39
- package/dist/web/public/js/serverCategoryDetails.js +60 -11
- package/dist/web/public/js/serverCategoryList.js +93 -9
- package/dist/web/public/js/settings.js +314 -0
- package/dist/web/public/onboard.html +2 -2
- package/dist/web/public/settings.html +135 -0
- package/dist/web/public/styles.css +32 -0
- package/dist/web/server.js +93 -1
- package/{src/web/public/js/onboard → docs}/ONBOARDING_PAGE_DESIGN.md +15 -125
- package/docs/Telemetry.md +136 -0
- package/memory-bank/activeContext.md +26 -0
- package/memory-bank/decisionLog.md +91 -0
- package/memory-bank/productContext.md +41 -0
- package/memory-bank/progress.md +35 -0
- package/memory-bank/systemPatterns.md +10 -0
- package/package.json +2 -1
- package/src/cli/index.ts +1 -48
- package/src/core/installers/clients/BaseClientInstaller.ts +64 -50
- package/src/core/installers/clients/ClientInstaller.ts +130 -130
- package/src/core/installers/requirements/BaseInstaller.ts +9 -1
- package/src/core/installers/requirements/CommandInstaller.ts +47 -13
- package/src/core/installers/requirements/GeneralInstaller.ts +48 -10
- package/src/core/installers/requirements/InstallerFactory.ts +4 -3
- package/src/core/installers/requirements/NpmInstaller.ts +90 -68
- package/src/core/installers/requirements/PipInstaller.ts +81 -55
- package/src/core/installers/requirements/RequirementInstaller.ts +4 -3
- package/src/core/loaders/InstallOperationManager.ts +367 -0
- package/src/core/loaders/SystemSettingsManager.ts +278 -0
- package/src/core/metadatas/constants.ts +9 -0
- package/src/core/metadatas/recordingConstants.ts +62 -0
- package/src/core/metadatas/types.ts +23 -0
- package/src/core/onboard/FeedOnboardService.ts +59 -5
- package/src/core/onboard/OnboardStatusManager.ts +2 -1
- package/src/core/validators/StdioServerValidator.ts +4 -3
- package/src/services/InstallationService.ts +54 -399
- package/src/services/MCPManager.ts +61 -64
- package/src/services/RequirementService.ts +564 -67
- package/src/services/ServerService.ts +0 -90
- package/src/services/TelemetryService.ts +59 -0
- package/src/utils/adoUtils.ts +6 -4
- package/src/utils/githubAuth.ts +84 -1
- package/src/utils/logger.ts +83 -1
- package/src/utils/macroExpressionUtils.ts +4 -21
- package/src/utils/osUtils.ts +92 -1
- package/src/utils/versionUtils.ts +98 -13
- package/src/web/public/css/modal.css +292 -1
- package/src/web/public/css/serverCategoryList.css +120 -0
- package/src/web/public/css/serverDetails.css +14 -1
- package/src/web/public/index.html +126 -21
- package/src/web/public/js/flights/flights.js +1 -1
- package/src/web/public/js/modal/index.js +8 -14
- package/src/web/public/js/modal/installModal.js +3 -4
- package/src/web/public/js/modal/installation.js +122 -137
- package/src/web/public/js/modal/loadingModal.js +155 -25
- package/src/web/public/js/modal/modalSetup.js +125 -43
- package/src/web/public/js/modal/modalUtils.js +0 -12
- package/src/web/public/js/modal.js +23 -10
- package/src/web/public/js/onboard/formProcessor.js +18 -11
- package/src/web/public/js/onboard/publishHandler.js +35 -3
- package/src/web/public/js/onboard/templates.js +5 -1
- package/src/web/public/js/onboard/uiHandlers.js +266 -39
- package/src/web/public/js/onboard/validationHandlers.js +71 -39
- package/src/web/public/js/serverCategoryDetails.js +60 -11
- package/src/web/public/js/serverCategoryList.js +93 -9
- package/src/web/public/js/settings.js +314 -0
- package/src/web/public/onboard.html +2 -2
- package/src/web/public/settings.html +135 -0
- package/src/web/public/styles.css +32 -0
- package/src/web/server.ts +96 -1
- package/dist/cli/commands/start.d.ts +0 -2
- package/dist/cli/commands/start.js +0 -32
- package/dist/cli/commands/sync.d.ts +0 -2
- package/dist/cli/commands/sync.js +0 -17
- package/dist/core/ConfigurationLoader.d.ts +0 -32
- package/dist/core/ConfigurationLoader.js +0 -236
- package/dist/core/ConfigurationProvider.d.ts +0 -35
- package/dist/core/ConfigurationProvider.js +0 -375
- package/dist/core/InstallationService.d.ts +0 -50
- package/dist/core/InstallationService.js +0 -350
- package/dist/core/MCPManager.d.ts +0 -28
- package/dist/core/MCPManager.js +0 -188
- package/dist/core/RequirementService.d.ts +0 -40
- package/dist/core/RequirementService.js +0 -110
- package/dist/core/ServerSchemaLoader.d.ts +0 -11
- package/dist/core/ServerSchemaLoader.js +0 -43
- package/dist/core/ServerSchemaProvider.d.ts +0 -17
- package/dist/core/ServerSchemaProvider.js +0 -120
- package/dist/core/constants.d.ts +0 -47
- package/dist/core/constants.js +0 -94
- package/dist/core/installers/BaseInstaller.d.ts +0 -74
- package/dist/core/installers/BaseInstaller.js +0 -253
- package/dist/core/installers/ClientInstaller.d.ts +0 -23
- package/dist/core/installers/ClientInstaller.js +0 -564
- package/dist/core/installers/CommandInstaller.d.ts +0 -37
- package/dist/core/installers/CommandInstaller.js +0 -173
- package/dist/core/installers/GeneralInstaller.d.ts +0 -33
- package/dist/core/installers/GeneralInstaller.js +0 -85
- package/dist/core/installers/InstallerFactory.d.ts +0 -54
- package/dist/core/installers/InstallerFactory.js +0 -97
- package/dist/core/installers/NpmInstaller.d.ts +0 -26
- package/dist/core/installers/NpmInstaller.js +0 -127
- package/dist/core/installers/PipInstaller.d.ts +0 -28
- package/dist/core/installers/PipInstaller.js +0 -127
- package/dist/core/installers/RequirementInstaller.d.ts +0 -33
- package/dist/core/installers/RequirementInstaller.js +0 -3
- package/dist/core/types.d.ts +0 -166
- package/dist/core/types.js +0 -16
- package/dist/services/InstallRequestValidator.d.ts +0 -21
- package/dist/services/InstallRequestValidator.js +0 -99
- package/dist/web/public/js/modal/installHandler.js +0 -227
- package/dist/web/public/js/modal/loadingUI.js +0 -74
- package/dist/web/public/js/modal/modalUI.js +0 -214
- package/dist/web/public/js/modal/version.js +0 -20
- package/src/web/public/js/modal/messageQueue.js +0 -112
|
@@ -2,6 +2,8 @@ import { RequirementConfig, RequirementStatus, OSType, ServerInstallOptions } fr
|
|
|
2
2
|
import { BaseInstaller } from './BaseInstaller.js';
|
|
3
3
|
import { getOSType, refreshPathEnv } from '../../../utils/osUtils.js';
|
|
4
4
|
import { Logger } from '../../../utils/logger.js';
|
|
5
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
6
|
+
import * as RecordingConstants from '../../metadatas/recordingConstants.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Mapping of command names to their package IDs on different platforms
|
|
@@ -138,8 +140,15 @@ export class CommandInstaller extends BaseInstaller {
|
|
|
138
140
|
* @param requirement The requirement to install
|
|
139
141
|
* @returns The status of the installation
|
|
140
142
|
*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Install the command
|
|
145
|
+
* @param requirement The requirement to install
|
|
146
|
+
* @param options Optional install options
|
|
147
|
+
* @param recorder Optional InstallOperationManager for recording steps
|
|
148
|
+
* @returns The status of the installation
|
|
149
|
+
*/
|
|
150
|
+
async install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
151
|
+
const doInstall = async (): Promise<RequirementStatus> => {
|
|
143
152
|
const status = await this.checkInstallation(requirement);
|
|
144
153
|
if (status.installed) {
|
|
145
154
|
return status;
|
|
@@ -150,18 +159,17 @@ export class CommandInstaller extends BaseInstaller {
|
|
|
150
159
|
let installCommand: string;
|
|
151
160
|
|
|
152
161
|
if (osType === OSType.Windows) {
|
|
153
|
-
// Windows installation using winget
|
|
154
162
|
installCommand = `winget install --id ${packageId}`;
|
|
155
163
|
if (requirement.version && requirement.version !== 'latest') {
|
|
156
164
|
installCommand += ` --version ${requirement.version}`;
|
|
157
165
|
}
|
|
158
166
|
} else if (osType === OSType.MacOS) {
|
|
159
|
-
// macOS installation using Homebrew
|
|
160
167
|
installCommand = `brew install ${packageId}`;
|
|
161
168
|
if (requirement.version && requirement.version !== 'latest') {
|
|
162
169
|
installCommand += `@${requirement.version}`;
|
|
163
170
|
}
|
|
164
171
|
} else {
|
|
172
|
+
if (recorder) await recorder.recordStep('CommandInstaller:UnsupportedOS', 'failed', `Unsupported OS for ${requirement.name}`);
|
|
165
173
|
throw new Error(`Unsupported operating system for installing ${requirement.name}`);
|
|
166
174
|
}
|
|
167
175
|
|
|
@@ -176,7 +184,6 @@ export class CommandInstaller extends BaseInstaller {
|
|
|
176
184
|
if (!updatedStatus.installed) {
|
|
177
185
|
throw new Error(`Failed to install ${requirement.name}`);
|
|
178
186
|
}
|
|
179
|
-
|
|
180
187
|
return {
|
|
181
188
|
name: requirement.name,
|
|
182
189
|
type: 'command',
|
|
@@ -184,14 +191,41 @@ export class CommandInstaller extends BaseInstaller {
|
|
|
184
191
|
version: updatedStatus.version || requirement.version,
|
|
185
192
|
inProgress: false
|
|
186
193
|
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
if (recorder) {
|
|
197
|
+
return recorder.recording(doInstall, {
|
|
198
|
+
stepName: RecordingConstants.STEP_COMMAND_INSTALLER_INSTALL,
|
|
199
|
+
inProgressMessage: `Installing command: ${requirement.name}`,
|
|
200
|
+
endMessage: (result) =>
|
|
201
|
+
result.installed
|
|
202
|
+
? `Install completed for ${requirement.name}`
|
|
203
|
+
: `Install failed for ${requirement.name}`,
|
|
204
|
+
onError: (error) => {
|
|
205
|
+
return {
|
|
206
|
+
result: {
|
|
207
|
+
name: requirement.name,
|
|
208
|
+
type: 'command',
|
|
209
|
+
installed: false,
|
|
210
|
+
error: error instanceof Error ? error.message : String(error),
|
|
211
|
+
inProgress: false,
|
|
212
|
+
},
|
|
213
|
+
message: error instanceof Error ? error.message : String(error),
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
} else {
|
|
218
|
+
try {
|
|
219
|
+
return await doInstall();
|
|
220
|
+
} catch (error) {
|
|
221
|
+
return {
|
|
222
|
+
name: requirement.name,
|
|
223
|
+
type: 'command',
|
|
224
|
+
installed: false,
|
|
225
|
+
error: error instanceof Error ? error.message : String(error),
|
|
226
|
+
inProgress: false,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
195
229
|
}
|
|
196
230
|
}
|
|
197
231
|
}
|
|
@@ -2,6 +2,8 @@ import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../.
|
|
|
2
2
|
import { BaseInstaller } from './BaseInstaller.js';
|
|
3
3
|
import { handleGitHubRelease } from '../../../utils/githubUtils.js';
|
|
4
4
|
import { handleArtifact } from '../../../utils/adoUtils.js';
|
|
5
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
6
|
+
import * as RecordingConstants from '../../metadatas/recordingConstants.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Installer implementation for general requirements (type 'other')
|
|
@@ -55,8 +57,17 @@ export class GeneralInstaller extends BaseInstaller {
|
|
|
55
57
|
* @param requirement The requirement to install
|
|
56
58
|
* @returns The status of the installation, including the install path in updateInfo
|
|
57
59
|
*/
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Install the general requirement
|
|
62
|
+
* For type 'other', this doesn't actually install anything, but downloads
|
|
63
|
+
* or locates the asset and returns the path for the caller to use
|
|
64
|
+
* @param requirement The requirement to install
|
|
65
|
+
* @param options Optional install options
|
|
66
|
+
* @param recorder Optional InstallOperationManager for recording steps
|
|
67
|
+
* @returns The status of the installation, including the install path in updateInfo
|
|
68
|
+
*/
|
|
69
|
+
async install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
70
|
+
const doInstall = async (): Promise<RequirementStatus> => {
|
|
60
71
|
// For type 'other', a registry must be specified
|
|
61
72
|
if (!requirement.registry) {
|
|
62
73
|
throw new Error('Registry must be specified for requirement type "other"');
|
|
@@ -82,14 +93,41 @@ export class GeneralInstaller extends BaseInstaller {
|
|
|
82
93
|
version: requirement.version,
|
|
83
94
|
inProgress: false,
|
|
84
95
|
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (recorder) {
|
|
99
|
+
return recorder.recording(doInstall, {
|
|
100
|
+
stepName: RecordingConstants.STEP_GENERAL_INSTALLER_INSTALL,
|
|
101
|
+
inProgressMessage: `Installing general requirement: ${requirement.name}`,
|
|
102
|
+
endMessage: (result) =>
|
|
103
|
+
result.installed
|
|
104
|
+
? `Install completed for ${requirement.name}`
|
|
105
|
+
: `Install failed for ${requirement.name}`,
|
|
106
|
+
onError: (error) => {
|
|
107
|
+
return {
|
|
108
|
+
result: {
|
|
109
|
+
name: requirement.name,
|
|
110
|
+
type: 'other',
|
|
111
|
+
installed: false,
|
|
112
|
+
error: error instanceof Error ? error.message : String(error),
|
|
113
|
+
inProgress: false,
|
|
114
|
+
},
|
|
115
|
+
message: error instanceof Error ? error.message : String(error),
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
try {
|
|
121
|
+
return await doInstall();
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return {
|
|
124
|
+
name: requirement.name,
|
|
125
|
+
type: 'other',
|
|
126
|
+
installed: false,
|
|
127
|
+
error: error instanceof Error ? error.message : String(error),
|
|
128
|
+
inProgress: false,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
93
131
|
}
|
|
94
132
|
}
|
|
95
133
|
}
|
|
@@ -6,7 +6,7 @@ import { CommandInstaller } from './CommandInstaller.js';
|
|
|
6
6
|
import { GeneralInstaller } from './GeneralInstaller.js';
|
|
7
7
|
import { exec } from 'child_process';
|
|
8
8
|
import util from 'util';
|
|
9
|
-
|
|
9
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
10
10
|
/**
|
|
11
11
|
* Factory for creating the appropriate installer for a requirement
|
|
12
12
|
*/
|
|
@@ -59,10 +59,11 @@ export class InstallerFactory {
|
|
|
59
59
|
/**
|
|
60
60
|
* Install a requirement using the appropriate installer
|
|
61
61
|
* @param requirement The requirement to install
|
|
62
|
+
* @param recorder Optional InstallOperationManager for recording steps
|
|
62
63
|
* @param options Installation options including python environment
|
|
63
64
|
* @returns The installation status
|
|
64
65
|
*/
|
|
65
|
-
public async install(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
66
|
+
public async install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
66
67
|
const installer = this.getInstaller(requirement);
|
|
67
68
|
if (!installer) {
|
|
68
69
|
return {
|
|
@@ -74,7 +75,7 @@ export class InstallerFactory {
|
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
return await installer.install(requirement, options);
|
|
78
|
+
return await installer.install(requirement, recorder, options);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
@@ -8,6 +8,9 @@ import path from 'path';
|
|
|
8
8
|
import fs from 'fs/promises';
|
|
9
9
|
import { SETTINGS_DIR } from '../../metadatas/constants.js'; // Corrected path
|
|
10
10
|
import { Logger } from '../../../utils/logger.js';
|
|
11
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
12
|
+
import * as RecordingConstants from '../../metadatas/recordingConstants.js';
|
|
13
|
+
|
|
11
14
|
/**
|
|
12
15
|
* Installer implementation for NPM packages
|
|
13
16
|
*/
|
|
@@ -152,7 +155,8 @@ export class NpmInstaller extends BaseInstaller {
|
|
|
152
155
|
private async _installPackage(
|
|
153
156
|
requirement: RequirementConfig,
|
|
154
157
|
packageSource: string,
|
|
155
|
-
targetDir: string
|
|
158
|
+
targetDir: string,
|
|
159
|
+
recorder: InstallOperationManager
|
|
156
160
|
): Promise<{ version: string }> {
|
|
157
161
|
Logger.debug(`Installing NPM package from "${packageSource}" into "${targetDir}"`);
|
|
158
162
|
await fs.mkdir(targetDir, { recursive: true });
|
|
@@ -161,89 +165,107 @@ export class NpmInstaller extends BaseInstaller {
|
|
|
161
165
|
Logger.debug(`Executing install command: ${installCommand}`);
|
|
162
166
|
const requirementName = this._getRequirementName(requirement);
|
|
163
167
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
return await recorder.recording(
|
|
169
|
+
async () => {
|
|
170
|
+
const { stdout: installStdout, stderr: installStderr } = await this.execPromise(installCommand);
|
|
171
|
+
Logger.debug(`NPM install stdout for ${packageSource} in ${targetDir}: ${installStdout}`);
|
|
172
|
+
if (installStderr && !installStderr.toLowerCase().includes('added') && !installStderr.toLowerCase().includes('updated') && !installStderr.toLowerCase().includes('found 0 vulnerabilities')) {
|
|
173
|
+
// Log stderr if it's not just typical success noise
|
|
174
|
+
Logger.log(`NPM install stderr for ${packageSource} in ${targetDir}: ${installStderr}`);
|
|
175
|
+
}
|
|
171
176
|
|
|
172
177
|
|
|
173
|
-
|
|
178
|
+
const installedVersion = await this._getInstalledVersion(requirementName, targetDir);
|
|
174
179
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
if (installedVersion) {
|
|
181
|
+
Logger.log(`Successfully installed and verified ${requirementName}@${installedVersion} into ${targetDir}`);
|
|
182
|
+
return { version: installedVersion };
|
|
183
|
+
} else {
|
|
184
|
+
throw new Error(`Successfully ran npm install for ${packageSource}, but ${requirement.name} version could not be determined via npm list in ${targetDir}, stderr: ${installStderr}`);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
stepName: RecordingConstants.STEP_INSTALLATION_COMMAND_EXECUTION,
|
|
189
|
+
inProgressMessage: `Running: ${installCommand}`,
|
|
190
|
+
onError: (error) => {
|
|
191
|
+
Logger.error(`Error during NPM installation: ${error instanceof Error ? error.message : String(error)}`);
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
180
194
|
}
|
|
181
|
-
|
|
182
|
-
} catch (error) {
|
|
183
|
-
Logger.error(`Failed to install or verify NPM package ${packageSource} into ${targetDir}`, error);
|
|
184
|
-
throw error;
|
|
185
|
-
}
|
|
195
|
+
)
|
|
186
196
|
}
|
|
187
197
|
|
|
188
|
-
|
|
189
198
|
/**
|
|
190
199
|
* Install the NPM package.
|
|
191
200
|
* @param requirement The requirement to install.
|
|
192
|
-
* @param
|
|
201
|
+
* @param recorder Optional InstallOperationManager for recording steps.
|
|
202
|
+
* @param options Installation options.
|
|
193
203
|
* @returns The status of the installation.
|
|
194
204
|
*/
|
|
195
|
-
async install(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
205
|
+
async install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
196
206
|
const targetDir = options?.settings?.folderName || this._getRequirementFolderPath(requirement);
|
|
197
207
|
await fs.mkdir(targetDir, { recursive: true });
|
|
208
|
+
return recorder.recording(
|
|
209
|
+
async (): Promise<RequirementStatus> => {
|
|
210
|
+
const status = await this.checkInstallation(requirement, { settings: { folderName: targetDir } });
|
|
211
|
+
if (status.installed && status.version && compareVersions(status.version, requirement.version) === 0 && !requirement.version.toLowerCase().includes('latest')) {
|
|
212
|
+
Logger.log(`${requirement.name}@${status.version} already installed in ${targetDir}.`);
|
|
213
|
+
return status;
|
|
214
|
+
}
|
|
198
215
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (status.installed && status.version && compareVersions(status.version, requirement.version) === 0 && !requirement.version.toLowerCase().includes('latest')) {
|
|
202
|
-
Logger.log(`${requirement.name}@${status.version} already installed in ${targetDir}.`);
|
|
203
|
-
return status;
|
|
204
|
-
}
|
|
216
|
+
let resolvedVersion = requirement.version;
|
|
217
|
+
let packageToInstall: string = `${requirement.name}@${requirement.version}`;
|
|
205
218
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
throw new Error('Invalid registry configuration for npm.');
|
|
219
|
+
if (requirement.registry) {
|
|
220
|
+
if (requirement.registry.githubRelease) {
|
|
221
|
+
const result = await handleGitHubRelease(requirement, requirement.registry.githubRelease);
|
|
222
|
+
packageToInstall = result.resolvedPath;
|
|
223
|
+
resolvedVersion = result.resolvedVersion;
|
|
224
|
+
} else if (requirement.registry.artifacts) {
|
|
225
|
+
const adoResult: AdoArtifactResult = await handleAdoArtifact(
|
|
226
|
+
requirement,
|
|
227
|
+
requirement.registry.artifacts,
|
|
228
|
+
options?.settings?.pythonCommand,
|
|
229
|
+
targetDir
|
|
230
|
+
);
|
|
231
|
+
packageToInstall = `${adoResult.package}@${adoResult.version}`;
|
|
232
|
+
resolvedVersion = adoResult.version;
|
|
233
|
+
} else {
|
|
234
|
+
if (recorder) await recorder.recordStep('NpmInstaller:RegistryConfig', 'failed', 'Invalid registry configuration for npm.');
|
|
235
|
+
throw new Error('Invalid registry configuration for npm.');
|
|
236
|
+
}
|
|
225
237
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
resolvedVersion = finalInstallResult.version;
|
|
238
|
+
const finalInstallResult = await this._installPackage(requirement, packageToInstall, targetDir, recorder);
|
|
239
|
+
resolvedVersion = finalInstallResult.version;
|
|
229
240
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
241
|
+
return {
|
|
242
|
+
name: requirement.name,
|
|
243
|
+
type: 'npm',
|
|
244
|
+
installed: true,
|
|
245
|
+
version: resolvedVersion,
|
|
246
|
+
inProgress: false,
|
|
247
|
+
npmPath: targetDir
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
stepName: RecordingConstants.STEP_NPM_INSTALLER_INSTALL,
|
|
252
|
+
inProgressMessage: `Installing npm package: ${requirement.name}`,
|
|
253
|
+
endMessage: (result) =>
|
|
254
|
+
result.installed
|
|
255
|
+
? `Install completed for ${requirement.name}`
|
|
256
|
+
: `Install failed for ${requirement.name}`,
|
|
257
|
+
onError: (error) => {
|
|
258
|
+
return {
|
|
259
|
+
result: {
|
|
260
|
+
name: requirement.name,
|
|
261
|
+
type: 'npm',
|
|
262
|
+
installed: false,
|
|
263
|
+
error: error instanceof Error ? error.message : String(error),
|
|
264
|
+
inProgress: false
|
|
265
|
+
},
|
|
266
|
+
message: error instanceof Error ? error.message : String(error),
|
|
267
|
+
};
|
|
268
|
+
},
|
|
269
|
+
});
|
|
248
270
|
}
|
|
249
271
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../../metadatas/types.js';
|
|
2
2
|
import { BaseInstaller } from './BaseInstaller.js';
|
|
3
3
|
import { handleGitHubRelease, getGitHubLatestVersion } from '../../../utils/githubUtils.js';
|
|
4
|
-
// Assuming getArtifactLatestVersion will be available in adoUtils.ts
|
|
5
4
|
import { handleArtifact as handleAdoArtifact, getArtifactLatestVersion } from '../../../utils/adoUtils.js';
|
|
6
5
|
import { compareVersions } from '../../../utils/versionUtils.js';
|
|
7
6
|
import { Logger } from '../../../utils/logger.js';
|
|
8
|
-
|
|
7
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
8
|
+
import * as RecordingConstants from '../../metadatas/recordingConstants.js';
|
|
9
9
|
/**
|
|
10
10
|
* Installer implementation for Python packages using pip
|
|
11
11
|
*/
|
|
@@ -113,69 +113,95 @@ export class PipInstaller extends BaseInstaller {
|
|
|
113
113
|
/**
|
|
114
114
|
* Install the Python package
|
|
115
115
|
* @param requirement The requirement to install
|
|
116
|
+
* @param recorder Optional InstallOperationManager for recording steps
|
|
116
117
|
* @param options Optional server install options
|
|
117
118
|
* @returns The status of the installation
|
|
118
119
|
*/
|
|
119
|
-
async install(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
120
|
-
try {
|
|
121
|
-
const status = await this.checkInstallation(requirement, options);
|
|
122
|
-
if (status.installed && status.version && compareVersions(status.version, requirement.version) === 0 && !requirement.version.toLowerCase().includes('latest')) {
|
|
123
|
-
Logger.log(`${requirement.name}==${status.version} already installed for ${this.getPythonCommand}.`);
|
|
124
|
-
return status;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const pipCmd = this.getPipCommand(options);
|
|
120
|
+
async install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus> {
|
|
128
121
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
122
|
+
return await recorder.recording(
|
|
123
|
+
async (): Promise<RequirementStatus> => {
|
|
124
|
+
const status = await this.checkInstallation(requirement, options);
|
|
125
|
+
if (status.installed && status.version && compareVersions(status.version, requirement.version) === 0 && !requirement.version.toLowerCase().includes('latest')) {
|
|
126
|
+
Logger.log(`${requirement.name}==${status.version} already installed for ${this.getPythonCommand}.`);
|
|
127
|
+
return status;
|
|
133
128
|
}
|
|
134
|
-
} else {
|
|
135
|
-
let packageSource: string;
|
|
136
129
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
packageSource = result.resolvedPath;
|
|
140
|
-
const { stderr } = await this.execPromise(`${pipCmd} install "${packageSource}"`);
|
|
141
|
-
if (stderr && stderr.toLowerCase().includes('error')) {
|
|
142
|
-
throw new Error(stderr);
|
|
143
|
-
}
|
|
144
|
-
} else if (requirement.registry.artifacts) {
|
|
145
|
-
const pythonCmd = this.getPythonCommand(options);
|
|
146
|
-
const adoArtifactResult = await handleAdoArtifact(requirement, requirement.registry.artifacts, pythonCmd);
|
|
130
|
+
const pipCmd = this.getPipCommand(options);
|
|
131
|
+
let command: string
|
|
147
132
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (!checkStatus.installed) {
|
|
154
|
-
throw new Error(`Pip installation failed with: ${stderr}`);
|
|
155
|
-
}
|
|
133
|
+
if (!requirement.registry) {
|
|
134
|
+
if (requirement.version && !requirement.version.includes('latest')) {
|
|
135
|
+
command = `${pipCmd} install ${requirement.name}==${requirement.version}`;
|
|
136
|
+
} else {
|
|
137
|
+
command = `${pipCmd} install --upgrade ${requirement.name}`;
|
|
156
138
|
}
|
|
157
139
|
} else {
|
|
158
|
-
|
|
140
|
+
let packageSource: string;
|
|
141
|
+
if (requirement.registry.githubRelease) {
|
|
142
|
+
const result = await handleGitHubRelease(requirement, requirement.registry.githubRelease);
|
|
143
|
+
packageSource = result.resolvedPath;
|
|
144
|
+
command = `${pipCmd} install "${packageSource}"`
|
|
145
|
+
} else if (requirement.registry.artifacts) {
|
|
146
|
+
const pythonCmd = this.getPythonCommand(options);
|
|
147
|
+
const adoArtifactResult = await handleAdoArtifact(requirement, requirement.registry.artifacts, pythonCmd);
|
|
148
|
+
|
|
149
|
+
command = `${pipCmd} install ${adoArtifactResult.package} --extra-index-url ${adoArtifactResult.registryUrl}`;
|
|
150
|
+
} else {
|
|
151
|
+
await recorder.recordStep('PipInstaller:RegistryConfig', 'failed', 'Invalid registry configuration');
|
|
152
|
+
throw new Error('Invalid registry configuration');
|
|
153
|
+
}
|
|
159
154
|
}
|
|
160
|
-
|
|
155
|
+
return await recorder.recording(
|
|
156
|
+
async () => {
|
|
157
|
+
const { stderr } = await this.execPromise(command);
|
|
158
|
+
if (stderr && stderr.toLowerCase().includes('error')) {
|
|
159
|
+
Logger.debug(`Pip installation error: ${stderr}`);
|
|
161
160
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
161
|
+
// wait for 5 seconds as python pip would be little delayed
|
|
162
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
163
|
+
const checkStatus = await this.checkInstallation(requirement, options);
|
|
164
|
+
if (!checkStatus.installed) {
|
|
165
|
+
Logger.error(`Package not found after the command, ${stderr}`);
|
|
166
|
+
throw new Error(`Pip installation failed with: ${stderr}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
name: requirement.name,
|
|
172
|
+
type: 'pip',
|
|
173
|
+
installed: true,
|
|
174
|
+
version: requirement.version, // This might need to be updated to actual installed version
|
|
175
|
+
inProgress: false,
|
|
176
|
+
pythonEnv: this.getPythonCommand(options)
|
|
177
|
+
};
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
stepName: `${RecordingConstants.STEP_INSTALL_COMMAND_PREFIX}: ${requirement.name} : ${requirement.version}`,
|
|
181
|
+
inProgressMessage: `Running: ${command}`,
|
|
182
|
+
endMessage: (result) => result.installed ? `Succeeded: ${command}` : `Failed: ${command}`,
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
stepName: RecordingConstants.STEP_PIP_INSTALLER_INSTALL,
|
|
188
|
+
inProgressMessage: `Installing pip package: ${requirement.name}`,
|
|
189
|
+
endMessage: (result) => result.installed
|
|
190
|
+
? `Install completed for ${requirement.name} with version ${result.version}`
|
|
191
|
+
: `Install failed for ${requirement.name}`,
|
|
192
|
+
onError: (error) => {
|
|
193
|
+
return {
|
|
194
|
+
result: {
|
|
195
|
+
name: requirement.name,
|
|
196
|
+
type: 'pip',
|
|
197
|
+
installed: false,
|
|
198
|
+
error: error instanceof Error ? error.message : String(error),
|
|
199
|
+
inProgress: false,
|
|
200
|
+
pythonEnv: this.getPythonCommand(options)
|
|
201
|
+
},
|
|
202
|
+
message: error instanceof Error ? error.message : String(error),
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
});
|
|
180
206
|
}
|
|
181
207
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../../metadatas/types.js';
|
|
2
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Interface for requirement installers.
|
|
@@ -12,15 +13,15 @@ export interface RequirementInstaller {
|
|
|
12
13
|
*/
|
|
13
14
|
canHandle(requirement: RequirementConfig): boolean;
|
|
14
15
|
|
|
15
|
-
|
|
16
16
|
supportCheckUpdates(): boolean;
|
|
17
|
-
|
|
18
17
|
/**
|
|
19
18
|
* Install the requirement
|
|
20
19
|
* @param requirement The requirement to install
|
|
20
|
+
* @param options Optional install options
|
|
21
|
+
* @param recorder Optional InstallOperationManager for recording steps
|
|
21
22
|
* @returns The status of the installation
|
|
22
23
|
*/
|
|
23
|
-
install(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
24
|
+
install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Check if the requirement is already installed
|