imcp 0.0.14 → 0.0.16
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/core/ConfigurationProvider.d.ts +1 -0
- package/dist/core/ConfigurationProvider.js +15 -0
- package/dist/core/InstallationService.js +2 -7
- package/dist/core/MCPManager.d.ts +11 -2
- package/dist/core/MCPManager.js +24 -1
- package/dist/core/RequirementService.js +2 -8
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +51 -0
- package/dist/core/installers/clients/BaseClientInstaller.js +160 -0
- package/dist/core/installers/clients/ClientInstaller.d.ts +16 -9
- package/dist/core/installers/clients/ClientInstaller.js +80 -527
- package/dist/core/installers/clients/ClientInstallerFactory.d.ts +20 -0
- package/dist/core/installers/clients/ClientInstallerFactory.js +37 -0
- package/dist/core/installers/clients/ClineInstaller.d.ts +18 -0
- package/dist/core/installers/clients/ClineInstaller.js +124 -0
- package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +34 -0
- package/dist/core/installers/clients/GithubCopilotInstaller.js +162 -0
- package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +15 -0
- package/dist/core/installers/clients/MSRooCodeInstaller.js +122 -0
- package/dist/core/installers/requirements/BaseInstaller.d.ts +11 -34
- package/dist/core/installers/requirements/BaseInstaller.js +5 -116
- package/dist/core/installers/requirements/CommandInstaller.d.ts +6 -1
- package/dist/core/installers/requirements/CommandInstaller.js +7 -0
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +6 -1
- package/dist/core/installers/requirements/GeneralInstaller.js +9 -4
- package/dist/core/installers/requirements/NpmInstaller.d.ts +46 -7
- package/dist/core/installers/requirements/NpmInstaller.js +150 -58
- package/dist/core/installers/requirements/PipInstaller.d.ts +9 -0
- package/dist/core/installers/requirements/PipInstaller.js +66 -28
- package/dist/core/onboard/FeedOnboardService.d.ts +50 -13
- package/dist/core/onboard/FeedOnboardService.js +263 -88
- package/dist/core/onboard/OnboardProcessor.d.ts +79 -0
- package/dist/core/onboard/OnboardProcessor.js +290 -0
- package/dist/core/onboard/OnboardStatus.d.ts +49 -0
- package/dist/core/onboard/OnboardStatus.js +10 -0
- package/dist/core/onboard/OnboardStatusManager.d.ts +57 -0
- package/dist/core/onboard/OnboardStatusManager.js +176 -0
- package/dist/core/types.d.ts +4 -5
- package/dist/core/validators/FeedValidator.d.ts +8 -1
- package/dist/core/validators/FeedValidator.js +60 -7
- package/dist/core/validators/IServerValidator.d.ts +19 -0
- package/dist/core/validators/IServerValidator.js +2 -0
- package/dist/core/validators/SSEServerValidator.d.ts +15 -0
- package/dist/core/validators/SSEServerValidator.js +39 -0
- package/dist/core/validators/ServerValidatorFactory.d.ts +24 -0
- package/dist/core/validators/ServerValidatorFactory.js +45 -0
- package/dist/core/validators/StdioServerValidator.d.ts +46 -0
- package/dist/core/validators/StdioServerValidator.js +229 -0
- package/dist/services/InstallRequestValidator.d.ts +1 -1
- package/dist/services/ServerService.d.ts +9 -6
- package/dist/services/ServerService.js +18 -7
- package/dist/utils/adoUtils.d.ts +29 -0
- package/dist/utils/adoUtils.js +252 -0
- package/dist/utils/clientUtils.d.ts +0 -7
- package/dist/utils/clientUtils.js +0 -42
- package/dist/utils/githubUtils.d.ts +10 -0
- package/dist/utils/githubUtils.js +22 -0
- package/dist/utils/macroExpressionUtils.d.ts +38 -0
- package/dist/utils/macroExpressionUtils.js +116 -0
- package/dist/utils/osUtils.d.ts +4 -20
- package/dist/utils/osUtils.js +78 -23
- package/dist/web/contract/serverContract.d.ts +3 -1
- package/dist/web/public/css/notifications.css +48 -17
- package/dist/web/public/css/onboard.css +66 -3
- package/dist/web/public/index.html +84 -16
- package/dist/web/public/js/api.js +3 -6
- package/dist/web/public/js/flights/flights.js +127 -0
- package/dist/web/public/js/modal/installation.js +5 -5
- package/dist/web/public/js/modal/modalSetup.js +3 -2
- package/dist/web/public/js/notifications.js +66 -27
- package/dist/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +338 -0
- package/dist/web/public/js/onboard/formProcessor.js +810 -255
- package/dist/web/public/js/onboard/index.js +328 -85
- package/dist/web/public/js/onboard/publishHandler.js +132 -0
- package/dist/web/public/js/onboard/state.js +61 -17
- package/dist/web/public/js/onboard/templates.js +217 -249
- package/dist/web/public/js/onboard/uiHandlers.js +679 -117
- package/dist/web/public/js/onboard/validationHandlers.js +378 -0
- package/dist/web/public/js/serverCategoryList.js +15 -2
- package/dist/web/public/onboard.html +191 -45
- package/dist/web/public/styles.css +91 -1
- package/dist/web/server.d.ts +0 -10
- package/dist/web/server.js +131 -22
- package/package.json +2 -2
- package/src/core/ConfigurationProvider.ts +15 -0
- package/src/core/InstallationService.ts +2 -7
- package/src/core/MCPManager.ts +26 -1
- package/src/core/RequirementService.ts +2 -9
- package/src/core/installers/clients/BaseClientInstaller.ts +196 -0
- package/src/core/installers/clients/ClientInstaller.ts +97 -608
- package/src/core/installers/clients/ClientInstallerFactory.ts +43 -0
- package/src/core/installers/clients/ClineInstaller.ts +135 -0
- package/src/core/installers/clients/GithubCopilotInstaller.ts +179 -0
- package/src/core/installers/clients/MSRooCodeInstaller.ts +133 -0
- package/src/core/installers/requirements/BaseInstaller.ts +13 -136
- package/src/core/installers/requirements/CommandInstaller.ts +9 -1
- package/src/core/installers/requirements/GeneralInstaller.ts +11 -4
- package/src/core/installers/requirements/NpmInstaller.ts +178 -61
- package/src/core/installers/requirements/PipInstaller.ts +68 -29
- package/src/core/onboard/FeedOnboardService.ts +346 -0
- package/src/core/onboard/OnboardProcessor.ts +305 -0
- package/src/core/onboard/OnboardStatus.ts +55 -0
- package/src/core/onboard/OnboardStatusManager.ts +188 -0
- package/src/core/types.ts +4 -5
- package/src/core/validators/FeedValidator.ts +79 -0
- package/src/core/validators/IServerValidator.ts +21 -0
- package/src/core/validators/SSEServerValidator.ts +43 -0
- package/src/core/validators/ServerValidatorFactory.ts +51 -0
- package/src/core/validators/StdioServerValidator.ts +259 -0
- package/src/services/InstallRequestValidator.ts +1 -1
- package/src/services/ServerService.ts +22 -7
- package/src/utils/adoUtils.ts +291 -0
- package/src/utils/clientUtils.ts +0 -44
- package/src/utils/githubUtils.ts +24 -0
- package/src/utils/macroExpressionUtils.ts +121 -0
- package/src/utils/osUtils.ts +89 -24
- package/src/web/contract/serverContract.ts +74 -0
- package/src/web/public/css/notifications.css +48 -17
- package/src/web/public/css/onboard.css +107 -0
- package/src/web/public/index.html +84 -16
- package/src/web/public/js/api.js +3 -6
- package/src/web/public/js/flights/flights.js +127 -0
- package/src/web/public/js/modal/installation.js +5 -5
- package/src/web/public/js/modal/modalSetup.js +3 -2
- package/src/web/public/js/notifications.js +66 -27
- package/src/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +338 -0
- package/src/web/public/js/onboard/formProcessor.js +864 -0
- package/src/web/public/js/onboard/index.js +374 -0
- package/src/web/public/js/onboard/publishHandler.js +132 -0
- package/src/web/public/js/onboard/state.js +76 -0
- package/src/web/public/js/onboard/templates.js +343 -0
- package/src/web/public/js/onboard/uiHandlers.js +758 -0
- package/src/web/public/js/onboard/validationHandlers.js +378 -0
- package/src/web/public/js/serverCategoryList.js +15 -2
- package/src/web/public/onboard.html +296 -0
- package/src/web/public/styles.css +91 -1
- package/src/web/server.ts +167 -58
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { SETTINGS_DIR } from '../core/constants.js';
|
|
2
|
+
import { Logger } from './logger.js';
|
|
3
|
+
import { exec } from 'child_process';
|
|
4
|
+
import util from 'util';
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
const execAsync = util.promisify(exec);
|
|
8
|
+
/**
|
|
9
|
+
* Sets up the NPM credential provider.
|
|
10
|
+
* Installs @microsoft/artifacts-npm-credprovider if not already installed.
|
|
11
|
+
* @private
|
|
12
|
+
*/
|
|
13
|
+
async function _setupNpmCredentialProvider() {
|
|
14
|
+
Logger.debug('Setting up NPM credential provider...');
|
|
15
|
+
const credProviderCommand = 'artifacts-npm-credprovider';
|
|
16
|
+
// Check if artifacts-npm-credprovider is installed by trying to get its version or a known command.
|
|
17
|
+
// A more robust check might involve checking a specific version or path.
|
|
18
|
+
let installed = false;
|
|
19
|
+
try {
|
|
20
|
+
// Attempt to get help output as a basic check for presence
|
|
21
|
+
const { stdout, stderr } = await execAsync(`${credProviderCommand} --help`);
|
|
22
|
+
Logger.debug(`${credProviderCommand} --help stdout: ${stdout}`);
|
|
23
|
+
if (stderr)
|
|
24
|
+
Logger.debug(`${credProviderCommand} --help stderr: ${stderr}`);
|
|
25
|
+
installed = true;
|
|
26
|
+
Logger.debug(`${credProviderCommand} appears to be installed.`);
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
Logger.debug(`${credProviderCommand} not found or --help failed, attempting installation. Error: ${e}`);
|
|
30
|
+
}
|
|
31
|
+
if (!installed) {
|
|
32
|
+
Logger.log(`Installing @microsoft/artifacts-npm-credprovider...`);
|
|
33
|
+
try {
|
|
34
|
+
const installCommand = `npm install -g @microsoft/artifacts-npm-credprovider --registry https://pkgs.dev.azure.com/mseng/226da8e7-b1c0-4167-9678-53f461e07706/_packaging/AzureArtifacts/npm/registry/`;
|
|
35
|
+
const { stdout: installStdout, stderr: installStderr } = await execAsync(installCommand);
|
|
36
|
+
Logger.debug(`@microsoft/artifacts-npm-credprovider install stdout: ${installStdout}`);
|
|
37
|
+
if (installStderr)
|
|
38
|
+
Logger.debug(`@microsoft/artifacts-npm-credprovider install stderr: ${installStderr}`);
|
|
39
|
+
Logger.log('@microsoft/artifacts-npm-credprovider installed successfully.');
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
Logger.error('Failed to install @microsoft/artifacts-npm-credprovider', error);
|
|
43
|
+
throw new Error(`Failed to install @microsoft/artifacts-npm-credprovider: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Installs pip requirements: keyring and artifacts-keyring.
|
|
49
|
+
* @param pythonCommand The python command to use (e.g., 'python' or 'python3').
|
|
50
|
+
* @private
|
|
51
|
+
*/
|
|
52
|
+
async function _installPipRequirements(pythonCommand) {
|
|
53
|
+
Logger.debug(`Installing pip requirements: keyring, artifacts-keyring using ${pythonCommand}`);
|
|
54
|
+
try {
|
|
55
|
+
const command = `${pythonCommand} -m pip install keyring artifacts-keyring`;
|
|
56
|
+
const { stdout, stderr } = await execAsync(command);
|
|
57
|
+
Logger.debug(`pip install keyring artifacts-keyring stdout: ${stdout}`);
|
|
58
|
+
if (stderr)
|
|
59
|
+
Logger.debug(`pip install keyring artifacts-keyring stderr: ${stderr}`);
|
|
60
|
+
Logger.log('Successfully installed keyring and artifacts-keyring.');
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
Logger.error('Failed to install pip requirements (keyring, artifacts-keyring)', error);
|
|
64
|
+
throw new Error(`Failed to install pip requirements: ${error instanceof Error ? error.message : String(error)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Configures NPM authentication for Azure DevOps Artifacts in a specified directory.
|
|
69
|
+
* This includes setting up the credential provider, creating an .npmrc file,
|
|
70
|
+
* and running the credential provider.
|
|
71
|
+
* @param execPromise The promise-based exec function.
|
|
72
|
+
* @param registry The Azure DevOps artifacts registry configuration.
|
|
73
|
+
* @param directoryPath The directory where .npmrc will be created and commands will be executed.
|
|
74
|
+
* @private
|
|
75
|
+
*/
|
|
76
|
+
async function _configureNpmAdoAuthInDirectory(execPromise, registry, directoryPath) {
|
|
77
|
+
if (!registry || !registry.registryUrl || !registry.registryName) {
|
|
78
|
+
throw new Error('Registry name and URL are required for NPM ADO auth configuration.');
|
|
79
|
+
}
|
|
80
|
+
await _setupNpmCredentialProvider();
|
|
81
|
+
const npmrcContent = `@${registry.registryName}:registry=${registry.registryUrl}\nalways-auth=true`;
|
|
82
|
+
const npmrcPath = path.join(directoryPath, '.npmrc');
|
|
83
|
+
await fs.writeFile(npmrcPath, npmrcContent.trim());
|
|
84
|
+
Logger.debug(`Created/Updated .npmrc file at: ${npmrcPath}`);
|
|
85
|
+
const env = { ...process.env, NUGET_CREDENTIALPROVIDER_VSTS_TOKENTYPE: 'SelfDescribing' };
|
|
86
|
+
Logger.debug(`Running artifacts-npm-credprovider in ${directoryPath}`);
|
|
87
|
+
const { stdout: credProviderStdout, stderr: credProviderStderr } = await execPromise('artifacts-npm-credprovider', { cwd: directoryPath, env });
|
|
88
|
+
Logger.debug(`artifacts-npm-credprovider stdout: ${credProviderStdout}`);
|
|
89
|
+
if (credProviderStderr)
|
|
90
|
+
Logger.debug(`artifacts-npm-credprovider stderr: ${credProviderStderr}`);
|
|
91
|
+
Logger.log(`Successfully ran artifacts-npm-credprovider in ${directoryPath}`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Handles fetching and setting up an Azure DevOps artifact.
|
|
95
|
+
* @param requirement The requirement configuration.
|
|
96
|
+
* @param registry The Azure DevOps artifacts registry configuration.
|
|
97
|
+
* @param pythonCommand Optional Python command (e.g., 'python', 'python3') for pip operations.
|
|
98
|
+
* @param targetDir Optional target directory for npm artifact setup. If not provided, a default will be used.
|
|
99
|
+
* @returns A promise that resolves with the artifact details.
|
|
100
|
+
*/
|
|
101
|
+
export async function handleArtifact(requirement, registry, pythonCommand = 'python', // Default to 'python' if not provided
|
|
102
|
+
targetDir // Optional target directory for npm
|
|
103
|
+
) {
|
|
104
|
+
if (!registry) {
|
|
105
|
+
throw new Error('Azure DevOps artifacts registry configuration is required.');
|
|
106
|
+
}
|
|
107
|
+
if (!registry.registryName || !registry.registryUrl) {
|
|
108
|
+
throw new Error('Registry name and URL are required for Azure DevOps artifacts.');
|
|
109
|
+
}
|
|
110
|
+
Logger.debug(`Handling ADO artifact for requirement: ${requirement.name}, type: ${requirement.type}`);
|
|
111
|
+
if (requirement.type === 'npm') {
|
|
112
|
+
const requirementDir = targetDir || path.join(SETTINGS_DIR, 'requirements', requirement.name, requirement.version);
|
|
113
|
+
await fs.mkdir(requirementDir, { recursive: true });
|
|
114
|
+
Logger.debug(`Ensured directory for npm requirement: ${requirementDir}`);
|
|
115
|
+
try {
|
|
116
|
+
await _configureNpmAdoAuthInDirectory(execAsync, registry, requirementDir);
|
|
117
|
+
Logger.log(`Successfully configured ADO NPM auth for ${requirement.name} in ${requirementDir}`);
|
|
118
|
+
const version = requirement.version.includes('latest') ? 'latest' : requirement.version;
|
|
119
|
+
return {
|
|
120
|
+
folderPath: requirementDir,
|
|
121
|
+
type: 'npm',
|
|
122
|
+
package: `@${registry.registryName}/${requirement.name}`,
|
|
123
|
+
registryUrl: registry.registryUrl,
|
|
124
|
+
version: version
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
Logger.error(`Failed to configure ADO NPM auth for ${requirement.name} in ${requirementDir}`, error);
|
|
129
|
+
throw new Error(`ADO NPM auth configuration failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (requirement.type === 'pip') {
|
|
133
|
+
await _installPipRequirements(pythonCommand);
|
|
134
|
+
const packageName = requirement.version.toLowerCase().includes('latest')
|
|
135
|
+
? `${requirement.name} --upgrade`
|
|
136
|
+
: `${requirement.name}==${requirement.version}`;
|
|
137
|
+
Logger.log(`Pip requirement ${packageName} configured with registry ${registry.registryUrl}`);
|
|
138
|
+
return {
|
|
139
|
+
type: 'pip',
|
|
140
|
+
package: packageName,
|
|
141
|
+
registryUrl: registry.registryUrl,
|
|
142
|
+
version: requirement.version
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
throw new Error(`Unsupported requirement type for ADO artifact: ${requirement.type}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Get the latest version of an artifact from Azure DevOps.
|
|
151
|
+
* This is a simplified implementation and might require further enhancements for robust authentication and error handling.
|
|
152
|
+
* @param execPromise The promise-based exec function.
|
|
153
|
+
* @param requirement The requirement configuration.
|
|
154
|
+
* @param registry The Azure DevOps artifacts registry configuration.
|
|
155
|
+
* @param options Optional server install options (e.g., for pythonCommand).
|
|
156
|
+
* @returns The latest version string, or undefined if not found or an error occurs.
|
|
157
|
+
*/
|
|
158
|
+
export async function getArtifactLatestVersion(requirement, registry, options, // Added import for ServerInstallOptions
|
|
159
|
+
targetDir // Optional target directory for npm
|
|
160
|
+
) {
|
|
161
|
+
if (!registry || !registry.registryUrl) {
|
|
162
|
+
Logger.error('ADO Artifact registry URL is missing for fetching latest version.');
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
Logger.debug(`Attempting to fetch latest version for ADO artifact: ${requirement.name} of type ${requirement.type}`);
|
|
166
|
+
if (requirement.type === 'npm') {
|
|
167
|
+
if (!registry.registryName) { // Ensure registryName is present
|
|
168
|
+
Logger.error('NPM ADO Artifact registry name is missing for fetching latest version.');
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
const requirementDir = targetDir || path.join(SETTINGS_DIR, 'requirements', requirement.name, requirement.version);
|
|
172
|
+
try {
|
|
173
|
+
await fs.mkdir(requirementDir, { recursive: true });
|
|
174
|
+
Logger.debug(`Ensured directory for NPM ADO version check: ${requirementDir}`);
|
|
175
|
+
// Configure auth within the requirementDir
|
|
176
|
+
await _configureNpmAdoAuthInDirectory(execAsync, registry, requirementDir);
|
|
177
|
+
Logger.log(`Successfully configured ADO NPM auth for version check of ${requirement.name} in ${requirementDir}`);
|
|
178
|
+
const fullPackageName = `@${registry.registryName}/${requirement.name}`;
|
|
179
|
+
const command = `npm view ${fullPackageName} version --registry ${registry.registryUrl}`;
|
|
180
|
+
Logger.debug(`Executing for NPM ADO latest version: ${command} in ${requirementDir}`);
|
|
181
|
+
const { stdout, stderr } = await execAsync(command, { cwd: requirementDir });
|
|
182
|
+
if (stderr && !stdout.trim()) {
|
|
183
|
+
Logger.error(`Error fetching NPM ADO version for ${fullPackageName} via npm view: ${stderr}`);
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
const version = stdout.trim();
|
|
187
|
+
if (version) {
|
|
188
|
+
Logger.debug(`Found latest NPM ADO version for ${fullPackageName}: ${version}`);
|
|
189
|
+
return version;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
Logger.log(`Could not parse latest NPM version from ADO for ${fullPackageName} from output: '${stdout}'`);
|
|
193
|
+
return undefined;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
Logger.error(`Exception fetching latest NPM version from ADO for ${requirement.name} in ${requirementDir}: ${error instanceof Error ? error.message : String(error)}`);
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (requirement.type === 'pip') {
|
|
202
|
+
try {
|
|
203
|
+
const pythonCmd = options?.settings?.pythonEnv || 'python';
|
|
204
|
+
const pipCmd = `${pythonCmd} -m pip`;
|
|
205
|
+
// Ensure keyring and artifacts-keyring are installed.
|
|
206
|
+
// This is usually handled by `handleArtifact` during install.
|
|
207
|
+
// For a standalone version check, we might need to ensure they exist.
|
|
208
|
+
// Consider calling _installPipRequirements(pythonCmd) if necessary, but it has side effects.
|
|
209
|
+
// For now, assume they are present if ADO pip artifacts are being used.
|
|
210
|
+
const command = `${pipCmd} index versions ${requirement.name} --extra-index-url ${registry.registryUrl}`;
|
|
211
|
+
Logger.debug(`Executing for Pip ADO latest version: ${command}`);
|
|
212
|
+
const { stdout, stderr } = await execAsync(command);
|
|
213
|
+
if (stderr && !stdout.trim()) { // If there's stderr and no significant stdout, it's likely an error
|
|
214
|
+
Logger.error(`Error fetching Pip ADO version for ${requirement.name}: ${stderr}`);
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
// Parse output like:
|
|
218
|
+
// mypackage (1.0.0)
|
|
219
|
+
// Available versions: 1.0.0, 0.9.0
|
|
220
|
+
// LATEST: 1.0.0
|
|
221
|
+
// Or:
|
|
222
|
+
// mypackage
|
|
223
|
+
// VERSIONS: 1.0.0, 0.9.0
|
|
224
|
+
// Latest: 1.0.0
|
|
225
|
+
const latestMatch = stdout.match(/(?:LATEST|Latest):\s*([^\s]+)/);
|
|
226
|
+
if (latestMatch && latestMatch[1]) {
|
|
227
|
+
Logger.debug(`Found latest Pip ADO version via LATEST line: ${latestMatch[1]}`);
|
|
228
|
+
return latestMatch[1];
|
|
229
|
+
}
|
|
230
|
+
// Fallback: try to parse from "Available versions" or "VERSIONS"
|
|
231
|
+
const versionsMatch = stdout.match(/(?:Available versions|VERSIONS):\s*([^\n]+)/);
|
|
232
|
+
if (versionsMatch && versionsMatch[1]) {
|
|
233
|
+
const versions = versionsMatch[1].split(',').map(v => v.trim()).filter(v => v);
|
|
234
|
+
if (versions.length > 0) {
|
|
235
|
+
// This is a naive approach, assumes the first listed is relevant or latest.
|
|
236
|
+
// Proper sorting (e.g. semver) would be better.
|
|
237
|
+
Logger.debug(`Found Pip ADO versions: ${versions.join(', ')}. Taking the first one: ${versions[0]}`);
|
|
238
|
+
return versions[0];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
Logger.log(`Could not parse latest Pip version from ADO for ${requirement.name} from output: ${stdout}`); // Changed Logger.warn to Logger.log
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
Logger.error(`Exception fetching latest Pip version from ADO for ${requirement.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
Logger.log(`getArtifactLatestVersion not implemented for type '${requirement.type}' or encountered an issue.`); // Changed Logger.warn to Logger.log
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=adoUtils.js.map
|
|
@@ -7,13 +7,6 @@
|
|
|
7
7
|
export declare function extractZipFile(zipPath: string, options: {
|
|
8
8
|
dir: string;
|
|
9
9
|
}): Promise<void>;
|
|
10
|
-
/**
|
|
11
|
-
* Resolves the path to an NPM module, replacing template variables
|
|
12
|
-
* First checks if the module path exists under NVM-controlled Node, then falls back to global npm
|
|
13
|
-
* @param pathString The path string potentially containing template variables
|
|
14
|
-
* @returns The resolved path
|
|
15
|
-
*/
|
|
16
|
-
export declare function resolveNpmModulePath(pathString: string): string;
|
|
17
10
|
export declare function readJsonFile(filePath: string, createIfNotExist?: boolean): Promise<any>;
|
|
18
11
|
/**
|
|
19
12
|
* Writes content to a JSON file
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
|
-
import * as fsSync from 'fs';
|
|
3
2
|
import * as path from 'path';
|
|
4
|
-
import { execSync } from 'child_process';
|
|
5
3
|
import extractZipModule from 'extract-zip';
|
|
6
|
-
import { Logger } from './logger.js';
|
|
7
4
|
/**
|
|
8
5
|
* Extract a zip file to a directory
|
|
9
6
|
* @param zipPath The path to the zip file
|
|
@@ -32,45 +29,6 @@ export async function extractZipFile(zipPath, options) {
|
|
|
32
29
|
throw new Error(`Failed to extract zip file ${zipPath}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
33
30
|
}
|
|
34
31
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Resolves the path to an NPM module, replacing template variables
|
|
37
|
-
* First checks if the module path exists under NVM-controlled Node, then falls back to global npm
|
|
38
|
-
* @param pathString The path string potentially containing template variables
|
|
39
|
-
* @returns The resolved path
|
|
40
|
-
*/
|
|
41
|
-
export function resolveNpmModulePath(pathString) {
|
|
42
|
-
// If the path doesn't contain the ${NPMPATH} template, return it as is
|
|
43
|
-
if (!pathString.includes('${NPMPATH}')) {
|
|
44
|
-
return pathString;
|
|
45
|
-
}
|
|
46
|
-
// First try to get NVM-controlled npm path
|
|
47
|
-
const nvmHome = process.env.NVM_HOME;
|
|
48
|
-
if (nvmHome) {
|
|
49
|
-
try {
|
|
50
|
-
// Get current node version
|
|
51
|
-
const nodeVersion = execSync('node -v').toString().trim();
|
|
52
|
-
// Construct the path to npm in the NVM directory
|
|
53
|
-
const nvmNodePath = path.join(nvmHome, nodeVersion);
|
|
54
|
-
const resolvedPath = pathString.replace('${NPMPATH}', nvmNodePath);
|
|
55
|
-
// Check if this path exists
|
|
56
|
-
try {
|
|
57
|
-
fsSync.accessSync(resolvedPath);
|
|
58
|
-
return resolvedPath;
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
Logger.debug(`NVM controlled path doesn't exist: ${resolvedPath}, will try global npm`);
|
|
62
|
-
// Path doesn't exist, will fall back to global npm
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
Logger.debug(`Error determining Node version: ${error}, will use global npm`);
|
|
67
|
-
// Error getting node version, will fall back to global npm
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Fall back to global npm path
|
|
71
|
-
const globalNpmPath = execSync('npm root -g').toString().trim();
|
|
72
|
-
return pathString.replace('${NPMPATH}', globalNpmPath);
|
|
73
|
-
}
|
|
74
32
|
/**
|
|
75
33
|
* Reads a JSON file and parses its content
|
|
76
34
|
* @param filePath Path to the JSON file
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { RegistryConfig, RequirementConfig } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Get the latest version available for a GitHub repository
|
|
4
|
+
* @param execPromise The promise-based exec function
|
|
5
|
+
* @param repository The GitHub repository in format 'owner/repo'
|
|
6
|
+
* @returns The latest version or tag
|
|
7
|
+
*/
|
|
8
|
+
export declare function getGitHubLatestVersion(execPromise: (command: string) => Promise<{
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
}>, repository: string): Promise<string>;
|
|
2
12
|
interface DownloadGithubReleaseResult {
|
|
3
13
|
version: string;
|
|
4
14
|
downloadPath: string;
|
|
@@ -5,6 +5,28 @@ import path from 'path';
|
|
|
5
5
|
import { extractZipFile } from './clientUtils.js';
|
|
6
6
|
import { SETTINGS_DIR } from '../core/constants.js';
|
|
7
7
|
const execAsync = util.promisify(exec);
|
|
8
|
+
/**
|
|
9
|
+
* Get the latest version available for a GitHub repository
|
|
10
|
+
* @param execPromise The promise-based exec function
|
|
11
|
+
* @param repository The GitHub repository in format 'owner/repo'
|
|
12
|
+
* @returns The latest version or tag
|
|
13
|
+
*/
|
|
14
|
+
export async function getGitHubLatestVersion(execPromise, repository) {
|
|
15
|
+
try {
|
|
16
|
+
// Use GitHub CLI to get the latest release
|
|
17
|
+
const { stdout } = await execPromise(`gh release view --repo ${repository} --json tagName --jq .tagName`);
|
|
18
|
+
const latestTag = stdout.trim();
|
|
19
|
+
// Remove 'v' prefix if present
|
|
20
|
+
return latestTag.startsWith('v') ? latestTag.substring(1) : latestTag;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
// If gh command fails, try to get the latest tag
|
|
24
|
+
const { stdout } = await execPromise(`git ls-remote --tags --refs https://github.com/${repository}.git | sort -t '/' -k 3 -V | tail -n 1 | awk -F/ '{print $3}'`);
|
|
25
|
+
let latestTag = stdout.trim();
|
|
26
|
+
// Remove 'v' prefix if present
|
|
27
|
+
return latestTag.startsWith('v') ? latestTag.substring(1) : latestTag;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
8
30
|
/**
|
|
9
31
|
* Downloads a GitHub release asset
|
|
10
32
|
* @param repo GitHub repository in format owner/repo
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ServerInstallOptions } from '../core/types.js';
|
|
2
|
+
export declare const MACRO_EXPRESSIONS: {
|
|
3
|
+
readonly PYTHON_PACKAGE: "${PYTHON_PACKAGE}";
|
|
4
|
+
readonly NPMPATH: "${NPMPATH}";
|
|
5
|
+
readonly BROWSER_PATH: "${BROWSER_PATH}";
|
|
6
|
+
};
|
|
7
|
+
export declare const MacroResolverFunctions: {
|
|
8
|
+
[key: string]: (finalConfig: any, options: ServerInstallOptions) => Promise<string | undefined>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the path for the ${PYTHON_PACKAGE} macro.
|
|
12
|
+
* It considers the pythonEnv setting and falls back to system Python.
|
|
13
|
+
* Also updates finalConfig.command if it's 'python' and pythonEnv is used.
|
|
14
|
+
* @param finalConfig The configuration object (mutated for command).
|
|
15
|
+
* @param options Server installation options.
|
|
16
|
+
* @returns The resolved Python package path or undefined.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolvePythonPackageMacro(finalConfig: any, options: ServerInstallOptions): Promise<string | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* Resolves the actual NPM module path.
|
|
21
|
+
* It checks a provided path, then NVM, then global npm.
|
|
22
|
+
* @param providedNpmPath An optional, pre-configured NPM path.
|
|
23
|
+
* @returns The resolved NPM module path or undefined if an error occurs.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveNpmModulePath(providedNpmPath: string | undefined): string;
|
|
26
|
+
/**
|
|
27
|
+
* Resolves the path to an NPM module for the ${NPMPATH} macro.
|
|
28
|
+
* Uses the resolveNpmModulePath function.
|
|
29
|
+
* @param _finalConfig Not used by this resolver.
|
|
30
|
+
* @param options Server installation options, may contain npmPath.
|
|
31
|
+
* @returns The resolved NPM path or undefined if an error occurs.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveNpmPathMacro(_finalConfig: any, options: ServerInstallOptions): Promise<string | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Resolves the path for the ${BROWSER_PATH} macro.
|
|
36
|
+
* @returns The system's browser path or undefined.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveBrowserPathMacro(): Promise<string | undefined>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Logger } from './logger.js';
|
|
2
|
+
import { getPythonPackagePath, getSystemPythonPackageDirectory, GetBrowserPath } from './osUtils.js';
|
|
3
|
+
import * as fsSync from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
export const MACRO_EXPRESSIONS = {
|
|
7
|
+
PYTHON_PACKAGE: '${PYTHON_PACKAGE}',
|
|
8
|
+
NPMPATH: '${NPMPATH}',
|
|
9
|
+
BROWSER_PATH: '${BROWSER_PATH}',
|
|
10
|
+
};
|
|
11
|
+
// Define a map for macro keys to their resolver functions
|
|
12
|
+
export const MacroResolverFunctions = {
|
|
13
|
+
[MACRO_EXPRESSIONS.PYTHON_PACKAGE]: resolvePythonPackageMacro,
|
|
14
|
+
[MACRO_EXPRESSIONS.NPMPATH]: resolveNpmPathMacro,
|
|
15
|
+
[MACRO_EXPRESSIONS.BROWSER_PATH]: resolveBrowserPathMacro,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the path for the ${PYTHON_PACKAGE} macro.
|
|
19
|
+
* It considers the pythonEnv setting and falls back to system Python.
|
|
20
|
+
* Also updates finalConfig.command if it's 'python' and pythonEnv is used.
|
|
21
|
+
* @param finalConfig The configuration object (mutated for command).
|
|
22
|
+
* @param options Server installation options.
|
|
23
|
+
* @returns The resolved Python package path or undefined.
|
|
24
|
+
*/
|
|
25
|
+
export async function resolvePythonPackageMacro(finalConfig, options) {
|
|
26
|
+
const pythonEnv = options.settings?.pythonEnv;
|
|
27
|
+
if (pythonEnv) {
|
|
28
|
+
Logger.debug(`Python environment specified for ${MACRO_EXPRESSIONS.PYTHON_PACKAGE}: ${pythonEnv}`);
|
|
29
|
+
const pythonDir = getPythonPackagePath(pythonEnv);
|
|
30
|
+
if (pythonDir) {
|
|
31
|
+
if (finalConfig.command === 'python') {
|
|
32
|
+
Logger.debug(`Replacing command 'python' with specified pythonEnv: ${pythonEnv} due to ${MACRO_EXPRESSIONS.PYTHON_PACKAGE} resolution`);
|
|
33
|
+
finalConfig.command = pythonEnv;
|
|
34
|
+
}
|
|
35
|
+
return pythonDir;
|
|
36
|
+
}
|
|
37
|
+
Logger.debug(`Could not determine directory for pythonEnv: ${pythonEnv}. ${MACRO_EXPRESSIONS.PYTHON_PACKAGE} will not be replaced using this path.`);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
Logger.debug(`No Python environment specified. Attempting to find system Python for ${MACRO_EXPRESSIONS.PYTHON_PACKAGE}.`);
|
|
42
|
+
const pythonDir = await getSystemPythonPackageDirectory();
|
|
43
|
+
if (pythonDir) {
|
|
44
|
+
return pythonDir;
|
|
45
|
+
}
|
|
46
|
+
Logger.debug(`Could not find system Python directory for ${MACRO_EXPRESSIONS.PYTHON_PACKAGE}.`);
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolves the actual NPM module path.
|
|
52
|
+
* It checks a provided path, then NVM, then global npm.
|
|
53
|
+
* @param providedNpmPath An optional, pre-configured NPM path.
|
|
54
|
+
* @returns The resolved NPM module path or undefined if an error occurs.
|
|
55
|
+
*/
|
|
56
|
+
export function resolveNpmModulePath(providedNpmPath) {
|
|
57
|
+
if (providedNpmPath) {
|
|
58
|
+
return `${providedNpmPath}/node_modules`;
|
|
59
|
+
}
|
|
60
|
+
const nvmHome = process.env.NVM_HOME;
|
|
61
|
+
if (nvmHome) {
|
|
62
|
+
try {
|
|
63
|
+
const nodeVersion = execSync('node -v').toString().trim();
|
|
64
|
+
const nvmNodePath = path.join(nvmHome, nodeVersion);
|
|
65
|
+
// Check if this path exists
|
|
66
|
+
try {
|
|
67
|
+
fsSync.accessSync(nvmNodePath);
|
|
68
|
+
Logger.debug(`Resolved ${MACRO_EXPRESSIONS.NPMPATH} via NVM to: ${nvmNodePath}`);
|
|
69
|
+
return nvmNodePath;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
Logger.debug(`NVM controlled path doesn't exist: ${nvmNodePath}, will try global npm`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
Logger.debug(`Error determining Node version for NVM: ${error}, will use global npm`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const globalNpmPath = execSync('npm root -g').toString().trim();
|
|
80
|
+
Logger.debug(`Resolved ${MACRO_EXPRESSIONS.NPMPATH} via global npm to: ${globalNpmPath}`);
|
|
81
|
+
return globalNpmPath;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolves the path to an NPM module for the ${NPMPATH} macro.
|
|
85
|
+
* Uses the resolveNpmModulePath function.
|
|
86
|
+
* @param _finalConfig Not used by this resolver.
|
|
87
|
+
* @param options Server installation options, may contain npmPath.
|
|
88
|
+
* @returns The resolved NPM path or undefined if an error occurs.
|
|
89
|
+
*/
|
|
90
|
+
export async function resolveNpmPathMacro(_finalConfig, options) {
|
|
91
|
+
Logger.debug(`Resolving ${MACRO_EXPRESSIONS.NPMPATH}. Provided npmPath from settings: ${options.settings?.npmPath}`);
|
|
92
|
+
try {
|
|
93
|
+
return resolveNpmModulePath(options.settings?.npmPath);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
Logger.error(`Failed to resolve ${MACRO_EXPRESSIONS.NPMPATH}:`, error);
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Resolves the path for the ${BROWSER_PATH} macro.
|
|
102
|
+
* @returns The system's browser path or undefined.
|
|
103
|
+
*/
|
|
104
|
+
export async function resolveBrowserPathMacro() {
|
|
105
|
+
Logger.debug(`Resolving ${MACRO_EXPRESSIONS.BROWSER_PATH}`);
|
|
106
|
+
try {
|
|
107
|
+
const browserPath = await GetBrowserPath();
|
|
108
|
+
Logger.debug(`Resolved ${MACRO_EXPRESSIONS.BROWSER_PATH} to: ${browserPath}`);
|
|
109
|
+
return browserPath;
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
Logger.error(`Failed to get system browser path for ${MACRO_EXPRESSIONS.BROWSER_PATH}:`, error);
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=macroExpressionUtils.js.map
|
package/dist/utils/osUtils.d.ts
CHANGED
|
@@ -3,31 +3,15 @@ export declare function getOSType(): OSType;
|
|
|
3
3
|
export declare function installCLI(tool: 'gh' | 'git'): Promise<void>;
|
|
4
4
|
/**
|
|
5
5
|
* Refreshes the PATH environment variable for the current Node.js process
|
|
6
|
-
* This is necessary because when tools are installed using package managers,
|
|
7
|
-
* they update the system PATH but the current Node process doesn't see those changes.
|
|
8
6
|
*/
|
|
9
7
|
export declare function refreshPathEnv(): Promise<void>;
|
|
10
|
-
export declare function isToolInstalled(tool: 'gh' | 'git', retries?: number): Promise<boolean>;
|
|
11
8
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @returns A promise that resolves when the browser is launched
|
|
9
|
+
* Check if a command is available on the system
|
|
10
|
+
* Handles special cases for VS Code on different platforms
|
|
15
11
|
*/
|
|
12
|
+
export declare function isCommandAvailable(command: string): Promise<boolean>;
|
|
13
|
+
export declare function isToolInstalled(tool: 'gh' | 'git', retries?: number): Promise<boolean>;
|
|
16
14
|
export declare function openBrowser(url: string): Promise<void>;
|
|
17
|
-
/**
|
|
18
|
-
* Gets the directory containing Python packages (site-packages) based on Python executable path.
|
|
19
|
-
* Handles different Python installations (system, venv, conda) across different OS platforms.
|
|
20
|
-
* @param pythonExecutablePath The full path to the Python executable
|
|
21
|
-
* @returns The site-packages directory path
|
|
22
|
-
*/
|
|
23
15
|
export declare function getPythonPackagePath(pythonExecutablePath: string): string;
|
|
24
|
-
/**
|
|
25
|
-
* Finds the directory of the system's default Python installation.
|
|
26
|
-
* @returns The directory path or null if not found.
|
|
27
|
-
*/
|
|
28
16
|
export declare function getSystemPythonPackageDirectory(): Promise<string | null>;
|
|
29
|
-
/**
|
|
30
|
-
* Gets the path of the system's default browser.
|
|
31
|
-
* @returns The path to the default browser executable.
|
|
32
|
-
*/
|
|
33
17
|
export declare function GetBrowserPath(): Promise<string>;
|