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.
- package/.roo/rules-code/rules.md +88 -0
- package/dist/cli/index.js +0 -0
- package/dist/core/metadatas/constants.d.ts +7 -0
- package/dist/core/metadatas/constants.js +7 -0
- package/dist/core/onboard/FeedOnboardService.d.ts +7 -3
- package/dist/core/onboard/FeedOnboardService.js +52 -5
- package/dist/core/onboard/OnboardProcessor.js +22 -22
- package/dist/services/MCPManager.js +66 -6
- package/dist/services/TelemetryService.d.ts +15 -0
- package/dist/services/TelemetryService.js +54 -0
- package/dist/utils/githubAuth.js +65 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +78 -1
- package/dist/utils/versionUtils.d.ts +1 -0
- package/dist/utils/versionUtils.js +29 -0
- package/dist/web/public/css/serverCategoryList.css +120 -0
- package/dist/web/public/index.html +6 -3
- package/dist/web/public/js/flights/flights.js +0 -1
- package/dist/web/public/js/onboard/formProcessor.js +18 -11
- package/dist/web/public/js/onboard/publishHandler.js +30 -0
- package/dist/web/public/js/onboard/templates.js +5 -1
- package/dist/web/public/js/onboard/uiHandlers.js +266 -39
- package/dist/web/public/js/onboard/validationHandlers.js +71 -39
- package/dist/web/public/js/serverCategoryList.js +91 -7
- package/dist/web/public/onboard.html +2 -2
- package/dist/web/server.js +11 -1
- package/{src/web/public/js/onboard → docs}/ONBOARDING_PAGE_DESIGN.md +15 -125
- package/docs/Telemetry.md +136 -0
- package/memory-bank/activeContext.md +14 -0
- package/memory-bank/decisionLog.md +28 -0
- package/memory-bank/productContext.md +41 -0
- package/memory-bank/progress.md +5 -0
- package/memory-bank/systemPatterns.md +3 -0
- package/package.json +2 -1
- package/src/core/metadatas/constants.ts +9 -0
- package/src/core/onboard/FeedOnboardService.ts +59 -5
- package/src/core/onboard/OnboardProcessor.ts +25 -23
- package/src/services/MCPManager.ts +78 -8
- package/src/services/TelemetryService.ts +59 -0
- package/src/utils/githubAuth.ts +84 -1
- package/src/utils/logger.ts +83 -1
- package/src/utils/versionUtils.ts +33 -0
- package/src/web/public/css/serverCategoryList.css +120 -0
- package/src/web/public/index.html +6 -3
- package/src/web/public/js/onboard/formProcessor.js +18 -11
- package/src/web/public/js/onboard/publishHandler.js +30 -0
- package/src/web/public/js/onboard/templates.js +5 -1
- package/src/web/public/js/onboard/uiHandlers.js +266 -39
- package/src/web/public/js/onboard/validationHandlers.js +71 -39
- package/src/web/public/js/serverCategoryList.js +91 -7
- package/src/web/public/onboard.html +2 -2
- package/src/web/server.ts +11 -1
- package/dist/cli/commands/start.d.ts +0 -2
- package/dist/cli/commands/start.js +0 -32
- package/dist/cli/commands/sync.d.ts +0 -2
- package/dist/cli/commands/sync.js +0 -17
- package/dist/core/ConfigurationLoader.d.ts +0 -32
- package/dist/core/ConfigurationLoader.js +0 -236
- package/dist/core/ConfigurationProvider.d.ts +0 -35
- package/dist/core/ConfigurationProvider.js +0 -375
- package/dist/core/InstallationService.d.ts +0 -50
- package/dist/core/InstallationService.js +0 -350
- package/dist/core/MCPManager.d.ts +0 -28
- package/dist/core/MCPManager.js +0 -188
- package/dist/core/RequirementService.d.ts +0 -40
- package/dist/core/RequirementService.js +0 -110
- package/dist/core/ServerSchemaLoader.d.ts +0 -11
- package/dist/core/ServerSchemaLoader.js +0 -43
- package/dist/core/ServerSchemaProvider.d.ts +0 -17
- package/dist/core/ServerSchemaProvider.js +0 -120
- package/dist/core/constants.d.ts +0 -47
- package/dist/core/constants.js +0 -94
- package/dist/core/installers/BaseInstaller.d.ts +0 -74
- package/dist/core/installers/BaseInstaller.js +0 -253
- package/dist/core/installers/ClientInstaller.d.ts +0 -23
- package/dist/core/installers/ClientInstaller.js +0 -564
- package/dist/core/installers/CommandInstaller.d.ts +0 -37
- package/dist/core/installers/CommandInstaller.js +0 -173
- package/dist/core/installers/GeneralInstaller.d.ts +0 -33
- package/dist/core/installers/GeneralInstaller.js +0 -85
- package/dist/core/installers/InstallerFactory.d.ts +0 -54
- package/dist/core/installers/InstallerFactory.js +0 -97
- package/dist/core/installers/NpmInstaller.d.ts +0 -26
- package/dist/core/installers/NpmInstaller.js +0 -127
- package/dist/core/installers/PipInstaller.d.ts +0 -28
- package/dist/core/installers/PipInstaller.js +0 -127
- package/dist/core/installers/RequirementInstaller.d.ts +0 -33
- package/dist/core/installers/RequirementInstaller.js +0 -3
- package/dist/core/types.d.ts +0 -166
- package/dist/core/types.js +0 -16
- package/dist/services/InstallRequestValidator.d.ts +0 -21
- package/dist/services/InstallRequestValidator.js +0 -99
- package/dist/web/public/js/modal/installHandler.js +0 -227
- package/dist/web/public/js/modal/loadingUI.js +0 -74
- package/dist/web/public/js/modal/modalUI.js +0 -214
- package/dist/web/public/js/modal/version.js +0 -20
|
@@ -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
|
-
* @
|
|
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:
|
|
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
|
-
* @
|
|
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);
|
|
@@ -117,29 +117,29 @@ export class OnboardProcessor {
|
|
|
117
117
|
// Create a mutable copy of mcpServers to update schema paths
|
|
118
118
|
const updatedMcpServers = [];
|
|
119
119
|
for (const server of config.mcpServers) {
|
|
120
|
-
if (!serverList.includes(server.name))
|
|
121
|
-
continue;
|
|
122
120
|
let updatedServer = { ...server }; // Shallow copy server config
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
121
|
+
if (serverList.includes(server.name)) {
|
|
122
|
+
if (updatedServer.schemas && typeof updatedServer.schemas === 'string' && updatedServer.schemas.trim() !== '') {
|
|
123
|
+
const originalSchemaPath = updatedServer.schemas;
|
|
124
|
+
const serverName = updatedServer.name;
|
|
125
|
+
const newSchemaFileName = `${serverName}.json`;
|
|
126
|
+
// Schemas are now directly under categorySchemasPath
|
|
127
|
+
const newSchemaPathInRepo = path.join(categorySchemasPath, newSchemaFileName);
|
|
128
|
+
try {
|
|
129
|
+
// Read content from the original schema path
|
|
130
|
+
const schemaContent = await fs.readFile(originalSchemaPath, 'utf-8');
|
|
131
|
+
// Write content to the new schema file in the repo
|
|
132
|
+
await fs.writeFile(newSchemaPathInRepo, schemaContent);
|
|
133
|
+
Logger.debug(`[${onboardingId}] Copied schema for server '${serverName}' from '${originalSchemaPath}' to '${newSchemaPathInRepo}'`);
|
|
134
|
+
// Update the schemas property to the new filename, as per instruction "rename schemas in McpServer as serverName].json"
|
|
135
|
+
updatedServer.schemas = newSchemaFileName;
|
|
136
|
+
}
|
|
137
|
+
catch (schemaError) {
|
|
138
|
+
const errorMsg = `Error processing schema for server '${serverName}' (source: ${originalSchemaPath}): ${schemaError instanceof Error ? schemaError.message : String(schemaError)}`;
|
|
139
|
+
Logger.error(`[${onboardingId}] ${errorMsg}`);
|
|
140
|
+
// Propagate the error to fail the onboarding step
|
|
141
|
+
throw new Error(errorMsg);
|
|
142
|
+
}
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
updatedMcpServers.push(updatedServer);
|
|
@@ -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 {
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
package/dist/utils/githubAuth.js
CHANGED
|
@@ -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
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -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
|
}
|