@codesherlock/codesherlock-beta-mcp-server 0.0.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 (87) hide show
  1. package/.env +9 -0
  2. package/README.md +185 -0
  3. package/build/handlers/analyzeCommitHandler.d.ts +36 -0
  4. package/build/handlers/analyzeCommitHandler.d.ts.map +1 -0
  5. package/build/handlers/analyzeCommitHandler.js +397 -0
  6. package/build/handlers/analyzeCommitHandler.js.map +1 -0
  7. package/build/handlers/events.d.ts +7 -0
  8. package/build/handlers/events.d.ts.map +1 -0
  9. package/build/handlers/events.js +15 -0
  10. package/build/handlers/events.js.map +1 -0
  11. package/build/handlers/resources.d.ts +10 -0
  12. package/build/handlers/resources.d.ts.map +1 -0
  13. package/build/handlers/resources.js +14 -0
  14. package/build/handlers/resources.js.map +1 -0
  15. package/build/handlers/tools.d.ts +6 -0
  16. package/build/handlers/tools.d.ts.map +1 -0
  17. package/build/handlers/tools.js +29 -0
  18. package/build/handlers/tools.js.map +1 -0
  19. package/build/index.d.ts +3 -0
  20. package/build/index.d.ts.map +1 -0
  21. package/build/index.js +82 -0
  22. package/build/index.js.map +1 -0
  23. package/build/schemas/toolSchemas.d.ts +50 -0
  24. package/build/schemas/toolSchemas.d.ts.map +1 -0
  25. package/build/schemas/toolSchemas.js +48 -0
  26. package/build/schemas/toolSchemas.js.map +1 -0
  27. package/build/services/backendApiService.d.ts +81 -0
  28. package/build/services/backendApiService.d.ts.map +1 -0
  29. package/build/services/backendApiService.js +265 -0
  30. package/build/services/backendApiService.js.map +1 -0
  31. package/build/services/commitReviewService.d.ts +71 -0
  32. package/build/services/commitReviewService.d.ts.map +1 -0
  33. package/build/services/commitReviewService.js +506 -0
  34. package/build/services/commitReviewService.js.map +1 -0
  35. package/build/services/gitService.d.ts +159 -0
  36. package/build/services/gitService.d.ts.map +1 -0
  37. package/build/services/gitService.js +778 -0
  38. package/build/services/gitService.js.map +1 -0
  39. package/build/services/loggingService.d.ts +64 -0
  40. package/build/services/loggingService.d.ts.map +1 -0
  41. package/build/services/loggingService.js +185 -0
  42. package/build/services/loggingService.js.map +1 -0
  43. package/build/services/zipService.d.ts +9 -0
  44. package/build/services/zipService.d.ts.map +1 -0
  45. package/build/services/zipService.js +47 -0
  46. package/build/services/zipService.js.map +1 -0
  47. package/build/tests/analysisFormatter.test.d.ts +2 -0
  48. package/build/tests/analysisFormatter.test.d.ts.map +1 -0
  49. package/build/tests/analysisFormatter.test.js +92 -0
  50. package/build/tests/analysisFormatter.test.js.map +1 -0
  51. package/build/tests/analyzeCommitHandler.test.d.ts +2 -0
  52. package/build/tests/analyzeCommitHandler.test.d.ts.map +1 -0
  53. package/build/tests/analyzeCommitHandler.test.js +111 -0
  54. package/build/tests/analyzeCommitHandler.test.js.map +1 -0
  55. package/build/tests/backendApiService.test.d.ts +2 -0
  56. package/build/tests/backendApiService.test.d.ts.map +1 -0
  57. package/build/tests/backendApiService.test.js +109 -0
  58. package/build/tests/backendApiService.test.js.map +1 -0
  59. package/build/tests/commitReviewService.test.d.ts +2 -0
  60. package/build/tests/commitReviewService.test.d.ts.map +1 -0
  61. package/build/tests/commitReviewService.test.js +120 -0
  62. package/build/tests/commitReviewService.test.js.map +1 -0
  63. package/build/tests/errorExtractor.test.d.ts +2 -0
  64. package/build/tests/errorExtractor.test.d.ts.map +1 -0
  65. package/build/tests/errorExtractor.test.js +61 -0
  66. package/build/tests/errorExtractor.test.js.map +1 -0
  67. package/build/tests/loggingService.test.d.ts +2 -0
  68. package/build/tests/loggingService.test.d.ts.map +1 -0
  69. package/build/tests/loggingService.test.js +153 -0
  70. package/build/tests/loggingService.test.js.map +1 -0
  71. package/build/tests/setup.test.d.ts +2 -0
  72. package/build/tests/setup.test.d.ts.map +1 -0
  73. package/build/tests/setup.test.js +7 -0
  74. package/build/tests/setup.test.js.map +1 -0
  75. package/build/tests/tools.test.d.ts +2 -0
  76. package/build/tests/tools.test.d.ts.map +1 -0
  77. package/build/tests/tools.test.js +58 -0
  78. package/build/tests/tools.test.js.map +1 -0
  79. package/build/utils/analysisFormatter.d.ts +40 -0
  80. package/build/utils/analysisFormatter.d.ts.map +1 -0
  81. package/build/utils/analysisFormatter.js +97 -0
  82. package/build/utils/analysisFormatter.js.map +1 -0
  83. package/build/utils/errorExtractor.d.ts +36 -0
  84. package/build/utils/errorExtractor.d.ts.map +1 -0
  85. package/build/utils/errorExtractor.js +178 -0
  86. package/build/utils/errorExtractor.js.map +1 -0
  87. package/package.json +55 -0
