@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,7 +1,7 @@
1
- import * as chrono from 'chrono-node';
1
+ import * as chrono from "chrono-node";
2
2
  // Import utils from the main barrel file (logger, ErrorHandler, RequestContext from ../internal/*)
3
- import { logger, ErrorHandler } from '../index.js';
4
- import { BaseErrorCode } from '../../types-global/errors.js'; // Corrected path
3
+ import { logger, ErrorHandler } from "../index.js";
4
+ import { BaseErrorCode } from "../../types-global/errors.js"; // Corrected path
5
5
  /**
6
6
  * Parses a natural language date string into a Date object.
7
7
  *
@@ -12,7 +12,7 @@ import { BaseErrorCode } from '../../types-global/errors.js'; // Corrected path
12
12
  * @throws McpError if parsing fails unexpectedly.
13
13
  */
14
14
  async function parseDateString(text, context, refDate) {
15
- const operation = 'parseDateString';
15
+ const operation = "parseDateString";
16
16
  const logContext = { ...context, operation, inputText: text, refDate };
17
17
  logger.debug(`Attempting to parse date string: "${text}"`, logContext);
18
18
  return await ErrorHandler.tryCatch(async () => {
@@ -42,7 +42,7 @@ async function parseDateString(text, context, refDate) {
42
42
  * @throws McpError if parsing fails unexpectedly.
43
43
  */
44
44
  async function parseDateStringDetailed(text, context, refDate) {
45
- const operation = 'parseDateStringDetailed';
45
+ const operation = "parseDateStringDetailed";
46
46
  const logContext = { ...context, operation, inputText: text, refDate };
47
47
  logger.debug(`Attempting detailed parse of date string: "${text}"`, logContext);
48
48
  return await ErrorHandler.tryCatch(async () => {
@@ -1,2 +1,2 @@
1
- export * from './jsonParser.js';
2
- export * from './dateParser.js';
1
+ export * from "./jsonParser.js";
2
+ export * from "./dateParser.js";
@@ -1,7 +1,7 @@
1
- import { parse as parsePartialJson, Allow as PartialJsonAllow } from 'partial-json';
2
- import { BaseErrorCode, McpError } from '../../types-global/errors.js';
1
+ import { parse as parsePartialJson, Allow as PartialJsonAllow, } from "partial-json";
2
+ import { BaseErrorCode, McpError } from "../../types-global/errors.js";
3
3
  // Import utils from the main barrel file (logger, RequestContext from ../internal/*)
4
- import { logger } from '../index.js';
4
+ import { logger } from "../index.js";
5
5
  /**
6
6
  * Enum mirroring partial-json's Allow constants for specifying
7
7
  * what types of partial JSON structures are permissible during parsing.
@@ -34,10 +34,13 @@ class JsonParser {
34
34
  const thinkContent = match[1].trim();
35
35
  const restOfString = match[2];
36
36
  if (thinkContent) {
37
- logger.debug('LLM <think> block detected and logged.', { ...context, thinkContent });
37
+ logger.debug("LLM <think> block detected and logged.", {
38
+ ...context,
39
+ thinkContent,
40
+ });
38
41
  }
39
42
  else {
40
- logger.debug('Empty LLM <think> block detected.', context);
43
+ logger.debug("Empty LLM <think> block detected.", context);
41
44
  }
42
45
  stringToParse = restOfString; // Parse only the part after </think>
43
46
  }
@@ -45,17 +48,18 @@ class JsonParser {
45
48
  stringToParse = stringToParse.trim();
46
49
  if (!stringToParse) {
47
50
  // If after removing think block and trimming, the string is empty, it's an error
48
- throw new McpError(BaseErrorCode.VALIDATION_ERROR, 'JSON string is empty after removing <think> block.', context);
51
+ throw new McpError(BaseErrorCode.VALIDATION_ERROR, "JSON string is empty after removing <think> block.", context);
49
52
  }
50
53
  try {
51
54
  // Ensure the string starts with '{' or '[' if we expect an object or array after stripping <think>
52
55
  // This helps catch cases where only non-JSON text remains.
53
- if (!stringToParse.startsWith('{') && !stringToParse.startsWith('[')) {
56
+ if (!stringToParse.startsWith("{") && !stringToParse.startsWith("[")) {
54
57
  // Check if it might be a simple string value that partial-json could parse
55
58
  // Allow simple strings only if specifically permitted or Allow.ALL is used
56
59
  const allowsString = (allowPartial & Allow.STR) === Allow.STR;
57
- if (!allowsString && !stringToParse.startsWith('"')) { // Allow quoted strings if Allow.STR is set
58
- throw new Error('Remaining content does not appear to be valid JSON object or array.');
60
+ if (!allowsString && !stringToParse.startsWith('"')) {
61
+ // Allow quoted strings if Allow.STR is set
62
+ throw new Error("Remaining content does not appear to be valid JSON object or array.");
59
63
  }
60
64
  // If it starts with a quote and strings are allowed, let parsePartialJson handle it
61
65
  }
@@ -64,11 +68,16 @@ class JsonParser {
64
68
  catch (error) {
65
69
  // Wrap the original error in an McpError for consistent error handling
66
70
  // Include the original error message for better debugging context.
67
- logger.error('Failed to parse JSON content.', { ...context, error: error.message, contentAttempted: stringToParse });
71
+ logger.error("Failed to parse JSON content.", {
72
+ ...context,
73
+ error: error.message,
74
+ contentAttempted: stringToParse,
75
+ });
68
76
  throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Failed to parse JSON: ${error.message}`, {
77
+ // Combine context and details into the third argument
69
78
  ...context,
70
79
  originalContent: stringToParse,
71
- rawError: error instanceof Error ? error.stack : String(error) // Include raw error info
80
+ rawError: error instanceof Error ? error.stack : String(error), // Include raw error info
72
81
  });
73
82
  }
74
83
  }
@@ -1,13 +1,13 @@
1
- import { randomBytes, randomUUID as cryptoRandomUUID } from 'crypto'; // Import cryptoRandomUUID
2
- import { BaseErrorCode, McpError } from '../../types-global/errors.js'; // Corrected path
1
+ import { randomBytes, randomUUID as cryptoRandomUUID } from "crypto"; // Import cryptoRandomUUID
2
+ import { BaseErrorCode, McpError } from "../../types-global/errors.js"; // Corrected path
3
3
  /**
4
4
  * Generic ID Generator class for creating and managing unique identifiers
5
5
  */
6
6
  export class IdGenerator {
7
7
  // Default charset
8
- static DEFAULT_CHARSET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
8
+ static DEFAULT_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
9
9
  // Default separator
10
- static DEFAULT_SEPARATOR = '_';
10
+ static DEFAULT_SEPARATOR = "_";
11
11
  // Default random part length
12
12
  static DEFAULT_LENGTH = 6;
13
13
  // Entity prefixes
@@ -50,7 +50,7 @@ export class IdGenerator {
50
50
  */
51
51
  generateRandomString(length = IdGenerator.DEFAULT_LENGTH, charset = IdGenerator.DEFAULT_CHARSET) {
52
52
  const bytes = randomBytes(length);
53
- let result = '';
53
+ let result = "";
54
54
  for (let i = 0; i < length; i++) {
55
55
  result += charset[bytes[i] % charset.length];
56
56
  }
@@ -63,11 +63,9 @@ export class IdGenerator {
63
63
  * @returns A unique identifier string
64
64
  */
65
65
  generate(prefix, options = {}) {
66
- const { length = IdGenerator.DEFAULT_LENGTH, separator = IdGenerator.DEFAULT_SEPARATOR, charset = IdGenerator.DEFAULT_CHARSET } = options;
66
+ const { length = IdGenerator.DEFAULT_LENGTH, separator = IdGenerator.DEFAULT_SEPARATOR, charset = IdGenerator.DEFAULT_CHARSET, } = options;
67
67
  const randomPart = this.generateRandomString(length, charset);
68
- return prefix
69
- ? `${prefix}${separator}${randomPart}`
70
- : randomPart;
68
+ return prefix ? `${prefix}${separator}${randomPart}` : randomPart;
71
69
  }
72
70
  /**
73
71
  * Generates a custom ID for an entity with format PREFIX_XXXXXX
@@ -92,7 +90,7 @@ export class IdGenerator {
92
90
  */
93
91
  isValid(id, entityType, options = {}) {
94
92
  const prefix = this.entityPrefixes[entityType];
95
- const { length = IdGenerator.DEFAULT_LENGTH, separator = IdGenerator.DEFAULT_SEPARATOR } = options;
93
+ const { length = IdGenerator.DEFAULT_LENGTH, separator = IdGenerator.DEFAULT_SEPARATOR, } = options;
96
94
  if (!prefix) {
97
95
  return false;
98
96
  }
@@ -1,3 +1,3 @@
1
- export * from './sanitization.js';
2
- export * from './rateLimiter.js';
3
- export * from './idGenerator.js';
1
+ export * from "./sanitization.js";
2
+ export * from "./rateLimiter.js";
3
+ export * from "./idGenerator.js";
@@ -1,7 +1,7 @@
1
- import { BaseErrorCode, McpError } from '../../types-global/errors.js';
1
+ import { BaseErrorCode, McpError } from "../../types-global/errors.js";
2
2
  // Import config and utils
3
- import { environment } from '../../config/index.js'; // Import environment from config
4
- import { logger } from '../index.js';
3
+ import { environment } from "../../config/index.js"; // Import environment from config
4
+ import { logger } from "../index.js";
5
5
  /**
6
6
  * Generic rate limiter that can be used across the application
7
7
  */
@@ -15,9 +15,9 @@ export class RateLimiter {
15
15
  static DEFAULT_CONFIG = {
16
16
  windowMs: 15 * 60 * 1000, // 15 minutes
17
17
  maxRequests: 100, // 100 requests per window
18
- errorMessage: 'Rate limit exceeded. Please try again in {waitTime} seconds.',
18
+ errorMessage: "Rate limit exceeded. Please try again in {waitTime} seconds.",
19
19
  skipInDevelopment: false,
20
- cleanupInterval: 5 * 60 * 1000 // 5 minutes
20
+ cleanupInterval: 5 * 60 * 1000, // 5 minutes
21
21
  };
22
22
  /**
23
23
  * Create a new rate limiter
@@ -63,7 +63,7 @@ export class RateLimiter {
63
63
  }
64
64
  if (expiredCount > 0) {
65
65
  logger.debug(`Cleaned up ${expiredCount} expired rate limit entries`, {
66
- totalRemaining: this.limits.size
66
+ totalRemaining: this.limits.size,
67
67
  });
68
68
  }
69
69
  }
@@ -90,7 +90,7 @@ export class RateLimiter {
90
90
  */
91
91
  reset() {
92
92
  this.limits.clear();
93
- logger.debug('Rate limiter reset, all limits cleared');
93
+ logger.debug("Rate limiter reset, all limits cleared");
94
94
  }
95
95
  /**
96
96
  * Check if a request exceeds the rate limit
@@ -100,7 +100,7 @@ export class RateLimiter {
100
100
  */
101
101
  check(key, context) {
102
102
  // Skip in development if configured, using the validated environment from config
103
- if (this.config.skipInDevelopment && environment === 'development') {
103
+ if (this.config.skipInDevelopment && environment === "development") {
104
104
  return;
105
105
  }
106
106
  // Generate key using custom generator if provided
@@ -117,7 +117,7 @@ export class RateLimiter {
117
117
  if (!entry || now >= entry.resetTime) {
118
118
  const newEntry = {
119
119
  count: 1,
120
- resetTime: now + this.config.windowMs
120
+ resetTime: now + this.config.windowMs,
121
121
  };
122
122
  this.limits.set(limitKey, newEntry);
123
123
  return newEntry;
@@ -125,9 +125,11 @@ export class RateLimiter {
125
125
  // Check if limit exceeded
126
126
  if (entry.count >= this.config.maxRequests) {
127
127
  const waitTime = Math.ceil((entry.resetTime - now) / 1000);
128
- const errorMessage = this.config.errorMessage?.replace('{waitTime}', waitTime.toString()) ||
129
- `Rate limit exceeded. Please try again in ${waitTime} seconds.`;
130
- throw new McpError(BaseErrorCode.RATE_LIMITED, errorMessage, { waitTime, key: limitKey });
128
+ const errorMessage = this.config.errorMessage?.replace("{waitTime}", waitTime.toString()) || `Rate limit exceeded. Please try again in ${waitTime} seconds.`;
129
+ throw new McpError(BaseErrorCode.RATE_LIMITED, errorMessage, {
130
+ waitTime,
131
+ key: limitKey,
132
+ });
131
133
  }
132
134
  // Increment counter and return updated entry
133
135
  entry.count++;
@@ -150,7 +152,7 @@ export class RateLimiter {
150
152
  current: entry.count,
151
153
  limit: this.config.maxRequests,
152
154
  remaining: Math.max(0, this.config.maxRequests - entry.count),
153
- resetTime: entry.resetTime
155
+ resetTime: entry.resetTime,
154
156
  };
155
157
  }
156
158
  /**
@@ -170,5 +172,5 @@ export class RateLimiter {
170
172
  */
171
173
  export const rateLimiter = new RateLimiter({
172
174
  windowMs: 15 * 60 * 1000, // 15 minutes
173
- maxRequests: 100 // 100 requests per window
175
+ maxRequests: 100, // 100 requests per window
174
176
  });