@cyanheads/git-mcp-server 2.1.1 → 2.1.2

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 (97) hide show
  1. package/README.md +8 -11
  2. package/dist/config/index.js +7 -7
  3. package/dist/index.js +35 -21
  4. package/dist/mcp-server/server.js +72 -56
  5. package/dist/mcp-server/tools/gitAdd/index.js +1 -1
  6. package/dist/mcp-server/tools/gitAdd/logic.js +88 -39
  7. package/dist/mcp-server/tools/gitAdd/registration.js +17 -14
  8. package/dist/mcp-server/tools/gitBranch/index.js +1 -1
  9. package/dist/mcp-server/tools/gitBranch/logic.js +213 -85
  10. package/dist/mcp-server/tools/gitBranch/registration.js +16 -13
  11. package/dist/mcp-server/tools/gitCheckout/index.js +1 -1
  12. package/dist/mcp-server/tools/gitCheckout/logic.js +85 -145
  13. package/dist/mcp-server/tools/gitCheckout/registration.js +16 -14
  14. package/dist/mcp-server/tools/gitCherryPick/index.js +1 -1
  15. package/dist/mcp-server/tools/gitCherryPick/logic.js +100 -41
  16. package/dist/mcp-server/tools/gitCherryPick/registration.js +21 -14
  17. package/dist/mcp-server/tools/gitClean/index.js +1 -1
  18. package/dist/mcp-server/tools/gitClean/logic.js +93 -41
  19. package/dist/mcp-server/tools/gitClean/registration.js +19 -16
  20. package/dist/mcp-server/tools/gitClearWorkingDir/index.js +1 -1
  21. package/dist/mcp-server/tools/gitClearWorkingDir/logic.js +14 -11
  22. package/dist/mcp-server/tools/gitClearWorkingDir/registration.js +19 -13
  23. package/dist/mcp-server/tools/gitClone/index.js +1 -1
  24. package/dist/mcp-server/tools/gitClone/logic.js +89 -30
  25. package/dist/mcp-server/tools/gitClone/registration.js +15 -12
  26. package/dist/mcp-server/tools/gitCommit/index.js +1 -1
  27. package/dist/mcp-server/tools/gitCommit/logic.js +198 -76
  28. package/dist/mcp-server/tools/gitCommit/registration.js +23 -20
  29. package/dist/mcp-server/tools/gitDiff/index.js +1 -1
  30. package/dist/mcp-server/tools/gitDiff/logic.js +124 -44
  31. package/dist/mcp-server/tools/gitDiff/registration.js +16 -14
  32. package/dist/mcp-server/tools/gitFetch/index.js +1 -1
  33. package/dist/mcp-server/tools/gitFetch/logic.js +78 -49
  34. package/dist/mcp-server/tools/gitFetch/registration.js +16 -14
  35. package/dist/mcp-server/tools/gitInit/index.js +1 -1
  36. package/dist/mcp-server/tools/gitInit/logic.js +88 -34
  37. package/dist/mcp-server/tools/gitInit/registration.js +32 -18
  38. package/dist/mcp-server/tools/gitLog/index.js +1 -1
  39. package/dist/mcp-server/tools/gitLog/logic.js +133 -47
  40. package/dist/mcp-server/tools/gitLog/registration.js +16 -14
  41. package/dist/mcp-server/tools/gitMerge/index.js +1 -1
  42. package/dist/mcp-server/tools/gitMerge/logic.js +102 -61
  43. package/dist/mcp-server/tools/gitMerge/registration.js +17 -14
  44. package/dist/mcp-server/tools/gitPull/index.js +1 -1
  45. package/dist/mcp-server/tools/gitPull/logic.js +90 -69
  46. package/dist/mcp-server/tools/gitPull/registration.js +16 -14
  47. package/dist/mcp-server/tools/gitPush/index.js +1 -1
  48. package/dist/mcp-server/tools/gitPush/logic.js +116 -100
  49. package/dist/mcp-server/tools/gitPush/registration.js +16 -14
  50. package/dist/mcp-server/tools/gitRebase/index.js +1 -1
  51. package/dist/mcp-server/tools/gitRebase/logic.js +121 -82
  52. package/dist/mcp-server/tools/gitRebase/registration.js +21 -14
  53. package/dist/mcp-server/tools/gitRemote/index.js +1 -1
  54. package/dist/mcp-server/tools/gitRemote/logic.js +108 -52
  55. package/dist/mcp-server/tools/gitRemote/registration.js +14 -11
  56. package/dist/mcp-server/tools/gitReset/index.js +1 -1
  57. package/dist/mcp-server/tools/gitReset/logic.js +65 -37
  58. package/dist/mcp-server/tools/gitReset/registration.js +14 -12
  59. package/dist/mcp-server/tools/gitSetWorkingDir/index.js +1 -1
  60. package/dist/mcp-server/tools/gitSetWorkingDir/logic.js +74 -34
  61. package/dist/mcp-server/tools/gitSetWorkingDir/registration.js +18 -11
  62. package/dist/mcp-server/tools/gitShow/index.js +1 -1
  63. package/dist/mcp-server/tools/gitShow/logic.js +78 -35
  64. package/dist/mcp-server/tools/gitShow/registration.js +17 -12
  65. package/dist/mcp-server/tools/gitStash/index.js +1 -1
  66. package/dist/mcp-server/tools/gitStash/logic.js +143 -58
  67. package/dist/mcp-server/tools/gitStash/registration.js +19 -12
  68. package/dist/mcp-server/tools/gitStatus/index.js +1 -1
  69. package/dist/mcp-server/tools/gitStatus/logic.js +100 -58
  70. package/dist/mcp-server/tools/gitStatus/registration.js +15 -12
  71. package/dist/mcp-server/tools/gitTag/index.js +1 -1
  72. package/dist/mcp-server/tools/gitTag/logic.js +124 -51
  73. package/dist/mcp-server/tools/gitTag/registration.js +14 -11
  74. package/dist/mcp-server/tools/gitWorktree/index.js +1 -1
  75. package/dist/mcp-server/tools/gitWorktree/logic.js +204 -95
  76. package/dist/mcp-server/tools/gitWorktree/registration.js +14 -11
  77. package/dist/mcp-server/tools/gitWrapupInstructions/index.js +1 -1
  78. package/dist/mcp-server/tools/gitWrapupInstructions/logic.js +21 -11
  79. package/dist/mcp-server/tools/gitWrapupInstructions/registration.js +14 -12
  80. package/dist/mcp-server/transports/httpTransport.js +187 -79
  81. package/dist/mcp-server/transports/stdioTransport.js +14 -8
  82. package/dist/types-global/errors.js +9 -4
  83. package/dist/utils/index.js +4 -4
  84. package/dist/utils/internal/errorHandler.js +62 -40
  85. package/dist/utils/internal/index.js +3 -3
  86. package/dist/utils/internal/logger.js +97 -54
  87. package/dist/utils/internal/requestContext.js +7 -5
  88. package/dist/utils/metrics/index.js +1 -1
  89. package/dist/utils/metrics/tokenCounter.js +18 -14
  90. package/dist/utils/parsing/dateParser.js +5 -5
  91. package/dist/utils/parsing/index.js +2 -2
  92. package/dist/utils/parsing/jsonParser.js +20 -11
  93. package/dist/utils/security/idGenerator.js +8 -10
  94. package/dist/utils/security/index.js +3 -3
  95. package/dist/utils/security/rateLimiter.js +16 -14
  96. package/dist/utils/security/sanitization.js +139 -82
  97. package/package.json +42 -20
