imcp 0.0.18 → 0.1.1

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 (96) hide show
  1. package/.roo/rules-code/rules.md +88 -0
  2. package/dist/cli/index.js +0 -0
  3. package/dist/core/metadatas/constants.d.ts +7 -0
  4. package/dist/core/metadatas/constants.js +7 -0
  5. package/dist/core/onboard/FeedOnboardService.d.ts +7 -3
  6. package/dist/core/onboard/FeedOnboardService.js +52 -5
  7. package/dist/core/onboard/OnboardProcessor.js +22 -22
  8. package/dist/services/MCPManager.js +66 -6
  9. package/dist/services/TelemetryService.d.ts +15 -0
  10. package/dist/services/TelemetryService.js +54 -0
  11. package/dist/utils/githubAuth.js +65 -0
  12. package/dist/utils/logger.d.ts +16 -0
  13. package/dist/utils/logger.js +78 -1
  14. package/dist/utils/versionUtils.d.ts +1 -0
  15. package/dist/utils/versionUtils.js +29 -0
  16. package/dist/web/public/css/serverCategoryList.css +120 -0
  17. package/dist/web/public/index.html +6 -3
  18. package/dist/web/public/js/flights/flights.js +0 -1
  19. package/dist/web/public/js/onboard/formProcessor.js +18 -11
  20. package/dist/web/public/js/onboard/publishHandler.js +30 -0
  21. package/dist/web/public/js/onboard/templates.js +5 -1
  22. package/dist/web/public/js/onboard/uiHandlers.js +266 -39
  23. package/dist/web/public/js/onboard/validationHandlers.js +71 -39
  24. package/dist/web/public/js/serverCategoryList.js +91 -7
  25. package/dist/web/public/onboard.html +2 -2
  26. package/dist/web/server.js +11 -1
  27. package/{src/web/public/js/onboard → docs}/ONBOARDING_PAGE_DESIGN.md +15 -125
  28. package/docs/Telemetry.md +136 -0
  29. package/memory-bank/activeContext.md +14 -0
  30. package/memory-bank/decisionLog.md +28 -0
  31. package/memory-bank/productContext.md +41 -0
  32. package/memory-bank/progress.md +5 -0
  33. package/memory-bank/systemPatterns.md +3 -0
  34. package/package.json +2 -1
  35. package/src/core/metadatas/constants.ts +9 -0
  36. package/src/core/onboard/FeedOnboardService.ts +59 -5
  37. package/src/core/onboard/OnboardProcessor.ts +25 -23
  38. package/src/services/MCPManager.ts +78 -8
  39. package/src/services/TelemetryService.ts +59 -0
  40. package/src/utils/githubAuth.ts +84 -1
  41. package/src/utils/logger.ts +83 -1
  42. package/src/utils/versionUtils.ts +33 -0
  43. package/src/web/public/css/serverCategoryList.css +120 -0
  44. package/src/web/public/index.html +6 -3
  45. package/src/web/public/js/onboard/formProcessor.js +18 -11
  46. package/src/web/public/js/onboard/publishHandler.js +30 -0
  47. package/src/web/public/js/onboard/templates.js +5 -1
  48. package/src/web/public/js/onboard/uiHandlers.js +266 -39
  49. package/src/web/public/js/onboard/validationHandlers.js +71 -39
  50. package/src/web/public/js/serverCategoryList.js +91 -7
  51. package/src/web/public/onboard.html +2 -2
  52. package/src/web/server.ts +11 -1
  53. package/dist/cli/commands/start.d.ts +0 -2
  54. package/dist/cli/commands/start.js +0 -32
  55. package/dist/cli/commands/sync.d.ts +0 -2
  56. package/dist/cli/commands/sync.js +0 -17
  57. package/dist/core/ConfigurationLoader.d.ts +0 -32
  58. package/dist/core/ConfigurationLoader.js +0 -236
  59. package/dist/core/ConfigurationProvider.d.ts +0 -35
  60. package/dist/core/ConfigurationProvider.js +0 -375
  61. package/dist/core/InstallationService.d.ts +0 -50
  62. package/dist/core/InstallationService.js +0 -350
  63. package/dist/core/MCPManager.d.ts +0 -28
  64. package/dist/core/MCPManager.js +0 -188
  65. package/dist/core/RequirementService.d.ts +0 -40
  66. package/dist/core/RequirementService.js +0 -110
  67. package/dist/core/ServerSchemaLoader.d.ts +0 -11
  68. package/dist/core/ServerSchemaLoader.js +0 -43
  69. package/dist/core/ServerSchemaProvider.d.ts +0 -17
  70. package/dist/core/ServerSchemaProvider.js +0 -120
  71. package/dist/core/constants.d.ts +0 -47
  72. package/dist/core/constants.js +0 -94
  73. package/dist/core/installers/BaseInstaller.d.ts +0 -74
  74. package/dist/core/installers/BaseInstaller.js +0 -253
  75. package/dist/core/installers/ClientInstaller.d.ts +0 -23
  76. package/dist/core/installers/ClientInstaller.js +0 -564
  77. package/dist/core/installers/CommandInstaller.d.ts +0 -37
  78. package/dist/core/installers/CommandInstaller.js +0 -173
  79. package/dist/core/installers/GeneralInstaller.d.ts +0 -33
  80. package/dist/core/installers/GeneralInstaller.js +0 -85
  81. package/dist/core/installers/InstallerFactory.d.ts +0 -54
  82. package/dist/core/installers/InstallerFactory.js +0 -97
  83. package/dist/core/installers/NpmInstaller.d.ts +0 -26
  84. package/dist/core/installers/NpmInstaller.js +0 -127
  85. package/dist/core/installers/PipInstaller.d.ts +0 -28
  86. package/dist/core/installers/PipInstaller.js +0 -127
  87. package/dist/core/installers/RequirementInstaller.d.ts +0 -33
  88. package/dist/core/installers/RequirementInstaller.js +0 -3
  89. package/dist/core/types.d.ts +0 -166
  90. package/dist/core/types.js +0 -16
  91. package/dist/services/InstallRequestValidator.d.ts +0 -21
  92. package/dist/services/InstallRequestValidator.js +0 -99
  93. package/dist/web/public/js/modal/installHandler.js +0 -227
  94. package/dist/web/public/js/modal/loadingUI.js +0 -74
  95. package/dist/web/public/js/modal/modalUI.js +0 -214
  96. package/dist/web/public/js/modal/version.js +0 -20
