imcp 0.0.19 → 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 (94) 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/services/MCPManager.js +66 -6
  8. package/dist/services/TelemetryService.d.ts +15 -0
  9. package/dist/services/TelemetryService.js +54 -0
  10. package/dist/utils/githubAuth.js +65 -0
  11. package/dist/utils/logger.d.ts +16 -0
  12. package/dist/utils/logger.js +78 -1
  13. package/dist/utils/versionUtils.d.ts +1 -0
  14. package/dist/utils/versionUtils.js +29 -0
  15. package/dist/web/public/css/serverCategoryList.css +120 -0
  16. package/dist/web/public/index.html +6 -3
  17. package/dist/web/public/js/flights/flights.js +0 -1
  18. package/dist/web/public/js/onboard/formProcessor.js +18 -11
  19. package/dist/web/public/js/onboard/publishHandler.js +30 -0
  20. package/dist/web/public/js/onboard/templates.js +5 -1
  21. package/dist/web/public/js/onboard/uiHandlers.js +266 -39
  22. package/dist/web/public/js/onboard/validationHandlers.js +71 -39
  23. package/dist/web/public/js/serverCategoryList.js +91 -7
  24. package/dist/web/public/onboard.html +2 -2
  25. package/dist/web/server.js +11 -1
  26. package/{src/web/public/js/onboard → docs}/ONBOARDING_PAGE_DESIGN.md +15 -125
  27. package/docs/Telemetry.md +136 -0
  28. package/memory-bank/activeContext.md +14 -0
  29. package/memory-bank/decisionLog.md +28 -0
  30. package/memory-bank/productContext.md +41 -0
  31. package/memory-bank/progress.md +5 -0
  32. package/memory-bank/systemPatterns.md +3 -0
  33. package/package.json +2 -1
  34. package/src/core/metadatas/constants.ts +9 -0
  35. package/src/core/onboard/FeedOnboardService.ts +59 -5
  36. package/src/services/MCPManager.ts +78 -8
  37. package/src/services/TelemetryService.ts +59 -0
  38. package/src/utils/githubAuth.ts +84 -1
  39. package/src/utils/logger.ts +83 -1
  40. package/src/utils/versionUtils.ts +33 -0
  41. package/src/web/public/css/serverCategoryList.css +120 -0
  42. package/src/web/public/index.html +6 -3
  43. package/src/web/public/js/onboard/formProcessor.js +18 -11
  44. package/src/web/public/js/onboard/publishHandler.js +30 -0
  45. package/src/web/public/js/onboard/templates.js +5 -1
  46. package/src/web/public/js/onboard/uiHandlers.js +266 -39
  47. package/src/web/public/js/onboard/validationHandlers.js +71 -39
  48. package/src/web/public/js/serverCategoryList.js +91 -7
  49. package/src/web/public/onboard.html +2 -2
  50. package/src/web/server.ts +11 -1
  51. package/dist/cli/commands/start.d.ts +0 -2
  52. package/dist/cli/commands/start.js +0 -32
  53. package/dist/cli/commands/sync.d.ts +0 -2
  54. package/dist/cli/commands/sync.js +0 -17
  55. package/dist/core/ConfigurationLoader.d.ts +0 -32
  56. package/dist/core/ConfigurationLoader.js +0 -236
  57. package/dist/core/ConfigurationProvider.d.ts +0 -35
  58. package/dist/core/ConfigurationProvider.js +0 -375
  59. package/dist/core/InstallationService.d.ts +0 -50
  60. package/dist/core/InstallationService.js +0 -350
  61. package/dist/core/MCPManager.d.ts +0 -28
  62. package/dist/core/MCPManager.js +0 -188
  63. package/dist/core/RequirementService.d.ts +0 -40
  64. package/dist/core/RequirementService.js +0 -110
  65. package/dist/core/ServerSchemaLoader.d.ts +0 -11
  66. package/dist/core/ServerSchemaLoader.js +0 -43
  67. package/dist/core/ServerSchemaProvider.d.ts +0 -17
  68. package/dist/core/ServerSchemaProvider.js +0 -120
  69. package/dist/core/constants.d.ts +0 -47
  70. package/dist/core/constants.js +0 -94
  71. package/dist/core/installers/BaseInstaller.d.ts +0 -74
  72. package/dist/core/installers/BaseInstaller.js +0 -253
  73. package/dist/core/installers/ClientInstaller.d.ts +0 -23
  74. package/dist/core/installers/ClientInstaller.js +0 -564
  75. package/dist/core/installers/CommandInstaller.d.ts +0 -37
  76. package/dist/core/installers/CommandInstaller.js +0 -173
  77. package/dist/core/installers/GeneralInstaller.d.ts +0 -33
  78. package/dist/core/installers/GeneralInstaller.js +0 -85
  79. package/dist/core/installers/InstallerFactory.d.ts +0 -54
  80. package/dist/core/installers/InstallerFactory.js +0 -97
  81. package/dist/core/installers/NpmInstaller.d.ts +0 -26
  82. package/dist/core/installers/NpmInstaller.js +0 -127
  83. package/dist/core/installers/PipInstaller.d.ts +0 -28
  84. package/dist/core/installers/PipInstaller.js +0 -127
  85. package/dist/core/installers/RequirementInstaller.d.ts +0 -33
  86. package/dist/core/installers/RequirementInstaller.js +0 -3
  87. package/dist/core/types.d.ts +0 -166
  88. package/dist/core/types.js +0 -16
  89. package/dist/services/InstallRequestValidator.d.ts +0 -21
  90. package/dist/services/InstallRequestValidator.js +0 -99
  91. package/dist/web/public/js/modal/installHandler.js +0 -227
  92. package/dist/web/public/js/modal/loadingUI.js +0 -74
  93. package/dist/web/public/js/modal/modalUI.js +0 -214
  94. package/dist/web/public/js/modal/version.js +0 -20
