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.
Files changed (183) hide show
  1. package/.roo/rules-code/rules.md +88 -0
  2. package/dist/cli/index.js +1 -45
  3. package/dist/core/installers/clients/BaseClientInstaller.d.ts +1 -5
  4. package/dist/core/installers/clients/BaseClientInstaller.js +40 -38
  5. package/dist/core/installers/clients/ClientInstaller.d.ts +9 -9
  6. package/dist/core/installers/clients/ClientInstaller.js +105 -99
  7. package/dist/core/installers/requirements/BaseInstaller.d.ts +9 -1
  8. package/dist/core/installers/requirements/CommandInstaller.d.ts +9 -1
  9. package/dist/core/installers/requirements/CommandInstaller.js +46 -12
  10. package/dist/core/installers/requirements/GeneralInstaller.d.ts +11 -1
  11. package/dist/core/installers/requirements/GeneralInstaller.js +46 -10
  12. package/dist/core/installers/requirements/InstallerFactory.d.ts +3 -1
  13. package/dist/core/installers/requirements/InstallerFactory.js +3 -2
  14. package/dist/core/installers/requirements/NpmInstaller.d.ts +4 -2
  15. package/dist/core/installers/requirements/NpmInstaller.js +38 -22
  16. package/dist/core/installers/requirements/PipInstaller.d.ts +3 -1
  17. package/dist/core/installers/requirements/PipInstaller.js +58 -36
  18. package/dist/core/installers/requirements/RequirementInstaller.d.ts +4 -1
  19. package/dist/core/loaders/InstallOperationManager.d.ts +115 -0
  20. package/dist/core/loaders/InstallOperationManager.js +311 -0
  21. package/dist/core/loaders/SystemSettingsManager.d.ts +54 -0
  22. package/dist/core/loaders/SystemSettingsManager.js +257 -0
  23. package/dist/core/metadatas/constants.d.ts +7 -0
  24. package/dist/core/metadatas/constants.js +7 -0
  25. package/dist/core/metadatas/recordingConstants.d.ts +44 -0
  26. package/dist/core/metadatas/recordingConstants.js +45 -0
  27. package/dist/core/metadatas/types.d.ts +21 -0
  28. package/dist/core/onboard/FeedOnboardService.d.ts +7 -3
  29. package/dist/core/onboard/FeedOnboardService.js +52 -5
  30. package/dist/core/onboard/InstallOperationManager.d.ts +23 -0
  31. package/dist/core/onboard/InstallOperationManager.js +144 -0
  32. package/dist/core/onboard/OnboardStatusManager.js +2 -1
  33. package/dist/core/validators/StdioServerValidator.js +4 -3
  34. package/dist/services/InstallationService.d.ts +2 -37
  35. package/dist/services/InstallationService.js +45 -313
  36. package/dist/services/MCPManager.d.ts +1 -1
  37. package/dist/services/MCPManager.js +53 -47
  38. package/dist/services/RequirementService.d.ts +85 -12
  39. package/dist/services/RequirementService.js +488 -49
  40. package/dist/services/ServerService.d.ts +0 -6
  41. package/dist/services/ServerService.js +0 -74
  42. package/dist/services/TelemetryService.d.ts +15 -0
  43. package/dist/services/TelemetryService.js +54 -0
  44. package/dist/utils/adoUtils.js +6 -3
  45. package/dist/utils/githubAuth.js +65 -0
  46. package/dist/utils/logger.d.ts +16 -0
  47. package/dist/utils/logger.js +78 -1
  48. package/dist/utils/macroExpressionUtils.js +3 -25
  49. package/dist/utils/osUtils.d.ts +22 -1
  50. package/dist/utils/osUtils.js +92 -1
  51. package/dist/utils/versionUtils.d.ts +20 -0
  52. package/dist/utils/versionUtils.js +76 -0
  53. package/dist/web/public/css/modal.css +292 -1
  54. package/dist/web/public/css/serverCategoryList.css +120 -0
  55. package/dist/web/public/css/serverDetails.css +14 -1
  56. package/dist/web/public/index.html +126 -21
  57. package/dist/web/public/js/flights/flights.js +1 -1
  58. package/dist/web/public/js/modal/index.js +8 -14
  59. package/dist/web/public/js/modal/installModal.js +3 -4
  60. package/dist/web/public/js/modal/installation.js +122 -137
  61. package/dist/web/public/js/modal/loadingModal.js +155 -25
  62. package/dist/web/public/js/modal/messageQueue.js +45 -101
  63. package/dist/web/public/js/modal/modalSetup.js +125 -43
  64. package/dist/web/public/js/modal/modalUtils.js +0 -12
  65. package/dist/web/public/js/modal.js +23 -10
  66. package/dist/web/public/js/onboard/formProcessor.js +18 -11
  67. package/dist/web/public/js/onboard/publishHandler.js +35 -3
  68. package/dist/web/public/js/onboard/templates.js +5 -1
  69. package/dist/web/public/js/onboard/uiHandlers.js +266 -39
  70. package/dist/web/public/js/onboard/validationHandlers.js +71 -39
  71. package/dist/web/public/js/serverCategoryDetails.js +60 -11
  72. package/dist/web/public/js/serverCategoryList.js +93 -9
  73. package/dist/web/public/js/settings.js +314 -0
  74. package/dist/web/public/onboard.html +2 -2
  75. package/dist/web/public/settings.html +135 -0
  76. package/dist/web/public/styles.css +32 -0
  77. package/dist/web/server.js +93 -1
  78. package/{src/web/public/js/onboard → docs}/ONBOARDING_PAGE_DESIGN.md +15 -125
  79. package/docs/Telemetry.md +136 -0
  80. package/memory-bank/activeContext.md +26 -0
  81. package/memory-bank/decisionLog.md +91 -0
  82. package/memory-bank/productContext.md +41 -0
  83. package/memory-bank/progress.md +35 -0
  84. package/memory-bank/systemPatterns.md +10 -0
  85. package/package.json +2 -1
  86. package/src/cli/index.ts +1 -48
  87. package/src/core/installers/clients/BaseClientInstaller.ts +64 -50
  88. package/src/core/installers/clients/ClientInstaller.ts +130 -130
  89. package/src/core/installers/requirements/BaseInstaller.ts +9 -1
  90. package/src/core/installers/requirements/CommandInstaller.ts +47 -13
  91. package/src/core/installers/requirements/GeneralInstaller.ts +48 -10
  92. package/src/core/installers/requirements/InstallerFactory.ts +4 -3
  93. package/src/core/installers/requirements/NpmInstaller.ts +90 -68
  94. package/src/core/installers/requirements/PipInstaller.ts +81 -55
  95. package/src/core/installers/requirements/RequirementInstaller.ts +4 -3
  96. package/src/core/loaders/InstallOperationManager.ts +367 -0
  97. package/src/core/loaders/SystemSettingsManager.ts +278 -0
  98. package/src/core/metadatas/constants.ts +9 -0
  99. package/src/core/metadatas/recordingConstants.ts +62 -0
  100. package/src/core/metadatas/types.ts +23 -0
  101. package/src/core/onboard/FeedOnboardService.ts +59 -5
  102. package/src/core/onboard/OnboardStatusManager.ts +2 -1
  103. package/src/core/validators/StdioServerValidator.ts +4 -3
  104. package/src/services/InstallationService.ts +54 -399
  105. package/src/services/MCPManager.ts +61 -64
  106. package/src/services/RequirementService.ts +564 -67
  107. package/src/services/ServerService.ts +0 -90
  108. package/src/services/TelemetryService.ts +59 -0
  109. package/src/utils/adoUtils.ts +6 -4
  110. package/src/utils/githubAuth.ts +84 -1
  111. package/src/utils/logger.ts +83 -1
  112. package/src/utils/macroExpressionUtils.ts +4 -21
  113. package/src/utils/osUtils.ts +92 -1
  114. package/src/utils/versionUtils.ts +98 -13
  115. package/src/web/public/css/modal.css +292 -1
  116. package/src/web/public/css/serverCategoryList.css +120 -0
  117. package/src/web/public/css/serverDetails.css +14 -1
  118. package/src/web/public/index.html +126 -21
  119. package/src/web/public/js/flights/flights.js +1 -1
  120. package/src/web/public/js/modal/index.js +8 -14
  121. package/src/web/public/js/modal/installModal.js +3 -4
  122. package/src/web/public/js/modal/installation.js +122 -137
  123. package/src/web/public/js/modal/loadingModal.js +155 -25
  124. package/src/web/public/js/modal/modalSetup.js +125 -43
  125. package/src/web/public/js/modal/modalUtils.js +0 -12
  126. package/src/web/public/js/modal.js +23 -10
  127. package/src/web/public/js/onboard/formProcessor.js +18 -11
  128. package/src/web/public/js/onboard/publishHandler.js +35 -3
  129. package/src/web/public/js/onboard/templates.js +5 -1
  130. package/src/web/public/js/onboard/uiHandlers.js +266 -39
  131. package/src/web/public/js/onboard/validationHandlers.js +71 -39
  132. package/src/web/public/js/serverCategoryDetails.js +60 -11
  133. package/src/web/public/js/serverCategoryList.js +93 -9
  134. package/src/web/public/js/settings.js +314 -0
  135. package/src/web/public/onboard.html +2 -2
  136. package/src/web/public/settings.html +135 -0
  137. package/src/web/public/styles.css +32 -0
  138. package/src/web/server.ts +96 -1
  139. package/dist/cli/commands/start.d.ts +0 -2
  140. package/dist/cli/commands/start.js +0 -32
  141. package/dist/cli/commands/sync.d.ts +0 -2
  142. package/dist/cli/commands/sync.js +0 -17
  143. package/dist/core/ConfigurationLoader.d.ts +0 -32
  144. package/dist/core/ConfigurationLoader.js +0 -236
  145. package/dist/core/ConfigurationProvider.d.ts +0 -35
  146. package/dist/core/ConfigurationProvider.js +0 -375
  147. package/dist/core/InstallationService.d.ts +0 -50
  148. package/dist/core/InstallationService.js +0 -350
  149. package/dist/core/MCPManager.d.ts +0 -28
  150. package/dist/core/MCPManager.js +0 -188
  151. package/dist/core/RequirementService.d.ts +0 -40
  152. package/dist/core/RequirementService.js +0 -110
  153. package/dist/core/ServerSchemaLoader.d.ts +0 -11
  154. package/dist/core/ServerSchemaLoader.js +0 -43
  155. package/dist/core/ServerSchemaProvider.d.ts +0 -17
  156. package/dist/core/ServerSchemaProvider.js +0 -120
  157. package/dist/core/constants.d.ts +0 -47
  158. package/dist/core/constants.js +0 -94
  159. package/dist/core/installers/BaseInstaller.d.ts +0 -74
  160. package/dist/core/installers/BaseInstaller.js +0 -253
  161. package/dist/core/installers/ClientInstaller.d.ts +0 -23
  162. package/dist/core/installers/ClientInstaller.js +0 -564
  163. package/dist/core/installers/CommandInstaller.d.ts +0 -37
  164. package/dist/core/installers/CommandInstaller.js +0 -173
  165. package/dist/core/installers/GeneralInstaller.d.ts +0 -33
  166. package/dist/core/installers/GeneralInstaller.js +0 -85
  167. package/dist/core/installers/InstallerFactory.d.ts +0 -54
  168. package/dist/core/installers/InstallerFactory.js +0 -97
  169. package/dist/core/installers/NpmInstaller.d.ts +0 -26
  170. package/dist/core/installers/NpmInstaller.js +0 -127
  171. package/dist/core/installers/PipInstaller.d.ts +0 -28
  172. package/dist/core/installers/PipInstaller.js +0 -127
  173. package/dist/core/installers/RequirementInstaller.d.ts +0 -33
  174. package/dist/core/installers/RequirementInstaller.js +0 -3
  175. package/dist/core/types.d.ts +0 -166
  176. package/dist/core/types.js +0 -16
  177. package/dist/services/InstallRequestValidator.d.ts +0 -21
  178. package/dist/services/InstallRequestValidator.js +0 -99
  179. package/dist/web/public/js/modal/installHandler.js +0 -227
  180. package/dist/web/public/js/modal/loadingUI.js +0 -74
  181. package/dist/web/public/js/modal/modalUI.js +0 -214
  182. package/dist/web/public/js/modal/version.js +0 -20
  183. package/src/web/public/js/modal/messageQueue.js +0 -112