@@ -1,10 +1,29 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { SETTINGS_DIR } from '../core/metadatas/constants.js';
3
+ import os from 'os';
4
+ import { SETTINGS_DIR, USER_INFO_PATH } from '../core/metadatas/constants.js';
5
+ import { TelemetryService } from '../services/TelemetryService.js';
6
+ import { getPackageVersion } from './versionUtils.js';
7
+ export var EventType;
8
+ (function (EventType) {
9
+ EventType["IMCP_SERVE"] = "imcp_serve";
10
+ EventType["SERVER_INSTALL"] = "server_install";
11
+ EventType["SERVER_UNINSTALL"] = "server_uninstall";
12
+ EventType["REQUIREMENT_UPDATE"] = "requirement_update";
13
+ EventType["FEED_ONBOARD"] = "feed_onboard";
14
+ EventType["FEED_VALIDATE"] = "feed_validate";
15
+ })(EventType || (EventType = {}));
16
+ export var EventStatus;
17
+ (function (EventStatus) {
18
+ EventStatus["SUCCESS"] = "success";
19
+ EventStatus["FAILED"] = "failed";
20
+ })(EventStatus || (EventStatus = {}));
4
21
  export class Logger {
5
22
  static verbose = false;
6
23
  static fileLoggingEnabled = true;
7
24
  static logsDir = path.join(SETTINGS_DIR, 'logs');
25
+ static isTestEnvironment = false;
26
+ static packageVersion = getPackageVersion();
8
27
  static setVerbose(isVerbose) {
9
28
  this.verbose = isVerbose;
10
29
  }
@@ -96,5 +115,63 @@ export class Logger {
96
115
  }
97
116
  await this.writeToLogFile('ERROR', logMessage);
98
117
  }
