imcp 0.1.1 → 0.1.3
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/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/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/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 +4 -58
- 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/utils/adoUtils.js +6 -3
- package/dist/utils/logger.js +1 -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 -1
- package/dist/utils/versionUtils.js +51 -4
- package/dist/web/public/css/modal.css +292 -1
- package/dist/web/public/css/serverDetails.css +14 -1
- package/dist/web/public/index.html +122 -20
- package/dist/web/public/js/flights/flights.js +1 -0
- 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/publishHandler.js +22 -20
- package/dist/web/public/js/serverCategoryDetails.js +60 -11
- package/dist/web/public/js/serverCategoryList.js +2 -2
- package/dist/web/public/js/settings.js +314 -0
- package/dist/web/public/settings.html +135 -0
- package/dist/web/public/styles.css +32 -0
- package/dist/web/server.js +82 -0
- package/memory-bank/activeContext.md +13 -1
- package/memory-bank/decisionLog.md +63 -0
- package/memory-bank/progress.md +30 -0
- package/memory-bank/systemPatterns.md +7 -0
- package/package.json +1 -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/recordingConstants.ts +62 -0
- package/src/core/metadatas/types.ts +23 -0
- 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 +4 -77
- package/src/services/RequirementService.ts +564 -67
- package/src/services/ServerService.ts +0 -90
- package/src/utils/adoUtils.ts +6 -4
- package/src/utils/logger.ts +1 -1
- package/src/utils/macroExpressionUtils.ts +4 -21
- package/src/utils/osUtils.ts +92 -1
- package/src/utils/versionUtils.ts +71 -19
- package/src/web/public/css/modal.css +292 -1
- package/src/web/public/css/serverDetails.css +14 -1
- package/src/web/public/index.html +122 -20
- 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/publishHandler.js +22 -20
- package/src/web/public/js/serverCategoryDetails.js +60 -11
- package/src/web/public/js/serverCategoryList.js +5 -5
- package/src/web/public/js/settings.js +314 -0
- package/src/web/public/settings.html +135 -0
- package/src/web/public/styles.css +32 -0
- package/src/web/server.ts +85 -0
- package/src/web/public/js/modal/messageQueue.js +0 -112
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
} from '../../metadatas/types.js';
|
|
10
10
|
import { Logger } from '../../../utils/logger.js';
|
|
11
11
|
import { ClientInstallerFactory } from './ClientInstallerFactory.js';
|
|
12
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
13
|
+
import { stat } from 'fs';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Main client installer class that orchestrates client installation process
|
|
@@ -26,56 +28,27 @@ export class ClientInstaller {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
|
-
*
|
|
30
|
-
*/
|
|
31
|
-
private generateOperationId(): string {
|
|
32
|
-
return `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Check if server requirements are ready
|
|
37
|
-
* Waits for requirements to be ready with timeout
|
|
31
|
+
* Install all specified clients
|
|
38
32
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if (!requirementsReady) {
|
|
43
|
-
const pendingStatus: OperationStatus = {
|
|
44
|
-
status: 'pending',
|
|
45
|
-
type: 'install',
|
|
46
|
-
target: 'server',
|
|
47
|
-
message: `Waiting for requirements to be ready for client: ${clientName}`,
|
|
48
|
-
operationId
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
await this.configProvider.updateServerOperationStatus(
|
|
52
|
-
this.categoryName,
|
|
53
|
-
this.serverName,
|
|
54
|
-
clientName,
|
|
55
|
-
pendingStatus
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
// Set up periodic checking with timeout
|
|
59
|
-
const startTime = Date.now();
|
|
60
|
-
const timeoutMs = 5 * 60 * 1000; // 5 minutes
|
|
61
|
-
const intervalMs = 5 * 1000; // 5 seconds
|
|
62
|
-
|
|
63
|
-
while (!requirementsReady && (Date.now() - startTime) < timeoutMs) {
|
|
64
|
-
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
65
|
-
requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
33
|
+
async install(options: ServerInstallOptions): Promise<ServerOperationResult> {
|
|
34
|
+
const initialStatuses: OperationStatus[] = [];
|
|
68
35
|
|
|
69
|
-
|
|
36
|
+
// Start installation for each client asynchronously
|
|
37
|
+
const installPromises = this.clients.map(async (clientName) => {
|
|
38
|
+
const status = await this.installClient(clientName, options);
|
|
39
|
+
initialStatuses.push(status);
|
|
40
|
+
return status;
|
|
41
|
+
});
|
|
70
42
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
if (npmPathRequirement && npmPathRequirement.npmPath) {
|
|
74
|
-
options.settings = options.settings || {};
|
|
75
|
-
options.settings.npmPath = npmPathRequirement.npmPath;
|
|
76
|
-
}
|
|
43
|
+
// Wait for all installations to complete
|
|
44
|
+
await Promise.all(installPromises);
|
|
77
45
|
|
|
78
|
-
|
|
46
|
+
// Return result
|
|
47
|
+
return {
|
|
48
|
+
success: true,
|
|
49
|
+
message: 'Client installations completed',
|
|
50
|
+
status: initialStatuses
|
|
51
|
+
};
|
|
79
52
|
}
|
|
80
53
|
|
|
81
54
|
/**
|
|
@@ -104,7 +77,41 @@ export class ClientInstaller {
|
|
|
104
77
|
operationId
|
|
105
78
|
};
|
|
106
79
|
|
|
107
|
-
|
|
80
|
+
// Async installation process
|
|
81
|
+
this.processInstallation(clientName, operationId, options)
|
|
82
|
+
.then((status) => {
|
|
83
|
+
if (status.status === 'completed' || status.status === 'failed') {
|
|
84
|
+
InstallOperationManager
|
|
85
|
+
.getInstance(this.categoryName, this.serverName)
|
|
86
|
+
.markOverallStatus(status.status)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.configProvider.updateServerOperationStatus(
|
|
90
|
+
this.categoryName,
|
|
91
|
+
this.serverName,
|
|
92
|
+
clientName,
|
|
93
|
+
status
|
|
94
|
+
);
|
|
95
|
+
})
|
|
96
|
+
.catch((error) => {
|
|
97
|
+
this.configProvider.updateServerOperationStatus(
|
|
98
|
+
this.categoryName,
|
|
99
|
+
this.serverName,
|
|
100
|
+
clientName,
|
|
101
|
+
{
|
|
102
|
+
status: 'failed',
|
|
103
|
+
type: 'install',
|
|
104
|
+
target: 'server',
|
|
105
|
+
message: `Error installing client ${clientName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
106
|
+
operationId,
|
|
107
|
+
error: error instanceof Error ? error.message : String(error)
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
Logger.error(`Error installing client ${clientName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
111
|
+
InstallOperationManager
|
|
112
|
+
.getInstance(this.categoryName, this.serverName)
|
|
113
|
+
.markOverallStatus('failed', error)
|
|
114
|
+
});
|
|
108
115
|
|
|
109
116
|
// Update server status with initial client installation status
|
|
110
117
|
await this.configProvider.updateServerOperationStatus(
|
|
@@ -116,107 +123,100 @@ export class ClientInstaller {
|
|
|
116
123
|
return initialStatus;
|
|
117
124
|
}
|
|
118
125
|
|
|
119
|
-
private async processInstallation(clientName: string, operationId: string, options: ServerInstallOptions): Promise<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
await this.configProvider.updateServerOperationStatus(
|
|
133
|
-
this.categoryName,
|
|
134
|
-
this.serverName,
|
|
135
|
-
clientName,
|
|
136
|
-
failedStatus
|
|
137
|
-
);
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
126
|
+
private async processInstallation(clientName: string, operationId: string, options: ServerInstallOptions): Promise<OperationStatus> {
|
|
127
|
+
const requirementsReady = await this.checkRequirements(operationId, clientName, options);
|
|
128
|
+
if (!requirementsReady) {
|
|
129
|
+
const failedStatus: OperationStatus = {
|
|
130
|
+
status: 'failed',
|
|
131
|
+
type: 'install',
|
|
132
|
+
target: 'server',
|
|
133
|
+
message: `Requirements not ready for client: ${clientName} after timeout`,
|
|
134
|
+
operationId
|
|
135
|
+
};
|
|
136
|
+
return failedStatus;
|
|
137
|
+
}
|
|
140
138
|
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
// Create client-specific installer
|
|
140
|
+
const installer = ClientInstallerFactory.getInstaller(clientName);
|
|
143
141
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
if (!installer) {
|
|
143
|
+
throw new Error(`Failed to create installer for client: ${clientName}`);
|
|
144
|
+
}
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
146
|
+
const serverConfig = await this.configProvider.getServerMcpConfig(this.categoryName, this.serverName);
|
|
147
|
+
if (!serverConfig) {
|
|
148
|
+
throw new Error(`Server configuration not found for category: ${this.categoryName}, server: ${this.serverName}`);
|
|
149
|
+
}
|
|
152
150
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
151
|
+
// If we've reached here, requirements are ready - update status to in-progress
|
|
152
|
+
const inProgressStatus: OperationStatus = {
|
|
153
|
+
status: 'in-progress',
|
|
154
|
+
type: 'install',
|
|
155
|
+
target: 'server',
|
|
156
|
+
message: `Installing client: ${clientName}`,
|
|
157
|
+
operationId: operationId
|
|
158
|
+
};
|
|
161
159
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
this.categoryName,
|
|
172
|
-
this.serverName,
|
|
173
|
-
clientName,
|
|
174
|
-
status
|
|
175
|
-
);
|
|
160
|
+
await this.configProvider.updateServerOperationStatus(
|
|
161
|
+
this.categoryName,
|
|
162
|
+
this.serverName,
|
|
163
|
+
clientName,
|
|
164
|
+
inProgressStatus
|
|
165
|
+
);
|
|
166
|
+
// Install client
|
|
167
|
+
return await installer.install(serverConfig, options, this.categoryName);
|
|
168
|
+
}
|
|
176
169
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Generate a unique operation ID for tracking installations
|
|
172
|
+
*/
|
|
173
|
+
private generateOperationId(): string {
|
|
174
|
+
return `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check if server requirements are ready
|
|
179
|
+
* Waits for requirements to be ready with timeout
|
|
180
|
+
*/
|
|
181
|
+
private async checkRequirements(operationId: string, clientName: string, options: ServerInstallOptions): Promise<boolean> {
|
|
182
|
+
let requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
|
|
183
|
+
|
|
184
|
+
if (!requirementsReady) {
|
|
185
|
+
const pendingStatus: OperationStatus = {
|
|
186
|
+
status: 'pending',
|
|
183
187
|
type: 'install',
|
|
184
188
|
target: 'server',
|
|
185
|
-
message: `
|
|
186
|
-
operationId
|
|
187
|
-
error: error instanceof Error ? error.message : String(error)
|
|
189
|
+
message: `Waiting for requirements to be ready for client: ${clientName}`,
|
|
190
|
+
operationId
|
|
188
191
|
};
|
|
189
192
|
|
|
190
193
|
await this.configProvider.updateServerOperationStatus(
|
|
191
194
|
this.categoryName,
|
|
192
195
|
this.serverName,
|
|
193
196
|
clientName,
|
|
194
|
-
|
|
197
|
+
pendingStatus
|
|
195
198
|
);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
199
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const initialStatuses: OperationStatus[] = [];
|
|
200
|
+
// Set up periodic checking with timeout
|
|
201
|
+
const startTime = Date.now();
|
|
202
|
+
const timeoutMs = 5 * 60 * 1000; // 5 minutes
|
|
203
|
+
const intervalMs = 5 * 1000; // 5 seconds
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
});
|
|
205
|
+
while (!requirementsReady && (Date.now() - startTime) < timeoutMs) {
|
|
206
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
207
|
+
requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
211
210
|
|
|
212
|
-
|
|
213
|
-
await Promise.all(installPromises);
|
|
211
|
+
var requirementsStatus: RequirementStatus[] = await this.configProvider.GetServerRequirementStatus(this.categoryName, this.serverName);
|
|
214
212
|
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
213
|
+
// Find first non-empty npmPath from requirements status
|
|
214
|
+
const npmPathRequirement = requirementsStatus.find(status => status.npmPath && status.npmPath.length > 0);
|
|
215
|
+
if (npmPathRequirement && npmPathRequirement.npmPath) {
|
|
216
|
+
options.settings = options.settings || {};
|
|
217
|
+
options.settings.npmPath = npmPathRequirement.npmPath;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return requirementsReady;
|
|
221
221
|
}
|
|
222
222
|
}
|
|
@@ -3,6 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import { SETTINGS_DIR } from '../../metadatas/constants.js';
|
|
4
4
|
import { RequirementInstaller } from './RequirementInstaller.js';
|
|
5
5
|
import { Logger } from '../../../utils/logger.js';
|
|
6
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Abstract base class with common functionality for all requirement installers
|
|
@@ -18,7 +19,14 @@ export abstract class BaseInstaller implements RequirementInstaller {
|
|
|
18
19
|
|
|
19
20
|
abstract canHandle(requirement: RequirementConfig): boolean;
|
|
20
21
|
abstract supportCheckUpdates(): boolean;
|
|
21
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Install the requirement
|
|
24
|
+
* @param requirement The requirement to install
|
|
25
|
+
* @param options Optional install options
|
|
26
|
+
* @param recorder Optional InstallOperationManager for recording steps
|
|
27
|
+
* @returns The status of the installation
|
|
28
|
+
*/
|
|
29
|
+
abstract install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
22
30
|
abstract checkInstallation(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
|
|
23
31
|
/**
|
|
24
32
|
* Get the latest version available for the requirement.
|
|
@@ -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
|
/**
|