@@ -0,0 +1,88 @@
1
+ *IMPORTANT* Before I attempt to complete a task with code changes, I MUST have to ask confirmation with user whether to update memory bank
2
+
3
+ memory*bank_strategy:
4
+ initialization: |
5
+ <thinking> - **CHECK FOR MEMORY BANK:**
6
+ </thinking>
7
+ <thinking>
8
+ * First, check if the memory-bank/ directory exists.
9
+ </thinking>
10
+ <thinking>
11
+ _ If memory-bank DOES exist, skip immediately to `if_memory_bank_exists`.
12
+ </thinking>
13
+ if_no_memory_bank: | 1. **Inform the User:**
14
+ "No Memory Bank was found. I recommend creating one to maintain project context. Would you like to switch to Flow-Architect mode to do this?" 2. **Conditional Actions:**
15
+ _ If the user declines:
16
+ <thinking>
17
+ I need to proceed with the task without Memory Bank functionality.
18
+ </thinking>
19
+ a. Inform the user that the Memory Bank will not be created.
20
+ b. Set the status to '[MEMORY BANK: INACTIVE]'.
21
+ c. Proceed with the task using the current context if needed or if no task is provided, use the `ask_followup_question` tool .
22
+ _ If the user agrees:
23
+ Switch to Flow-Architect mode to create the Memory Bank.
24
+ if_memory_bank_exists: |
25
+ \*\*READ \_ALL_ MEMORY BANK FILES\*\*
26
+ <thinking>
27
+ I will read all memory bank files, one at a time.
28
+ </thinking>
29
+ Plan: Read all mandatory files sequentially. 1. Read `productContext.md` 2. Read `activeContext.md` 3. Read `systemPatterns.md` 4. Read `decisionLog.md` 5. Read `progress.md` 6. Set status to [MEMORY BANK: ACTIVE] and inform user. 7. Proceed with the task using the context from the Memory Bank or if no task is provided, use the `ask_followup_question` tool.
30
+
31
+ general:
32
+ status_prefix: "Begin EVERY response with either '[MEMORY BANK: ACTIVE]' or '[MEMORY BANK: INACTIVE]', according to the current state of the Memory Bank."
33
+
34
+ memory_bank_updates:
35
+ frequency:
36
+
37
+ - "UPDATE MEMORY BANK THROUGHOUT THE CHAT SESSION, WHEN SIGNIFICANT CHANGES OCCUR IN THE PROJECT."
38
+ decisionLog.md:
39
+ trigger: "When a significant architectural decision is made (new component, data flow change, technology choice, etc.). Use your judgment to determine significance."
40
+ action: |
41
+ <thinking>
42
+ I need to update decisionLog.md with a decision, the rationale, and any implications.
43
+ </thinking>
44
+ Use insert*content to \_append* new information. Never overwrite existing entries. Always include a timestamp.
45
+ format: |
46
+ "[YYYY-MM-DD HH:MM:SS] - [Summary of Change/Focus/Issue]"
47
+ productContext.md:
48
+ trigger: "When the high-level project description, goals, features, or overall architecture changes significantly. Use your judgment to determine significance."
49
+ action: |
50
+ <thinking>
51
+ A fundamental change has occurred which warrants an update to productContext.md.
52
+ </thinking>
53
+ Use insert*content to \_append* new information or use apply*diff to modify existing entries if necessary. Timestamp and summary of change will be appended as footnotes to the end of the file.
54
+ format: "[YYYY-MM-DD HH:MM:SS] - [Summary of Change]"
55
+ systemPatterns.md:
56
+ trigger: "When new architectural patterns are introduced or existing ones are modified. Use your judgement."
57
+ action: |
58
+ <thinking>
59
+ I need to update systemPatterns.md with a brief summary and time stamp.
60
+ </thinking>
61
+ Use insert_content to \_append* new patterns or use apply*diff to modify existing entries if warranted. Always include a timestamp.
62
+ format: "[YYYY-MM-DD HH:MM:SS] - [Description of Pattern/Change]"
63
+ activeContext.md:
64
+ trigger: "When the current focus of work changes, or when significant progress is made. Use your judgement."
65
+ action: |
66
+ <thinking>
67
+ I need to update activeContext.md with a brief summary and time stamp.
68
+ </thinking>
69
+ Use insert_content to \_append* to the relevant section (Current Focus, Recent Changes, Open Questions/Issues) or use apply*diff to modify existing entries if warranted. Always include a timestamp.
70
+ format: "[YYYY-MM-DD HH:MM:SS] - [Summary of Change/Focus/Issue]"
71
+ progress.md:
72
+ trigger: "When a task begins, is completed, or if there are any changes Use your judgement."
73
+ action: |
74
+ <thinking>
75
+ I need to update progress.md with a brief summary and time stamp.
76
+ </thinking>
77
+ Use insert_content to \_append* the new entry, never overwrite existing entries. Always include a timestamp.
78
+ format: "[YYYY-MM-DD HH:MM:SS] - [Summary of Change/Focus/Issue]"
79
+
80
+ umb:
81
+ trigger: "^(Update Memory Bank|UMB)$"
82
+ instructions: - "Halt Current Task: Stop current activity" - "Acknowledge Command: '[MEMORY BANK: UPDATING]'" - "Review Chat History"
83
+ core_update_process: | 1. Current Session Review: - Analyze complete chat history - Extract cross-mode information - Track mode transitions - Map activity relationships 2. Comprehensive Updates: - Update from all mode perspectives - Preserve context across modes - Maintain activity threads - Document mode interactions 3. Memory Bank Synchronization: - Update all affected *.md files - Ensure cross-mode consistency - Preserve activity context - Document continuation points
84
+ task_focus: "During a UMB update, focus on capturing any clarifications, questions answered, or context provided *during the chat session*. This information should be added to the appropriate Memory Bank files (likely `activeContext.md` or `decisionLog.md`), using the other modes' update formats as a guide. *Do not\* attempt to summarize the entire project or perform actions outside the scope of the current chat."
85
+ cross-mode_updates: "During a UMB update, ensure that all relevant information from the chat session is captured and added to the Memory Bank. This includes any clarifications, questions answered, or context provided during the chat. Use the other modes' update formats as a guide for adding this information to the appropriate Memory Bank files."
86
+ post_umb_actions: - "Memory Bank fully synchronized" - "All mode contexts preserved" - "Session can be safely closed" - "Next assistant will have complete context"
87
+ override_file_restrictions: true
88
+ override_mode_restrictions: true
package/dist/cli/index.js CHANGED
@@ -2,17 +2,7 @@
2
2
  import { Command } from 'commander';