118
+ static getUsername() {
119
+ try {
120
+ // If on Windows, use os username directly
121
+ if (process.platform === 'win32') {
122
+ return os.userInfo().username;
123
+ }
124
+ // For Mac/Linux users
125
+ try {
126
+ const userInfoPath = USER_INFO_PATH;
127
+ if (fs.existsSync(userInfoPath)) {
128
+ const userInfo = JSON.parse(fs.readFileSync(userInfoPath, 'utf8'));
129
+ if (userInfo.alias) {
130
+ return userInfo.alias;
131
+ }
132
+ }
133
+ }
134
+ catch (error) {
135
+ this.error('Failed to get user info from file', error);
136
+ }
137
+ // Fall back to os username if all else fails
138
+ return os.userInfo().username;
139
+ }
140
+ catch (error) {
141
+ this.error('Failed to get username', error);
142
+ return 'unknown';
143
+ }
144
+ }
145
+ static trackEvent(eventType, dimensions) {
146
+ try {
147
+ const username = this.getUsername();
148
+ // Add username and package version to dimensions
149
+ const allDimensions = {
150
+ username,
151
+ packageVersion: this.packageVersion,
152
+ ...dimensions
153
+ };
154
+ // Log to file
155
+ if (this.verbose) {
156
+ this.log(`Event: ${eventType}`);
157
+ this.log(JSON.stringify(allDimensions, null, 2));
158
+ }
159
+ // Skip AppInsights in test environment
160
+ if (Logger.isTestEnvironment) {
161
+ return;
162
+ }
163
+ // Log to Application Insights
164
+ try {
165
+ TelemetryService.trackEvent(eventType, allDimensions);
166
+ TelemetryService.flush();
167
+ }
168
+ catch (insightsError) {
169
+ this.error('Failed to track event in Application Insights', insightsError);
170
+ }
171
+ }
172
+ catch (error) {
173
+ this.error('Failed to log event', error);
174
+ }
175
+ }
99
176
  }
100
177
  //# sourceMappingURL=logger.js.map
@@ -1,3 +1,4 @@
1
+ export declare function getPackageVersion(): string;
1
2
  /**
2
3
  * Utility functions for version comparison and management
3
4
  */
@@ -1,3 +1,32 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ export function getPackageVersion() {
5
+ try {
6
+ // First try npm environment variable (available during npm scripts)
7
+ if (process.env.npm_package_version) {
8
+ return process.env.npm_package_version;
9
+ }
10
+ // Fall back to reading package.json
11
+ // Get directory name of current module
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+ // Traverse up to find package.json (max 3 levels up)
14
+ let currentDir = __dirname;
15
+ for (let i = 0; i < 3; i++) {
16
+ const packagePath = path.join(currentDir, 'package.json');
17
+ if (fs.existsSync(packagePath)) {
18
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
19
+ return packageJson.version;
20
+ }
21
+ currentDir = path.join(currentDir, '..');
22
+ }
23
+ return 'unknown';
24
+ }
25
+ catch (error) {
26
+ console.error('Failed to get package version:', error);
27
+ return 'unknown';
28
+ }
29
+ }
1
30
  /**
2
31
  * Utility functions for version comparison and management
3
32
  */
@@ -0,0 +1,120 @@
1
+ /* Server Category List Styles */
2
+ .category-toggle {
3
+ cursor: pointer;
4
+ display: flex;
5
+ align-items: center;
6
+ color: #4b5563; /* gray-600 */
7
+ transition: all 0.2s;
8
+ }
9
+
10
+ .category-toggle:hover {
11
+ color: #1e40af; /* blue-800 */
12
+ }
13
+
14
+ .category-toggle i {
15
+ font-size: 1.25rem;
16
+ transition: transform 0.2s;
17
+ }
18
+
19
+ .category-toggle.collapsed i {
20
+ transform: rotate(-90deg);
21
+ }
22
+
23
+ .server-list-container {
24
+ transition: height 0.3s ease, opacity 0.3s ease, margin 0.3s ease;
25
+ overflow: hidden;
26
+ }
27
+
28
+ .server-list-container.collapsed {
29
+ height: 0 !important;
30
+ opacity: 0;
31
+ margin-top: 0;
32
+ margin-bottom: 0;
33
+ }
34
+
35
+ .category-section {
36
+ margin-bottom: 1rem;
37
+ border-bottom: 1px solid #e5e7eb; /* gray-200 */
38
+ padding-bottom: 0.5rem;
39
+ }
40
+
41
+ .category-section:last-child {
42
+ border-bottom: none;
43
+ margin-bottom: 0;
44
+ }
45
+
46
+ .category-header {
47
+ display: flex;
48
+ justify-content: space-between;
49
+ align-items: center;
50
+ margin-bottom: 0.5rem;
51
+ }
52
+
53
+ /* Pin button styles */
54
+ .pin-button {
55
+ cursor: pointer;
56
+ display: flex;
57
+ align-items: center;
58
+ color: #9ca3af; /* gray-400 */
59
+ margin-right: 8px;
60
+ transition: all 0.2s ease;
61
+ }
62
+
63
+ .pin-button:hover {
64
+ color: #4b5563; /* gray-600 */
65
+ }
66
+
67
+ .pin-button.pinned {
68
+ color: #2563eb; /* blue-600 */
69
+ }
70
+
71
+ .pin-button.pinned:hover {
72
+ color: #1d4ed8; /* blue-700 */
73
+ }
74
+
75
+ /* Pinned server section */
76
+ .server-item.pinned {
77
+ border-left: 3px solid #2563eb; /* blue-600 */
78
+ background-color: #f0f7ff; /* very light blue */
79
+ position: relative;
80
+ transition: all 0.2s ease-in-out;
81
+ }
82
+
83
+ /* Pin animation */
84
+ .server-item {
85
+ transition: transform 0.3s ease, border-left 0.2s ease, background-color 0.2s ease;
86
+ }
87
+
88
+ /* Visual indicator for pinned items at the top */
89
+ .server-item.pinned::before {
90
+ content: "";
91
+ position: absolute;
92
+ top: -3px;
93
+ left: 0;
94
+ right: 0;
95
+ height: 3px;
96
+ background-color: #2563eb; /* blue-600 */
97
+ opacity: 0;
98
+ transition: opacity 0.2s ease;
99
+ }
100
+
101
+ /* Show top indicator for the first pinned item */
102
+ .server-item.pinned:first-child::before {
103
+ opacity: 1;
104
+ }
105
+
106
+ /* Add hover effect to pinned items */
107
+ .server-item.pinned:hover {
108
+ background-color: #e6f0ff; /* slightly darker on hover */
109
+ }
110
+
111
+ /* Pin animation effect */
112
+ @keyframes pin-animation {
113
+ 0% { transform: scale(1); }
114
+ 50% { transform: scale(1.03); }
115
+ 100% { transform: scale(1); }
116
+ }
117
+
118
+ .pin-animation {
119
+ animation: pin-animation 0.3s ease;
120
+ }
@@ -9,11 +9,12 @@
9
9
  <link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet">
