imcp 0.0.12 → 0.0.14

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 (81) hide show
  1. package/dist/core/ConfigurationProvider.d.ts +2 -1
  2. package/dist/core/ConfigurationProvider.js +20 -24
  3. package/dist/core/InstallationService.d.ts +17 -0
  4. package/dist/core/InstallationService.js +127 -61
  5. package/dist/core/MCPManager.d.ts +1 -0
  6. package/dist/core/MCPManager.js +3 -0
  7. package/dist/core/RequirementService.d.ts +4 -4
  8. package/dist/core/RequirementService.js +11 -7
  9. package/dist/core/ServerSchemaProvider.d.ts +1 -1
  10. package/dist/core/ServerSchemaProvider.js +15 -10
  11. package/dist/core/constants.d.ts +3 -0
  12. package/dist/core/constants.js +4 -1
  13. package/dist/core/installers/clients/ClientInstaller.js +58 -40
  14. package/dist/core/installers/requirements/PipInstaller.js +10 -5
  15. package/dist/core/onboard/FeedOnboardService.d.ts +35 -0
  16. package/dist/core/onboard/FeedOnboardService.js +137 -0
  17. package/dist/core/types.d.ts +6 -1
  18. package/dist/core/validators/FeedValidator.d.ts +13 -0
  19. package/dist/core/validators/FeedValidator.js +27 -0
  20. package/dist/services/ServerService.d.ts +5 -0
  21. package/dist/services/ServerService.js +15 -0
  22. package/dist/utils/githubAuth.js +0 -10
  23. package/dist/utils/githubUtils.d.ts +16 -0
  24. package/dist/utils/githubUtils.js +55 -39
  25. package/dist/web/contract/serverContract.d.ts +64 -0
  26. package/dist/web/contract/serverContract.js +2 -0
  27. package/dist/web/public/css/detailsWidget.css +157 -32
  28. package/dist/web/public/css/onboard.css +44 -0
  29. package/dist/web/public/css/serverDetails.css +35 -19
  30. package/dist/web/public/index.html +16 -10
  31. package/dist/web/public/js/detailsWidget.js +43 -40
  32. package/dist/web/public/js/modal/index.js +58 -0
  33. package/dist/web/public/js/modal/installHandler.js +227 -0
  34. package/dist/web/public/js/modal/installModal.js +163 -0
  35. package/dist/web/public/js/modal/installation.js +281 -0
  36. package/dist/web/public/js/modal/loadingModal.js +52 -0
  37. package/dist/web/public/js/modal/loadingUI.js +74 -0
  38. package/dist/web/public/js/modal/messageQueue.js +112 -0
  39. package/dist/web/public/js/modal/modalSetup.js +512 -0
  40. package/dist/web/public/js/modal/modalUI.js +214 -0
  41. package/dist/web/public/js/modal/modalUtils.js +49 -0
  42. package/dist/web/public/js/modal/version.js +20 -0
  43. package/dist/web/public/js/modal/versionUtils.js +20 -0
  44. package/dist/web/public/js/modal.js +25 -1041
  45. package/dist/web/public/js/onboard/formProcessor.js +309 -0
  46. package/dist/web/public/js/onboard/index.js +131 -0
  47. package/dist/web/public/js/onboard/state.js +32 -0
  48. package/dist/web/public/js/onboard/templates.js +375 -0
  49. package/dist/web/public/js/onboard/uiHandlers.js +196 -0
  50. package/dist/web/public/js/serverCategoryDetails.js +211 -123
  51. package/dist/web/public/onboard.html +150 -0
  52. package/dist/web/server.js +25 -0
  53. package/package.json +3 -4
  54. package/src/core/ConfigurationProvider.ts +37 -29
  55. package/src/core/InstallationService.ts +176 -62
  56. package/src/core/MCPManager.ts +4 -0
  57. package/src/core/RequirementService.ts +12 -8
  58. package/src/core/ServerSchemaLoader.ts +48 -0
  59. package/src/core/ServerSchemaProvider.ts +137 -0
  60. package/src/core/constants.ts +4 -1
  61. package/src/core/installers/clients/ClientInstaller.ts +66 -49
  62. package/src/core/installers/requirements/PipInstaller.ts +10 -5
  63. package/src/core/types.ts +6 -1
  64. package/src/services/ServerService.ts +15 -0
  65. package/src/utils/githubAuth.ts +14 -27
  66. package/src/utils/githubUtils.ts +84 -47
  67. package/src/web/public/css/detailsWidget.css +235 -0
  68. package/src/web/public/css/serverDetails.css +126 -0
  69. package/src/web/public/index.html +16 -10
  70. package/src/web/public/js/detailsWidget.js +264 -0
  71. package/src/web/public/js/modal/index.js +58 -0
  72. package/src/web/public/js/modal/installModal.js +163 -0
  73. package/src/web/public/js/modal/installation.js +281 -0
  74. package/src/web/public/js/modal/loadingModal.js +52 -0
  75. package/src/web/public/js/modal/messageQueue.js +112 -0
  76. package/src/web/public/js/modal/modalSetup.js +512 -0
  77. package/src/web/public/js/modal/modalUtils.js +49 -0
  78. package/src/web/public/js/modal/versionUtils.js +20 -0
  79. package/src/web/public/js/modal.js +25 -1041
  80. package/src/web/public/js/serverCategoryDetails.js +211 -123
  81. package/src/web/server.ts +31 -0