3
3
  import { createServeCommand } from './commands/serve.js';
4
4
  import { Logger } from '../utils/logger.js';
5
- import axios from 'axios';
6
- import path from 'path';
7
- import { fileURLToPath } from 'url';
8
- import fs from 'fs';
9
- import { compareVersions } from '../utils/versionUtils.js';
10
- // Custom error interface for Commander.js errors
11
- // ANSI color codes
12
- const COLORS = {
13
- reset: '\x1b[0m',
14
- yellow: '\x1b[33m'
15
- };
5
+ import { checkForUpdates } from '../utils/versionUtils.js';
16
6
  async function main() {
17
7
  // Initialize the MCP manager
18
8
  // await mcpManager.initialize();
@@ -64,40 +54,6 @@ process.on('unhandledRejection', (error) => {
64
54
  }
65
55
  process.exit(1);
66
56
  });
67
- /**
68
- * Check if there's a newer version of the package available
69
- */
70
- async function checkForUpdates() {
71
- try {
72
- // Get the current package version
73
- const __filename = fileURLToPath(import.meta.url);
74
- const __dirname = path.dirname(__filename);
75
- const packagePath = path.resolve(__dirname, '../../package.json');
76
- const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
77
- const currentVersion = packageJson.name && packageJson.version ? packageJson.version : '0.0.0';
78
- const packageName = packageJson.name || 'imcp';
79
- try {
80
- // Get the latest version from npm registry (only for published packages)
81
- const npmResponse = await axios.get(`https://registry.npmjs.org/${packageName}`);
82
- if (npmResponse.data && npmResponse.data['dist-tags'] && npmResponse.data['dist-tags'].latest) {
83
- const latestVersion = npmResponse.data['dist-tags'].latest;
84
- // Compare versions properly to ensure we're only notifying for newer versions
85
- if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
86
- console.log(`${COLORS.yellow}Update available for ${packageName}: ${currentVersion} → ${latestVersion}${COLORS.reset}`);
87
- console.log(`${COLORS.yellow}Run \`npm install -g ${packageName}@latest\` to update${COLORS.reset}`);
88
- }
89
- }
90
- }
91
- catch (npmError) {
92
- // Log the npm error
93
- Logger.debug(`Failed to check npm registry: ${npmError instanceof Error ? npmError.message : String(npmError)}`);
94
- }
95
- }
96
- catch (error) {
97
- // Silently fail - don't interrupt the command if update check fails
98
- Logger.debug(`Failed to check for updates: ${error instanceof Error ? error.message : String(error)}`);
99
- }
100
- }
101
57
  // Start the CLI