10
10
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
11
11
  <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
12
- <link rel="stylesheet" href="styles.css">
12
+ <link rel="stylesheet" href="styles.css">
13
13
  <link rel="stylesheet" href="css/modal.css">
14
14
  <link rel="stylesheet" href="css/notifications.css">
15
15
  <link rel="stylesheet" href="css/serverDetails.css">
16
16
  <link rel="stylesheet" href="css/detailsWidget.css">
17
+ <link rel="stylesheet" href="css/serverCategoryList.css">
17
18
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
18
19
 
19
20
  <!-- Alert container for notifications -->
@@ -25,8 +26,10 @@
25
26
  <div class="container mx-auto px-4 py-6">
26
27
  <div class="flex items-center justify-between mb-8">
27
28
  <h1 class="text-3xl font-bold text-gray-900 flex items-center">
28
- <i class='bx bx-server mr-3 text-blue-600'></i>
29
- IMCP Server Manager
29
+ <a href="index.html" class="flex items-center text-gray-900 hover:text-blue-600 transition-colors">
30
+ <i class='bx bx-server mr-3 text-blue-600'></i>
31
+ IMCP Server Manager
32
+ </a>
30
33
  </h1>
31
34
  <div class="lg:w-2/3 flex justify-end items-center gap-4">
32
35
  <div class="relative w-48 focus-within:w-96 transition-all duration-300 ease-in-out">
@@ -4,7 +4,6 @@ const FLIGHT_STORAGE_KEY = 'activeFlightSettings';
4
4
 
5
5
  // Default flight settings
6
6
  const defaultFlights = {
7
- enableOnboard: false, // Default: Onboarding is enabled. Set to false to disable.
8
7
  // Add other default flights here, e.g., newFeatureX: false,
9
8
  };
10
9
 