@@ -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
File without changes
@@ -18,6 +18,13 @@ export declare const SETTINGS_DIR: string;
18
18
  * Local feeds directory path
19
19
  */
20
20
  export declare const LOCAL_FEEDS_DIR: string;
21
+ /**
22
+ * Path to the user information file
23
+ */
24
+ export declare const USER_INFO_PATH: string;
25
+ /**
26
+ * Path to the local feeds schema directory
27
+ */
21
28
  export declare const LOCAL_FEEDS_SCHEMA_DIR: string;
22
29
  /**
23
30
  * Supported client configurations.
@@ -27,6 +27,13 @@ export const SETTINGS_DIR = (() => {
27
27
  * Local feeds directory path
28
28
  */
29
29
  export const LOCAL_FEEDS_DIR = path.join(SETTINGS_DIR, 'feeds');
30
+ /**
31
+ * Path to the user information file
32
+ */
33
+ export const USER_INFO_PATH = path.join(SETTINGS_DIR, 'settings', 'user_info.json');
34
+ /**
35
+ * Path to the local feeds schema directory
36
+ */
30
37
  export const LOCAL_FEEDS_SCHEMA_DIR = path.join(LOCAL_FEEDS_DIR, 'schemas');
31
38
  const CODE_STRORAGE_DIR = (() => {
32
39
  switch (process.platform) {
@@ -13,16 +13,20 @@ export declare class FeedOnboardService {
13
13
  */
14
14
  private createOperationId;
15
15
  /**
16
- * Onboard a new feed configuration
16
+ * Onboard a new feed configuration. This method performs validation and initiates the onboarding process.
17
17
  * @param config Feed configuration to onboard
18
+ * @param forExistingCategory Whether this onboarding is for an existing category
19
+ * @returns Promise resolving to operation status with optional feed configuration
18
20
  */
19
21
  onboardFeed(config: FeedConfiguration, forExistingCategory?: boolean): Promise<OperationStatus & {
20
22
  feedConfiguration?: FeedConfiguration;
21
23
  }>;
22
24
  /**
23
- * Validate a feed configuration without performing full onboarding
25
+ * Validate a feed configuration without performing full onboarding.
26
+ * This method performs static validation and initiates the validation process.
24
27
  * @param config Feed configuration to validate
25
- * @returns Operation status indicating the result of the validation initiation
28
+ * @param forExistingCategory Whether this validation is for an existing category
29
+ * @returns Promise resolving to operation status with optional feed configuration
26
30
  */
27
31
  validateFeed(config: FeedConfiguration, forExistingCategory?: boolean): Promise<OperationStatus & {
28
32
  feedConfiguration?: FeedConfiguration;
@@ -1,7 +1,7 @@
1
1
  import { configProvider } from '../loaders/ConfigurationProvider.js';
2
2
  import { ServerSchemaProvider } from '../loaders/ServerSchemaProvider.js';
3
3
  import { feedValidator } from '../validators/FeedValidator.js';
4
- import { Logger } from '../../utils/logger.js';
4
+ import { Logger, EventType, EventStatus } from '../../utils/logger.js';
5
5
  import { OnboardingProcessStatus } from './OnboardStatus.js';
6
6
  import { onboardStatusManager } from './OnboardStatusManager.js';
7
7
  import { onboardProcessor } from './OnboardProcessor.js';
@@ -23,8 +23,10 @@ export class FeedOnboardService {
23
23
  return `${feedName}_${operationType}`;
24
24
  }
25
25
  /**
26
- * Onboard a new feed configuration
26
+ * Onboard a new feed configuration. This method performs validation and initiates the onboarding process.
27
27
  * @param config Feed configuration to onboard
28
+ * @param forExistingCategory Whether this onboarding is for an existing category
29
+ * @returns Promise resolving to operation status with optional feed configuration
28
30
  */
29
31
  async onboardFeed(config, forExistingCategory) {
30
32
  // Perform static validation first
@@ -40,10 +42,19 @@ export class FeedOnboardService {
40
42
  // For now, let's return a FAILED status for the attempted FULL_ONBOARDING initiation.
41
43
  // A more robust solution might involve a different return type or error code.
42
44
  const onboardingId = this.createOperationId(config.name, 'FULL_ONBOARDING'); // Hypothetical ID
45
+ const errorMessage = `No prior successful validation found for feed: ${config.name}. Please validate the configuration before publishing.`;
46
+ // Track failed event
47
+ Logger.trackEvent(EventType.FEED_ONBOARD, {
48
+ status: EventStatus.FAILED,
49
+ feedName: config.name,
50
+ errorMessage,
51
+ onboardingId: onboardingId,
52
+ feedConfiguration: config
53
+ });
43
54
  return {
44
55
  onboardingId: onboardingId,
45
56
  status: OnboardingProcessStatus.FAILED, // Or a new status like 'VALIDATION_REQUIRED'
46
- message: 'The feed configuration has not been validated or has changed. Please validate the configuration before publishing.',
57
+ message: errorMessage,
47
58
  lastQueried: new Date().toISOString(),
48
59
  feedConfiguration: config
49
60
  };
@@ -58,9 +69,11 @@ export class FeedOnboardService {
58
69
  };
59
70
  }
60
71
  /**
61
- * Validate a feed configuration without performing full onboarding
72
+ * Validate a feed configuration without performing full onboarding.
73
+ * This method performs static validation and initiates the validation process.
62
74
  * @param config Feed configuration to validate
63
- * @returns Operation status indicating the result of the validation initiation
75
+ * @param forExistingCategory Whether this validation is for an existing category
76
+ * @returns Promise resolving to operation status with optional feed configuration
64
77
  */
65
78
  async validateFeed(config, forExistingCategory) {
66
79
  // Perform static validation first
@@ -307,10 +320,28 @@ export class FeedOnboardService {
307
320
  validationStatus: result.validationStatus // Ensure validationStatus is also updated on success
308
321
  });
309
322
  Logger.log(`[${onboardingId}] Successfully validated feed: ${config.name}`);
323
+ // Track successful validation
324
+ Logger.trackEvent(EventType.FEED_VALIDATE, {
325
+ status: EventStatus.SUCCESS,
326
+ feedName: config.name,
327
+ operationType: 'VALIDATION_ONLY',
328
+ onboardingId: onboardingId,
329
+ feedConfiguration: config
330
+ });
310
331
  }
311
332
  catch (error) {
333
+ const errorMessage = error instanceof Error ? error.message : String(error);
312
334
  // Error is already logged and status updated by _validateFeedConfiguration or its callers
313
335
  Logger.error(`[${onboardingId}] Feed validation process failed for ${config.name} (already handled):`, error);
336
+ // Track validation failure
337
+ Logger.trackEvent(EventType.FEED_VALIDATE, {
338
+ status: EventStatus.FAILED,
339
+ feedName: config.name,
340
+ operationType: 'VALIDATION_ONLY',
341
+ errorMessage: errorMessage,
342
+ onboardingId: onboardingId,
343
+ feedConfiguration: config
344
+ });
314
345
  }
315
346
  }
316
347
  /**
@@ -359,6 +390,14 @@ export class FeedOnboardService {
359
390
  await configProvider.initialize(feedFilePath, { prLink: prInfo.url, adhocServers: serverList }); // configProvider is already an instance
360
391
  Logger.log(`[${onboardingId}] ConfigurationProvider re-initialized.`);
361
392
  Logger.log(`[${onboardingId}] Successfully completed full onboarding for feed: ${config.name}`);
393
+ // Track successful onboarding
394
+ Logger.trackEvent(EventType.FEED_ONBOARD, {
395
+ status: EventStatus.SUCCESS,
396
+ feedName: config.name,
397
+ onboardingId: onboardingId,
398
+ prUrl: prInfo.url,
399
+ feedConfiguration: config
400
+ });
362
401
  }
363
402
  catch (reinitError) {
364
403
  Logger.warn(`[${onboardingId}] Failed to re-initialize providers after PR creation for feed ${config.name}:`);
@@ -368,6 +407,14 @@ export class FeedOnboardService {
368
407
  catch (error) {
369
408
  Logger.error(`[${onboardingId}] Full feed onboarding process failed:`, error);
370
409
  const errorMessage = error instanceof Error ? error.message : String(error);
410
+ // Track onboarding failure
411
+ Logger.trackEvent(EventType.FEED_ONBOARD, {
412
+ status: EventStatus.FAILED,
413
+ feedName: config.name,
414
+ onboardingId: onboardingId,
415
+ errorMessage,
416
+ feedConfiguration: config
417
+ });
371
418
  // Check if status is already FAILED (e.g., by _validateFeedConfiguration)
372
419
  // to avoid overwriting a more specific error message or step from validation.
373
420
  const currentStatus = await onboardStatusManager.getStatus(config.name, operationType);
@@ -3,7 +3,8 @@ import { ConfigurationProvider } from '../core/loaders/ConfigurationProvider.js'
3
3
  import { ServerSchemaProvider } from '../core/loaders/ServerSchemaProvider.js';
4
4
  import { InstallationService } from './InstallationService.js';
5
5
  import { MCPEvent, } from '../core/metadatas/types.js';
6
- import { Logger } from '../utils/logger.js';
6
+ import { OnboardingProcessStatus } from '../core/onboard/OnboardStatus.js';
7
+ import { Logger, EventType, EventStatus } from '../utils/logger.js';
7
8
  import { FeedOnboardService } from '../core/onboard/FeedOnboardService.js';
8
9
  export class MCPManager extends EventEmitter {
9
10
  installationService;
@@ -53,6 +54,14 @@ export class MCPManager extends EventEmitter {
53
54
  };
54
55
  }
55
56
  const installResult = await this.installationService.install(categoryName, serverName, requestOptions);
57
+ // Log the event with appropriate status
58
+ Logger.trackEvent(EventType.SERVER_INSTALL, {
59
+ status: installResult.success ? EventStatus.SUCCESS : EventStatus.FAILED,
60
+ errorMessage: !installResult.success ? installResult.message : undefined,
61
+ categoryName,
62
+ serverName,
63
+ ...requestOptions
64
+ });
56
65
  if (!installResult.success) {
57
66
  return installResult;
58
67
  }
@@ -60,15 +69,24 @@ export class MCPManager extends EventEmitter {
60
69
  return installResult;
61
70
  }
62
71
  catch (error) {
63
- console.error(`Unexpected error during installServer for ${serverName}:`, error);
72
+ const errorMessage = `Failed to install ${serverName}: ${error instanceof Error ? error.message : String(error)}`;
73
+ Logger.error(errorMessage, error);
74
+ Logger.trackEvent(EventType.SERVER_INSTALL, {
75
+ status: EventStatus.FAILED,
76
+ errorMessage,
77
+ categoryName,
78
+ serverName,
79
+ ...requestOptions
80
+ });
64
81
  return {
65
82
  success: false,
66
- message: `Failed to install ${serverName}: ${error instanceof Error ? error.message : String(error)}`,
83
+ message: errorMessage,
67
84
  error: error instanceof Error ? error : new Error(String(error)),
68
85
  };
69
86
  }
70
87
  }
71
88
  async uninstallServer(categoryName, serverName, options = {}) {
89
+ const { targets = [], removeData = false } = options;
72
90
  try {
73
91
  const serverCategory = await this.configProvider.getServerCategory(categoryName);
74
92
  if (!serverCategory) {
@@ -77,7 +95,6 @@ export class MCPManager extends EventEmitter {
77
95
  message: `Server category ${categoryName} is not onboarded`,
78
96
  };
79
97
  }
80
- const { targets = [], removeData = false } = options;
81
98
  // Clear installation status for specified targets
82
99
  const currentStatus = serverCategory.installationStatus || {
83
100
  requirementsStatus: {},
@@ -101,6 +118,13 @@ export class MCPManager extends EventEmitter {
101
118
  serversStatus[serverName] = serverStatus;
102
119
  // Update status keeping requirements
103
120
  await this.configProvider.updateInstallationStatus(categoryName, currentStatus.requirementsStatus || {}, serversStatus);
121
+ Logger.trackEvent(EventType.SERVER_UNINSTALL, {
122
+ status: EventStatus.SUCCESS,
123
+ categoryName,
124
+ serverName,
125
+ targets,
126
+ removeData
127
+ });
104
128
  this.emit(MCPEvent.SERVER_UNINSTALLED, { serverName, targets });
105
129
  return {
106
130
  success: true,
@@ -108,9 +132,18 @@ export class MCPManager extends EventEmitter {
108
132
  };
109
133
  }
110
134
  catch (error) {
135
+ const errorMessage = `Failed to uninstall ${serverName}: ${error instanceof Error ? error.message : String(error)}`;
136
+ Logger.trackEvent(EventType.SERVER_UNINSTALL, {
137
+ status: EventStatus.FAILED,
138
+ errorMessage,
139
+ categoryName,
140
+ serverName,
141
+ targets: targets || [],
142
+ removeData: removeData || false
143
+ });
111
144
  return {
112
145
  success: false,
113
- message: `Failed to uninstall ${serverName}`,
146
+ message: errorMessage,
114
147
  error: error,
115
148
  };
116
149
  }
@@ -143,16 +176,32 @@ export class MCPManager extends EventEmitter {
143
176
  const updatedStatus = await requirementService.updateRequirement(requirement, updateVersion);
144
177
  // Update the status in configuration
145
178
  await this.configProvider.updateRequirementStatus(categoryName, requirementName, updatedStatus);
179
+ Logger.trackEvent(EventType.REQUIREMENT_UPDATE, {
180
+ status: EventStatus.SUCCESS,
181
+ categoryName,
182
+ serverName,
183
+ requirementName,
184
+ updateVersion
185
+ });
146
186
  return {
147
187
  success: true,
148
188
  message: `Successfully updated ${requirementName} to version ${updateVersion}`,
149
189
  };
150
190
  }
151
191
  catch (error) {
192
+ const errorMessage = `Failed to update ${requirementName}: ${error instanceof Error ? error.message : String(error)}`;
152
193
  console.error(`Error updating requirement ${requirementName}:`, error);
194
+ Logger.trackEvent(EventType.REQUIREMENT_UPDATE, {
195
+ status: EventStatus.FAILED,
196
+ errorMessage,
197
+ categoryName,
198
+ serverName,
199
+ requirementName,
200
+ updateVersion
201
+ });
153
202
  return {
154
203
  success: false,
155
- message: `Failed to update ${requirementName}: ${error instanceof Error ? error.message : String(error)}`,
204
+ message: errorMessage,
156
205
  error: error instanceof Error ? error : new Error(String(error)),
157
206
  };
158
207
  }
@@ -164,6 +213,11 @@ export class MCPManager extends EventEmitter {
164
213
  async onboardFeed(config) {
165
214
  try {
166
215
  const result = await this.feedOnboardService.onboardFeed(config);
216
+ Logger.trackEvent(EventType.FEED_ONBOARD, {
217
+ status: result.status === OnboardingProcessStatus.SUCCEEDED ? EventStatus.SUCCESS : EventStatus.FAILED,
218
+ errorMessage: result.message,
219
+ feedConfig: config
220
+ });
167
221
  // After successful onboarding initiation, sync feeds to get the latest changes
168
222
  // Syncing should ideally happen after the PR is merged, but for now,
169
223
  // syncing here makes the new (pending) category available locally if needed.
@@ -172,7 +226,13 @@ export class MCPManager extends EventEmitter {
172
226
  return result;
173
227
  }
174
228
  catch (error) {
229
+ const errorMessage = error instanceof Error ? error.message : String(error);
175
230
  Logger.error('Failed to onboard feed in MCPManager:', error);
231
+ Logger.trackEvent(EventType.FEED_ONBOARD, {
232
+ status: EventStatus.FAILED,
233
+ errorMessage,
234
+ feedName: config.name
235
+ });
176
236
  throw error; // Rethrow or handle by returning a failed OperationStatus
177
237
  }
178
238
  }
@@ -0,0 +1,15 @@
1
+ export declare class TelemetryService {
2
+ private static client;
3
+ private static readonly instrumentationKey;
4
+ static trackEvent(name: string, properties?: {
5
+ [key: string]: string;
6
+ }): void;
7
+ static trackException(error: Error, properties?: {
8
+ [key: string]: string;
9
+ }): void;
10
+ static trackTrace(message: string, properties?: {
11
+ [key: string]: string;
12
+ }): void;
13
+ static trackMetric(name: string, value: number): void;
14
+ static flush(): Promise<void>;
15
+ }
@@ -0,0 +1,54 @@
1
+ import * as appInsights from 'applicationinsights';
2
+ export class TelemetryService {
3
+ static client = null;
4
+ static instrumentationKey = 'InstrumentationKey=c5fc06c7-a96c-4d80-9aff-bc9c933db0d1';
5
+ static {
6
+ // Initialize Application Insights
7
+ try {
8
+ const client = new appInsights.TelemetryClient(TelemetryService.instrumentationKey);
9
+ client.config.disableAppInsights = false;
10
+ client.config.maxBatchSize = 250;
11
+ client.context.tags[client.context.keys.cloudRole] = 'imcp';
12
+ TelemetryService.client = client;
13
+ console.log('Application Insights initialized');
14
+ }
15
+ catch (error) {
16
+ console.error('Failed to initialize Application Insights:', error);
17
+ }
18
+ }
19
+ static trackEvent(name, properties) {
20
+ if (!this.client) {
21
+ return;
22
+ }
23
+ this.client.trackEvent({ name, properties });
24
+ }
25
+ static trackException(error, properties) {
26
+ if (!this.client) {
27
+ return;
28
+ }
29
+ this.client.trackException({ exception: error, properties });
30
+ }
31
+ static trackTrace(message, properties) {
32
+ if (!this.client) {
33
+ return;
34
+ }
35
+ this.client.trackTrace({ message, properties });
36
+ }
37
+ static trackMetric(name, value) {
38
+ if (!this.client) {
39
+ return;
40
+ }
41
+ this.client.trackMetric({ name, value });
42
+ }
43
+ static flush() {
44
+ return new Promise((resolve) => {
45
+ if (!this.client) {
46
+ resolve();
47
+ return;
48
+ }
49
+ this.client.flush();
50
+ resolve();
51
+ });
52
+ }
53
+ }
54
+ //# sourceMappingURL=TelemetryService.js.map
@@ -2,6 +2,9 @@ import { isToolInstalled, installCLI } from './osUtils.js';
2
2
  import { exec, spawn } from 'child_process';
3
3
  import util from 'util';
4
4
  import { Logger } from './logger.js';
5
+ import fs from 'fs/promises';
6
+ import path from 'path';
7
+ import { USER_INFO_PATH } from '../core/metadatas/constants.js';
5
8
  const execAsync = util.promisify(exec);
6
9
  // Create a promisified version of spawn that returns a Promise
7
10
  const spawnAsync = (command, args, options = {}) => {
@@ -63,6 +66,8 @@ export async function checkGithubAuth() {
63
66
  });
64
67
  throw new GithubAuthError(error);
65
68
  }
69
+ // After Microsoft account verification, persist user information
70
+ await persistUserInfo();
66
71
  Logger.debug('GitHub authentication verified successfully with Microsoft account');
67
72
  }
68
73
  catch (error) {
@@ -86,6 +91,8 @@ export async function checkGithubAuth() {
86
91
  if (!viewer.login.toLowerCase().endsWith('_microsoft')) {
87
92
  throw new GithubAuthError('You must be logged in with a Microsoft account (username should end with _microsoft).');
88
93
  }
94
+ // After Microsoft account verification, persist user information
95
+ await persistUserInfo();
89
96
  Logger.debug(`Successfully authenticated as ${viewer.login}`);
90
97
  return; // Auth successful, continue execution
91
98
  }
@@ -110,4 +117,62 @@ export async function checkGithubAuth() {
110
117
  }
111
118
  }
112
119
  }
120
+ /**
121
+ * Persists GitHub user information to the system-specific settings directory.
122
+ * Only performs persistence on non-Windows systems (Linux/macOS).
123
+ */
124
+ async function persistUserInfo() {
125
+ try {
126
+ Logger.debug('Starting user information persistence check');
127
+ // 1. Skip persistence on Windows systems
128
+ if (process.platform === 'win32') {
129
+ Logger.debug('Skipping user info persistence on Windows system');
130
+ return;
131
+ }
132
+ // 2. Check if file exists and has all required keys
133
+ try {
134
+ if (await fs.access(USER_INFO_PATH).then(() => true).catch(() => false)) {
135
+ const existingContent = await fs.readFile(USER_INFO_PATH, 'utf8');
136
+ const existingData = JSON.parse(existingContent);
137
+ if (existingData.alias && existingData.name && existingData.email) {
138
+ Logger.debug('User info already exists with all required fields, skipping update');
139
+ return;
140
+ }
141
+ }
142
+ }
143
+ catch (err) {
144
+ Logger.debug('No valid existing user info found, proceeding with persistence');
145
+ }
146
+ // Proceed with persistence since both checks passed
147
+ Logger.debug('Proceeding with user information persistence');
148
+ // Get user info from GitHub API
149
+ const { stdout: userDataStr } = await execAsync('gh api user');
150
+ const userData = JSON.parse(userDataStr);
151
+ const { login, name, email } = userData;
152
+ Logger.debug({ message: 'Retrieved user information from GitHub API', login, name, email });
153
+ // Check if login ends with _microsoft
154
+ if (!login.toLowerCase().endsWith('_microsoft')) {
155
+ Logger.log(`GitHub login "${login}" does not end with _microsoft, skipping user information persistence`);
156
+ return;
157
+ }
158
+ // Create directory if it doesn't exist
159
+ await fs.mkdir(path.dirname(USER_INFO_PATH), { recursive: true });
160
+ Logger.debug(`Ensuring directory exists for user info at ${USER_INFO_PATH}`);
161
+ // Extract alias from login (remove _microsoft suffix)
162
+ const alias = login.toLowerCase().replace(/_microsoft$/, '');
163
+ // Prepare user information
164
+ const userInfo = {
165
+ alias,
166
+ name,
167
+ email
168
+ };
169
+ // Write user information to file
170
+ await fs.writeFile(USER_INFO_PATH, JSON.stringify(userInfo, null, 2));
171
+ Logger.debug({ message: 'User information persisted successfully', path: USER_INFO_PATH, alias });
172
+ }
173
+ catch (error) {
174
+ Logger.error('Failed to persist user information:', error);
175
+ // Don't throw - persistence failure shouldn't block auth flow
176
+ }
177
+ }
113
178
  //# sourceMappingURL=githubAuth.js.map
@@ -1,7 +1,21 @@
1
+ export declare enum EventType {
2
+ IMCP_SERVE = "imcp_serve",
3
+ SERVER_INSTALL = "server_install",
4
+ SERVER_UNINSTALL = "server_uninstall",
5
+ REQUIREMENT_UPDATE = "requirement_update",
6
+ FEED_ONBOARD = "feed_onboard",
7
+ FEED_VALIDATE = "feed_validate"
8
+ }
9
+ export declare enum EventStatus {
10
+ SUCCESS = "success",
11
+ FAILED = "failed"
12
+ }
1
13
  export declare class Logger {
2
14
  private static verbose;
3
15
  private static fileLoggingEnabled;
4
16
  private static logsDir;
17
+ private static isTestEnvironment;
18
+ private static packageVersion;
5
19
  static setVerbose(isVerbose: boolean): void;
6
20
  static setFileLogging(enabled: boolean): void;
7
21
  private static ensureLogsDirExists;
@@ -13,4 +27,6 @@ export declare class Logger {
13
27
  static warn(message: string): Promise<void>;
14
28
  static debug(message: string | object): Promise<void>;
15
29
  static error(message: string, error?: unknown): Promise<void>;
30
+ private static getUsername;
31
+ static trackEvent(eventType: EventType, dimensions: Record<string, any>): void;
16
32
  }