imcp 0.1.7 → 0.1.8-dev
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/commands/install.js +1 -106
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/list.js +1 -90
- package/dist/cli/commands/list.js.map +1 -0
- package/dist/cli/commands/pull.js +1 -16
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/commands/serve.js +1 -33
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/uninstall.js +1 -46
- package/dist/cli/commands/uninstall.js.map +1 -0
- package/dist/cli/index.js +1 -65
- package/dist/cli/index.js.map +1 -0
- package/dist/core/installers/clients/BaseClientInstaller.js +1 -282
- package/dist/core/installers/clients/BaseClientInstaller.js.map +1 -0
- package/dist/core/installers/clients/ClientInstaller.js +1 -163
- package/dist/core/installers/clients/ClientInstaller.js.map +1 -0
- package/dist/core/installers/clients/ClientInstallerFactory.js +1 -36
- package/dist/core/installers/clients/ClientInstallerFactory.js.map +1 -0
- package/dist/core/installers/clients/ClineInstaller.js +1 -30
- package/dist/core/installers/clients/ClineInstaller.js.map +1 -0
- package/dist/core/installers/clients/ExtensionInstaller.js +1 -151
- package/dist/core/installers/clients/ExtensionInstaller.js.map +1 -0
- package/dist/core/installers/clients/GithubCopilotInstaller.js +1 -68
- package/dist/core/installers/clients/GithubCopilotInstaller.js.map +1 -0
- package/dist/core/installers/clients/MSRooCodeInstaller.js +1 -28
- package/dist/core/installers/clients/MSRooCodeInstaller.js.map +1 -0
- package/dist/core/installers/index.js +1 -8
- package/dist/core/installers/index.js.map +1 -0
- package/dist/core/installers/requirements/BaseInstaller.js +1 -56
- package/dist/core/installers/requirements/BaseInstaller.js.map +1 -0
- package/dist/core/installers/requirements/CommandInstaller.js +1 -213
- package/dist/core/installers/requirements/CommandInstaller.js.map +1 -0
- package/dist/core/installers/requirements/GeneralInstaller.js +1 -126
- package/dist/core/installers/requirements/GeneralInstaller.js.map +1 -0
- package/dist/core/installers/requirements/InstallerFactory.js +1 -99
- package/dist/core/installers/requirements/InstallerFactory.js.map +1 -0
- package/dist/core/installers/requirements/NpmInstaller.js +1 -235
- package/dist/core/installers/requirements/NpmInstaller.js.map +1 -0
- package/dist/core/installers/requirements/NugetInstaller.js +1 -188
- package/dist/core/installers/requirements/NugetInstaller.js.map +1 -0
- package/dist/core/installers/requirements/PipInstaller.js +1 -192
- package/dist/core/installers/requirements/PipInstaller.js.map +1 -0
- package/dist/core/installers/requirements/RequirementInstaller.js +1 -2
- package/dist/core/installers/requirements/RequirementInstaller.js.map +1 -0
- package/dist/core/loaders/ConfigurationLoader.js +1 -256
- package/dist/core/loaders/ConfigurationLoader.js.map +1 -0
- package/dist/core/loaders/ConfigurationProvider.js +1 -383
- package/dist/core/loaders/ConfigurationProvider.js.map +1 -0
- package/dist/core/loaders/InstallOperationManager.js +1 -310
- package/dist/core/loaders/InstallOperationManager.js.map +1 -0
- package/dist/core/loaders/ServerSchemaLoader.js +1 -108
- package/dist/core/loaders/ServerSchemaLoader.js.map +1 -0
- package/dist/core/loaders/ServerSchemaProvider.js +1 -89
- package/dist/core/loaders/ServerSchemaProvider.js.map +1 -0
- package/dist/core/loaders/SystemSettingsManager.js +1 -256
- package/dist/core/loaders/SystemSettingsManager.js.map +1 -0
- package/dist/core/metadatas/constants.js +1 -100
- package/dist/core/metadatas/constants.js.map +1 -0
- package/dist/core/metadatas/recordingConstants.js +1 -46
- package/dist/core/metadatas/recordingConstants.js.map +1 -0
- package/dist/core/metadatas/types.js +1 -15
- package/dist/core/metadatas/types.js.map +1 -0
- package/dist/core/onboard/FeedOnboardService.js +1 -422
- package/dist/core/onboard/FeedOnboardService.js.map +1 -0
- package/dist/core/onboard/OnboardProcessor.js +1 -333
- package/dist/core/onboard/OnboardProcessor.js.map +1 -0
- package/dist/core/onboard/OnboardStatus.js +1 -9
- package/dist/core/onboard/OnboardStatus.js.map +1 -0
- package/dist/core/onboard/OnboardStatusManager.js +1 -360
- package/dist/core/onboard/OnboardStatusManager.js.map +1 -0
- package/dist/core/validators/FeedValidator.js +1 -133
- package/dist/core/validators/FeedValidator.js.map +1 -0
- package/dist/core/validators/IServerValidator.js +1 -1
- package/dist/core/validators/IServerValidator.js.map +1 -0
- package/dist/core/validators/SSEServerValidator.js +1 -38
- package/dist/core/validators/SSEServerValidator.js.map +1 -0
- package/dist/core/validators/ServerValidatorFactory.js +1 -44
- package/dist/core/validators/ServerValidatorFactory.js.map +1 -0
- package/dist/core/validators/StdioServerValidator.js +1 -281
- package/dist/core/validators/StdioServerValidator.js.map +1 -0
- package/dist/index.js +1 -18
- package/dist/index.js.map +1 -0
- package/dist/services/InstallationService.js +1 -81
- package/dist/services/InstallationService.js.map +1 -0
- package/dist/services/MCPManager.js +1 -197
- package/dist/services/MCPManager.js.map +1 -0
- package/dist/services/RequirementService.js +1 -548
- package/dist/services/RequirementService.js.map +1 -0
- package/dist/services/ServerService.js +1 -127
- package/dist/services/ServerService.js.map +1 -0
- package/dist/services/TelemetryService.js +1 -53
- package/dist/services/TelemetryService.js.map +1 -0
- package/dist/utils/UpdateCheckTracker.js +1 -79
- package/dist/utils/UpdateCheckTracker.js.map +1 -0
- package/dist/utils/adoUtils.js +1 -254
- package/dist/utils/adoUtils.js.map +1 -0
- package/dist/utils/clientUtils.js +1 -65
- package/dist/utils/clientUtils.js.map +1 -0
- package/dist/utils/feedUtils.js +1 -28
- package/dist/utils/feedUtils.js.map +1 -0
- package/dist/utils/githubAuth.js +1 -177
- package/dist/utils/githubAuth.js.map +1 -0
- package/dist/utils/githubUtils.js +1 -125
- package/dist/utils/githubUtils.js.map +1 -0
- package/dist/utils/logger.js +1 -176
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/macroExpressionUtils.js +1 -93
- package/dist/utils/macroExpressionUtils.js.map +1 -0
- package/dist/utils/osUtils.js +1 -664
- package/dist/utils/osUtils.js.map +1 -0
- package/dist/utils/versionUtils.js +1 -101
- package/dist/utils/versionUtils.js.map +1 -0
- package/dist/web/contract/serverContract.js +1 -1
- package/dist/web/contract/serverContract.js.map +1 -0
- package/dist/web/public/js/api.js +2 -132
- package/dist/web/public/js/api.js.map +1 -0
- package/dist/web/public/js/detailsWidget.js +2 -264
- package/dist/web/public/js/detailsWidget.js.map +1 -0
- package/dist/web/public/js/flights/flights.js +2 -127
- package/dist/web/public/js/flights/flights.js.map +1 -0
- package/dist/web/public/js/modal/index.js +2 -52
- package/dist/web/public/js/modal/index.js.map +1 -0
- package/dist/web/public/js/modal/installModal.js +2 -162
- package/dist/web/public/js/modal/installModal.js.map +1 -0
- package/dist/web/public/js/modal/installation.js +2 -266
- package/dist/web/public/js/modal/installation.js.map +1 -0
- package/dist/web/public/js/modal/loadingModal.js +2 -182
- package/dist/web/public/js/modal/loadingModal.js.map +1 -0
- package/dist/web/public/js/modal/modalSetup.js +2 -595
- package/dist/web/public/js/modal/modalSetup.js.map +1 -0
- package/dist/web/public/js/modal/modalUtils.js +2 -37
- package/dist/web/public/js/modal/modalUtils.js.map +1 -0
- package/dist/web/public/js/modal/versionUtils.js +2 -20
- package/dist/web/public/js/modal/versionUtils.js.map +1 -0
- package/dist/web/public/js/modal.js +2 -42
- package/dist/web/public/js/modal.js.map +1 -0
- package/dist/web/public/js/notifications.js +2 -137
- package/dist/web/public/js/notifications.js.map +1 -0
- package/dist/web/public/js/onboard/formProcessor.js +2 -1037
- package/dist/web/public/js/onboard/formProcessor.js.map +1 -0
- package/dist/web/public/js/onboard/index.js +2 -374
- package/dist/web/public/js/onboard/index.js.map +1 -0
- package/dist/web/public/js/onboard/publishHandler.js +2 -172
- package/dist/web/public/js/onboard/publishHandler.js.map +1 -0
- package/dist/web/public/js/onboard/state.js +2 -76
- package/dist/web/public/js/onboard/state.js.map +1 -0
- package/dist/web/public/js/onboard/templates.js +2 -342
- package/dist/web/public/js/onboard/templates.js.map +1 -0
- package/dist/web/public/js/onboard/uiHandlers.js +2 -1076
- package/dist/web/public/js/onboard/uiHandlers.js.map +1 -0
- package/dist/web/public/js/onboard/validationHandlers.js +2 -493
- package/dist/web/public/js/onboard/validationHandlers.js.map +1 -0
- package/dist/web/public/js/serverCategoryDetails.js +2 -364
- package/dist/web/public/js/serverCategoryDetails.js.map +1 -0
- package/dist/web/public/js/serverCategoryList.js +2 -241
- package/dist/web/public/js/serverCategoryList.js.map +1 -0
- package/dist/web/public/js/settings.js +2 -314
- package/dist/web/public/js/settings.js.map +1 -0
- package/dist/web/server.js +1 -404
- package/dist/web/server.js.map +1 -0
- package/package.json +8 -2
- package/.github/ISSUE_TEMPLATE/JitAccess.yml +0 -28
- package/.github/acl/access.yml +0 -20
- package/.github/compliance/inventory.yml +0 -5
- package/.github/policies/jit.yml +0 -19
- package/.github/workflows/build.yml +0 -28
- package/.roo/rules-code/rules.md +0 -88
- 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/messageQueue.js +0 -112
- package/dist/web/public/js/modal/modalUI.js +0 -214
- package/dist/web/public/js/modal/version.js +0 -20
- package/dist/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +0 -370
- package/docs/ONBOARDING_PAGE_DESIGN.md +0 -260
- package/docs/Telemetry.md +0 -136
- package/memory-bank/activeContext.md +0 -26
- package/memory-bank/decisionLog.md +0 -91
- package/memory-bank/productContext.md +0 -41
- package/memory-bank/progress.md +0 -35
- package/memory-bank/systemPatterns.md +0 -10
- package/src/cli/commands/install.ts +0 -139
- package/src/cli/commands/list.ts +0 -113
- package/src/cli/commands/pull.ts +0 -16
- package/src/cli/commands/serve.ts +0 -39
- package/src/cli/commands/uninstall.ts +0 -64
- package/src/cli/index.ts +0 -82
- package/src/core/installers/clients/BaseClientInstaller.ts +0 -341
- package/src/core/installers/clients/ClientInstaller.ts +0 -222
- package/src/core/installers/clients/ClientInstallerFactory.ts +0 -43
- package/src/core/installers/clients/ClineInstaller.ts +0 -35
- package/src/core/installers/clients/ExtensionInstaller.ts +0 -165
- package/src/core/installers/clients/GithubCopilotInstaller.ts +0 -79
- package/src/core/installers/clients/MSRooCodeInstaller.ts +0 -32
- package/src/core/installers/index.ts +0 -11
- package/src/core/installers/requirements/BaseInstaller.ts +0 -85
- package/src/core/installers/requirements/CommandInstaller.ts +0 -231
- package/src/core/installers/requirements/GeneralInstaller.ts +0 -133
- package/src/core/installers/requirements/InstallerFactory.ts +0 -114
- package/src/core/installers/requirements/NpmInstaller.ts +0 -271
- package/src/core/installers/requirements/NugetInstaller.ts +0 -203
- package/src/core/installers/requirements/PipInstaller.ts +0 -207
- package/src/core/installers/requirements/RequirementInstaller.ts +0 -42
- package/src/core/loaders/ConfigurationLoader.ts +0 -298
- package/src/core/loaders/ConfigurationProvider.ts +0 -462
- package/src/core/loaders/InstallOperationManager.ts +0 -367
- package/src/core/loaders/ServerSchemaLoader.ts +0 -117
- package/src/core/loaders/ServerSchemaProvider.ts +0 -99
- package/src/core/loaders/SystemSettingsManager.ts +0 -278
- package/src/core/metadatas/constants.ts +0 -122
- package/src/core/metadatas/recordingConstants.ts +0 -65
- package/src/core/metadatas/types.ts +0 -202
- package/src/core/onboard/FeedOnboardService.ts +0 -501
- package/src/core/onboard/OnboardProcessor.ts +0 -356
- package/src/core/onboard/OnboardStatus.ts +0 -60
- package/src/core/onboard/OnboardStatusManager.ts +0 -416
- package/src/core/validators/FeedValidator.ts +0 -135
- package/src/core/validators/IServerValidator.ts +0 -21
- package/src/core/validators/SSEServerValidator.ts +0 -43
- package/src/core/validators/ServerValidatorFactory.ts +0 -51
- package/src/core/validators/StdioServerValidator.ts +0 -313
- package/src/index.ts +0 -44
- package/src/services/InstallationService.ts +0 -102
- package/src/services/MCPManager.ts +0 -249
- package/src/services/RequirementService.ts +0 -627
- package/src/services/ServerService.ts +0 -161
- package/src/services/TelemetryService.ts +0 -59
- package/src/utils/UpdateCheckTracker.ts +0 -86
- package/src/utils/adoUtils.ts +0 -293
- package/src/utils/clientUtils.ts +0 -72
- package/src/utils/feedUtils.ts +0 -31
- package/src/utils/githubAuth.ts +0 -212
- package/src/utils/githubUtils.ts +0 -164
- package/src/utils/logger.ts +0 -195
- package/src/utils/macroExpressionUtils.ts +0 -104
- package/src/utils/osUtils.ts +0 -700
- package/src/utils/versionUtils.ts +0 -114
- package/src/web/contract/serverContract.ts +0 -74
- package/src/web/public/css/detailsWidget.css +0 -235
- package/src/web/public/css/modal.css +0 -757
- package/src/web/public/css/notifications.css +0 -101
- package/src/web/public/css/onboard.css +0 -107
- package/src/web/public/css/serverCategoryList.css +0 -120
- package/src/web/public/css/serverDetails.css +0 -139
- package/src/web/public/index.html +0 -359
- package/src/web/public/js/api.js +0 -132
- package/src/web/public/js/detailsWidget.js +0 -264
- package/src/web/public/js/flights/flights.js +0 -127
- package/src/web/public/js/modal/index.js +0 -52
- package/src/web/public/js/modal/installModal.js +0 -162
- package/src/web/public/js/modal/installation.js +0 -266
- package/src/web/public/js/modal/loadingModal.js +0 -182
- package/src/web/public/js/modal/modalSetup.js +0 -595
- package/src/web/public/js/modal/modalUtils.js +0 -37
- package/src/web/public/js/modal/versionUtils.js +0 -20
- package/src/web/public/js/modal.js +0 -42
- package/src/web/public/js/notifications.js +0 -137
- package/src/web/public/js/onboard/formProcessor.js +0 -1037
- package/src/web/public/js/onboard/index.js +0 -374
- package/src/web/public/js/onboard/publishHandler.js +0 -172
- package/src/web/public/js/onboard/state.js +0 -76
- package/src/web/public/js/onboard/templates.js +0 -342
- package/src/web/public/js/onboard/uiHandlers.js +0 -1076
- package/src/web/public/js/onboard/validationHandlers.js +0 -493
- package/src/web/public/js/serverCategoryDetails.js +0 -364
- package/src/web/public/js/serverCategoryList.js +0 -241
- package/src/web/public/js/settings.js +0 -314
- package/src/web/public/modal.html +0 -84
- package/src/web/public/onboard.html +0 -296
- package/src/web/public/settings.html +0 -135
- package/src/web/public/styles.css +0 -277
- package/src/web/server.ts +0 -478
- package/tsconfig.json +0 -18
- package/wiki/Installation.md +0 -3
- package/wiki/Publish.md +0 -3
package/src/utils/osUtils.ts
DELETED
|
@@ -1,700 +0,0 @@
|
|
|
1
|
-
import { OSType } from '../core/metadatas/types.js';
|
|
2
|
-
import os from 'os';
|
|
3
|
-
import { exec } from 'child_process';
|
|
4
|
-
import util from 'util';
|
|
5
|
-
import { Logger } from './logger.js';
|
|
6
|
-
import fs from 'fs';
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { execSync } from 'child_process';
|
|
9
|
-
import * as fsSync from 'fs';
|
|
10
|
-
|
|
11
|
-
const execAsync = util.promisify(exec);
|
|
12
|
-
|
|
13
|
-
export function getOSType(): OSType {
|
|
14
|
-
const platform = os.platform();
|
|
15
|
-
Logger.debug({
|
|
16
|
-
action: 'get_os_type',
|
|
17
|
-
platform
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
switch (platform) {
|
|
21
|
-
case 'win32':
|
|
22
|
-
return OSType.Windows;
|
|
23
|
-
case 'darwin':
|
|
24
|
-
return OSType.MacOS;
|
|
25
|
-
case 'linux':
|
|
26
|
-
return OSType.Linux;
|
|
27
|
-
default:
|
|
28
|
-
const error = `Unsupported operating system: ${platform}`;
|
|
29
|
-
Logger.error(error);
|
|
30
|
-
throw new Error(error);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function installCLI(tool: 'gh' | 'git'): Promise<void> {
|
|
35
|
-
const osType = getOSType();
|
|
36
|
-
Logger.debug({
|
|
37
|
-
action: 'install_cli',
|
|
38
|
-
tool,
|
|
39
|
-
osType
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
switch (osType) {
|
|
44
|
-
case OSType.Windows:
|
|
45
|
-
if (tool === 'git') {
|
|
46
|
-
await execAsync('winget install --id Git.Git -e --source winget --silent');
|
|
47
|
-
} else {
|
|
48
|
-
await execAsync('winget install --id GitHub.cli --silent');
|
|
49
|
-
}
|
|
50
|
-
// Refresh PATH environment variable after installation
|
|
51
|
-
await refreshPathEnv();
|
|
52
|
-
break;
|
|
53
|
-
|
|
54
|
-
case OSType.MacOS:
|
|
55
|
-
if (tool === 'git') {
|
|
56
|
-
await execAsync('brew install git');
|
|
57
|
-
} else {
|
|
58
|
-
await execAsync('brew install gh');
|
|
59
|
-
}
|
|
60
|
-
// On macOS, we may need to source profile files
|
|
61
|
-
if (tool === 'git') {
|
|
62
|
-
await execAsync('source ~/.zshrc || source ~/.bash_profile || source ~/.bashrc || true');
|
|
63
|
-
}
|
|
64
|
-
break;
|
|
65
|
-
|
|
66
|
-
case OSType.Linux:
|
|
67
|
-
if (tool === 'git') {
|
|
68
|
-
await execAsync('sudo apt-get update && sudo apt-get install -y git');
|
|
69
|
-
} else {
|
|
70
|
-
await execAsync('curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null && sudo apt update && sudo apt install -y gh');
|
|
71
|
-
}
|
|
72
|
-
// Source bash profile to refresh PATH
|
|
73
|
-
await execAsync('source ~/.bashrc || source ~/.profile || true');
|
|
74
|
-
break;
|
|
75
|
-
|
|
76
|
-
default:
|
|
77
|
-
throw new Error(`Unsupported operating system for installing ${tool}`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Wait a moment for system to register the new binaries
|
|
81
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
82
|
-
|
|
83
|
-
Logger.debug({
|
|
84
|
-
action: 'install_cli_success',
|
|
85
|
-
tool,
|
|
86
|
-
osType
|
|
87
|
-
});
|
|
88
|
-
} catch (error) {
|
|
89
|
-
Logger.error('Failed to install CLI tool', {
|
|
90
|
-
tool,
|
|
91
|
-
osType,
|
|
92
|
-
error
|
|
93
|
-
});
|
|
94
|
-
throw error;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Refreshes the PATH environment variable for the current Node.js process
|
|
100
|
-
*/
|
|
101
|
-
export async function refreshPathEnv(): Promise<void> {
|
|
102
|
-
const osType = getOSType();
|
|
103
|
-
Logger.debug({
|
|
104
|
-
action: 'refresh_path_env',
|
|
105
|
-
osType
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
switch (osType) {
|
|
110
|
-
case OSType.Windows:
|
|
111
|
-
// On Windows, get the PATH from registry
|
|
112
|
-
const { stdout: winPath } = await execAsync('powershell -command "[Environment]::GetEnvironmentVariable(\'Path\', \'Machine\') + \';\' + [Environment]::GetEnvironmentVariable(\'Path\', \'User\')"');
|
|
113
|
-
if (winPath) {
|
|
114
|
-
process.env.PATH = winPath.trim();
|
|
115
|
-
Logger.debug('Refreshed PATH from Windows registry');
|
|
116
|
-
}
|
|
117
|
-
break;
|
|
118
|
-
|
|
119
|
-
case OSType.MacOS:
|
|
120
|
-
case OSType.Linux:
|
|
121
|
-
// On Unix systems, typical installation locations if PATH isn't updated
|
|
122
|
-
const commonPaths = [
|
|
123
|
-
'/usr/local/bin',
|
|
124
|
-
'/usr/bin',
|
|
125
|
-
'/bin',
|
|
126
|
-
'/usr/sbin',
|
|
127
|
-
'/sbin',
|
|
128
|
-
'/usr/local/git/bin',
|
|
129
|
-
'/opt/homebrew/bin', // For M1 Macs
|
|
130
|
-
`${os.homedir()}/.local/bin`
|
|
131
|
-
];
|
|
132
|
-
|
|
133
|
-
// Ensure these paths are in process.env.PATH
|
|
134
|
-
if (process.env.PATH) {
|
|
135
|
-
const currentPaths = process.env.PATH.split(':');
|
|
136
|
-
const newPaths = [...new Set([...currentPaths, ...commonPaths])];
|
|
137
|
-
process.env.PATH = newPaths.join(':');
|
|
138
|
-
Logger.debug('Expanded PATH with common Unix binary locations');
|
|
139
|
-
}
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
Logger.debug({
|
|
144
|
-
action: 'refresh_path_env_success',
|
|
145
|
-
path: process.env.PATH
|
|
146
|
-
});
|
|
147
|
-
} catch (error) {
|
|
148
|
-
Logger.error('Failed to refresh PATH environment variable', error);
|
|
149
|
-
// Continue execution even if PATH refresh fails
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Check if a command is available on the system
|
|
155
|
-
* Handles special cases for VS Code on different platforms
|
|
156
|
-
*/
|
|
157
|
-
export async function isCommandAvailable(command: string): Promise<boolean> {
|
|
158
|
-
try {
|
|
159
|
-
// For VS Code on macOS, check both command-line tool and app bundle
|
|
160
|
-
if (process.platform === 'darwin' && (command === 'code' || command === 'code-insiders')) {
|
|
161
|
-
try {
|
|
162
|
-
// Try which command first
|
|
163
|
-
await execAsync(`which ${command}`);
|
|
164
|
-
return true;
|
|
165
|
-
} catch (error) {
|
|
166
|
-
// If which fails, check application bundles
|
|
167
|
-
const systemVSCodePath = command === 'code' ?
|
|
168
|
-
'/Applications/Visual Studio Code.app' :
|
|
169
|
-
'/Applications/Visual Studio Code - Insiders.app';
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
// Check system Applications first
|
|
173
|
-
await execAsync(`test -d "${systemVSCodePath}"`);
|
|
174
|
-
return true;
|
|
175
|
-
} catch (error) {
|
|
176
|
-
// If system Applications check fails, try user Applications
|
|
177
|
-
const homedir = process.env.HOME;
|
|
178
|
-
if (homedir) {
|
|
179
|
-
const userVSCodePath = command === 'code' ?
|
|
180
|
-
`${homedir}/Applications/Visual Studio Code.app` :
|
|
181
|
-
`${homedir}/Applications/Visual Studio Code - Insiders.app`;
|
|
182
|
-
|
|
183
|
-
try {
|
|
184
|
-
await execAsync(`test -d "${userVSCodePath}"`);
|
|
185
|
-
return true;
|
|
186
|
-
} catch (error) {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// For Windows, use where command
|
|
196
|
-
if (process.platform === 'win32') {
|
|
197
|
-
await execAsync(`where ${command}`);
|
|
198
|
-
return true;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// For all other cases (Unix-like systems), use which command
|
|
202
|
-
await execAsync(`which ${command}`);
|
|
203
|
-
return true;
|
|
204
|
-
} catch (error) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
export async function isToolInstalled(tool: 'gh' | 'git', retries = 3): Promise<boolean> {
|
|
210
|
-
try {
|
|
211
|
-
Logger.debug({
|
|
212
|
-
action: 'check_tool_installed',
|
|
213
|
-
tool,
|
|
214
|
-
retries
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// Try to execute tool command
|
|
218
|
-
try {
|
|
219
|
-
await execAsync(`${tool} --version`);
|
|
220
|
-
Logger.debug({
|
|
221
|
-
action: 'check_tool_installed_success',
|
|
222
|
-
tool,
|
|
223
|
-
installed: true
|
|
224
|
-
});
|
|
225
|
-
return true;
|
|
226
|
-
} catch (error) {
|
|
227
|
-
// If we have retries left, refresh PATH and try again
|
|
228
|
-
if (retries > 0) {
|
|
229
|
-
Logger.debug(`${tool} not found, refreshing PATH and retrying...`);
|
|
230
|
-
|
|
231
|
-
// Refresh environment PATH variable
|
|
232
|
-
await refreshPathEnv();
|
|
233
|
-
|
|
234
|
-
// Wait a moment before retrying
|
|
235
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
236
|
-
|
|
237
|
-
// Recursive retry with decremented counter
|
|
238
|
-
return isToolInstalled(tool, retries - 1);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// No retries left, tool is not installed
|
|
242
|
-
Logger.debug({
|
|
243
|
-
action: 'check_tool_installed_success',
|
|
244
|
-
tool,
|
|
245
|
-
installed: false
|
|
246
|
-
});
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
} catch (error) {
|
|
250
|
-
Logger.error(`Error checking if ${tool} is installed`, error);
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export async function openBrowser(url: string): Promise<void> {
|
|
256
|
-
const osType = getOSType();
|
|
257
|
-
Logger.debug({
|
|
258
|
-
action: 'open_browser',
|
|
259
|
-
url,
|
|
260
|
-
osType
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
switch (osType) {
|
|
265
|
-
case OSType.Windows:
|
|
266
|
-
await execAsync(`start ${url}`);
|
|
267
|
-
break;
|
|
268
|
-
case OSType.MacOS:
|
|
269
|
-
await execAsync(`open ${url}`);
|
|
270
|
-
break;
|
|
271
|
-
case OSType.Linux:
|
|
272
|
-
// Try different commands that might be available
|
|
273
|
-
try {
|
|
274
|
-
await execAsync(`xdg-open ${url}`);
|
|
275
|
-
} catch (error) {
|
|
276
|
-
// Try alternative commands
|
|
277
|
-
try {
|
|
278
|
-
await execAsync(`sensible-browser ${url}`);
|
|
279
|
-
} catch (error) {
|
|
280
|
-
await execAsync(`gnome-open ${url}`);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
break;
|
|
284
|
-
default:
|
|
285
|
-
throw new Error(`Unsupported operating system for opening browser`);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
Logger.debug({
|
|
289
|
-
action: 'open_browser_success',
|
|
290
|
-
url,
|
|
291
|
-
osType
|
|
292
|
-
});
|
|
293
|
-
} catch (error) {
|
|
294
|
-
Logger.error('Failed to open browser', {
|
|
295
|
-
url,
|
|
296
|
-
osType,
|
|
297
|
-
error
|
|
298
|
-
});
|
|
299
|
-
// Don't throw the error - just log it and continue
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export function getPythonPackagePath(pythonExecutablePath: string): string {
|
|
304
|
-
Logger.debug({
|
|
305
|
-
action: 'get_python_package_path',
|
|
306
|
-
pythonExecutablePath
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
try {
|
|
310
|
-
const dir = path.dirname(pythonExecutablePath);
|
|
311
|
-
const isWindows = process.platform === 'win32';
|
|
312
|
-
|
|
313
|
-
// Handle common Python installation patterns
|
|
314
|
-
if (isWindows) {
|
|
315
|
-
// Windows: Handle different Python installations
|
|
316
|
-
if (dir.endsWith('WindowsApps')) {
|
|
317
|
-
// For Windows Store Python, find the actual Python installation directory
|
|
318
|
-
const entries = fs.readdirSync(dir);
|
|
319
|
-
const pythonDir = entries.find(e => e.startsWith('PythonSoftwareFoundation.Python'));
|
|
320
|
-
if (pythonDir && pythonDir.includes('.')) {
|
|
321
|
-
// Extract version from format like "PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0"
|
|
322
|
-
const parts = pythonDir.split('.');
|
|
323
|
-
const majorVer = parts[2];
|
|
324
|
-
const minorVer = parts[3].split('_')[0];
|
|
325
|
-
const version = majorVer + minorVer; // Combines "3" and "13" to "313"
|
|
326
|
-
const localAppData = process.env.LOCALAPPDATA;
|
|
327
|
-
|
|
328
|
-
if (localAppData) {
|
|
329
|
-
const sitePkgsPath = path.join(
|
|
330
|
-
localAppData,
|
|
331
|
-
'Packages',
|
|
332
|
-
pythonDir,
|
|
333
|
-
'LocalCache',
|
|
334
|
-
'local-packages',
|
|
335
|
-
'Python' + version,
|
|
336
|
-
'site-packages'
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
Logger.debug(`Resolved Windows Store Python site-packages path: ${sitePkgsPath}`);
|
|
340
|
-
return sitePkgsPath;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
Logger.debug('Could not resolve Windows Store Python site-packages path');
|
|
345
|
-
// Fallback to user's site-packages
|
|
346
|
-
return path.join(process.env.APPDATA || '', 'Python', 'Python3', 'site-packages');
|
|
347
|
-
} else if (dir.endsWith('Scripts')) {
|
|
348
|
-
// Virtual environment structure on Windows: <venv>/Scripts/python.exe
|
|
349
|
-
const venvRoot = path.dirname(dir);
|
|
350
|
-
return path.join(venvRoot, 'Lib', 'site-packages');
|
|
351
|
-
} else {
|
|
352
|
-
// System Python or Conda on Windows
|
|
353
|
-
return path.join(dir, 'Lib', 'site-packages');
|
|
354
|
-
}
|
|
355
|
-
} else {
|
|
356
|
-
// Unix systems (MacOS/Linux)
|
|
357
|
-
if (dir.endsWith('bin')) {
|
|
358
|
-
// Virtual environment structure on Unix: <venv>/bin/python
|
|
359
|
-
const venvRoot = path.dirname(dir);
|
|
360
|
-
// Try to find python version-specific site-packages
|
|
361
|
-
const libDir = path.join(venvRoot, 'lib');
|
|
362
|
-
if (fs.existsSync(libDir)) {
|
|
363
|
-
const pythonDirs = fs.readdirSync(libDir).filter(d => d.startsWith('python'));
|
|
364
|
-
if (pythonDirs.length > 0) {
|
|
365
|
-
// Use the first python directory found
|
|
366
|
-
return path.join(libDir, pythonDirs[0], 'site-packages');
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
// Fallback to a generic lib/python3/site-packages if version-specific not found
|
|
370
|
-
return path.join(venvRoot, 'lib', 'python3', 'site-packages');
|
|
371
|
-
} else if (dir.toLowerCase().includes('python')) {
|
|
372
|
-
// System Python or Conda on Unix
|
|
373
|
-
const libDir = path.join(dir, 'lib');
|
|
374
|
-
if (fs.existsSync(libDir)) {
|
|
375
|
-
const pythonDirs = fs.readdirSync(libDir).filter(d => d.startsWith('python'));
|
|
376
|
-
if (pythonDirs.length > 0) {
|
|
377
|
-
// Use the first python directory found
|
|
378
|
-
return path.join(libDir, pythonDirs[0], 'site-packages');
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
// Fallback to a generic lib/python3/site-packages
|
|
382
|
-
return path.join(dir, 'lib', 'python3', 'site-packages');
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Default fallback: return the original directory
|
|
387
|
-
Logger.debug('No standard Python directory structure found, using original directory');
|
|
388
|
-
return dir;
|
|
389
|
-
} catch (error) {
|
|
390
|
-
Logger.error('Error getting Python package path', {
|
|
391
|
-
pythonExecutablePath,
|
|
392
|
-
error
|
|
393
|
-
});
|
|
394
|
-
return path.dirname(pythonExecutablePath);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
export async function getSystemPythonPackageDirectory(): Promise<string | null> {
|
|
399
|
-
const command = process.platform === 'win32' ? 'where python' : 'which python';
|
|
400
|
-
|
|
401
|
-
Logger.debug({
|
|
402
|
-
action: 'get_system_python_package_directory',
|
|
403
|
-
command
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
const { stdout } = await execAsync(command);
|
|
408
|
-
// Use the first path found, trim whitespace
|
|
409
|
-
const pythonPath = stdout.split('\n')[0].trim();
|
|
410
|
-
if (pythonPath) {
|
|
411
|
-
const packagePath = getPythonPackagePath(pythonPath);
|
|
412
|
-
Logger.debug({
|
|
413
|
-
action: 'get_system_python_package_directory_success',
|
|
414
|
-
pythonPath,
|
|
415
|
-
packagePath
|
|
416
|
-
});
|
|
417
|
-
return packagePath;
|
|
418
|
-
}
|
|
419
|
-
Logger.debug('No Python executable found');
|
|
420
|
-
return null;
|
|
421
|
-
} catch (error) {
|
|
422
|
-
Logger.debug(`Could not find system python using "${command}": ${error}`);
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Get the system Python executable path.
|
|
428
|
-
* This function returns the absolute path to the system Python executable (e.g., /Users/penwa/miniconda3/envs/browser-use-temp/bin/python).
|
|
429
|
-
* It uses 'which python' (Unix) or 'where python' (Windows) to locate the executable.
|
|
430
|
-
* @returns {Promise<string | null>} The path to the Python executable, or null if not found.
|
|
431
|
-
*/
|
|
432
|
-
export async function getSystemPythonExecutablePath(): Promise<string | null> {
|
|
433
|
-
const command = process.platform === 'win32' ? 'where python' : 'which python';
|
|
434
|
-
|
|
435
|
-
Logger.debug({
|
|
436
|
-
action: 'get_system_python_executable_path',
|
|
437
|
-
command
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
try {
|
|
441
|
-
const { stdout } = await execAsync(command);
|
|
442
|
-
// Use the first path found, trim whitespace
|
|
443
|
-
const pythonPath = stdout.split('\n')[0].trim();
|
|
444
|
-
if (pythonPath) {
|
|
445
|
-
Logger.debug({
|
|
446
|
-
action: 'get_system_python_executable_path_success',
|
|
447
|
-
pythonPath
|
|
448
|
-
});
|
|
449
|
-
return pythonPath;
|
|
450
|
-
}
|
|
451
|
-
Logger.debug('No Python executable found');
|
|
452
|
-
return null;
|
|
453
|
-
} catch (error) {
|
|
454
|
-
Logger.debug(`Could not find system python using "${command}": ${error}`);
|
|
455
|
-
return null;
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export async function getBrowserPath(): Promise<string> {
|
|
460
|
-
const osType = getOSType();
|
|
461
|
-
Logger.debug({
|
|
462
|
-
action: 'get_system_browser_path',
|
|
463
|
-
osType
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
try {
|
|
467
|
-
switch (osType) {
|
|
468
|
-
case OSType.Windows: {
|
|
469
|
-
// Check for Edge first
|
|
470
|
-
const edgePaths = [
|
|
471
|
-
`${process.env['PROGRAMFILES(X86)']}\\Microsoft\\Edge\\Application\\msedge.exe`,
|
|
472
|
-
`${process.env['PROGRAMFILES']}\\Microsoft\\Edge\\Application\\msedge.exe`
|
|
473
|
-
];
|
|
474
|
-
for (const path of edgePaths) {
|
|
475
|
-
if (fs.existsSync(path)) {
|
|
476
|
-
return path;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
// Then check for Chrome
|
|
481
|
-
const chromePaths = [
|
|
482
|
-
`${process.env['PROGRAMFILES(X86)']}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
483
|
-
`${process.env['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe`
|
|
484
|
-
];
|
|
485
|
-
for (const path of chromePaths) {
|
|
486
|
-
if (fs.existsSync(path)) {
|
|
487
|
-
return path;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
break;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
case OSType.MacOS: {
|
|
494
|
-
// Check for Edge first
|
|
495
|
-
const edgePath = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge';
|
|
496
|
-
if (fs.existsSync(edgePath)) {
|
|
497
|
-
return edgePath;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Then check for Chrome
|
|
501
|
-
const chromePath = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
502
|
-
if (fs.existsSync(chromePath)) {
|
|
503
|
-
return chromePath;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Finally check for Safari
|
|
507
|
-
const safariPath = '/Applications/Safari.app/Contents/MacOS/Safari';
|
|
508
|
-
if (fs.existsSync(safariPath)) {
|
|
509
|
-
return safariPath;
|
|
510
|
-
}
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
case OSType.Linux: {
|
|
515
|
-
// Try Edge first
|
|
516
|
-
try {
|
|
517
|
-
const { stdout: edgePath } = await execAsync('which microsoft-edge');
|
|
518
|
-
if (edgePath.trim()) {
|
|
519
|
-
return edgePath.trim();
|
|
520
|
-
}
|
|
521
|
-
} catch { }
|
|
522
|
-
|
|
523
|
-
// Then try Chrome or Chromium
|
|
524
|
-
try {
|
|
525
|
-
const { stdout: chromePath } = await execAsync('which google-chrome chromium');
|
|
526
|
-
if (chromePath.trim()) {
|
|
527
|
-
return chromePath.trim();
|
|
528
|
-
}
|
|
529
|
-
} catch { }
|
|
530
|
-
break;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// If no browser found, throw error
|
|
535
|
-
throw new Error('No supported browser found on the system');
|
|
536
|
-
} catch (error) {
|
|
537
|
-
Logger.error('Failed to get browser path', error);
|
|
538
|
-
throw error;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/**
|
|
543
|
-
* Get the global NPM path
|
|
544
|
-
* This function checks if NVM is installed and retrieves the global NPM path accordingly.
|
|
545
|
-
* If NVM is not installed, it falls back to the global NPM path.
|
|
546
|
-
* @returns The global NPM path as a string.
|
|
547
|
-
* @throws Error if the NPM path cannot be determined.
|
|
548
|
-
* */
|
|
549
|
-
export function getGlobalNPMPackagePath(): string {
|
|
550
|
-
const nvmHome = process.env.NVM_HOME;
|
|
551
|
-
if (nvmHome) {
|
|
552
|
-
try {
|
|
553
|
-
const nodeVersion = execSync('node -v').toString().trim();
|
|
554
|
-
const nvmNodePath = path.join(nvmHome, nodeVersion);
|
|
555
|
-
// Check if this path exists
|
|
556
|
-
try {
|
|
557
|
-
fsSync.accessSync(nvmNodePath);
|
|
558
|
-
return nvmNodePath;
|
|
559
|
-
} catch (error) {
|
|
560
|
-
Logger.debug(`NVM controlled path doesn't exist: ${nvmNodePath}, will try global npm`);
|
|
561
|
-
}
|
|
562
|
-
} catch (error) {
|
|
563
|
-
Logger.debug(`Error determining Node version for NVM: ${error}, will use global npm`);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
const globalNpmPath = execSync('npm root -g').toString().trim();
|
|
568
|
-
return globalNpmPath;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Get the NPM executable path on the current platform (Windows, macOS, Linux).
|
|
574
|
-
* On Windows, uses PowerShell to locate npm. On macOS/Linux, uses 'which' to locate npm.
|
|
575
|
-
* Returns the directory containing the npm executable, or a platform-appropriate default if not found.
|
|
576
|
-
*/
|
|
577
|
-
export async function getNpmExecutablePath(): Promise<string> {
|
|
578
|
-
try {
|
|
579
|
-
if (process.platform === 'win32') {
|
|
580
|
-
const { stdout } = await execAsync('powershell -Command "get-command npm | Select-Object -ExpandProperty Source"');
|
|
581
|
-
return stdout.trim().replace(/\\npm\.cmd$/, '');
|
|
582
|
-
} else {
|
|
583
|
-
// macOS or Linux
|
|
584
|
-
const { stdout } = await execAsync('which npm');
|
|
585
|
-
// Remove the trailing '/npm' to get the directory
|
|
586
|
-
return stdout.trim().replace(/\/npm$/, '');
|
|
587
|
-
}
|
|
588
|
-
} catch (error) {
|
|
589
|
-
Logger.error('Error getting npm path:', error);
|
|
590
|
-
if (process.platform === 'win32') {
|
|
591
|
-
return 'C:\\Program Files\\nodejs';
|
|
592
|
-
} else {
|
|
593
|
-
// Common default for Unix systems
|
|
594
|
-
return '/usr/local/bin';
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
/**
|
|
600
|
-
* Ensures the .NET global tools path is added to the system PATH for the current user
|
|
601
|
-
* on macOS and Linux by modifying shell configuration files.
|
|
602
|
-
* This function is idempotent and will not add the path if it already exists.
|
|
603
|
-
*/
|
|
604
|
-
export async function ensureDotnetToolsInPath(): Promise<void> {
|
|
605
|
-
const osType = getOSType();
|
|
606
|
-
Logger.debug({
|
|
607
|
-
action: 'ensure_dotnet_tools_in_path',
|
|
608
|
-
osType
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
if (osType === OSType.Windows) {
|
|
612
|
-
Logger.debug('.NET tools PATH is usually handled by the installer on Windows. Skipping explicit PATH modification.');
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
if (osType === OSType.MacOS || osType === OSType.Linux) {
|
|
617
|
-
const dotnetToolsPath = getDotnetGlobalToolsPath(); // This is typically ~/.dotnet/tools
|
|
618
|
-
const exportLine = `export PATH="${dotnetToolsPath}:$PATH"`;
|
|
619
|
-
|
|
620
|
-
// Determine shell configuration files to check/update
|
|
621
|
-
const shellConfigFiles: string[] = [];
|
|
622
|
-
const shell = process.env.SHELL;
|
|
623
|
-
|
|
624
|
-
if (shell && shell.includes('zsh')) {
|
|
625
|
-
shellConfigFiles.push(path.join(os.homedir(), '.zshrc'));
|
|
626
|
-
} else if (shell && shell.includes('bash')) {
|
|
627
|
-
shellConfigFiles.push(path.join(os.homedir(), '.bashrc'));
|
|
628
|
-
// .bash_profile is often sourced by .bashrc or used for login shells
|
|
629
|
-
shellConfigFiles.push(path.join(os.homedir(), '.bash_profile'));
|
|
630
|
-
} else {
|
|
631
|
-
// Fallback for other shells or if SHELL is not set
|
|
632
|
-
shellConfigFiles.push(path.join(os.homedir(), '.profile'));
|
|
633
|
-
shellConfigFiles.push(path.join(os.homedir(), '.bashrc'));
|
|
634
|
-
shellConfigFiles.push(path.join(os.homedir(), '.zshrc'));
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
let updatedAnyFile = false;
|
|
638
|
-
|
|
639
|
-
for (const configFile of shellConfigFiles) {
|
|
640
|
-
try {
|
|
641
|
-
if (fs.existsSync(configFile)) {
|
|
642
|
-
const content = await fs.promises.readFile(configFile, 'utf-8');
|
|
643
|
-
// Check if the exact line or a line setting dotnetToolsPath in PATH exists
|
|
644
|
-
// A more robust check might involve parsing, but this covers common cases.
|
|
645
|
-
// Regex to check if dotnetToolsPath is part of an PATH export, avoiding duplicates.
|
|
646
|
-
// It looks for `export PATH=...$dotnetToolsPath...` or `export PATH=...${HOME}/.dotnet/tools...`
|
|
647
|
-
const pathRegex = new RegExp(`export\\s+PATH=.*${dotnetToolsPath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}.*`);
|
|
648
|
-
const homePathRegex = new RegExp(`export\\s+PATH=.*\\$HOME\\/\\.dotnet\\/tools.*`);
|
|
649
|
-
|
|
650
|
-
if (!pathRegex.test(content) && !homePathRegex.test(content)) {
|
|
651
|
-
Logger.debug(`Adding .NET tools path to ${configFile}`);
|
|
652
|
-
await fs.promises.appendFile(configFile, `\n# Add .NET Core SDK tools to PATH\n${exportLine}\n`);
|
|
653
|
-
Logger.log(`Appended '${exportLine}' to ${configFile}. You may need to source this file or restart your terminal.`);
|
|
654
|
-
updatedAnyFile = true;
|
|
655
|
-
} else {
|
|
656
|
-
Logger.debug(`.NET tools path already configured in ${configFile}`);
|
|
657
|
-
}
|
|
658
|
-
} else if (shellConfigFiles.length === 1 || configFile === path.join(os.homedir(), '.profile')) {
|
|
659
|
-
// If it's the only config file determined or it's .profile, and it doesn't exist, create it.
|
|
660
|
-
Logger.debug(`${configFile} does not exist. Creating and adding .NET tools path.`);
|
|
661
|
-
await fs.promises.writeFile(configFile, `# Add .NET Core SDK tools to PATH\n${exportLine}\n`);
|
|
662
|
-
Logger.log(`Created ${configFile} and added '${exportLine}'. You may need to source this file or restart your terminal.`);
|
|
663
|
-
updatedAnyFile = true;
|
|
664
|
-
}
|
|
665
|
-
} catch (error) {
|
|
666
|
-
Logger.error(`Failed to update ${configFile} for .NET tools PATH: ${error instanceof Error ? error.message : String(error)}`);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
if (updatedAnyFile) {
|
|
670
|
-
Logger.log(`Dotnet tools path has been added to shell configuration. Please source the relevant file (e.g., 'source ~/.zshrc') or restart your terminal session for changes to take effect.`);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// Also update the current process's PATH environment variable
|
|
674
|
-
if (process.env.PATH && !process.env.PATH.includes(dotnetToolsPath)) {
|
|
675
|
-
process.env.PATH = `${dotnetToolsPath}:${process.env.PATH}`;
|
|
676
|
-
Logger.debug(`Updated current process.env.PATH to include: ${dotnetToolsPath}`);
|
|
677
|
-
} else if (!process.env.PATH) {
|
|
678
|
-
process.env.PATH = dotnetToolsPath;
|
|
679
|
-
Logger.debug(`Set current process.env.PATH to: ${dotnetToolsPath}`);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
/**
|
|
684
|
-
*
|
|
685
|
-
* @returns The path to the .dotnet global tools directory.
|
|
686
|
-
*/
|
|
687
|
-
export function getDotnetGlobalToolsPath(): string {
|
|
688
|
-
const homeDir = os.homedir();
|
|
689
|
-
|
|
690
|
-
if (process.platform === 'win32') {
|
|
691
|
-
// Example: C:\Users\YourName\.dotnet\tools
|
|
692
|
-
return path.join(homeDir, '.dotnet', 'tools');
|
|
693
|
-
} else if (process.platform === 'darwin' || process.platform === 'linux') {
|
|
694
|
-
// macOS or Linux: ~/.dotnet/tools
|
|
695
|
-
return path.join(homeDir, '.dotnet', 'tools');
|
|
696
|
-
} else {
|
|
697
|
-
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|