@@ -10,17 +10,7 @@ function setupRealTimeValidation(formId) {
10
10
  const form = document.getElementById(formId);
11
11
  if (!form) return;
12
12
 
13
- // Helper function to show validation message
14
- const showValidationMessage = (element, message, isError = true) => {
15
- let messageDiv = element.nextElementSibling;
16
- if (!messageDiv || !messageDiv.classList.contains('validation-message')) {
17
- messageDiv = document.createElement('div');
18
- messageDiv.className = `validation-message text-xs mt-1 ${isError ? 'text-red-500' : 'text-green-500'}`;
19
- element.insertAdjacentElement('afterend', messageDiv);
20
- }
21
- messageDiv.textContent = message;
22
- messageDiv.className = `validation-message text-xs mt-1 ${isError ? 'text-red-500' : 'text-green-500'}`;
23
- };
13
+ if (!form) return;
24
14
 
25
15
  // Name input validation (category or server)
26
16
  const nameInput = form.querySelector('input[name="name"]');
@@ -1026,5 +1016,22 @@ export function resetOnboardFormDynamicContent(formId = 'onboardForm', serversLi
1026
1016
  setupRealTimeValidation(formId);
1027
1017
  }
1028
1018
 
1019
+ /**
1020
+ * Shows validation message under an input field
1021
+ * @param {HTMLElement} element - The element to show validation message for
1022
+ * @param {string} message - The validation message to display
1023
+ * @param {boolean} isError - Whether this is an error message
1024
+ */
1025
+ export function showValidationMessage(element, message, isError = true) {
1026
+ let messageDiv = element.nextElementSibling;
1027
+ if (!messageDiv || !messageDiv.classList.contains('validation-message')) {
1028
+ messageDiv = document.createElement('div');
1029
+ messageDiv.className = `validation-message text-xs mt-1 ${isError ? 'text-red-500' : 'text-green-500'}`;
1030
+ element.insertAdjacentElement('afterend', messageDiv);
1031
+ }
1032
+ messageDiv.textContent = message;
1033
+ messageDiv.className = `validation-message text-xs mt-1 ${isError ? 'text-red-500' : 'text-green-500'}`;
1034
+ }
1035
+
1029
1036
  // Export setupRealTimeValidation for external use if needed
1030
1037
  export { setupRealTimeValidation };
@@ -2,6 +2,7 @@
2
2
  import { showToast } from '../notifications.js';
3
3
  import { getFormData } from './formProcessor.js';
4
4
  import {
5
+ validateFormFields,
5
6
  pollOperationStatus,
6
7
  updateOperationDisplay,
7
8
  getElementIdsByTab,
@@ -37,6 +38,35 @@ export async function handlePublish(event, activeTab, currentSelectedCategoryDat
37
38
  return;
38
39
  }
39
40
 
41
+ // Validate form fields
42
+ const validationResult = validateFormFields(onboardForm, activeTab);
43
+ if (!validationResult.isValid) {
44
+ showToast('Please fix all validation errors before proceeding.', 'error');
45
+ return;
46
+ }
47
+
48
+ if (activeTab === 'create-category') {
49
+ const formData = getFormData(onboardForm, false);
50
+ if (!formData.mcpServers || formData.mcpServers.length === 0) {
51
+ showToast('At least one MCP server must be configured for a new category.', 'error');
52
+ return;
53
+ }
54
+
55
+ // Check category name format
56
+ const nameInput = onboardForm.querySelector('input[name="name"]');
57
+ if (nameInput && nameInput.value.trim()) {
58
+ if (!/^[a-zA-Z0-9-_]+$/.test(nameInput.value.trim())) {
59
+ showValidationMessage(nameInput, 'Only alphanumeric characters, hyphens, and underscores allowed', true);
60
+ hasErrors = true;
61
+ }
62
+ }
63
+ }
64
+
65
+ if (hasErrors) {
66
+ showToast('Please fix all validation errors before proceeding.', 'error');
67
+ return;
68
+ }
69
+
40
70
  publishButton.disabled = true;
41
71
  publishButton.innerHTML = "<i class='bx bx-loader-alt bx-spin mr-2'></i>Publishing...";
42
72
  validateButton.disabled = true; // Also disable validate button during publish
@@ -17,7 +17,7 @@ export const serverTemplate = (serverIndex, isReadOnly = false, serverData = nul
17
17
 
18
18
  const disabledAttr = makeServerFullyEditable ? '' : 'disabled';
19
19
  const readOnlyClasses = makeServerFullyEditable ? '' : 'bg-gray-100 cursor-not-allowed opacity-70';
20
-
20
+
21
21
  // "Remove Server" button should be hidden if the server is NOT fully editable.
22
22
  // A server is fully editable if the context isn't read-only OR if it's an adhoc server.
23
23
  const hideRemoveServerButtonClass = !makeServerFullyEditable ? 'hidden' : '';
@@ -42,6 +42,10 @@ export const serverTemplate = (serverIndex, isReadOnly = false, serverData = nul
42
42
  class="action-button-in-server p-1.5 text-sm text-red-600 hover:text-red-800 hover:bg-red-50 rounded-md flex items-center mr-2 ${hideRemoveServerButtonClass}" title="Remove Server">
43
43
  <i class='bx bx-trash text-lg'></i>
44
44
  </button>
45
+ <button type="button" onclick="event.stopPropagation(); window.duplicateServer(${serverIndex}, '${serversListId}')"
46
+ class="action-button-in-server duplicate-mcp-server-button p-1.5 text-sm text-blue-600 hover:text-blue-800 hover:bg-blue-50 rounded-md flex items-center mr-2" title="Duplicate Server">
47
+ <i class='bx bx-copy text-lg'></i>
48
+ </button>
45
49
  <i class='bx bxs-chevron-down text-xl toggle-icon'></i>
46
50
  </div>
47
51
  </div>