@@ -49,7 +49,7 @@ export class McpError extends Error {
49
49
  this.code = code;
50
50
  this.details = details;
51
51
  // Set the error name for identification
52
- this.name = 'McpError';
52
+ this.name = "McpError";
53
53
  // Ensure the prototype chain is correct
54
54
  Object.setPrototypeOf(this, McpError.prototype);
55
55
  }
@@ -58,11 +58,16 @@ export class McpError extends Error {
58
58
  * Zod schema for validating error objects, potentially used for parsing
59
59
  * error responses or validating error structures internally.
60
60
  */
61
- export const ErrorSchema = z.object({
61
+ export const ErrorSchema = z
62
+ .object({
62
63
  /** The error code, corresponding to BaseErrorCode enum values. */
63
64
  code: z.nativeEnum(BaseErrorCode).describe("Standardized error code"),
64
65
  /** A human-readable description of the error. */
65
66
  message: z.string().describe("Detailed error message"),
66
67
  /** Optional additional details or context about the error. */
67
- details: z.record(z.unknown()).optional().describe("Optional structured error details")
68
- }).describe("Schema for validating structured error objects.");
68
+ details: z
69
+ .record(z.unknown())
70
+ .optional()
71
+ .describe("Optional structured error details"),
72
+ })
73
+ .describe("Schema for validating structured error objects.");
@@ -1,8 +1,8 @@
1
1
  // Re-export all utilities from their categorized subdirectories
2
- export * from './internal/index.js';
3
- export * from './parsing/index.js';
4
- export * from './security/index.js';
5
- export * from './metrics/index.js';
2
+ export * from "./internal/index.js";
3
+ export * from "./parsing/index.js";
4
+ export * from "./security/index.js";
5
+ export * from "./metrics/index.js";
6
6
  // It's good practice to have index.ts files in each subdirectory
7
7
  // that export the contents of that directory.
8
8
  // Assuming those will be created or already exist.
@@ -1,37 +1,61 @@
1
- import { BaseErrorCode, McpError } from '../../types-global/errors.js'; // Corrected path
2
- import { logger } from './logger.js';
3
- import { sanitizeInputForLogging } from '../index.js'; // Import from main barrel file
1
+ import { BaseErrorCode, McpError } from "../../types-global/errors.js"; // Corrected path
2
+ import { logger } from "./logger.js";
3
+ import { sanitizeInputForLogging } from "../index.js"; // Import from main barrel file
4
4
  /**
5
5
  * Simple mapper that maps error types to error codes
6
6
  */
7
7
  const ERROR_TYPE_MAPPINGS = {
8
- 'SyntaxError': BaseErrorCode.VALIDATION_ERROR,
9
- 'TypeError': BaseErrorCode.VALIDATION_ERROR,
10
- 'ReferenceError': BaseErrorCode.INTERNAL_ERROR,
11
- 'RangeError': BaseErrorCode.VALIDATION_ERROR,
12
- 'URIError': BaseErrorCode.VALIDATION_ERROR,
13
- 'EvalError': BaseErrorCode.INTERNAL_ERROR
8
+ SyntaxError: BaseErrorCode.VALIDATION_ERROR,
9
+ TypeError: BaseErrorCode.VALIDATION_ERROR,
10
+ ReferenceError: BaseErrorCode.INTERNAL_ERROR,
11
+ RangeError: BaseErrorCode.VALIDATION_ERROR,
12
+ URIError: BaseErrorCode.VALIDATION_ERROR,
13
+ EvalError: BaseErrorCode.INTERNAL_ERROR,
14
14
  };
15
15
  /**
16
16
  * Common error patterns for automatic classification
17
17
  */
18
18
  const COMMON_ERROR_PATTERNS = [
19
19
  // Authentication related errors
20
- { pattern: /auth|unauthorized|unauthenticated|not.*logged.*in|invalid.*token|expired.*token/i, errorCode: BaseErrorCode.UNAUTHORIZED },
20
+ {
21
+ pattern: /auth|unauthorized|unauthenticated|not.*logged.*in|invalid.*token|expired.*token/i,
22
+ errorCode: BaseErrorCode.UNAUTHORIZED,
23
+ },
21
24
  // Permission related errors
22
- { pattern: /permission|forbidden|access.*denied|not.*allowed/i, errorCode: BaseErrorCode.FORBIDDEN },
25
+ {
26
+ pattern: /permission|forbidden|access.*denied|not.*allowed/i,
27
+ errorCode: BaseErrorCode.FORBIDDEN,
28
+ },
23
29
  // Not found errors
24
- { pattern: /not.*found|missing|no.*such|doesn't.*exist|couldn't.*find/i, errorCode: BaseErrorCode.NOT_FOUND },
30
+ {
31
+ pattern: /not.*found|missing|no.*such|doesn't.*exist|couldn't.*find/i,
32
+ errorCode: BaseErrorCode.NOT_FOUND,
33
+ },
25
34
  // Validation errors
26
- { pattern: /invalid|validation|malformed|bad request|wrong format/i, errorCode: BaseErrorCode.VALIDATION_ERROR },
35
+ {
36
+ pattern: /invalid|validation|malformed|bad request|wrong format/i,
37
+ errorCode: BaseErrorCode.VALIDATION_ERROR,
38
+ },
27
39
  // Conflict errors
28
- { pattern: /conflict|already.*exists|duplicate|unique.*constraint/i, errorCode: BaseErrorCode.CONFLICT },
40
+ {
41
+ pattern: /conflict|already.*exists|duplicate|unique.*constraint/i,
42
+ errorCode: BaseErrorCode.CONFLICT,
43
+ },
29
44
  // Rate limiting
30
- { pattern: /rate.*limit|too.*many.*requests|throttled/i, errorCode: BaseErrorCode.RATE_LIMITED },
45
+ {
46
+ pattern: /rate.*limit|too.*many.*requests|throttled/i,
47
+ errorCode: BaseErrorCode.RATE_LIMITED,
48
+ },
31
49
  // Timeout errors
32
- { pattern: /timeout|timed.*out|deadline.*exceeded/i, errorCode: BaseErrorCode.TIMEOUT },
50
+ {
51
+ pattern: /timeout|timed.*out|deadline.*exceeded/i,
52
+ errorCode: BaseErrorCode.TIMEOUT,
53
+ },
33
54
  // External service errors
34
- { pattern: /service.*unavailable|bad.*gateway|gateway.*timeout/i, errorCode: BaseErrorCode.SERVICE_UNAVAILABLE }
55
+ {
56
+ pattern: /service.*unavailable|bad.*gateway|gateway.*timeout/i,
57
+ errorCode: BaseErrorCode.SERVICE_UNAVAILABLE,
58
+ },
35
59
  ];
36
60
  /**
37
61
  * Get a readable name for an error
@@ -40,17 +64,15 @@ const COMMON_ERROR_PATTERNS = [
40
64
  */
41
65
  function getErrorName(error) {
42
66
  if (error instanceof Error) {
43
- return error.name || 'Error';
67
+ return error.name || "Error";
44
68
  }
45
69
  if (error === null) {
46
- return 'NullError';
70
+ return "NullError";
47
71
  }
48
72
  if (error === undefined) {
49
- return 'UndefinedError';
73
+ return "UndefinedError";
50
74
  }
51
- return typeof error === 'object'
52
- ? 'ObjectError'
53
- : 'UnknownError';
75
+ return typeof error === "object" ? "ObjectError" : "UnknownError";
54
76
  }
55
77
  /**
56
78
  * Get a message from an error
@@ -62,14 +84,12 @@ function getErrorMessage(error) {
62
84
  return error.message;
63
85
  }
64
86
  if (error === null) {
65
- return 'Null error occurred';
87
+ return "Null error occurred";
66
88
  }
67
89
  if (error === undefined) {
68
- return 'Undefined error occurred';
90
+ return "Undefined error occurred";
69
91
  }
70
- return typeof error === 'string'
71
- ? error
72
- : String(error);
92
+ return typeof error === "string" ? error : String(error);
73
93
  }
74
94
  /**
75
95
  * Error handler utility class with various error handling methods
@@ -95,7 +115,7 @@ export class ErrorHandler {
95
115
  for (const pattern of COMMON_ERROR_PATTERNS) {
96
116
  const regex = pattern.pattern instanceof RegExp
97
117
  ? pattern.pattern
98
- : new RegExp(pattern.pattern, 'i');
118
+ : new RegExp(pattern.pattern, "i");
99
119
  if (regex.test(errorMessage) || regex.test(errorName)) {
100
120
  return pattern.errorCode;
101
121
  }
@@ -110,13 +130,15 @@ export class ErrorHandler {
110
130
  * @returns The transformed error
111
131
  */
112
132
  static handleError(error, options) {
113
- const { context, operation, input, rethrow = false, errorCode: explicitErrorCode, includeStack = true, critical = false } = options;
133
+ const { context, operation, input, rethrow = false, errorCode: explicitErrorCode, includeStack = true, critical = false, } = options;
114
134
  // If it's already an McpError, use it directly but apply additional context
115
135
  if (error instanceof McpError) {
116
136
  // Add any additional context
117
137
  if (context && Object.keys(context).length > 0) {
118
138
  // Ensure details is an object before spreading
119
- const existingDetails = typeof error.details === 'object' && error.details !== null ? error.details : {};
139
+ const existingDetails = typeof error.details === "object" && error.details !== null
140
+ ? error.details
141
+ : {};
120
142
  error.details = { ...existingDetails, ...context };
121
143
  }
122
144
  // Log the error with sanitized input
@@ -126,7 +148,7 @@ export class ErrorHandler {
126
148
  input: input ? sanitizeInputForLogging(input) : undefined,
127
149
  stack: includeStack ? error.stack : undefined,
128
150
  critical,
129
- ...context
151
+ ...context,
130
152
  });
131
153
  if (rethrow) {
132
154
  throw error;
@@ -144,7 +166,7 @@ export class ErrorHandler {
144
166
  requestId: context?.requestId,
145
167
  stack: includeStack && error instanceof Error ? error.stack : undefined,
146
168
  critical,
147
- ...context
169
+ ...context,
148
170
  });
149
171
  // Choose the error code (explicit > determined > default)
150
172
  const errorCode = explicitErrorCode ||
@@ -159,7 +181,7 @@ export class ErrorHandler {
159
181
  transformedError = new McpError(errorCode, `Error ${operation}: ${getErrorMessage(error)}`, // Use helper function
160
182
  {
161
183
  originalError: getErrorName(error),
162
- ...context
184
+ ...context,
163
185
  });
164
186
  }
165
187
  // Rethrow if requested
@@ -198,9 +220,7 @@ export class ErrorHandler {
198
220
  if (defaultFactory) {
199
221
  return defaultFactory(error);
200
222
  }
201
- return error instanceof Error
202
- ? error
203
- : new Error(String(error));
223
+ return error instanceof Error ? error : new Error(String(error));
204
224
  }
205
225
  // Removed createErrorMapper method for simplification
206
226
  /**
@@ -214,20 +234,22 @@ export class ErrorHandler {
214
234
  code: error.code,
215
235
  message: error.message,
216
236
  // Ensure details is an object
217
- details: typeof error.details === 'object' && error.details !== null ? error.details : {}
237
+ details: typeof error.details === "object" && error.details !== null
238
+ ? error.details
239
+ : {},
218
240
  };
219
241
  }
220
242
  if (error instanceof Error) {
221
243
  return {
222
244
  code: ErrorHandler.determineErrorCode(error),
223
245
  message: error.message,
224
- details: { errorType: error.name }
246
+ details: { errorType: error.name },
225
247
  };
226
248
  }
227
249
  return {
228
250
  code: BaseErrorCode.UNKNOWN_ERROR,
229
251
  message: String(error),
230
- details: { errorType: typeof error }
252
+ details: { errorType: typeof error },
231
253
  };
232
254
  }
233
255
  /**
@@ -1,3 +1,3 @@
1
- export * from './errorHandler.js';
2
- export * from './logger.js';
3
- export * from './requestContext.js';
1
+ export * from "./errorHandler.js";
2
+ export * from "./logger.js";
3
+ export * from "./requestContext.js";
@@ -1,35 +1,43 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import winston from 'winston';
5
- import { config } from '../../config/index.js';
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ import winston from "winston";
5
+ import { config } from "../../config/index.js";
6
6
  // Define the numeric severity for comparison (lower is more severe)
7
7
  const mcpLevelSeverity = {
8
- emerg: 0, alert: 1, crit: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7
8
+ emerg: 0,
9
+ alert: 1,
10
+ crit: 2,
11
+ error: 3,
12
+ warning: 4,
13
+ notice: 5,
14
+ info: 6,
15
+ debug: 7,
9
16
  };
10
17
  // Map MCP levels to Winston's core levels for file logging
11
18
  const mcpToWinstonLevel = {
12
- debug: 'debug',
13
- info: 'info',
14
- notice: 'info', // Map notice to info for file logging
15
- warning: 'warn',
16
- error: 'error',
17
- crit: 'error', // Map critical levels to error for file logging
18
- alert: 'error',
19
- emerg: 'error',
19
+ debug: "debug",
20
+ info: "info",
21
+ notice: "info", // Map notice to info for file logging
22
+ warning: "warn",
23
+ error: "error",
24
+ crit: "error", // Map critical levels to error for file logging
25
+ alert: "error",
26
+ emerg: "error",
20
27
  };
21
28
  // Resolve __dirname for ESM
22
29
  const __filename = fileURLToPath(import.meta.url);
23
30
  const __dirname = path.dirname(__filename);
24
31
  // Calculate project root robustly (works from src/ or dist/)
25
- const isRunningFromDist = __dirname.includes(path.sep + 'dist' + path.sep);
32
+ const isRunningFromDist = __dirname.includes(path.sep + "dist" + path.sep);
26
33
  const levelsToGoUp = isRunningFromDist ? 3 : 2;
27
- const pathSegments = Array(levelsToGoUp).fill('..');
34
+ const pathSegments = Array(levelsToGoUp).fill("..");
28
35
  const projectRoot = path.resolve(__dirname, ...pathSegments);
29
- const logsDir = path.join(projectRoot, 'logs');
36
+ const logsDir = path.join(projectRoot, "logs");
30
37
  // Security: ensure logsDir is within projectRoot
31
38
  const resolvedLogsDir = path.resolve(logsDir);
32
- const isLogsDirSafe = resolvedLogsDir === projectRoot || resolvedLogsDir.startsWith(projectRoot + path.sep);
39
+ const isLogsDirSafe = resolvedLogsDir === projectRoot ||
40
+ resolvedLogsDir.startsWith(projectRoot + path.sep);
33
41
  if (!isLogsDirSafe) {
34
42
  // Use console.error for critical pre-init errors.
35
43
  // Only log to console if TTY to avoid polluting stdout for stdio MCP clients.
@@ -42,21 +50,24 @@ if (!isLogsDirSafe) {
42
50
  * This is extracted to avoid duplication between initialize and setLevel.
43
51
  */
44
52
  function createWinstonConsoleFormat() {
45
- return winston.format.combine(winston.format.colorize(), winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), winston.format.printf(({ timestamp, level, message, ...meta }) => {
46
- let metaString = '';
53
+ return winston.format.combine(winston.format.colorize(), winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), winston.format.printf(({ timestamp, level, message, ...meta }) => {
54
+ let metaString = "";
47
55
  const metaCopy = { ...meta };
48
- if (metaCopy.error && typeof metaCopy.error === 'object') {
56
+ if (metaCopy.error && typeof metaCopy.error === "object") {
49
57
  const errorObj = metaCopy.error;
50
58
  if (errorObj.message)
51
59
  metaString += `\n Error: ${errorObj.message}`;
52
60
  if (errorObj.stack)
53
- metaString += `\n Stack: ${String(errorObj.stack).split('\n').map((l) => ` ${l}`).join('\n')}`;
61
+ metaString += `\n Stack: ${String(errorObj.stack)
62
+ .split("\n")
63
+ .map((l) => ` ${l}`)
64
+ .join("\n")}`;
54
65
  delete metaCopy.error;
55
66
  }
56
67
  if (Object.keys(metaCopy).length > 0) {
57
68
  try {
58
69
  const remainingMetaJson = JSON.stringify(metaCopy, null, 2);
59
- if (remainingMetaJson !== '{}')
70
+ if (remainingMetaJson !== "{}")
60
71
  metaString += `\n Meta: ${remainingMetaJson}`;
61
72
  }
62
73
  catch (stringifyError) {
@@ -75,17 +86,17 @@ class Logger {
75
86
  winstonLogger;
76
87
  initialized = false;
77
88
  mcpNotificationSender;
78
- currentMcpLevel = 'info'; // Default MCP level
79
- currentWinstonLevel = 'info'; // Default Winston level
89
+ currentMcpLevel = "info"; // Default MCP level
90
+ currentWinstonLevel = "info"; // Default Winston level
80
91
  constructor() { }
81
92
  /**
82
93
  * Initialize Winston logger for file transport. Must be called once at app start.
83
94
  * Console transport is added conditionally.
84
95
  * @param level Initial minimum level to log ('info' default).
85
96
  */
86
- async initialize(level = 'info') {
97
+ async initialize(level = "info") {
87
98
  if (this.initialized) {
88
- this.warning('Logger already initialized.', { loggerSetup: true });
99
+ this.warning("Logger already initialized.", { loggerSetup: true });
89
100
  return;
90
101
  }
91
102
  this.currentMcpLevel = level;
@@ -111,7 +122,26 @@ class Logger {
111
122
  const transports = [];
112
123
  // Add file transports only if the directory is safe
113
124
  if (isLogsDirSafe) {
114
- transports.push(new winston.transports.File({ filename: path.join(resolvedLogsDir, 'error.log'), level: 'error', format: fileFormat }), new winston.transports.File({ filename: path.join(resolvedLogsDir, 'warn.log'), level: 'warn', format: fileFormat }), new winston.transports.File({ filename: path.join(resolvedLogsDir, 'info.log'), level: 'info', format: fileFormat }), new winston.transports.File({ filename: path.join(resolvedLogsDir, 'debug.log'), level: 'debug', format: fileFormat }), new winston.transports.File({ filename: path.join(resolvedLogsDir, 'combined.log'), format: fileFormat }));
125
+ transports.push(new winston.transports.File({
126
+ filename: path.join(resolvedLogsDir, "error.log"),
127
+ level: "error",
128
+ format: fileFormat,
129
+ }), new winston.transports.File({
130
+ filename: path.join(resolvedLogsDir, "warn.log"),
131
+ level: "warn",
132
+ format: fileFormat,
133
+ }), new winston.transports.File({
134
+ filename: path.join(resolvedLogsDir, "info.log"),
135
+ level: "info",
136
+ format: fileFormat,
137
+ }), new winston.transports.File({
138
+ filename: path.join(resolvedLogsDir, "debug.log"),
139
+ level: "debug",
140
+ format: fileFormat,
141
+ }), new winston.transports.File({
142
+ filename: path.join(resolvedLogsDir, "combined.log"),
143
+ format: fileFormat,
144
+ }));
115
145
  }
116
146
  else {
117
147
  // Conditional console output for pre-init warnings.
@@ -124,22 +154,24 @@ class Logger {
124
154
  // Conditionally add Console transport only if:
125
155
  // 1. MCP level is 'debug'
126
156
  // 2. stdout is a TTY (interactive terminal, not piped)
127
- if (this.currentMcpLevel === 'debug' && process.stdout.isTTY) {
157
+ if (this.currentMcpLevel === "debug" && process.stdout.isTTY) {
128
158
  const consoleFormat = createWinstonConsoleFormat();
129
159
  transports.push(new winston.transports.Console({
130
- level: 'debug',
160
+ level: "debug",
131
161
  format: consoleFormat,
132
162
  }));
133
- consoleLoggingEnabledMessage = 'Console logging enabled at level: debug (stdout is TTY)';
163
+ consoleLoggingEnabledMessage =
164
+ "Console logging enabled at level: debug (stdout is TTY)";
134
165
  }
135
- else if (this.currentMcpLevel === 'debug' && !process.stdout.isTTY) {
136
- consoleLoggingSkippedMessage = 'Console logging skipped: Level is debug, but stdout is not a TTY (likely stdio transport).';
166
+ else if (this.currentMcpLevel === "debug" && !process.stdout.isTTY) {
167
+ consoleLoggingSkippedMessage =
168
+ "Console logging skipped: Level is debug, but stdout is not a TTY (likely stdio transport).";
137
169
  }
138
170
  // Create logger with the initial Winston level and configured transports
139
171
  this.winstonLogger = winston.createLogger({
140
172
  level: this.currentWinstonLevel,
141
173
  transports,
142
- exitOnError: false
174
+ exitOnError: false,
143
175
  });
144
176
  // Log deferred messages now that winstonLogger is initialized
145
177
  if (logsDirCreatedMessage) {
@@ -153,14 +185,14 @@ class Logger {
153
185
  }
154
186
  this.initialized = true;
155
187
  await Promise.resolve(); // Yield to event loop
156
- this.info(`Logger initialized. File logging level: ${this.currentWinstonLevel}. MCP logging level: ${this.currentMcpLevel}. Console logging: ${process.stdout.isTTY && this.currentMcpLevel === 'debug' ? 'enabled' : 'disabled'}`, { loggerSetup: true });
188
+ this.info(`Logger initialized. File logging level: ${this.currentWinstonLevel}. MCP logging level: ${this.currentMcpLevel}. Console logging: ${process.stdout.isTTY && this.currentMcpLevel === "debug" ? "enabled" : "disabled"}`, { loggerSetup: true });
157
189
  }
158
190
  /**
159
191
  * Sets the function used to send MCP 'notifications/message'.
160
192
  */
161
193
  setMcpNotificationSender(sender) {
162
194
  this.mcpNotificationSender = sender;
163
- const status = sender ? 'enabled' : 'disabled';
195
+ const status = sender ? "enabled" : "disabled";
164
196
  this.info(`MCP notification sending ${status}.`, { loggerSetup: true });
165
197
  }
166
198
  /**
@@ -183,21 +215,24 @@ class Logger {
183
215
  this.currentWinstonLevel = mcpToWinstonLevel[newLevel];
184
216
  this.winstonLogger.level = this.currentWinstonLevel;
185
217
  // Add or remove console transport based on the new level and TTY status
186
- const consoleTransport = this.winstonLogger.transports.find(t => t instanceof winston.transports.Console);
187
- const shouldHaveConsole = newLevel === 'debug' && process.stdout.isTTY;
218
+ const consoleTransport = this.winstonLogger.transports.find((t) => t instanceof winston.transports.Console);
219
+ const shouldHaveConsole = newLevel === "debug" && process.stdout.isTTY;
188
220
  if (shouldHaveConsole && !consoleTransport) {
189
221
  // Add console transport
190
222
  const consoleFormat = createWinstonConsoleFormat();
191
- this.winstonLogger.add(new winston.transports.Console({ level: 'debug', format: consoleFormat }));
192
- this.info('Console logging dynamically enabled.', { loggerSetup: true });
223
+ this.winstonLogger.add(new winston.transports.Console({
224
+ level: "debug",
225
+ format: consoleFormat,
226
+ }));
227
+ this.info("Console logging dynamically enabled.", { loggerSetup: true });
193
228
  }
194
229
  else if (!shouldHaveConsole && consoleTransport) {
195
230
  // Remove console transport
196
231
  this.winstonLogger.remove(consoleTransport);
197
- this.info('Console logging dynamically disabled.', { loggerSetup: true });
232
+ this.info("Console logging dynamically disabled.", { loggerSetup: true });
198
233
  }
199
234
  if (oldLevel !== newLevel) {
200
- this.info(`Log level changed. File logging level: ${this.currentWinstonLevel}. MCP logging level: ${this.currentMcpLevel}. Console logging: ${shouldHaveConsole ? 'enabled' : 'disabled'}`, { loggerSetup: true });
235
+ this.info(`Log level changed. File logging level: ${this.currentWinstonLevel}. MCP logging level: ${this.currentMcpLevel}. Console logging: ${shouldHaveConsole ? "enabled" : "disabled"}`, { loggerSetup: true });
201
236
  }
202
237
  }
203
238
  /** Get singleton instance. */
@@ -212,7 +247,7 @@ class Logger {
212
247
  if (!this.initialized || !this.winstonLogger) {
213
248
  // Conditional console output if logger not usable.
214
249
  if (process.stdout.isTTY) {
215
- console.warn('Logger not initialized; message dropped.');
250
+ console.warn("Logger not initialized; message dropped.");
216
251
  }
217
252
  return false;
218
253
  }
@@ -239,7 +274,7 @@ class Logger {
239
274
  mcpDataPayload.context = context;
240
275
  if (error) {
241
276
  mcpDataPayload.error = { message: error.message };
242
- if (this.currentMcpLevel === 'debug' && error.stack) {
277
+ if (this.currentMcpLevel === "debug" && error.stack) {
243
278
  mcpDataPayload.error.stack = error.stack.substring(0, 500);
244
279
  }
245
280
  }
@@ -251,38 +286,46 @@ class Logger {
251
286
  originalLevel: level,
252
287
  originalMessage: msg,
253
288
  sendError: sendError instanceof Error ? sendError.message : String(sendError),
254
- mcpPayload: mcpDataPayload
289
+ mcpPayload: mcpDataPayload,
255
290
  });
256
291
  }
257
292
  }
258
293
  }
259
294
  // --- Public Logging Methods ---
260
- debug(msg, context) { this.log('debug', msg, context); }
261
- info(msg, context) { this.log('info', msg, context); }
262
- notice(msg, context) { this.log('notice', msg, context); }
263
- warning(msg, context) { this.log('warning', msg, context); }
295
+ debug(msg, context) {
296
+ this.log("debug", msg, context);
297
+ }
298
+ info(msg, context) {
299
+ this.log("info", msg, context);
300
+ }
301
+ notice(msg, context) {
302
+ this.log("notice", msg, context);
303
+ }
304
+ warning(msg, context) {
305
+ this.log("warning", msg, context);
306
+ }
264
307
  error(msg, err, context) {
265
308
  const errorObj = err instanceof Error ? err : undefined;
266
309
  const combinedContext = err instanceof Error ? context : { ...(err || {}), ...(context || {}) };
267
- this.log('error', msg, combinedContext, errorObj);
310
+ this.log("error", msg, combinedContext, errorObj);
268
311
  }
269
312
  crit(msg, err, context) {
270
313
  const errorObj = err instanceof Error ? err : undefined;
271
314
  const combinedContext = err instanceof Error ? context : { ...(err || {}), ...(context || {}) };
272
- this.log('crit', msg, combinedContext, errorObj);
315
+ this.log("crit", msg, combinedContext, errorObj);
273
316
  }
274
317
  alert(msg, err, context) {
275
318
  const errorObj = err instanceof Error ? err : undefined;
276
319
  const combinedContext = err instanceof Error ? context : { ...(err || {}), ...(context || {}) };
277
- this.log('alert', msg, combinedContext, errorObj);
320
+ this.log("alert", msg, combinedContext, errorObj);
278
321
  }
279
322
  emerg(msg, err, context) {
280
323
  const errorObj = err instanceof Error ? err : undefined;
281
324
  const combinedContext = err instanceof Error ? context : { ...(err || {}), ...(context || {}) };
282
- this.log('emerg', msg, combinedContext, errorObj);
325
+ this.log("emerg", msg, combinedContext, errorObj);
283
326
  }
284
327
  fatal(msg, context, error) {
285
- this.log('emerg', msg, context, error);
328
+ this.log("emerg", msg, context, error);
286
329
  }
287
330
  }
288
331
  // Export singleton instance
@@ -1,6 +1,6 @@
1
- import { logger } from './logger.js';
1
+ import { logger } from "./logger.js";
2
2
  // Import utils from the main barrel file (generateUUID from ../security/idGenerator.js)
3
- import { generateUUID } from '../index.js';
3
+ import { generateUUID } from "../index.js";
4
4
  // Direct instance for request context utilities
5
5
  const requestContextServiceInstance = {
6
6
  config: {},
@@ -12,9 +12,11 @@ const requestContextServiceInstance = {
12
12
  configure(config) {
13
13
  this.config = {
14
14
  ...this.config,
15
- ...config
15
+ ...config,
16
16
  };
17
- logger.debug('RequestContext configuration updated', { config: this.config });
17
+ logger.debug("RequestContext configuration updated", {
18
+ config: this.config,
19
+ });
18
20
  return { ...this.config };
19
21
  },
20
22
  /**
@@ -35,7 +37,7 @@ const requestContextServiceInstance = {
35
37
  return {
36
38
  requestId,
37
39
  timestamp,
38
- ...additionalContext
40
+ ...additionalContext,
39
41
  };
40
42
  },
41
43
  // generateSecureRandomString function removed as it was unused and redundant
@@ -1 +1 @@
1
- export * from './tokenCounter.js';
1
+ export * from "./tokenCounter.js";