@cyanheads/git-mcp-server 2.1.0 → 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 +23 -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 +45 -23
@@ -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";
@@ -1,9 +1,9 @@
1
- import { encoding_for_model } from 'tiktoken';
2
- import { BaseErrorCode } from '../../types-global/errors.js';
1
+ import { encoding_for_model } from "tiktoken";
2
+ import { BaseErrorCode } from "../../types-global/errors.js";
3
3
  // Import utils from the main barrel file (ErrorHandler, logger, RequestContext from ../internal/*)
4
- import { ErrorHandler, logger } from '../index.js';
4
+ import { ErrorHandler, logger } from "../index.js";
5
5
  // Define the model used specifically for token counting
6
- const TOKENIZATION_MODEL = 'gpt-4o'; // Note this is strictly for token counting, not the model used for inference
6
+ const TOKENIZATION_MODEL = "gpt-4o"; // Note this is strictly for token counting, not the model used for inference
7
7
  /**
8
8
  * Calculates the number of tokens for a given text using the 'gpt-4o' tokenizer.
9
9
  * Uses ErrorHandler for consistent error management.
@@ -27,11 +27,11 @@ export async function countTokens(text, context) {
27
27
  encoding?.free(); // Ensure the encoder is freed if it was successfully created
28
28
  }
29
29
  }, {
30
- operation: 'countTokens',
30
+ operation: "countTokens",
31
31
  context: context,
32
- input: { textSample: text.substring(0, 50) + '...' }, // Log sanitized input
32
+ input: { textSample: text.substring(0, 50) + "..." }, // Log sanitized input
33
33
  errorCode: BaseErrorCode.INTERNAL_ERROR, // Use INTERNAL_ERROR for external lib issues
34
- rethrow: true // Rethrow as McpError
34
+ rethrow: true, // Rethrow as McpError
35
35
  // Removed onErrorReturn as we now rethrow
36
36
  });
37
37
  }
@@ -65,13 +65,13 @@ context) {
65
65
  // Encode role
66
66
  num_tokens += encoding.encode(message.role).length;
67
67
  // Encode content - handle potential null or array content (vision)
68
- if (typeof message.content === 'string') {
68
+ if (typeof message.content === "string") {
69
69
  num_tokens += encoding.encode(message.content).length;
70
70
  }
71
71
  else if (Array.isArray(message.content)) {
72
72
  // Handle multi-part content (e.g., text + image) - simplified: encode text parts only
73
73
  for (const part of message.content) {
74
- if (part.type === 'text') {
74
+ if (part.type === "text") {
75
75
  num_tokens += encoding.encode(part.text).length;
76
76
  }
77
77
  else {
@@ -83,13 +83,15 @@ context) {
83
83
  }
84
84
  } // else: content is null, add 0 tokens
85
85
  // Encode name if present (often associated with 'tool' or 'function' roles in newer models)
86
- if ('name' in message && message.name) {
86
+ if ("name" in message && message.name) {
87
87
  num_tokens += tokens_per_name;
88
88
  num_tokens += encoding.encode(message.name).length;
89
89
  }
90
90
  // --- Handle tool calls (specific to newer models) ---
91
91
  // Assistant message requesting tool calls
92
- if (message.role === 'assistant' && 'tool_calls' in message && message.tool_calls) {
92
+ if (message.role === "assistant" &&
93
+ "tool_calls" in message &&
94
+ message.tool_calls) {
93
95
  for (const tool_call of message.tool_calls) {
94
96
  // Add tokens for the function name and arguments
95
97
  if (tool_call.function.name) {
@@ -102,7 +104,9 @@ context) {
102
104
  }
103
105
  }
104
106
  // Tool message providing results
105
- if (message.role === 'tool' && 'tool_call_id' in message && message.tool_call_id) {
107
+ if (message.role === "tool" &&
108
+ "tool_call_id" in message &&
109
+ message.tool_call_id) {
106
110
  num_tokens += encoding.encode(message.tool_call_id).length;
107
111
  // Content of the tool message (the result) is already handled by the string content check above
108
112
  }
@@ -114,11 +118,11 @@ context) {
114
118
  encoding?.free();
115
119
  }
116
120
  }, {
117
- operation: 'countChatTokens',
121
+ operation: "countChatTokens",
118
122
  context: context,
119
123
  input: { messageCount: messages.length }, // Log sanitized input
120
124
  errorCode: BaseErrorCode.INTERNAL_ERROR, // Use INTERNAL_ERROR
121
- rethrow: true // Rethrow as McpError
125
+ rethrow: true, // Rethrow as McpError
122
126
  // Removed onErrorReturn
123
127
  });
124
128
  }