@@ -0,0 +1,109 @@
1
+ import { BackendApiService } from '../services/backendApiService.js';
2
+ import { logger } from '../services/loggingService.js';
3
+ import WebSocket from 'ws';
4
+ import JSZip from 'jszip';
5
+ // Mock dependencies
6
+ jest.mock('../services/loggingService');
7
+ jest.mock('ws');
8
+ jest.mock('jszip');
9
+ // Mock global fetch
10
+ global.fetch = jest.fn();
11
+ describe('BackendApiService', () => {
12
+ let backendApiService;
13
+ const baseUrl = 'http://api.example.com';
14
+ const apiKey = 'test-api-key';
15
+ beforeEach(() => {
16
+ jest.clearAllMocks();
17
+ backendApiService = new BackendApiService(baseUrl, apiKey);
18
+ // Mock JSZip implementation
19
+ JSZip.mockImplementation(() => ({
20
+ file: jest.fn(),
21
+ generateAsync: jest.fn().mockResolvedValue(Buffer.from('zip-content')),
22
+ }));
23
+ });
24
+ describe('submitCommitReview', () => {
25
+ const mockParams = {
26
+ factor: 'power_analysis',
27
+ user_id: 'user123',
28
+ repo_name: 'test-repo',
29
+ commit_id: 'commit123',
30
+ username: 'tester',
31
+ files_json: JSON.stringify([{ file: 'test.ts' }]),
32
+ organization_name: 'org1',
33
+ };
34
+ it('should submit review successfully', async () => {
35
+ const mockResponseData = { analysis_id: 'analysis123' };
36
+ global.fetch.mockResolvedValue({
37
+ ok: true,
38
+ json: jest.fn().mockResolvedValue(mockResponseData),
39
+ });
40
+ const result = await backendApiService.submitCommitReview(mockParams);
41
+ expect(result.success).toBe(true);
42
+ expect(result.analysisId).toBe('analysis123');
43
+ expect(global.fetch).toHaveBeenCalledWith(`${baseUrl}/v2/commit-review/power_analysis`, expect.objectContaining({
44
+ method: 'POST',
45
+ headers: expect.objectContaining({
46
+ 'X-CS-MCP-API-Key': apiKey,
47
+ }),
48
+ body: expect.any(FormData),
49
+ }));
50
+ });
51
+ it('should handle HTTP errors', async () => {
52
+ global.fetch.mockResolvedValue({
53
+ ok: false,
54
+ status: 500,
55
+ text: jest.fn().mockResolvedValue('Internal Server Error'),
56
+ });
57
+ await expect(backendApiService.submitCommitReview(mockParams)).rejects.toThrow('HTTP error! status: 500, detail: Internal Server Error');
58
+ expect(logger.logError).toHaveBeenCalled();
59
+ });
60
+ it('should handle network errors', async () => {
61
+ const networkError = new Error('Network error');
62
+ global.fetch.mockRejectedValue(networkError);
63
+ await expect(backendApiService.submitCommitReview(mockParams)).rejects.toThrow(networkError);
64
+ expect(logger.logError).toHaveBeenCalled();
65
+ });
66
+ });
67
+ describe('connectWebSocket', () => {
68
+ let mockWs;
69
+ beforeEach(() => {
70
+ mockWs = {
71
+ on: jest.fn(),
72
+ close: jest.fn(),
73
+ };
74
+ WebSocket.mockImplementation(() => mockWs);
75
+ });
76
+ it('should connect to WebSocket successfully', async () => {
77
+ const userId = 'user123';
78
+ const connectPromise = backendApiService.connectWebSocket(userId, jest.fn());
79
+ // Simulate 'open' event
80
+ const openCallback = mockWs.on.mock.calls.find((call) => call[0] === 'open')[1];
81
+ openCallback();
82
+ const ws = await connectPromise;
83
+ expect(ws).toBe(mockWs);
84
+ expect(WebSocket).toHaveBeenCalledWith(expect.stringContaining(`ws://api.example.com/v2/ws/${userId}`));
85
+ });
86
+ it('should handle WebSocket messages', async () => {
87
+ const onMessage = jest.fn();
88
+ const connectPromise = backendApiService.connectWebSocket('user123', onMessage);
89
+ // Open connection
90
+ const openCallback = mockWs.on.mock.calls.find((call) => call[0] === 'open')[1];
91
+ openCallback();
92
+ await connectPromise;
93
+ // Simulate message
94
+ const messageCallback = mockWs.on.mock.calls.find((call) => call[0] === 'message')[1];
95
+ const mockData = JSON.stringify({ status_code: 200, content: { status: 'complete' } });
96
+ messageCallback(Buffer.from(mockData));
97
+ expect(onMessage).toHaveBeenCalledWith(expect.objectContaining({ status_code: 200 }));
98
+ });
99
+ it('should handle WebSocket errors during connection', async () => {
100
+ const connectPromise = backendApiService.connectWebSocket('user123', jest.fn());
101
+ // Simulate error
102
+ const errorCallback = mockWs.on.mock.calls.find((call) => call[0] === 'error')[1];
103
+ const error = new Error('Connection failed');
104
+ errorCallback(error);
105
+ await expect(connectPromise).rejects.toThrow('Connection failed');
106
+ });
107
+ });
108
+ });
109
+ //# sourceMappingURL=backendApiService.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backendApiService.test.js","sourceRoot":"","sources":["../../src/tests/backendApiService.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=commitReviewService.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitReviewService.test.d.ts","sourceRoot":"","sources":["../../src/tests/commitReviewService.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { CommitReviewService } from '../services/commitReviewService.js';
2
+ import { BackendApiService } from '../services/backendApiService.js';
3
+ import { EventEmitter } from 'events';
4
+ jest.setTimeout(10000);
5
+ // Mock dependencies
6
+ jest.mock('../services/backendApiService');
7
+ jest.mock('../services/loggingService');
8
+ describe('CommitReviewService', () => {
9
+ let commitReviewService;
10
+ let mockBackendApiService;
11
+ const createMockWebSocket = () => {
12
+ const ws = new EventEmitter();
13
+ ws.readyState = 1; // OPEN
14
+ ws.close = jest.fn(() => ws.emit('close', 1000, Buffer.from('')));
15
+ return ws;
16
+ };
17
+ beforeEach(() => {
18
+ jest.clearAllMocks();
19
+ mockBackendApiService = new BackendApiService('url');
20
+ commitReviewService = new CommitReviewService(mockBackendApiService);
21
+ });
22
+ describe('submitAndWaitForResults', () => {
23
+ const mockParams = {
24
+ factor: 'power_analysis',
25
+ user_id: 'user123',
26
+ repo_name: 'test-repo',
27
+ commit_id: 'commit123',
28
+ username: 'tester',
29
+ file_changes: [],
30
+ organization_name: 'org1',
31
+ };
32
+ it('should submit review and collect results successfully', async () => {
33
+ mockBackendApiService.submitCommitReview.mockResolvedValue({
34
+ success: true,
35
+ analysisId: 'analysis123',
36
+ message: 'Submitted',
37
+ });
38
+ const ws = createMockWebSocket();
39
+ mockBackendApiService.connectWebSocket.mockResolvedValue(ws);
40
+ const resultPromise = commitReviewService.submitAndWaitForResults(mockParams);
41
+ // Simulate messages after handlers are attached
42
+ setTimeout(() => {
43
+ ws.emit('message', Buffer.from(JSON.stringify({
44
+ status_code: 200,
45
+ content: {
46
+ analysis_type: 'commit_review',
47
+ analysis: { issue: 'bug' },
48
+ language: 'ts',
49
+ file_name: 'test.ts',
50
+ is_complete: false,
51
+ },
52
+ analysis_id: 123,
53
+ })));
54
+ ws.emit('message', Buffer.from(JSON.stringify({
55
+ status_code: 200,
56
+ content: {
57
+ analysis_type: 'commit_review',
58
+ status: 'complete',
59
+ is_complete: true,
60
+ },
61
+ })));
62
+ }, 0);
63
+ const result = await resultPromise;
64
+ expect(result.success).toBe(true);
65
+ expect(result.analysisId).toBe('analysis123');
66
+ expect(result.results).toHaveLength(1);
67
+ expect(result.results?.[0]).toEqual({
68
+ analysis: { issue: 'bug' },
69
+ language: 'ts',
70
+ file_name: 'test.ts',
71
+ analysisId: 123,
72
+ });
73
+ expect(mockBackendApiService.submitCommitReview).toHaveBeenCalled();
74
+ expect(mockBackendApiService.connectWebSocket).toHaveBeenCalled();
75
+ });
76
+ it('should handle WebSocket errors', async () => {
77
+ mockBackendApiService.submitCommitReview.mockResolvedValue({
78
+ success: true,
79
+ analysisId: 'analysis123',
80
+ });
81
+ const ws = createMockWebSocket();
82
+ mockBackendApiService.connectWebSocket.mockResolvedValue(ws);
83
+ const resultPromise = commitReviewService.submitAndWaitForResults(mockParams);
84
+ setTimeout(() => {
85
+ ws.emit('error', new Error('WebSocket error'));
86
+ }, 0);
87
+ const result = await resultPromise;
88
+ expect(result.success).toBe(false);
89
+ expect(result.error).toContain('WebSocket error');
90
+ });
91
+ it('should handle backend submission failure', async () => {
92
+ const error = new Error('Submission failed');
93
+ mockBackendApiService.submitCommitReview.mockRejectedValue(error);
94
+ const ws = createMockWebSocket();
95
+ mockBackendApiService.connectWebSocket.mockResolvedValue(ws);
96
+ const result = await commitReviewService.submitAndWaitForResults(mockParams);
97
+ expect(result.success).toBe(false);
98
+ expect(result.error).toBe('Submission failed');
99
+ });
100
+ it('should handle non-200 status code in WebSocket message', async () => {
101
+ mockBackendApiService.submitCommitReview.mockResolvedValue({
102
+ success: true,
103
+ analysisId: 'analysis123',
104
+ });
105
+ const ws = createMockWebSocket();
106
+ mockBackendApiService.connectWebSocket.mockResolvedValue(ws);
107
+ const resultPromise = commitReviewService.submitAndWaitForResults(mockParams);
108
+ setTimeout(() => {
109
+ ws.emit('message', Buffer.from(JSON.stringify({
110
+ status_code: 400,
111
+ error_message: 'Bad Request',
112
+ })));
113
+ }, 0);
114
+ const result = await resultPromise;
115
+ expect(result.success).toBe(false);
116
+ expect(result.error).toBe('Bad Request');
117
+ });
118
+ });
119
+ });
120
+ //# sourceMappingURL=commitReviewService.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commitReviewService.test.js","sourceRoot":"","sources":["../../src/tests/commitReviewService.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=errorExtractor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorExtractor.test.d.ts","sourceRoot":"","sources":["../../src/tests/errorExtractor.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,61 @@
1
+ import { extractErrorDetails } from "../utils/errorExtractor.js";
2
+ describe("extractErrorDetails", () => {
3
+ it("maps authentication errors (401)", () => {
4
+ const err = new Error("Authentication failed");
5
+ err.statusCode = 401;
6
+ const details = extractErrorDetails(err);
7
+ expect(details.errorType).toBe("authentication_error");
8
+ expect(details.retryable).toBe(false);
9
+ });
10
+ it("maps not found errors (404) with custom message", () => {
11
+ const err = new Error("User not found");
12
+ err.statusCode = 404;
13
+ const details = extractErrorDetails(err);
14
+ expect(details.errorType).toBe("not_found_error");
15
+ expect(details.userMessage).toContain("User not found");
16
+ });
17
+ it("maps validation errors (422) and keeps user-friendly message", () => {
18
+ const err = new Error("Invalid JSON format in files.json");
19
+ err.statusCode = 422;
20
+ const details = extractErrorDetails(err);
21
+ expect(details.errorType).toBe("validation_error");
22
+ expect(details.userMessage).toContain("Invalid file format");
23
+ });
24
+ it("maps git related errors to git_error and retryable true", () => {
25
+ const details = extractErrorDetails(new Error("Git operation failed"));
26
+ expect(details.errorType).toBe("git_error");
27
+ expect(details.retryable).toBe(true);
28
+ });
29
+ it("maps websocket errors to websocket_error and retryable true", () => {
30
+ const details = extractErrorDetails(new Error("WebSocket connection closed unexpectedly"));
31
+ expect(details.errorType).toBe("websocket_error");
32
+ expect(details.retryable).toBe(true);
33
+ });
34
+ it("maps internal errors (500) and sets retryable true", () => {
35
+ const err = new Error("Internal server error");
36
+ err.statusCode = 500;
37
+ const details = extractErrorDetails(err);
38
+ expect(details.errorType).toBe("internal_error");
39
+ expect(details.retryable).toBe(true);
40
+ });
41
+ it("maps other 4xx client errors to api_error", () => {
42
+ const err = new Error("Teapot error");
43
+ err.statusCode = 418;
44
+ const details = extractErrorDetails(err);
45
+ expect(details.errorType).toBe("api_error");
46
+ expect(details.retryable).toBe(false);
47
+ });
48
+ it("maps other 5xx server errors to api_error and retryable true", () => {
49
+ const err = new Error("Bad gateway");
50
+ err.statusCode = 502;
51
+ const details = extractErrorDetails(err);
52
+ expect(details.errorType).toBe("api_error");
53
+ expect(details.retryable).toBe(true);
54
+ });
55
+ it("uses status parsed from message when missing on object", () => {
56
+ const details = extractErrorDetails(new Error("HTTP error! status: 404, detail: missing"));
57
+ expect(details.statusCode).toBe(404);
58
+ expect(details.errorType).toBe("not_found_error");
59
+ });
60
+ });
61
+ //# sourceMappingURL=errorExtractor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorExtractor.test.js","sourceRoot":"","sources":["../../src/tests/errorExtractor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=loggingService.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loggingService.test.d.ts","sourceRoot":"","sources":["../../src/tests/loggingService.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,153 @@
1
+ import { LoggingService } from '../services/loggingService.js';
2
+ import * as appInsights from 'applicationinsights';
3
+ // Mock applicationinsights
4
+ jest.mock('applicationinsights', () => {
5
+ const trackTrace = jest.fn();
6
+ const trackException = jest.fn();
7
+ const trackEvent = jest.fn();
8
+ const trackMetric = jest.fn();
9
+ const trackDependency = jest.fn();
10
+ const flush = jest.fn();
11
+ return {
12
+ setup: jest.fn().mockReturnThis(),
13
+ setAutoDependencyCorrelation: jest.fn().mockReturnThis(),
14
+ setAutoCollectRequests: jest.fn().mockReturnThis(),
15
+ setAutoCollectPerformance: jest.fn().mockReturnThis(),
16
+ setAutoCollectExceptions: jest.fn().mockReturnThis(),
17
+ setAutoCollectDependencies: jest.fn().mockReturnThis(),
18
+ setAutoCollectConsole: jest.fn().mockReturnThis(),
19
+ setUseDiskRetryCaching: jest.fn().mockReturnThis(),
20
+ setSendLiveMetrics: jest.fn().mockReturnThis(),
21
+ start: jest.fn(),
22
+ defaultClient: {
23
+ trackTrace,
24
+ trackException,
25
+ trackEvent,
26
+ trackMetric,
27
+ trackDependency,
28
+ flush,
29
+ },
30
+ TelemetryClient: jest.fn(),
31
+ };
32
+ });
33
+ describe('LoggingService', () => {
34
+ let loggingService;
35
+ let stderrSpy;
36
+ beforeEach(() => {
37
+ // Reset singleton instance if possible or just get the instance
38
+ // Since it's a singleton, we might need to be careful.
39
+ // However, for unit tests, we can just get the instance.
40
+ loggingService = LoggingService.getInstance();
41
+ // Spy on stderr to capture debug logs
42
+ stderrSpy = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
43
+ // Reset mocks
44
+ jest.clearAllMocks();
45
+ });
46
+ afterEach(() => {
47
+ stderrSpy.mockRestore();
48
+ });
49
+ describe('initialization', () => {
50
+ it('should initialize successfully with a connection string', async () => {
51
+ // We need to access the private property 'isInitialized' or reset it if we want to test init multiple times
52
+ // Since we can't easily reset private state without casting to any, we'll try to initialize
53
+ // If it's already initialized from a previous test run (singleton), this might hit the "already initialized" path
54
+ // Force reset for testing purposes
55
+ loggingService.isInitialized = false;
56
+ loggingService.client = null;
57
+ await loggingService.initialize('fake-connection-string');
58
+ expect(appInsights.setup).toHaveBeenCalledWith('fake-connection-string');
59
+ expect(appInsights.start).toHaveBeenCalled();
60
+ expect(loggingService.isInitialized).toBe(true);
61
+ });
62
+ it('should log error if no connection string provided', async () => {
63
+ loggingService.isInitialized = false;
64
+ await loggingService.initialize(undefined);
65
+ expect(stderrSpy).toHaveBeenCalledWith(expect.stringContaining('Application Insights connection string missing; logging disabled.\n'));
66
+ expect(appInsights.setup).not.toHaveBeenCalled();
67
+ });
68
+ it('should skip re-initialization if already initialized', async () => {
69
+ loggingService.isInitialized = true;
70
+ await loggingService.initialize('another-string');
71
+ expect(appInsights.setup).not.toHaveBeenCalled();
72
+ expect(stderrSpy).not.toHaveBeenCalled();
73
+ });
74
+ });
75
+ describe('logging methods', () => {
76
+ beforeEach(() => {
77
+ // Ensure service is "initialized" with a mock client for these tests
78
+ loggingService.isInitialized = true;
79
+ loggingService.client = appInsights.defaultClient;
80
+ });
81
+ it('logInfo should track trace with severity 1', () => {
82
+ loggingService.logInfo('test info', { key: 'value' });
83
+ expect(appInsights.defaultClient.trackTrace).toHaveBeenCalledWith({
84
+ message: 'test info',
85
+ severity: 1,
86
+ properties: { key: 'value' },
87
+ });
88
+ });
89
+ it('logWarning should track trace with severity 2', () => {
90
+ loggingService.logWarning('test warning', { key: 'value' });
91
+ expect(appInsights.defaultClient.trackTrace).toHaveBeenCalledWith({
92
+ message: 'test warning',
93
+ severity: 2,
94
+ properties: { key: 'value' },
95
+ });
96
+ });
97
+ it('logError should track exception if error object provided', () => {
98
+ const error = new Error('test error');
99
+ loggingService.logError('error message', error, { key: 'value' });
100
+ expect(appInsights.defaultClient.trackException).toHaveBeenCalledWith({
101
+ exception: error,
102
+ properties: { key: 'value', customMessage: 'error message' },
103
+ });
104
+ });
105
+ it('logError should track trace with severity 3 if no error object provided', () => {
106
+ loggingService.logError('error message', undefined, { key: 'value' });
107
+ expect(appInsights.defaultClient.trackTrace).toHaveBeenCalledWith({
108
+ message: 'error message',
109
+ severity: 3,
110
+ properties: { key: 'value' },
111
+ });
112
+ });
113
+ it('logEvent should track event', () => {
114
+ loggingService.logEvent('test event', { prop: 'val' }, { measure: 1 });
115
+ expect(appInsights.defaultClient.trackEvent).toHaveBeenCalledWith({
116
+ name: 'test event',
117
+ properties: { prop: 'val' },
118
+ measurements: { measure: 1 },
119
+ });
120
+ });
121
+ it('trackMetric should track metric', () => {
122
+ loggingService.trackMetric('test metric', 100, { prop: 'val' });
123
+ expect(appInsights.defaultClient.trackMetric).toHaveBeenCalledWith({
124
+ name: 'test metric',
125
+ value: 100,
126
+ properties: { prop: 'val' },
127
+ });
128
+ });
129
+ it('trackDependency should track dependency', () => {
130
+ loggingService.trackDependency('dep name', 'command', 100, true, 'SQL');
131
+ expect(appInsights.defaultClient.trackDependency).toHaveBeenCalledWith({
132
+ name: 'dep name',
133
+ data: 'command',
134
+ duration: 100,
135
+ success: true,
136
+ dependencyTypeName: 'SQL',
137
+ });
138
+ });
139
+ });
140
+ describe('flush', () => {
141
+ it('should flush telemetry', async () => {
142
+ loggingService.client = appInsights.defaultClient;
143
+ // Mock setTimeout to execute immediately
144
+ jest.useFakeTimers();
145
+ const flushPromise = loggingService.flush();
146
+ jest.runAllTimers();
147
+ await flushPromise;
148
+ jest.useRealTimers();
149
+ expect(appInsights.defaultClient.flush).toHaveBeenCalled();
150
+ });
151
+ });
152
+ });
153
+ //# sourceMappingURL=loggingService.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loggingService.test.js","sourceRoot":"","sources":["../../src/tests/loggingService.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=setup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.test.d.ts","sourceRoot":"","sources":["../../src/tests/setup.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ describe('Unit Testing Setup', () => {
2
+ it('should pass this dummy test', () => {
3
+ expect(true).toBe(true);
4
+ });
5
+ });
6
+ export {};
7
+ //# sourceMappingURL=setup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.test.js","sourceRoot":"","sources":["../../src/tests/setup.test.ts"],"names":[],"mappings":"AAAA,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tools.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.test.d.ts","sourceRoot":"","sources":["../../src/tests/tools.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ import { registerTools } from "../handlers/tools.js";
2
+ import { AnalyzeCommitInputSchema, AnalyzeCommitOutputSchema } from "../schemas/toolSchemas.js";
3
+ // Mock service classes and handler factory
4
+ const mockGitServiceInstance = { type: "git" };
5
+ const mockBackendApiServiceInstance = { type: "backend" };
6
+ const mockCommitReviewServiceInstance = { type: "commit" };
7
+ const mockHandler = jest.fn();
8
+ jest.mock("../services/gitService.js", () => {
9
+ return {
10
+ GitService: jest.fn().mockImplementation(() => mockGitServiceInstance),
11
+ };
12
+ });
13
+ jest.mock("../services/backendApiService.js", () => {
14
+ return {
15
+ BackendApiService: jest.fn().mockImplementation(() => mockBackendApiServiceInstance),
16
+ };
17
+ });
18
+ jest.mock("../services/commitReviewService.js", () => {
19
+ return {
20
+ CommitReviewService: jest.fn().mockImplementation(() => mockCommitReviewServiceInstance),
21
+ };
22
+ });
23
+ jest.mock("../handlers/analyzeCommitHandler.js", () => {
24
+ return {
25
+ createAnalyzeCommitHandler: jest.fn(() => mockHandler),
26
+ };
27
+ });
28
+ describe("registerTools", () => {
29
+ const originalEnv = { ...process.env };
30
+ beforeEach(() => {
31
+ jest.clearAllMocks();
32
+ process.env = { ...originalEnv, BACKEND_API_URL: "http://api.local", MCP_API_KEY: "secret" };
33
+ });
34
+ afterAll(() => {
35
+ process.env = originalEnv;
36
+ });
37
+ it("registers analyze_commit tool with constructed services and handler", () => {
38
+ const server = { registerTool: jest.fn() };
39
+ registerTools(server);
40
+ const { GitService } = require("../services/gitService.js");
41
+ const { BackendApiService } = require("../services/backendApiService.js");
42
+ const { CommitReviewService } = require("../services/commitReviewService.js");
43
+ const { createAnalyzeCommitHandler } = require("../handlers/analyzeCommitHandler.js");
44
+ // Services instantiated once
45
+ expect(GitService).toHaveBeenCalledTimes(1);
46
+ expect(BackendApiService).toHaveBeenCalledWith("http://api.local", "secret");
47
+ expect(CommitReviewService).toHaveBeenCalledWith(mockBackendApiServiceInstance);
48
+ // Handler created with service instances
49
+ expect(createAnalyzeCommitHandler).toHaveBeenCalledWith(mockGitServiceInstance, mockCommitReviewServiceInstance, mockBackendApiServiceInstance);
50
+ // Tool registered with correct metadata and handler
51
+ expect(server.registerTool).toHaveBeenCalledWith("analyze_commit", expect.objectContaining({
52
+ title: "Analyze Commit",
53
+ inputSchema: AnalyzeCommitInputSchema,
54
+ outputSchema: AnalyzeCommitOutputSchema,
55
+ }), mockHandler);
56
+ });
57
+ });
58
+ //# sourceMappingURL=tools.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../src/tests/tools.test.ts"],"names":[],"mappings":"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"}