102
58
  main().catch((error) => {
103
59
  if (error instanceof Error) {
@@ -40,10 +40,6 @@ export declare abstract class BaseClientInstaller {
40
40
  * Override in child classes to provide custom SSE configuration
41
41
  */
42
42
  protected handleSseMode(settings: any, serverName: string, installConfig: any): void;
43
- /**
44
- * Get the NPM path on Windows
45
- */
46
- private getNpmPath;
47
43
  /**
48
44
  * Checks if VS Code or VS Code Insiders is installed and installs the client extension.
49
45
  * @param operationId The operation ID for tracking.
@@ -66,7 +62,7 @@ export declare abstract class BaseClientInstaller {
66
62
  * @param serverConfig Server configuration
67
63
  * @param options Installation options including environment variables and arguments
68
64
  */
69
- install(serverConfig: McpConfig, options: ServerInstallOptions): Promise<OperationStatus>;
65
+ install(serverConfig: McpConfig, options: ServerInstallOptions, categoryName?: string): Promise<OperationStatus>;
70
66
  /**
71
67
  * Abstract method that must be implemented by client-specific installers
72
68
  */
@@ -1,10 +1,12 @@
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 { MACRO_EXPRESSIONS, MacroResolverFunctions } from '../../../utils/macroExpressionUtils.js';
8
+ import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
9
+ import * as RecordingConstants from '../../metadatas/recordingConstants.js';
8
10
  const execAsync = promisify(exec);
9
11
  /**
10
12
  * Base class for client installers with shared functionality
@@ -96,7 +98,7 @@ export class BaseClientInstaller {
96
98
  */
97
99
  async handleWindowsNpx(config) {
98
100
  if (process.platform === 'win32' && config.command === 'npx') {
99
- const npmPath = await this.getNpmPath();
101
+ const npmPath = await getNpmExecutablePath();
100
102
  return {
101
103
  ...config,
102
104
  command: 'cmd',
@@ -146,19 +148,6 @@ export class BaseClientInstaller {
146
148
  url: installConfig.url
147
149
  };
148
150
  }
149
- /**
150
- * Get the NPM path on Windows
151
- */
152
- async getNpmPath() {
153
- try {
154
- const { stdout } = await execAsync('powershell -Command "get-command npm | Select-Object -ExpandProperty Source"');
155
- return stdout.trim().replace(/\\npm\.cmd$/, '');
156
- }
157
- catch (error) {
158
- Logger.error('Error getting npm path:', error);
159
- return 'C:\\Program Files\\nodejs';
160
- }
161
- }
162
151
  /**
163
152
  * Checks if VS Code or VS Code Insiders is installed and installs the client extension.
164
153
  * @param operationId The operation ID for tracking.
@@ -238,44 +227,57 @@ export class BaseClientInstaller {
238
227
  * @param serverConfig Server configuration
239
228
  * @param options Installation options including environment variables and arguments
240
229
  */
241
- async install(serverConfig, options) {
230
+ async install(serverConfig, options, categoryName) {
242
231
  const operationId = this.generateOperationId();
243
- try {
244
- const vsCodeCheckResult = await this.checkVSCodeAndInstallExtension(operationId);
245
- if (vsCodeCheckResult) {
246
- return vsCodeCheckResult;
247
- }
248
- const installConfig = await this.setupInstallConfig(serverConfig, options);
232
+ const recorder = InstallOperationManager.getInstance(categoryName || serverConfig.name, serverConfig.name);
233
+ return await recorder.recording(async () => {
234
+ await recorder.recording(() => this.checkVSCodeAndInstallExtension(operationId), {
235
+ stepName: RecordingConstants.STEP_CHECK_VSCODE_AND_INSTALL_EXTENSION,
236
+ onResult: (result) => result?.status !== 'failed'
237
+ });
238
+ const installConfig = await recorder.recording(() => this.setupInstallConfig(serverConfig, options), {
239
+ stepName: RecordingConstants.STEP_SETUP_INSTALLATION_CONFIG
240
+ });
249
241
  if (serverConfig.mode) {
250
242
  installConfig.mode = serverConfig.mode;
251
243
  }
252
- // Update VS Code settings
253
- const results = await this.updateVSCodeSettings(serverConfig.name, installConfig);
244
+ const results = await recorder.recording(() => this.updateVSCodeSettings(serverConfig.name, installConfig), {
245
+ stepName: RecordingConstants.STEP_UPDATE_VSCODE_SETTINGS,
246
+ onResult: (result) => result?.some(r => r.success)
247
+ });
254
248
  // Determine overall success
255
249
  const anySuccess = results.some(r => r.success);
256
250
  const successPaths = results.filter(r => r.success).map(r => r.path);
257
251
  const errors = results.filter(r => !r.success).map(r => r.error);
252
+ const finalMessage = anySuccess
253
+ ? `Successfully installed ${this.clientName} client. Updated settings in: ${successPaths.join(', ')}`
254
+ : `Failed to install ${this.clientName} client. Errors: ${errors.join('; ')}`;
258
255
  return {
259
256
  status: anySuccess ? 'completed' : 'failed',
260
257
  type: 'install',
261
258
  target: 'server',
262
- message: anySuccess
263
- ? `Successfully installed ${this.clientName} client. Updated settings in: ${successPaths.join(', ')}`
264
- : `Failed to install ${this.clientName} client. Errors: ${errors.join('; ')}`,
259
+ message: finalMessage,
265
260
  operationId,
266
261
  error: anySuccess ? undefined : errors.join('; ')
267
262
  };
268
- }
269
- catch (error) {
270
- return {
271
- status: 'failed',
272
- type: 'install',
273
- target: 'server',
274
- message: `Unexpected error installing ${this.clientName} client: ${error instanceof Error ? error.message : String(error)}`,
275
- operationId,
276
- error: error instanceof Error ? error.message : String(error)
277
- };
278
- }
263
+ }, {
264
+ stepName: RecordingConstants.STEP_INSTALLATION,
265
+ onResult: (result) => result?.status !== 'failed',
266
+ endMessage: (result) => result?.message,
267
+ onError: (error) => {
268
+ const errorMsg = `Unexpected error installing ${this.clientName} client: ${error instanceof Error ? error.message : String(error)}`;
269
+ return {
270
+ result: {
271
+ status: 'failed',
272
+ type: 'install',
273
+ target: 'server',
274
+ message: errorMsg,
275
+ operationId,
276
+ error: error instanceof Error ? error.message : String(error)
277
+ }, message: errorMsg
278
+ };
279
+ }
280
+ });
279
281
  }
280
282
  }
281
283
  //# sourceMappingURL=BaseClientInstaller.js.map
@@ -10,21 +10,21 @@ export declare class ClientInstaller {
10
10
  private configProvider;
11
11
  constructor(categoryName: string, serverName: string, clients: string[]);
12
12
  /**
13
- * Generate a unique operation ID for tracking installations
14
- */
15
- private generateOperationId;
16
- /**
17
- * Check if server requirements are ready
18
- * Waits for requirements to be ready with timeout
13
+ * Install all specified clients
19
14
  */
20
- private checkRequirements;
15
+ install(options: ServerInstallOptions): Promise<ServerOperationResult>;
21
16
  /**
22
17
  * Install client with requirements checking
23
18
  */
24
19
  private installClient;
25
20
  private processInstallation;
26
21
  /**
27
- * Install all specified clients
22
+ * Generate a unique operation ID for tracking installations
23
+ */
24
+ private generateOperationId;
25
+ /**
26
+ * Check if server requirements are ready
27
+ * Waits for requirements to be ready with timeout
28
28
  */
29
- install(options: ServerInstallOptions): Promise<ServerOperationResult>;
29
+ private checkRequirements;
30
30
  }
@@ -1,5 +1,7 @@
1
1
  import { ConfigurationProvider } from '../../loaders/ConfigurationProvider.js';
2
+ import { Logger } from '../../../utils/logger.js';
2
3
  import { ClientInstallerFactory } from './ClientInstallerFactory.js';
4
+ import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
3
5
  /**
4
6
  * Main client installer class that orchestrates client installation process
5
7
  * Handles requirements checking and delegates to specific client installers
@@ -16,43 +18,24 @@ export class ClientInstaller {
16
18
  this.configProvider = ConfigurationProvider.getInstance();
17
19
  }
18
20
  /**
19
- * Generate a unique operation ID for tracking installations
20
- */
21
- generateOperationId() {
22
- return `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
23
- }
24
- /**
25
- * Check if server requirements are ready
26
- * Waits for requirements to be ready with timeout
21
+ * Install all specified clients
27
22
  */
28
- async checkRequirements(operationId, clientName, options) {
29
- let requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
30
- if (!requirementsReady) {
31
- const pendingStatus = {
32
- status: 'pending',
33
- type: 'install',
34
- target: 'server',
35
- message: `Waiting for requirements to be ready for client: ${clientName}`,
36
- operationId
37
- };
38
- await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, pendingStatus);
39
- // Set up periodic checking with timeout
40
- const startTime = Date.now();
41
- const timeoutMs = 5 * 60 * 1000; // 5 minutes
42
- const intervalMs = 5 * 1000; // 5 seconds
43
- while (!requirementsReady && (Date.now() - startTime) < timeoutMs) {
44
- await new Promise(resolve => setTimeout(resolve, intervalMs));
45
- requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
46
- }
47
- }
48
- var requirementsStatus = await this.configProvider.GetServerRequirementStatus(this.categoryName, this.serverName);
49
- // Find first non-empty npmPath from requirements status
50
- const npmPathRequirement = requirementsStatus.find(status => status.npmPath && status.npmPath.length > 0);
51
- if (npmPathRequirement && npmPathRequirement.npmPath) {
52
- options.settings = options.settings || {};
53
- options.settings.npmPath = npmPathRequirement.npmPath;
54
- }
55
- return requirementsReady;
23
+ async install(options) {
24
+ const initialStatuses = [];
25
+ // Start installation for each client asynchronously
26
+ const installPromises = this.clients.map(async (clientName) => {
27
+ const status = await this.installClient(clientName, options);
28
+ initialStatuses.push(status);
29
+ return status;
30
+ });
31
+ // Wait for all installations to complete
32
+ await Promise.all(installPromises);
33
+ // Return result
34
+ return {
35
+ success: true,
36
+ message: 'Client installations completed',
37
+ status: initialStatuses
38
+ };
56
39
  }
57
40
  /**
58
41
  * Install client with requirements checking
@@ -77,82 +60,105 @@ export class ClientInstaller {
77
60
  message: `Initializing installation for client: ${clientName}`,
78
61
  operationId
79
62
  };
80
- this.processInstallation(clientName, operationId, options);
63
+ // Async installation process
64
+ this.processInstallation(clientName, operationId, options)
65
+ .then((status) => {
66
+ if (status.status === 'completed' || status.status === 'failed') {
67
+ InstallOperationManager
68
+ .getInstance(this.categoryName, this.serverName)
69
+ .markOverallStatus(status.status);
70
+ }
71
+ this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, status);
72
+ })
73
+ .catch((error) => {
74
+ this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, {
75
+ status: 'failed',
76
+ type: 'install',
77
+ target: 'server',
78
+ message: `Error installing client ${clientName}: ${error instanceof Error ? error.message : String(error)}`,
79
+ operationId,
80
+ error: error instanceof Error ? error.message : String(error)
81
+ });
82
+ Logger.error(`Error installing client ${clientName}: ${error instanceof Error ? error.message : String(error)}`);
83
+ InstallOperationManager
84
+ .getInstance(this.categoryName, this.serverName)
85
+ .markOverallStatus('failed', error);
86
+ });
81
87
  // Update server status with initial client installation status
82
88
  await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, initialStatus);
83
89
  return initialStatus;
84
90
  }
85
91
  async processInstallation(clientName, operationId, options) {
86
- try {
87
- // Check requirements
88
- const requirementsReady = await this.checkRequirements(operationId, clientName, options);
89
- if (!requirementsReady) {
90
- const failedStatus = {
91
- status: 'failed',
92
- type: 'install',
93
- target: 'server',
94
- message: `Requirements not ready for client: ${clientName} after timeout`,
95
- operationId
96
- };
97
- await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, failedStatus);
98
- return;
99
- }
100
- // Create client-specific installer
101
- const installer = ClientInstallerFactory.getInstaller(clientName);
102
- if (!installer) {
103
- throw new Error(`Failed to create installer for client: ${clientName}`);
104
- }
105
- const serverConfig = await this.configProvider.getServerMcpConfig(this.categoryName, this.serverName);
106
- if (!serverConfig) {
107
- throw new Error(`Server configuration not found for category: ${this.categoryName}, server: ${this.serverName}`);
108
- }
109
- // If we've reached here, requirements are ready - update status to in-progress
110
- const inProgressStatus = {
111
- status: 'in-progress',
112
- type: 'install',
113
- target: 'server',
114
- message: `Installing client: ${clientName}`,
115
- operationId: operationId
116
- };
117
- await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, inProgressStatus);
118
- // Install client
119
- const status = await installer.install(serverConfig, options);
120
- await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, status);
121
- if (status.status === 'completed') {
122
- await this.configProvider.reloadClientMCPSettings();
123
- }
124
- }
125
- catch (error) {
126
- const errorStatus = {
92
+ const requirementsReady = await this.checkRequirements(operationId, clientName, options);
93
+ if (!requirementsReady) {
94
+ const failedStatus = {
127
95
  status: 'failed',
128
96
  type: 'install',
129
97
  target: 'server',
130
- message: `Error installing client ${clientName}: ${error instanceof Error ? error.message : String(error)}`,
131
- operationId,
132
- error: error instanceof Error ? error.message : String(error)
98
+ message: `Requirements not ready for client: ${clientName} after timeout`,
99
+ operationId
133
100
  };
134
- await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, errorStatus);
101
+ return failedStatus;
102
+ }
103
+ // Create client-specific installer
104
+ const installer = ClientInstallerFactory.getInstaller(clientName);
105
+ if (!installer) {
106
+ throw new Error(`Failed to create installer for client: ${clientName}`);
135
107
  }
108
+ const serverConfig = await this.configProvider.getServerMcpConfig(this.categoryName, this.serverName);
109
+ if (!serverConfig) {
110
+ throw new Error(`Server configuration not found for category: ${this.categoryName}, server: ${this.serverName}`);
111
+ }
112
+ // If we've reached here, requirements are ready - update status to in-progress
113
+ const inProgressStatus = {
114
+ status: 'in-progress',
115
+ type: 'install',
116
+ target: 'server',
117
+ message: `Installing client: ${clientName}`,
118
+ operationId: operationId
119
+ };
120
+ await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, inProgressStatus);
121
+ // Install client
122
+ return await installer.install(serverConfig, options, this.categoryName);
136
123
  }
137
124
  /**
138
- * Install all specified clients
125
+ * Generate a unique operation ID for tracking installations
126
+ */
127
+ generateOperationId() {
128
+ return `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
129
+ }
130
+ /**
131
+ * Check if server requirements are ready
132
+ * Waits for requirements to be ready with timeout
139
133
  */
140
- async install(options) {
141
- const initialStatuses = [];
142
- // Start installation for each client asynchronously
143
- const installPromises = this.clients.map(async (clientName) => {
144
- const status = await this.installClient(clientName, options);
145
- initialStatuses.push(status);
146
- return status;
147
- });
148
- // Wait for all installations to complete
149
- await Promise.all(installPromises);
150
- // Return result
151
- return {
152
- success: true,
153
- message: 'Client installations completed',
154
- status: initialStatuses
155
- };
134
+ async checkRequirements(operationId, clientName, options) {
135
+ let requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
136
+ if (!requirementsReady) {
137
+ const pendingStatus = {
138
+ status: 'pending',
139
+ type: 'install',
140
+ target: 'server',
141
+ message: `Waiting for requirements to be ready for client: ${clientName}`,
142
+ operationId
143
+ };
144
+ await this.configProvider.updateServerOperationStatus(this.categoryName, this.serverName, clientName, pendingStatus);
145
+ // Set up periodic checking with timeout
146
+ const startTime = Date.now();
147
+ const timeoutMs = 5 * 60 * 1000; // 5 minutes
148
+ const intervalMs = 5 * 1000; // 5 seconds
149
+ while (!requirementsReady && (Date.now() - startTime) < timeoutMs) {
150
+ await new Promise(resolve => setTimeout(resolve, intervalMs));
151
+ requirementsReady = await this.configProvider.isRequirementsReady(this.categoryName, this.serverName);
152
+ }
153
+ }
154
+ var requirementsStatus = await this.configProvider.GetServerRequirementStatus(this.categoryName, this.serverName);
155
+ // Find first non-empty npmPath from requirements status
156
+ const npmPathRequirement = requirementsStatus.find(status => status.npmPath && status.npmPath.length > 0);
157
+ if (npmPathRequirement && npmPathRequirement.npmPath) {
158
+ options.settings = options.settings || {};
159
+ options.settings.npmPath = npmPathRequirement.npmPath;
160
+ }
161
+ return requirementsReady;
156
162
  }
157
163
  }
158
164
  //# sourceMappingURL=ClientInstaller.js.map
@@ -1,5 +1,6 @@
1
1
  import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../../metadatas/types.js';
2
2
  import { RequirementInstaller } from './RequirementInstaller.js';
3
+ import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
3
4
  /**
4
5
  * Abstract base class with common functionality for all requirement installers
5
6
  */
@@ -15,7 +16,14 @@ export declare abstract class BaseInstaller implements RequirementInstaller {
15
16
  }>);
16
17
  abstract canHandle(requirement: RequirementConfig): boolean;
17
18
  abstract supportCheckUpdates(): boolean;
18
- abstract install(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
19
+ /**
20
+ * Install the requirement
21
+ * @param requirement The requirement to install
22
+ * @param options Optional install options
23
+ * @param recorder Optional InstallOperationManager for recording steps
24
+ * @returns The status of the installation
25
+ */
26
+ abstract install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus>;
19
27
  abstract checkInstallation(requirement: RequirementConfig, options?: ServerInstallOptions): Promise<RequirementStatus>;
20
28
  /**
21
29
  * Get the latest version available for the requirement.
@@ -1,5 +1,6 @@
1
1
  import { RequirementConfig, RequirementStatus, ServerInstallOptions } from '../../metadatas/types.js';
2
2
  import { BaseInstaller } from './BaseInstaller.js';
3
+ import { InstallOperationManager } from '../../loaders/InstallOperationManager.js';
3
4
  /**
4
5
  * Installer implementation for command-line tools
5
6
  */
@@ -38,5 +39,12 @@ export declare class CommandInstaller extends BaseInstaller {
38
39
  * @param requirement The requirement to install
39
40
  * @returns The status of the installation
40
41
  */
41
- install(requirement: RequirementConfig): Promise<RequirementStatus>;
42
+ /**
43
+ * Install the command
44
+ * @param requirement The requirement to install
45
+ * @param options Optional install options
46
+ * @param recorder Optional InstallOperationManager for recording steps
47
+ * @returns The status of the installation
48
+ */
49
+ install(requirement: RequirementConfig, recorder: InstallOperationManager, options?: ServerInstallOptions): Promise<RequirementStatus>;
42
50
  }