@@ -0,0 +1,309 @@
1
+ // Form data processing and API calls
2
+ export async function submitForm(event) {
3
+ event.preventDefault();
4
+ const formData = new FormData(event.target);
5
+ const jsonData = formDataToJson(formData);
6
+
7
+ try {
8
+ const response = await fetch('/api/categories/onboard', {
9
+ method: 'POST',
10
+ headers: {
11
+ 'Content-Type': 'application/json'
12
+ },
13
+ body: JSON.stringify({
14
+ categoryData: {
15
+ name: jsonData.name || '',
16
+ displayName: jsonData.displayName || '',
17
+ description: jsonData.description,
18
+ repository: jsonData.repository,
19
+ requirements: jsonData.requirements,
20
+ mcpServers: jsonData.servers?.map(server => ({
21
+ name: server.name,
22
+ description: server.description,
23
+ mode: server.mode,
24
+ schemas: server.schemas,
25
+ dependencies: server.dependencies,
26
+ installation: {
27
+ command: server.installation?.command,
28
+ args: server.installation?.args,
29
+ env: server.installation?.env?.reduce((acc, env) => {
30
+ acc[env.name] = {
31
+ name: env.name,
32
+ default: env.default,
33
+ required: env.required || false,
34
+ description: env.description
35
+ };
36
+ return acc;
37
+ }, {})
38
+ }
39
+ }))
40
+ },
41
+ isUpdate: new URLSearchParams(window.location.search).has('category')
42
+ })
43
+ });
44
+
45
+ if (!response.ok) {
46
+ throw new Error(`HTTP error! status: ${response.status}`);
47
+ }
48
+
49
+ const result = await response.json();
50
+ console.log('Form submitted successfully:', result);
51
+ alert('Form submitted successfully!');
52
+ } catch (error) {
53
+ console.error('Error submitting form:', error);
54
+ alert('Error submitting form. Please try again.');
55
+ }
56
+ }
57
+
58
+ export function formDataToJson(formData) {
59
+ // Basic category information
60
+ const categoryData = {
61
+ name: formData.get('name'),
62
+ displayName: formData.get('displayName'),
63
+ description: formData.get('description'),
64
+ repository: formData.get('repository')
65
+ };
66
+
67
+ const servers = [];
68
+
69
+ // Process servers
70
+ for (let [key, value] of formData.entries()) {
71
+ if (key.startsWith('servers[')) {
72
+ const matches = key.match(/servers\[(\d+)\]\.(.+)/);
73
+ if (matches) {
74
+ const [, index, field] = matches;
75
+
76
+ if (!servers[index]) {
77
+ servers[index] = {
78
+ requirements: [],
79
+ installation: {
80
+ env: []
81
+ }
82
+ };
83
+ }
84
+
85
+ // Handle nested fields
86
+ if (field.includes('.')) {
87
+ const fieldParts = field.split('.');
88
+ let current = servers[index];
89
+
90
+ for (let i = 0; i < fieldParts.length - 1; i++) {
91
+ if (/\[\d+\]/.test(fieldParts[i])) {
92
+ const arrayMatches = fieldParts[i].match(/(.+)\[(\d+)\]/);
93
+ if (arrayMatches) {
94
+ const [, arrayName, arrayIndex] = arrayMatches;
95
+ if (!current[arrayName]) {
96
+ current[arrayName] = [];
97
+ }
98
+ if (!current[arrayName][arrayIndex]) {
99
+ current[arrayName][arrayIndex] = {};
100
+ }
101
+ current = current[arrayName][arrayIndex];
102
+ }
103
+ } else {
104
+ if (!current[fieldParts[i]]) {
105
+ current[fieldParts[i]] = {};
106
+ }
107
+ current = current[fieldParts[i]];
108
+ }
109
+ }
110
+
111
+ const lastField = fieldParts[fieldParts.length - 1];
112
+ if (lastField === 'required') {
113
+ current[lastField] = formData.get(key) === 'on';
114
+ } else {
115
+ current[lastField] = value;
116
+ }
117
+ } else {
118
+ servers[index][field] = value;
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ // Process and clean up requirements
125
+
126
+ // Clean up servers data
127
+ const cleanServers = servers.filter(Boolean).map(server => {
128
+ const serverRequirements = (server.requirements || []).filter(Boolean).map(req => ({
129
+ name: req.name,
130
+ version: req.version,
131
+ order: req.order || undefined
132
+ }));
133
+
134
+ const cleanServer = {
135
+ name: server.name,
136
+ mode: server.mode,
137
+ description: server.description,
138
+ schemas: server.schemas || undefined,
139
+ dependencies: {
140
+ requirements: serverRequirements
141
+ },
142
+ requirements: (server.requirements || []).filter(Boolean).map(req => ({
143
+ name: req.name,
144
+ type: req.type,
145
+ version: req.version,
146
+ order: req.order || undefined,
147
+ alias: req.type === 'command' ? req.alias : undefined,
148
+ ...(req.registryType && req.registryType !== 'public' && {
149
+ registry: {
150
+ ...(req.registryType === 'github' && {
151
+ githubRelease: {
152
+ repository: req.registry?.githubRelease?.repository,
153
+ assetsName: req.registry?.githubRelease?.assetsName,
154
+ assetName: req.registry?.githubRelease?.assetName
155
+ }
156
+ }),
157
+ ...(req.registryType === 'artifacts' && {
158
+ artifacts: {
159
+ registryUrl: req.registry?.artifacts?.registryUrl,
160
+ assetName: req.registry?.artifacts?.assetName
161
+ }
162
+ }),
163
+ ...(req.registryType === 'local' && {
164
+ local: {
165
+ localPath: req.registry?.local?.localPath,
166
+ assetName: req.registry?.local?.assetName
167
+ }
168
+ })
169
+ }
170
+ })
171
+ }))
172
+ };
173
+
174
+ if (server.installation) {
175
+ cleanServer.installation = {
176
+ command: server.installation.command,
177
+ args: server.installation.args || undefined,
178
+ env: (server.installation.env || [])
179
+ .filter(Boolean)
180
+ .map(env => ({
181
+ name: env.name,
182
+ default: env.default || undefined,
183
+ required: env.required || false,
184
+ description: env.description || undefined
185
+ }))
186
+ };
187
+ }
188
+
189
+ return cleanServer;
190
+ });
191
+
192
+ // Collect all requirements from servers
193
+ const allRequirements = new Map();
194
+
195
+ cleanServers.forEach(server => {
196
+ server.requirements?.forEach(req => {
197
+ const key = `${req.type}:${req.name}`;
198
+ if (!allRequirements.has(key)) {
199
+ allRequirements.set(key, req);
200
+ }
201
+ });
202
+ });
203
+
204
+ return {
205
+ name: categoryData.name,
206
+ displayName: categoryData.displayName,
207
+ description: categoryData.description,
208
+ repository: categoryData.repository,
209
+ requirements: Array.from(allRequirements.values()),
210
+ servers: cleanServers
211
+ };
212
+ }
213
+
214
+ export function populateForm(data) {
215
+ const { requirements = [], servers = [] } = data;
216
+
217
+ // Populate requirements
218
+ requirements.forEach((requirement, index) => {
219
+ window.addRequirement();
220
+
221
+ // Set basic fields
222
+ document.querySelector(`[name="requirements[${index}].name"]`).value = requirement.name;
223
+ document.querySelector(`[name="requirements[${index}].type"]`).value = requirement.type;
224
+ document.querySelector(`[name="requirements[${index}].version"]`).value = requirement.version;
225
+
226
+ if (requirement.order) {
227
+ document.querySelector(`[name="requirements[${index}].order"]`).value = requirement.order;
228
+ }
229
+
230
+ if (requirement.type === 'command' && requirement.alias) {
231
+ document.querySelector(`[name="requirements[${index}].alias"]`).value = requirement.alias;
232
+ document.getElementById(`alias-field-${index}`).classList.remove('hidden');
233
+ }
234
+
235
+ // Handle registry configuration
236
+ if (requirement.registry) {
237
+ let registryType;
238
+ if (requirement.registry.githubRelease) registryType = 'github';
239
+ else if (requirement.registry.artifacts) registryType = 'artifacts';
240
+ else if (requirement.registry.local) registryType = 'local';
241
+
242
+ if (registryType) {
243
+ const registrySelect = document.querySelector(`[name="requirements[${index}].registryType"]`);
244
+ registrySelect.value = registryType;
245
+ window.toggleRegistryConfig(index);
246
+
247
+ // Populate registry-specific fields
248
+ if (registryType === 'github') {
249
+ const { repository, assetsName, assetName } = requirement.registry.githubRelease;
250
+ if (repository) document.querySelector(`[name="requirements[${index}].registry.githubRelease.repository"]`).value = repository;
251
+ if (assetsName) document.querySelector(`[name="requirements[${index}].registry.githubRelease.assetsName"]`).value = assetsName;
252
+ if (assetName) document.querySelector(`[name="requirements[${index}].registry.githubRelease.assetName"]`).value = assetName;
253
+ } else if (registryType === 'artifacts') {
254
+ const { registryUrl, assetName } = requirement.registry.artifacts;
255
+ if (registryUrl) document.querySelector(`[name="requirements[${index}].registry.artifacts.registryUrl"]`).value = registryUrl;
256
+ if (assetName) document.querySelector(`[name="requirements[${index}].registry.artifacts.assetName"]`).value = assetName;
257
+ } else if (registryType === 'local') {
258
+ const { localPath, assetName } = requirement.registry.local;
259
+ if (localPath) document.querySelector(`[name="requirements[${index}].registry.local.localPath"]`).value = localPath;
260
+ if (assetName) document.querySelector(`[name="requirements[${index}].registry.local.assetName"]`).value = assetName;
261
+ }
262
+ }
263
+ }
264
+ });
265
+
266
+ // Populate servers
267
+ servers.forEach((server, serverIndex) => {
268
+ window.addServer();
269
+
270
+ // Set basic fields
271
+ document.querySelector(`[name="servers[${serverIndex}].name"]`).value = server.name;
272
+ document.querySelector(`[name="servers[${serverIndex}].mode"]`).value = server.mode;
273
+ document.querySelector(`[name="servers[${serverIndex}].description"]`).value = server.description;
274
+
275
+ if (server.schemas) {
276
+ document.getElementById(`schema-path-${serverIndex}`).value = server.schemas;
277
+ }
278
+
279
+ // Set installation configuration
280
+ if (server.installation) {
281
+ document.querySelector(`[name="servers[${serverIndex}].installation.command"]`).value = server.installation.command;
282
+ if (server.installation.args) {
283
+ document.querySelector(`[name="servers[${serverIndex}].installation.args"]`).value = server.installation.args;
284
+ }
285
+
286
+ // Add environment variables
287
+ server.installation.env?.forEach((env, envIndex) => {
288
+ window.addEnvVariable(serverIndex);
289
+ document.querySelector(`[name="servers[${serverIndex}].installation.env[${envIndex}].name"]`).value = env.name;
290
+ if (env.default) document.querySelector(`[name="servers[${serverIndex}].installation.env[${envIndex}].default"]`).value = env.default;
291
+ if (env.required) document.querySelector(`[name="servers[${serverIndex}].installation.env[${envIndex}].required"]`).checked = true;
292
+ if (env.description) document.querySelector(`[name="servers[${serverIndex}].installation.env[${envIndex}].description"]`).value = env.description;
293
+ });
294
+ }
295
+
296
+ // Add requirements from dependencies
297
+ server.dependencies?.requirements?.forEach((req, reqIndex) => {
298
+ window.addServerRequirement(serverIndex);
299
+
300
+ // Set basic fields
301
+ document.querySelector(`[name="servers[${serverIndex}].requirements[${reqIndex}].name"]`).value = req.name;
302
+ document.querySelector(`[name="servers[${serverIndex}].requirements[${reqIndex}].version"]`).value = req.version;
303
+
304
+ if (req.order) {
305
+ document.querySelector(`[name="servers[${serverIndex}].requirements[${reqIndex}].order"]`).value = req.order;
306
+ }
307
+ });
308
+ });
309
+ }
@@ -0,0 +1,131 @@
1
+ import {
2
+ addRequirement,
3
+ removeRequirement,
4
+ addServer,
5
+ removeServer,
6
+ addEnvVariable,
7
+ removeEnvVariable,
8
+ addServerRequirement,
9
+ removeServerRequirement,
10
+ toggleAliasField,
11
+ toggleServerAliasField,
12
+ toggleRegistryConfig,
13
+ toggleServerRegistryConfig,
14
+ browseLocalSchema
15
+ } from './uiHandlers.js';
16
+
17
+ import {
18
+ submitForm,
19
+ formDataToJson,
20
+ populateForm
21
+ } from './formProcessor.js';
22
+
23
+ // Load existing category data if editing
24
+ async function loadExistingCategory() {
25
+ const urlParams = new URLSearchParams(window.location.search);
26
+ const categoryName = urlParams.get('category');
27
+
28
+ if (categoryName) {
29
+ try {
30
+ const response = await fetch(`/api/categories/${categoryName}`);
31
+ if (!response.ok) {
32
+ throw new Error(`HTTP error! status: ${response.status}`);
33
+ }
34
+
35
+ const result = await response.json();
36
+ if (result.success && result.data) {
37
+ const { feedConfiguration } = result.data;
38
+ populateForm({
39
+ name: feedConfiguration.name,
40
+ displayName: feedConfiguration.displayName,
41
+ description: feedConfiguration.description,
42
+ repository: feedConfiguration.repository,
43
+ requirements: feedConfiguration.requirements || [],
44
+ servers: feedConfiguration.mcpServers || []
45
+ });
46
+ }
47
+ } catch (error) {
48
+ console.error('Error loading category:', error);
49
+ alert('Error loading category data. Please try again.');
50
+ }
51
+ }
52
+ }
53
+
54
+ // Initialize event listeners
55
+ document.addEventListener('DOMContentLoaded', async () => {
56
+ // Load existing category data if in edit mode
57
+ await loadExistingCategory();
58
+
59
+ // Add form submit handlers
60
+ const categoryForm = document.getElementById('onboardForm');
61
+ if (categoryForm) {
62
+ categoryForm.addEventListener('submit', submitForm);
63
+ }
64
+
65
+ const serverForm = document.getElementById('onboardServerForm');
66
+ if (serverForm) {
67
+ serverForm.addEventListener('submit', submitForm);
68
+ }
69
+
70
+ // Setup tab switching functionality
71
+ const tabCreateCategory = document.getElementById('tab-create-category');
72
+ const tabCreateServer = document.getElementById('tab-create-server');
73
+ const panelCreateCategory = document.getElementById('panel-create-category');
74
+ const panelCreateServer = document.getElementById('panel-create-server');
75
+
76
+ if (tabCreateCategory && tabCreateServer) {
77
+ tabCreateCategory.addEventListener('click', () => {
78
+ // Update tab styles
79
+ tabCreateCategory.classList.add('text-blue-600', 'border-blue-600');
80
+ tabCreateCategory.classList.remove('text-gray-600', 'border-transparent');
81
+ tabCreateServer.classList.remove('text-blue-600', 'border-blue-600');
82
+ tabCreateServer.classList.add('text-gray-600', 'border-transparent');
83
+
84
+ // Show/hide panels
85
+ panelCreateCategory.classList.remove('hidden');
86
+ panelCreateServer.classList.add('hidden');
87
+ });
88
+
89
+ tabCreateServer.addEventListener('click', () => {
90
+ // Update tab styles
91
+ tabCreateServer.classList.add('text-blue-600', 'border-blue-600');
92
+ tabCreateServer.classList.remove('text-gray-600', 'border-transparent');
93
+ tabCreateCategory.classList.remove('text-blue-600', 'border-blue-600');
94
+ tabCreateCategory.classList.add('text-gray-600', 'border-transparent');
95
+
96
+ // Show/hide panels
97
+ panelCreateServer.classList.remove('hidden');
98
+ panelCreateCategory.classList.add('hidden');
99
+ });
100
+ }
101
+
102
+ // Initialize button handlers
103
+ const addRequirementBtn = document.getElementById('addRequirementBtn');
104
+ if (addRequirementBtn) {
105
+ addRequirementBtn.addEventListener('click', addRequirement);
106
+ }
107
+
108
+ const addServerBtn = document.getElementById('addServerBtn');
109
+ if (addServerBtn) {
110
+ addServerBtn.addEventListener('click', addServer);
111
+ }
112
+
113
+ // Expose necessary functions to window for HTML event handlers
114
+ Object.assign(window, {
115
+ addRequirement,
116
+ removeRequirement,
117
+ addServer,
118
+ removeServer,
119
+ addEnvVariable,
120
+ removeEnvVariable,
121
+ addServerRequirement,
122
+ removeServerRequirement,
123
+ toggleAliasField,
124
+ toggleServerAliasField,
125
+ toggleRegistryConfig,
126
+ toggleServerRegistryConfig,
127
+ browseLocalSchema,
128
+ formDataToJson,
129
+ populateForm
130
+ });
131
+ });
@@ -0,0 +1,32 @@
1
+ // Global state management
2
+ export const state = {
3
+ requirementCounter: 0,
4
+ serverCounter: 0,
5
+ envCounters: new Map(),
6
+ serverRequirementCounters: new Map()
7
+ };
8
+
9
+ export const incrementRequirementCounter = () => state.requirementCounter++;
10
+ export const incrementServerCounter = () => state.serverCounter++;
11
+
12
+ export const setEnvCounter = (serverIndex, value) => {
13
+ state.envCounters.set(serverIndex, value);
14
+ };
15
+
16
+ export const getEnvCounter = (serverIndex) => state.envCounters.get(serverIndex) || 0;
17
+
18
+ export const deleteEnvCounter = (serverIndex) => {
19
+ state.envCounters.delete(serverIndex);
20
+ };
21
+
22
+ export const setServerRequirementCounter = (serverIndex, value) => {
23
+ state.serverRequirementCounters.set(serverIndex, value);
24
+ };
25
+
26
+ export const getServerRequirementCounter = (serverIndex) => {
27
+ return state.serverRequirementCounters.get(serverIndex) || 0;
28
+ };
29
+
30
+ export const deleteServerRequirementCounter = (serverIndex) => {
31
+ state.serverRequirementCounters.delete(serverIndex);
32
+ };