imcp 0.0.19 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.roo/rules-code/rules.md +88 -0
- package/dist/cli/index.js +1 -45
- package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -5
- package/dist/core/installers/clients/BaseClientInstaller.js +40 -38
- package/dist/core/installers/clients/ClientInstaller.d.ts +9 -9
- package/dist/core/installers/clients/ClientInstaller.js +105 -99
- package/dist/core/installers/requirements/BaseInstaller.d.ts +9 -1
- package/dist/core/installers/requirements/CommandInstaller.d.ts +9 -1
- package/dist/core/installers/requirements/CommandInstaller.js +46 -12
- package/dist/core/installers/requirements/GeneralInstaller.d.ts +11 -1
- package/dist/core/installers/requirements/GeneralInstaller.js +46 -10
- package/dist/core/installers/requirements/InstallerFactory.d.ts +3 -1
- package/dist/core/installers/requirements/InstallerFactory.js +3 -2
- package/dist/core/installers/requirements/NpmInstaller.d.ts +4 -2
- package/dist/core/installers/requirements/NpmInstaller.js +38 -22
- package/dist/core/installers/requirements/PipInstaller.d.ts +3 -1
- package/dist/core/installers/requirements/PipInstaller.js +58 -36
- package/dist/core/installers/requirements/RequirementInstaller.d.ts +4 -1
- package/dist/core/loaders/InstallOperationManager.d.ts +115 -0
- package/dist/core/loaders/InstallOperationManager.js +311 -0
- package/dist/core/loaders/SystemSettingsManager.d.ts +54 -0
- package/dist/core/loaders/SystemSettingsManager.js +257 -0
- package/dist/core/metadatas/constants.d.ts +7 -0
- package/dist/core/metadatas/constants.js +7 -0
- package/dist/core/metadatas/recordingConstants.d.ts +44 -0
- package/dist/core/metadatas/recordingConstants.js +45 -0
- package/dist/core/metadatas/types.d.ts +21 -0
- package/dist/core/onboard/FeedOnboardService.d.ts +7 -3
- package/dist/core/onboard/FeedOnboardService.js +52 -5
- package/dist/core/onboard/InstallOperationManager.d.ts +23 -0
- package/dist/core/onboard/InstallOperationManager.js +144 -0
- package/dist/core/onboard/OnboardStatusManager.js +2 -1
- package/dist/core/validators/StdioServerValidator.js +4 -3
- package/dist/services/InstallationService.d.ts +2 -37
- package/dist/services/InstallationService.js +45 -313
- package/dist/services/MCPManager.d.ts +1 -1
- package/dist/services/MCPManager.js +53 -47
- package/dist/services/RequirementService.d.ts +85 -12
- package/dist/services/RequirementService.js +488 -49
- package/dist/services/ServerService.d.ts +0 -6
- package/dist/services/ServerService.js +0 -74
- package/dist/services/TelemetryService.d.ts +15 -0
- package/dist/services/TelemetryService.js +54 -0
- package/dist/utils/adoUtils.js +6 -3
- package/dist/utils/githubAuth.js +65 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +78 -1
- package/dist/utils/macroExpressionUtils.js +3 -25
- package/dist/utils/osUtils.d.ts +22 -1
- package/dist/utils/osUtils.js +92 -1
- package/dist/utils/versionUtils.d.ts +20 -0
- package/dist/utils/versionUtils.js +76 -0
- package/dist/web/public/css/modal.css +292 -1
- package/dist/web/public/css/serverCategoryList.css +120 -0
- package/dist/web/public/css/serverDetails.css +14 -1
- package/dist/web/public/index.html +126 -21
- package/dist/web/public/js/flights/flights.js +1 -1
- package/dist/web/public/js/modal/index.js +8 -14
- package/dist/web/public/js/modal/installModal.js +3 -4
- package/dist/web/public/js/modal/installation.js +122 -137
- package/dist/web/public/js/modal/loadingModal.js +155 -25
- package/dist/web/public/js/modal/messageQueue.js +45 -101
- package/dist/web/public/js/modal/modalSetup.js +125 -43
- package/dist/web/public/js/modal/modalUtils.js +0 -12
- package/dist/web/public/js/modal.js +23 -10
- package/dist/web/public/js/onboard/formProcessor.js +18 -11
- package/dist/web/public/js/onboard/publishHandler.js +35 -3
- package/dist/web/public/js/onboard/templates.js +5 -1
- package/dist/web/public/js/onboard/uiHandlers.js +266 -39
- package/dist/web/public/js/onboard/validationHandlers.js +71 -39
- package/dist/web/public/js/serverCategoryDetails.js +60 -11
- package/dist/web/public/js/serverCategoryList.js +93 -9
- package/dist/web/public/js/settings.js +314 -0
- package/dist/web/public/onboard.html +2 -2
- package/dist/web/public/settings.html +135 -0
- package/dist/web/public/styles.css +32 -0
- package/dist/web/server.js +93 -1
- package/{src/web/public/js/onboard → docs}/ONBOARDING_PAGE_DESIGN.md +15 -125
- package/docs/Telemetry.md +136 -0
- package/memory-bank/activeContext.md +26 -0
- package/memory-bank/decisionLog.md +91 -0
- package/memory-bank/productContext.md +41 -0
- package/memory-bank/progress.md +35 -0
- package/memory-bank/systemPatterns.md +10 -0
- package/package.json +2 -1
- package/src/cli/index.ts +1 -48
- package/src/core/installers/clients/BaseClientInstaller.ts +64 -50
- package/src/core/installers/clients/ClientInstaller.ts +130 -130
- package/src/core/installers/requirements/BaseInstaller.ts +9 -1
- package/src/core/installers/requirements/CommandInstaller.ts +47 -13
- package/src/core/installers/requirements/GeneralInstaller.ts +48 -10
- package/src/core/installers/requirements/InstallerFactory.ts +4 -3
- package/src/core/installers/requirements/NpmInstaller.ts +90 -68
- package/src/core/installers/requirements/PipInstaller.ts +81 -55
- package/src/core/installers/requirements/RequirementInstaller.ts +4 -3
- package/src/core/loaders/InstallOperationManager.ts +367 -0
- package/src/core/loaders/SystemSettingsManager.ts +278 -0
- package/src/core/metadatas/constants.ts +9 -0
- package/src/core/metadatas/recordingConstants.ts +62 -0
- package/src/core/metadatas/types.ts +23 -0
- package/src/core/onboard/FeedOnboardService.ts +59 -5
- package/src/core/onboard/OnboardStatusManager.ts +2 -1
- package/src/core/validators/StdioServerValidator.ts +4 -3
- package/src/services/InstallationService.ts +54 -399
- package/src/services/MCPManager.ts +61 -64
- package/src/services/RequirementService.ts +564 -67
- package/src/services/ServerService.ts +0 -90
- package/src/services/TelemetryService.ts +59 -0
- package/src/utils/adoUtils.ts +6 -4
- package/src/utils/githubAuth.ts +84 -1
- package/src/utils/logger.ts +83 -1
- package/src/utils/macroExpressionUtils.ts +4 -21
- package/src/utils/osUtils.ts +92 -1
- package/src/utils/versionUtils.ts +98 -13
- package/src/web/public/css/modal.css +292 -1
- package/src/web/public/css/serverCategoryList.css +120 -0
- package/src/web/public/css/serverDetails.css +14 -1
- package/src/web/public/index.html +126 -21
- package/src/web/public/js/flights/flights.js +1 -1
- package/src/web/public/js/modal/index.js +8 -14
- package/src/web/public/js/modal/installModal.js +3 -4
- package/src/web/public/js/modal/installation.js +122 -137
- package/src/web/public/js/modal/loadingModal.js +155 -25
- package/src/web/public/js/modal/modalSetup.js +125 -43
- package/src/web/public/js/modal/modalUtils.js +0 -12
- package/src/web/public/js/modal.js +23 -10
- package/src/web/public/js/onboard/formProcessor.js +18 -11
- package/src/web/public/js/onboard/publishHandler.js +35 -3
- package/src/web/public/js/onboard/templates.js +5 -1
- package/src/web/public/js/onboard/uiHandlers.js +266 -39
- package/src/web/public/js/onboard/validationHandlers.js +71 -39
- package/src/web/public/js/serverCategoryDetails.js +60 -11
- package/src/web/public/js/serverCategoryList.js +93 -9
- package/src/web/public/js/settings.js +314 -0
- package/src/web/public/onboard.html +2 -2
- package/src/web/public/settings.html +135 -0
- package/src/web/public/styles.css +32 -0
- package/src/web/server.ts +96 -1
- package/dist/cli/commands/start.d.ts +0 -2
- package/dist/cli/commands/start.js +0 -32
- package/dist/cli/commands/sync.d.ts +0 -2
- package/dist/cli/commands/sync.js +0 -17
- package/dist/core/ConfigurationLoader.d.ts +0 -32
- package/dist/core/ConfigurationLoader.js +0 -236
- package/dist/core/ConfigurationProvider.d.ts +0 -35
- package/dist/core/ConfigurationProvider.js +0 -375
- package/dist/core/InstallationService.d.ts +0 -50
- package/dist/core/InstallationService.js +0 -350
- package/dist/core/MCPManager.d.ts +0 -28
- package/dist/core/MCPManager.js +0 -188
- package/dist/core/RequirementService.d.ts +0 -40
- package/dist/core/RequirementService.js +0 -110
- package/dist/core/ServerSchemaLoader.d.ts +0 -11
- package/dist/core/ServerSchemaLoader.js +0 -43
- package/dist/core/ServerSchemaProvider.d.ts +0 -17
- package/dist/core/ServerSchemaProvider.js +0 -120
- package/dist/core/constants.d.ts +0 -47
- package/dist/core/constants.js +0 -94
- package/dist/core/installers/BaseInstaller.d.ts +0 -74
- package/dist/core/installers/BaseInstaller.js +0 -253
- package/dist/core/installers/ClientInstaller.d.ts +0 -23
- package/dist/core/installers/ClientInstaller.js +0 -564
- package/dist/core/installers/CommandInstaller.d.ts +0 -37
- package/dist/core/installers/CommandInstaller.js +0 -173
- package/dist/core/installers/GeneralInstaller.d.ts +0 -33
- package/dist/core/installers/GeneralInstaller.js +0 -85
- package/dist/core/installers/InstallerFactory.d.ts +0 -54
- package/dist/core/installers/InstallerFactory.js +0 -97
- package/dist/core/installers/NpmInstaller.d.ts +0 -26
- package/dist/core/installers/NpmInstaller.js +0 -127
- package/dist/core/installers/PipInstaller.d.ts +0 -28
- package/dist/core/installers/PipInstaller.js +0 -127
- package/dist/core/installers/RequirementInstaller.d.ts +0 -33
- package/dist/core/installers/RequirementInstaller.js +0 -3
- package/dist/core/types.d.ts +0 -166
- package/dist/core/types.js +0 -16
- package/dist/services/InstallRequestValidator.d.ts +0 -21
- package/dist/services/InstallRequestValidator.js +0 -99
- package/dist/web/public/js/modal/installHandler.js +0 -227
- package/dist/web/public/js/modal/loadingUI.js +0 -74
- package/dist/web/public/js/modal/modalUI.js +0 -214
- package/dist/web/public/js/modal/version.js +0 -20
- package/src/web/public/js/modal/messageQueue.js +0 -112
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Progress Log
|
|
2
|
+
|
|
3
|
+
- [YYYY-MM-DD HH:MM:SS] - Initializing Memory Bank.
|
|
4
|
+
|
|
5
|
+
- [2025-05-16 09:22:36] - Completed: Made "IMCP Server Manager" title clickable in `src/web/public/index.html`.
|
|
6
|
+
- [2025-05-16 13:28:10] - Completed: Refactored requirement management from `InstallationService` to `RequirementService`. Fixed `reqConfig` scoping and type fallbacks in `RequirementService.processRequirementUpdates`.
|
|
7
|
+
|
|
8
|
+
[2025-05-16 16:07:34] - Completed: Redesign installation operation status and polling mechanism.
|
|
9
|
+
- Added `InstallOperationDetails` type to `src/core/metadatas/types.ts`.
|
|
10
|
+
- Created `InstallOperationManager` in `src/core/loaders/InstallOperationManager.ts`.
|
|
11
|
+
- Added API endpoint for installation status in `src/web/server.ts`.
|
|
12
|
+
- Integrated `recordStep` in `InstallationService`, `RequirementService`, and `BaseClientInstaller`.
|
|
13
|
+
|
|
14
|
+
[2025-05-16 16:50:21] - Enhanced installation status:
|
|
15
|
+
- Added `overallStatus` to `InstallOperationDetails` in `src/core/metadatas/types.ts`.
|
|
16
|
+
- Updated `InstallOperationManager` in `src/core/loaders/InstallOperationManager.ts` to manage `overallStatus`.
|
|
17
|
+
- Modified frontend polling in `src/web/public/js/modal/installation.js` to use the new API `/api/categories/:categoryName/servers/:serverName/installation/status` and display detailed steps.
|
|
18
|
+
|
|
19
|
+
[2025-05-17 00:26:16] - Began refactoring InstallOperationManager to be instance-based per category/server, with new file structure for status. Memory bank updated to reflect architectural and pattern changes.
|
|
20
|
+
|
|
21
|
+
[2025-05-17 15:02:44] - Completed: Refactored `RequirementService.ts` to use instance-based `InstallOperationManager` and its `recording`/`recordingAsync` methods. This involved updating `processRequirementUpdates`, `checkAndInstallRequirements`, and `installRequirementsInBackground`.
|
|
22
|
+
|
|
23
|
+
[2025-05-18 11:33:23] - Completed: Standardized step recording names by creating `src/core/metadatas/recordingConstants.ts`. This centralizes static step names and documents dynamic patterns for installation/onboarding operations.
|
|
24
|
+
|
|
25
|
+
[2025-05-18 13:21:30] - Completed: Implemented main modal refresh logic to replace page reload.
|
|
26
|
+
- `loadingModal.js`: Dispatches `refreshMainModalContent` event on close.
|
|
27
|
+
- `installation.js`: Stores `categoryName` and `serverName` in `localStorage`.
|
|
28
|
+
- `modal.js`: Listens for event, retrieves context from `localStorage`, and calls `showInstallModal` with both `categoryName` and `serverName`.
|
|
29
|
+
- This resolves "Server configuration not found" errors and improves UX.
|
|
30
|
+
[2025-05-17 15:26:15] - Refactored all requirement installer classes and factory to support InstallOperationManager step recording. All install methods now accept a recorder and log critical steps.
|
|
31
|
+
|
|
32
|
+
[2025-05-19 00:14:13] - Completed: Updated settings page (`src/web/public/settings.html` and `src/web/public/js/settings.js`):
|
|
33
|
+
- Removed "NPM Global Package Path" display.
|
|
34
|
+
- Added prompt with a question icon for User Configurations, displayed on the same line as the section title.
|
|
35
|
+
- Implemented secret input type for keys containing "key" in User Configurations, with an eye icon button *inside* the value input field to toggle visibility (maintaining original input box sizes).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# System Patterns
|
|
2
|
+
|
|
3
|
+
- [YYYY-MM-DD HH:MM:SS] - Initializing Memory Bank.
|
|
4
|
+
|
|
5
|
+
[2025-05-18 13:21:30] - Implemented an event-driven modal refresh pattern for the installation UI.
|
|
6
|
+
- Pattern: Instead of page reloads, the loading modal (`loadingModal.js`) dispatches a custom DOM event (`refreshMainModalContent`) upon closing.
|
|
7
|
+
- Context Persistence: The initiating action (e.g., in `installation.js`) stores necessary context (like `lastSelectedCategory` and `lastSelectedServerName`) in `localStorage`.
|
|
8
|
+
- Event Handling: The main modal controller (`modal.js`) listens for this event, retrieves context from `localStorage`, and re-initializes/refreshes its content (`showInstallModal`) with the persisted context.
|
|
9
|
+
- Benefit: This decouples the loading modal from the main modal, allows for non-disruptive UI updates, and maintains user context effectively.
|
|
10
|
+
[2025-05-17 00:26:06] - Changed InstallOperationManager from singleton/static to instance-based, with per-category/server file storage pattern: Settings_Dir/InstallOperationStatus/CategoryName/ServerName.json. This introduces a more granular, object-oriented persistence and management pattern for install operation status.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Node.js SDK for Model Context Protocol (MCP)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"author": "",
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"applicationinsights": "^2.9.3",
|
|
28
29
|
"axios": "^1.6.2",
|
|
29
30
|
"commander": "^11.1.0",
|
|
30
31
|
"express": "^4.18.2",
|
package/src/cli/index.ts
CHANGED
|
@@ -8,19 +8,9 @@ import { createUninstallCommand } from './commands/uninstall.js';
|
|
|
8
8
|
import { createPullCommand } from './commands/pull.js';
|
|
9
9
|
import { mcpManager } from '../services/MCPManager.js';
|
|
10
10
|
import { Logger } from '../utils/logger.js';
|
|
11
|
-
import
|
|
12
|
-
import path from 'path';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
import fs from 'fs';
|
|
15
|
-
import { compareVersions } from '../utils/versionUtils.js';
|
|
11
|
+
import { checkForUpdates } from '../utils/versionUtils.js';
|
|
16
12
|
|
|
17
13
|
// Custom error interface for Commander.js errors
|
|
18
|
-
// ANSI color codes
|
|
19
|
-
const COLORS = {
|
|
20
|
-
reset: '\x1b[0m',
|
|
21
|
-
yellow: '\x1b[33m'
|
|
22
|
-
};
|
|
23
|
-
|
|
24
14
|
interface CommanderError extends Error {
|
|
25
15
|
code?: string;
|
|
26
16
|
}
|
|
@@ -81,43 +71,6 @@ process.on('unhandledRejection', (error: unknown) => {
|
|
|
81
71
|
process.exit(1);
|
|
82
72
|
});
|
|
83
73
|
|
|
84
|
-
/**
|
|
85
|
-
* Check if there's a newer version of the package available
|
|
86
|
-
*/
|
|
87
|
-
|
|
88
|
-
async function checkForUpdates(): Promise<void> {
|
|
89
|
-
try {
|
|
90
|
-
// Get the current package version
|
|
91
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
92
|
-
const __dirname = path.dirname(__filename);
|
|
93
|
-
const packagePath = path.resolve(__dirname, '../../package.json');
|
|
94
|
-
const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
95
|
-
const currentVersion = packageJson.name && packageJson.version ? packageJson.version : '0.0.0';
|
|
96
|
-
const packageName = packageJson.name || 'imcp';
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
// Get the latest version from npm registry (only for published packages)
|
|
100
|
-
const npmResponse = await axios.get(`https://registry.npmjs.org/${packageName}`);
|
|
101
|
-
|
|
102
|
-
if (npmResponse.data && npmResponse.data['dist-tags'] && npmResponse.data['dist-tags'].latest) {
|
|
103
|
-
const latestVersion = npmResponse.data['dist-tags'].latest;
|
|
104
|
-
|
|
105
|
-
// Compare versions properly to ensure we're only notifying for newer versions
|
|
106
|
-
if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
|
|
107
|
-
console.log(`${COLORS.yellow}Update available for ${packageName}: ${currentVersion} → ${latestVersion}${COLORS.reset}`);
|
|
108
|
-
console.log(`${COLORS.yellow}Run \`npm install -g ${packageName}@latest\` to update${COLORS.reset}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} catch (npmError) {
|
|
112
|
-
// Log the npm error
|
|
113
|
-
Logger.debug(`Failed to check npm registry: ${npmError instanceof Error ? npmError.message : String(npmError)}`);
|
|
114
|
-
}
|
|
115
|
-
} catch (error) {
|
|
116
|
-
// Silently fail - don't interrupt the command if update check fails
|
|
117
|
-
Logger.debug(`Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
74
|
// Start the CLI
|
|
122
75
|
main().catch((error: unknown) => {
|
|
123
76
|
if (error instanceof Error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Logger } from '../../../utils/logger.js';
|
|
2
2
|
import { exec } from 'child_process';
|
|
3
3
|
import { promisify } from 'util';
|
|
4
|
-
import { isCommandAvailable } from '../../../utils/osUtils.js';
|
|
4
|
+
import { isCommandAvailable, getNpmExecutablePath } from '../../../utils/osUtils.js';
|
|
5
5
|
import { ExtensionInstaller } from './ExtensionInstaller.js';
|
|
6
6
|
import { SUPPORTED_CLIENTS } from '../../metadatas/constants.js';
|
|
7
7
|
import {
|
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
MACRO_EXPRESSIONS,
|
|
14
14
|
MacroResolverFunctions
|
|
15
15
|
} from '../../../utils/macroExpressionUtils.js';
|
|
16
|
+
import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
|
|
17
|
+
import * as RecordingConstants from '../../metadatas/recordingConstants.js';
|
|
16
18
|
|
|
17
19
|
const execAsync = promisify(exec);
|
|
18
20
|
|
|
@@ -123,7 +125,7 @@ export abstract class BaseClientInstaller {
|
|
|
123
125
|
*/
|
|
124
126
|
protected async handleWindowsNpx(config: any): Promise<any> {
|
|
125
127
|
if (process.platform === 'win32' && config.command === 'npx') {
|
|
126
|
-
const npmPath = await
|
|
128
|
+
const npmPath = await getNpmExecutablePath();
|
|
127
129
|
return {
|
|
128
130
|
...config,
|
|
129
131
|
command: 'cmd',
|
|
@@ -179,19 +181,6 @@ export abstract class BaseClientInstaller {
|
|
|
179
181
|
};
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
/**
|
|
183
|
-
* Get the NPM path on Windows
|
|
184
|
-
*/
|
|
185
|
-
private async getNpmPath(): Promise<string> {
|
|
186
|
-
try {
|
|
187
|
-
const { stdout } = await execAsync('powershell -Command "get-command npm | Select-Object -ExpandProperty Source"');
|
|
188
|
-
return stdout.trim().replace(/\\npm\.cmd$/, '');
|
|
189
|
-
} catch (error) {
|
|
190
|
-
Logger.error('Error getting npm path:', error);
|
|
191
|
-
return 'C:\\Program Files\\nodejs';
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
184
|
/**
|
|
196
185
|
* Checks if VS Code or VS Code Insiders is installed and installs the client extension.
|
|
197
186
|
* @param operationId The operation ID for tracking.
|
|
@@ -276,48 +265,73 @@ export abstract class BaseClientInstaller {
|
|
|
276
265
|
* @param serverConfig Server configuration
|
|
277
266
|
* @param options Installation options including environment variables and arguments
|
|
278
267
|
*/
|
|
279
|
-
async install(serverConfig: McpConfig, options: ServerInstallOptions): Promise<OperationStatus> {
|
|
268
|
+
async install(serverConfig: McpConfig, options: ServerInstallOptions, categoryName?: string): Promise<OperationStatus> {
|
|
280
269
|
const operationId = this.generateOperationId();
|
|
281
270
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
271
|
+
const recorder = InstallOperationManager.getInstance(categoryName || serverConfig.name, serverConfig.name);
|
|
272
|
+
return await recorder.recording(
|
|
273
|
+
async () => {
|
|
274
|
+
await recorder.recording(
|
|
275
|
+
() => this.checkVSCodeAndInstallExtension(operationId), {
|
|
276
|
+
stepName: RecordingConstants.STEP_CHECK_VSCODE_AND_INSTALL_EXTENSION,
|
|
277
|
+
onResult: (result) => result?.status !== 'failed'
|
|
278
|
+
}
|
|
279
|
+
)
|
|
287
280
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
281
|
+
const installConfig = await recorder.recording(
|
|
282
|
+
() => this.setupInstallConfig(serverConfig, options), {
|
|
283
|
+
stepName: RecordingConstants.STEP_SETUP_INSTALLATION_CONFIG
|
|
284
|
+
});
|
|
292
285
|
|
|
293
|
-
|
|
294
|
-
|
|
286
|
+
if (serverConfig.mode) {
|
|
287
|
+
installConfig.mode = serverConfig.mode;
|
|
288
|
+
}
|
|
295
289
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
290
|
+
const results = await recorder.recording(
|
|
291
|
+
() => this.updateVSCodeSettings(serverConfig.name, installConfig), {
|
|
292
|
+
stepName: RecordingConstants.STEP_UPDATE_VSCODE_SETTINGS,
|
|
293
|
+
onResult: (result) => result?.some(r => r.success)
|
|
294
|
+
}
|
|
295
|
+
);
|
|
300
296
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
297
|
+
// Determine overall success
|
|
298
|
+
const anySuccess = results.some(r => r.success);
|
|
299
|
+
const successPaths = results.filter(r => r.success).map(r => r.path);
|
|
300
|
+
const errors = results.filter(r => !r.success).map(r => r.error);
|
|
301
|
+
|
|
302
|
+
const finalMessage = anySuccess
|
|
306
303
|
? `Successfully installed ${this.clientName} client. Updated settings in: ${successPaths.join(', ')}`
|
|
307
|
-
: `Failed to install ${this.clientName} client. Errors: ${errors.join('; ')}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
304
|
+
: `Failed to install ${this.clientName} client. Errors: ${errors.join('; ')}`;
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
status: anySuccess ? 'completed' : 'failed',
|
|
308
|
+
type: 'install',
|
|
309
|
+
target: 'server',
|
|
310
|
+
message: finalMessage,
|
|
311
|
+
operationId,
|
|
312
|
+
error: anySuccess ? undefined : errors.join('; ')
|
|
313
|
+
};
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
stepName: RecordingConstants.STEP_INSTALLATION,
|
|
317
|
+
onResult: (result) => result?.status !== 'failed',
|
|
318
|
+
endMessage: (result) => (result as OperationStatus)?.message,
|
|
319
|
+
onError: (error) => {
|
|
320
|
+
const errorMsg = `Unexpected error installing ${this.clientName} client: ${error instanceof Error ? error.message : String(error)}`;
|
|
321
|
+
return {
|
|
322
|
+
result: {
|
|
323
|
+
status: 'failed',
|
|
324
|
+
type: 'install',
|
|
325
|
+
target: 'server',
|
|
326
|
+
message: errorMsg,
|
|
327
|
+
operationId,
|
|
328
|
+
error: error instanceof Error ? error.message : String(error)
|
|
329
|
+
}, message: errorMsg
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
);
|
|
334
|
+
|
|
321
335
|
}
|
|
322
336
|
|
|
323
337
|
/**
|
|
@@ -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.
|