@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,11 +1,11 @@
1
1
  // Import utils from barrel (logger from ../utils/internal/logger.js)
2
- import { logger } from '../../../utils/index.js';
2
+ import { logger } from "../../../utils/index.js";
3
3
  // Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
4
- import { ErrorHandler } from '../../../utils/index.js';
4
+ import { ErrorHandler } from "../../../utils/index.js";
5
5
  // Import utils from barrel (requestContextService from ../utils/internal/requestContext.js)
6
- import { BaseErrorCode } from '../../../types-global/errors.js'; // Keep direct import for types-global
7
- import { requestContextService } from '../../../utils/index.js';
8
- import { GitCherryPickInputSchema, gitCherryPickLogic } from './logic.js';
6
+ import { BaseErrorCode } from "../../../types-global/errors.js"; // Keep direct import for types-global
7
+ import { requestContextService } from "../../../utils/index.js";
8
+ import { GitCherryPickInputSchema, gitCherryPickLogic, } from "./logic.js";
9
9
  let _getWorkingDirectory;
10
10
  let _getSessionId;
11
11
  /**
@@ -16,10 +16,10 @@ let _getSessionId;
16
16
  export function initializeGitCherryPickStateAccessors(getWdFn, getSidFn) {
17
17
  _getWorkingDirectory = getWdFn;
18
18
  _getSessionId = getSidFn;
19
- logger.info('State accessors initialized for git_cherry_pick tool registration.');
19
+ logger.info("State accessors initialized for git_cherry_pick tool registration.");
20
20
  }
21
- const TOOL_NAME = 'git_cherry_pick';
22
- const TOOL_DESCRIPTION = 'Applies the changes introduced by existing commits. Supports picking single commits or ranges, handling merge commits, and options like --no-commit and --signoff. Returns results as a JSON object, indicating success, failure, or conflicts.';
21
+ const TOOL_NAME = "git_cherry_pick";
22
+ const TOOL_DESCRIPTION = "Applies the changes introduced by existing commits. Supports picking single commits or ranges, handling merge commits, and options like --no-commit and --signoff. Returns results as a JSON object, indicating success, failure, or conflicts.";
23
23
  /**
24
24
  * Registers the git_cherry_pick tool with the MCP server.
25
25
  *
@@ -29,15 +29,18 @@ const TOOL_DESCRIPTION = 'Applies the changes introduced by existing commits. Su
29
29
  */
30
30
  export const registerGitCherryPickTool = async (server) => {
31
31
  if (!_getWorkingDirectory || !_getSessionId) {
32
- throw new Error('State accessors for git_cherry_pick must be initialized before registration.');
32
+ throw new Error("State accessors for git_cherry_pick must be initialized before registration.");
33
33
  }
34
- const operation = 'registerGitCherryPickTool';
34
+ const operation = "registerGitCherryPickTool";
35
35
  const context = requestContextService.createRequestContext({ operation });
36
36
  await ErrorHandler.tryCatch(async () => {
37
37
  server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitCherryPickInputSchema.shape, async (validatedArgs, callContext) => {
38
38
  const toolInput = validatedArgs;
39
39
  const toolOperation = `tool:${TOOL_NAME}`;
40
- const requestContext = requestContextService.createRequestContext({ operation: toolOperation, parentContext: callContext });
40
+ const requestContext = requestContextService.createRequestContext({
41
+ operation: toolOperation,
42
+ parentContext: callContext,
43
+ });
41
44
  const sessionId = _getSessionId(requestContext);
42
45
  const getWorkingDirectoryForSession = () => _getWorkingDirectory(sessionId);
43
46
  const logicContext = {
@@ -49,15 +52,19 @@ export const registerGitCherryPickTool = async (server) => {
49
52
  return await ErrorHandler.tryCatch(async () => {
50
53
  const cherryPickResult = await gitCherryPickLogic(toolInput, logicContext);
51
54
  const resultContent = {
52
- type: 'text',
55
+ type: "text",
53
56
  text: JSON.stringify(cherryPickResult, null, 2), // Pretty-print JSON
54
- contentType: 'application/json',
57
+ contentType: "application/json",
55
58
  };
56
59
  if (cherryPickResult.success) {
57
60
  logger.info(`Tool ${TOOL_NAME} executed successfully (Conflicts: ${!!cherryPickResult.conflicts}), returning JSON`, logicContext);
58
61
  }
59
62
  else {
60
- logger.warning(`Tool ${TOOL_NAME} failed: ${cherryPickResult.message}`, { ...logicContext, errorDetails: cherryPickResult.error, conflicts: cherryPickResult.conflicts });
63
+ logger.warning(`Tool ${TOOL_NAME} failed: ${cherryPickResult.message}`, {
64
+ ...logicContext,
65
+ errorDetails: cherryPickResult.error,
66
+ conflicts: cherryPickResult.conflicts,
67
+ });
61
68
  }
62
69
  return { content: [resultContent] };
63
70
  }, {
@@ -2,6 +2,6 @@
2
2
  * @fileoverview Barrel file for the git_clean tool.
3
3
  * Exports the registration function and state accessor initialization function.
4
4
  */
5
- export { registerGitCleanTool, initializeGitCleanStateAccessors } from './registration.js';
5
+ export { registerGitCleanTool, initializeGitCleanStateAccessors, } from "./registration.js";
6
6
  // Export types if needed elsewhere, e.g.:
7
7
  // export type { GitCleanInput, GitCleanResult } from './logic.js';
@@ -1,21 +1,37 @@
1
- import { exec } from 'child_process';
2
- import { promisify } from 'util';
3
- import { z } from 'zod';
1
+ import { exec } from "child_process";
2
+ import { promisify } from "util";
3
+ import { z } from "zod";
4
4
  // Import utils from barrel (logger from ../utils/internal/logger.js)
5
- import { logger } from '../../../utils/index.js';
5
+ import { logger } from "../../../utils/index.js";
6
6
  // Import utils from barrel (RequestContext from ../utils/internal/requestContext.js)
7
- import { BaseErrorCode, McpError } from '../../../types-global/errors.js'; // Keep direct import for types-global
7
+ import { BaseErrorCode, McpError } from "../../../types-global/errors.js"; // Keep direct import for types-global
8
8
  // Import utils from barrel (sanitization from ../utils/security/sanitization.js)
9
- import { sanitization } from '../../../utils/index.js';
9
+ import { sanitization } from "../../../utils/index.js";
10
10
  const execAsync = promisify(exec);
11
11
  // Define the input schema for the git_clean tool using Zod
12
12
  // No refinements needed here, but the 'force' check is critical in the logic
13
13
  export const GitCleanInputSchema = z.object({
14
- path: z.string().min(1).optional().default('.').describe("Path to the local Git repository. Defaults to the directory set via `git_set_working_dir` for the session; set 'git_set_working_dir' if not set."),
15
- force: z.boolean().describe("REQUIRED confirmation to run the command. Must be explicitly set to true to perform the clean operation. If false or omitted, the command will not run."),
16
- dryRun: z.boolean().default(false).describe("Show what would be deleted without actually deleting (-n flag)."),
17
- directories: z.boolean().default(false).describe("Remove untracked directories in addition to files (-d flag)."),
18
- ignored: z.boolean().default(false).describe("Remove ignored files as well (-x flag). Use with extreme caution."),
14
+ path: z
15
+ .string()
16
+ .min(1)
17
+ .optional()
18
+ .default(".")
19
+ .describe("Path to the local Git repository. Defaults to the directory set via `git_set_working_dir` for the session; set 'git_set_working_dir' if not set."),
20
+ force: z
21
+ .boolean()
22
+ .describe("REQUIRED confirmation to run the command. Must be explicitly set to true to perform the clean operation. If false or omitted, the command will not run."),
23
+ dryRun: z
24
+ .boolean()
25
+ .default(false)
26
+ .describe("Show what would be deleted without actually deleting (-n flag)."),
27
+ directories: z
28
+ .boolean()
29
+ .default(false)
30
+ .describe("Remove untracked directories in addition to files (-d flag)."),
31
+ ignored: z
32
+ .boolean()
33
+ .default(false)
34
+ .describe("Remove ignored files as well (-x flag). Use with extreme caution."),
19
35
  // exclude: z.string().optional().describe("Exclude files matching pattern (-e <pattern>)"), // Consider adding later
20
36
  });
21
37
  /**
@@ -28,11 +44,14 @@ export const GitCleanInputSchema = z.object({
28
44
  * @throws {McpError} Throws an McpError for path/validation failures, if force=false, or unexpected errors.
29
45
  */
30
46
  export async function gitCleanLogic(input, context) {
31
- const operation = 'gitCleanLogic';
47
+ const operation = "gitCleanLogic";
32
48
  logger.debug(`Executing ${operation}`, { ...context, input });
33
49
  // --- CRITICAL SAFETY CHECK ---
34
50
  if (!input.force) {
35
- logger.error("Attempted to run git clean without force=true.", { ...context, operation });
51
+ logger.error("Attempted to run git clean without force=true.", {
52
+ ...context,
53
+ operation,
54
+ });
36
55
  throw new McpError(BaseErrorCode.VALIDATION_ERROR, "Operation aborted: 'force' parameter must be explicitly set to true to execute 'git clean'. This is a destructive command.", { context, operation });
37
56
  }
38
57
  // Log that the force check passed
@@ -41,25 +60,41 @@ export async function gitCleanLogic(input, context) {
41
60
  try {
42
61
  // Resolve and sanitize the target path
43
62
  const workingDir = context.getWorkingDirectory();
44
- targetPath = (input.path && input.path !== '.')
45
- ? input.path
46
- : workingDir ?? '.';
47
- if (targetPath === '.' && !workingDir) {
63
+ targetPath =
64
+ input.path && input.path !== "." ? input.path : (workingDir ?? ".");
65
+ if (targetPath === "." && !workingDir) {
48
66
  logger.warning("Executing git clean in server's CWD as no path provided and no session WD set.", { ...context, operation });
49
67
  targetPath = process.cwd();
50
68
  }
51
- else if (targetPath === '.' && workingDir) {
69
+ else if (targetPath === "." && workingDir) {
52
70
  targetPath = workingDir;
53
- logger.debug(`Using session working directory: ${targetPath}`, { ...context, operation, sessionId: context.sessionId });
71
+ logger.debug(`Using session working directory: ${targetPath}`, {
72
+ ...context,
73
+ operation,
74
+ sessionId: context.sessionId,
75
+ });
54
76
  }
55
77
  else {
56
- logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
78
+ logger.debug(`Using provided path: ${targetPath}`, {
79
+ ...context,
80
+ operation,
81
+ });
57
82
  }
58
- targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true }).sanitizedPath;
59
- logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
83
+ targetPath = sanitization.sanitizePath(targetPath, {
84
+ allowAbsolute: true,
85
+ }).sanitizedPath;
86
+ logger.debug("Sanitized path", {
87
+ ...context,
88
+ operation,
89
+ sanitizedPath: targetPath,
90
+ });
60
91
  }
61
92
  catch (error) {
62
- logger.error('Path resolution or sanitization failed', { ...context, operation, error });
93
+ logger.error("Path resolution or sanitization failed", {
94
+ ...context,
95
+ operation,
96
+ error,
97
+ });
63
98
  if (error instanceof McpError)
64
99
  throw error;
65
100
  throw new McpError(BaseErrorCode.VALIDATION_ERROR, `Invalid path: ${error instanceof Error ? error.message : String(error)}`, { context, operation, originalError: error });
@@ -69,45 +104,62 @@ export async function gitCleanLogic(input, context) {
69
104
  // Force (-f) is always added because the logic checks input.force
70
105
  let command = `git -C "${targetPath}" clean -f`;
71
106
  if (input.dryRun) {
72
- command += ' -n';
107
+ command += " -n";
73
108
  }
74
109
  if (input.directories) {
75
- command += ' -d';
110
+ command += " -d";
76
111
  }
77
112
  if (input.ignored) {
78
- command += ' -x';
113
+ command += " -x";
79
114
  }
80
115
  logger.debug(`Executing command: ${command}`, { ...context, operation });
81
116
  const { stdout, stderr } = await execAsync(command);
82
117
  if (stderr) {
83
118
  // Log stderr as warning, as git clean might report non-fatal issues here
84
- logger.warning(`Git clean command produced stderr`, { ...context, operation, stderr });
119
+ logger.warning(`Git clean command produced stderr`, {
120
+ ...context,
121
+ operation,
122
+ stderr,
123
+ });
85
124
  }
86
125
  // Parse stdout to list affected files
87
- const filesAffected = stdout.trim().split('\n')
88
- .map(line => line.replace(/^Would remove /i, '').replace(/^Removing /i, '').trim()) // Clean up prefixes
89
- .filter(file => file); // Remove empty lines
126
+ const filesAffected = stdout
127
+ .trim()
128
+ .split("\n")
129
+ .map((line) => line
130
+ .replace(/^Would remove /i, "")
131
+ .replace(/^Removing /i, "")
132
+ .trim()) // Clean up prefixes
133
+ .filter((file) => file); // Remove empty lines
90
134
  const message = input.dryRun
91
135
  ? `Dry run complete. Files that would be removed: ${filesAffected.length}`
92
136
  : `Clean operation complete. Files removed: ${filesAffected.length}`;
93
- logger.info(`${operation} executed successfully`, { ...context, operation, path: targetPath, dryRun: input.dryRun, filesAffectedCount: filesAffected.length });
137
+ logger.info(message, {
138
+ ...context,
139
+ operation,
140
+ path: targetPath,
141
+ dryRun: input.dryRun,
142
+ filesAffectedCount: filesAffected.length,
143
+ });
94
144
  return { success: true, message, filesAffected, dryRun: input.dryRun };
95
145
  }
96
146
  catch (error) {
97
- const errorMessage = error.stderr || error.message || '';
98
- logger.error(`Failed to execute git clean command`, { ...context, operation, path: targetPath, error: errorMessage, stderr: error.stderr, stdout: error.stdout });
147
+ const errorMessage = error.stderr || error.message || "";
148
+ logger.error(`Failed to execute git clean command`, {
149
+ ...context,
150
+ operation,
151
+ path: targetPath,
152
+ error: errorMessage,
153
+ stderr: error.stderr,
154
+ stdout: error.stdout,
155
+ });
99
156
  // Specific error handling
100
- if (errorMessage.toLowerCase().includes('not a git repository')) {
157
+ if (errorMessage.toLowerCase().includes("not a git repository")) {
101
158
  throw new McpError(BaseErrorCode.NOT_FOUND, `Path is not a Git repository: ${targetPath}`, { context, operation, originalError: error });
102
159
  }
103
160
  // Git clean usually doesn't fail with specific messages like others,
104
161
  // but returns non-zero exit code on general failure.
105
- // Return structured failure for other git errors
106
- return {
107
- success: false,
108
- message: `Git clean failed for path: ${targetPath}.`,
109
- error: errorMessage,
110
- dryRun: input.dryRun // Still report dryRun status
111
- };
162
+ // Throw a generic McpError for other failures
163
+ throw new McpError(BaseErrorCode.INTERNAL_ERROR, `Git clean failed for path: ${targetPath}. Error: ${errorMessage}`, { context, operation, originalError: error });
112
164
  }
113
165
  }
@@ -1,12 +1,12 @@
1
1
  // Import utils from barrel (logger from ../utils/internal/logger.js)
2
- import { logger } from '../../../utils/index.js';
2
+ import { logger } from "../../../utils/index.js";
3
3
  // Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
4
- import { ErrorHandler } from '../../../utils/index.js';
4
+ import { ErrorHandler } from "../../../utils/index.js";
5
5
  // Import utils from barrel (requestContextService from ../utils/internal/requestContext.js)
6
- import { requestContextService } from '../../../utils/index.js';
6
+ import { requestContextService } from "../../../utils/index.js";
7
7
  // Import the schema and types
8
- import { BaseErrorCode } from '../../../types-global/errors.js'; // Keep direct import for types-global
9
- import { GitCleanInputSchema, gitCleanLogic } from './logic.js';
8
+ import { BaseErrorCode } from "../../../types-global/errors.js"; // Keep direct import for types-global
9
+ import { GitCleanInputSchema, gitCleanLogic, } from "./logic.js";
10
10
  let _getWorkingDirectory;
11
11
  let _getSessionId;
12
12
  /**
@@ -17,10 +17,10 @@ let _getSessionId;
17
17
  export function initializeGitCleanStateAccessors(getWdFn, getSidFn) {
18
18
  _getWorkingDirectory = getWdFn;
19
19
  _getSessionId = getSidFn;
20
- logger.info('State accessors initialized for git_clean tool registration.');
20
+ logger.info("State accessors initialized for git_clean tool registration.");
21
21
  }
22
- const TOOL_NAME = 'git_clean';
23
- const TOOL_DESCRIPTION = 'Removes untracked files from the working directory. Supports dry runs, removing directories, and removing ignored files. CRITICAL: Requires explicit `force: true` parameter for safety as this is a destructive operation. Returns results as a JSON object.';
22
+ const TOOL_NAME = "git_clean";
23
+ const TOOL_DESCRIPTION = "Removes untracked files from the working directory. Supports dry runs, removing directories, and removing ignored files. CRITICAL: Requires explicit `force: true` parameter for safety as this is a destructive operation. Returns results as a JSON object.";
24
24
  /**
25
25
  * Registers the git_clean tool with the MCP server.
26
26
  *
@@ -30,9 +30,9 @@ const TOOL_DESCRIPTION = 'Removes untracked files from the working directory. Su
30
30
  */
31
31
  export const registerGitCleanTool = async (server) => {
32
32
  if (!_getWorkingDirectory || !_getSessionId) {
33
- throw new Error('State accessors for git_clean must be initialized before registration.');
33
+ throw new Error("State accessors for git_clean must be initialized before registration.");
34
34
  }
35
- const operation = 'registerGitCleanTool';
35
+ const operation = "registerGitCleanTool";
36
36
  const context = requestContextService.createRequestContext({ operation });
37
37
  await ErrorHandler.tryCatch(async () => {
38
38
  // Register the tool using the schema's shape (no refinements here)
@@ -42,7 +42,10 @@ export const registerGitCleanTool = async (server) => {
42
42
  // Cast validatedArgs to the specific input type for use within the handler
43
43
  const toolInput = validatedArgs;
44
44
  const toolOperation = `tool:${TOOL_NAME}`;
45
- const requestContext = requestContextService.createRequestContext({ operation: toolOperation, parentContext: callContext });
45
+ const requestContext = requestContextService.createRequestContext({
46
+ operation: toolOperation,
47
+ parentContext: callContext,
48
+ });
46
49
  // --- SAFETY CHECK (Redundant but good practice) ---
47
50
  // The core logic already checks this, but adding a check here ensures
48
51
  // the intent is clear even before calling the logic.
@@ -50,13 +53,13 @@ export const registerGitCleanTool = async (server) => {
50
53
  logger.error(`Tool ${TOOL_NAME} called without force=true. Aborting.`, requestContext);
51
54
  // Return a structured error via CallToolResult
52
55
  const errorContent = {
53
- type: 'text',
56
+ type: "text",
54
57
  text: JSON.stringify({
55
58
  success: false,
56
59
  message: "Operation aborted: 'force' parameter must be explicitly set to true to execute 'git clean'.",
57
- dryRun: toolInput.dryRun // Include dryRun status
60
+ dryRun: toolInput.dryRun, // Include dryRun status
58
61
  }, null, 2),
59
- contentType: 'application/json',
62
+ contentType: "application/json",
60
63
  };
61
64
  return { content: [errorContent], isError: true }; // Indicate it's an error result
62
65
  }
@@ -75,9 +78,9 @@ export const registerGitCleanTool = async (server) => {
75
78
  const cleanResult = await gitCleanLogic(toolInput, logicContext);
76
79
  // Format the result as JSON within TextContent
77
80
  const resultContent = {
78
- type: 'text',
81
+ type: "text",
79
82
  text: JSON.stringify(cleanResult, null, 2),
80
- contentType: 'application/json',
83
+ contentType: "application/json",
81
84
  };
82
85
  // Log based on the success flag in the result
83
86
  if (cleanResult.success) {
@@ -2,6 +2,6 @@
2
2
  * @fileoverview Barrel file for the git_clear_working_dir tool.
3
3
  * Exports the registration function and related components.
4
4
  */
5
- export { registerGitClearWorkingDirTool, initializeGitClearWorkingDirStateAccessors } from './registration.js';
5
+ export { registerGitClearWorkingDirTool, initializeGitClearWorkingDirStateAccessors, } from "./registration.js";
6
6
  // Export types if needed elsewhere, e.g.:
7
7
  // export type { GitClearWorkingDirInput, GitClearWorkingDirResult } from './logic.js';
@@ -1,7 +1,7 @@
1
- import { z } from 'zod';
1
+ import { z } from "zod";
2
2
  // Import utils from barrel (logger from ../utils/internal/logger.js)
3
- import { BaseErrorCode, McpError } from '../../../types-global/errors.js'; // Keep direct import for types-global
4
- import { logger } from '../../../utils/index.js';
3
+ import { BaseErrorCode, McpError } from "../../../types-global/errors.js"; // Keep direct import for types-global
4
+ import { logger } from "../../../utils/index.js";
5
5
  // Define the Zod schema for input validation (no arguments needed)
6
6
  export const GitClearWorkingDirInputSchema = z.object({});
7
7
  /**
@@ -13,24 +13,27 @@ export const GitClearWorkingDirInputSchema = z.object({});
13
13
  * @returns {Promise<GitClearWorkingDirResult>} The result of the operation.
14
14
  * @throws {McpError} Throws McpError for operational errors.
15
15
  */
16
- export async function gitClearWorkingDirLogic(input, context // Assuming context provides session info and clearer
17
- ) {
18
- const operation = 'gitClearWorkingDirLogic';
19
- logger.info('Executing git_clear_working_dir logic', { ...context, operation });
16
+ export async function gitClearWorkingDirLogic(input, context) {
17
+ const operation = "gitClearWorkingDirLogic";
18
+ logger.debug(`Executing ${operation}`, { ...context, input });
20
19
  // --- Update Session State ---
21
20
  // This part needs access to the session state mechanism defined in server.ts
22
21
  // We assume the context provides a way to clear the working directory for the current session.
23
22
  try {
24
23
  context.clearWorkingDirectory();
25
- logger.info(`Working directory cleared for session ${context.sessionId || 'stdio'}`, { ...context, operation });
24
+ const message = `Working directory cleared for session ${context.sessionId || "stdio"}`;
25
+ logger.info(message, { ...context, operation });
26
26
  }
27
27
  catch (error) {
28
- logger.error('Failed to clear working directory in session state', error, { ...context, operation });
28
+ logger.error("Failed to clear working directory in session state", error, {
29
+ ...context,
30
+ operation,
31
+ });
29
32
  // This indicates an internal logic error in how state is passed/managed.
30
- throw new McpError(BaseErrorCode.INTERNAL_ERROR, 'Failed to update session state.', { context, operation });
33
+ throw new McpError(BaseErrorCode.INTERNAL_ERROR, "Failed to update session state.", { context, operation });
31
34
  }
32
35
  return {
33
36
  success: true,
34
- message: 'Global working directory setting cleared.',
37
+ message: "Global working directory setting cleared.",
35
38
  };
36
39
  }
@@ -1,11 +1,11 @@
1
1
  // Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
2
- import { ErrorHandler } from '../../../utils/index.js';
2
+ import { ErrorHandler } from "../../../utils/index.js";
3
3
  // Import utils from barrel (logger from ../utils/internal/logger.js)
4
- import { logger } from '../../../utils/index.js';
4
+ import { logger } from "../../../utils/index.js";
5
5
  // Import utils from barrel (requestContextService, RequestContext from ../utils/internal/requestContext.js)
6
- import { BaseErrorCode } from '../../../types-global/errors.js'; // Keep direct import for types-global
7
- import { requestContextService } from '../../../utils/index.js';
8
- import { GitClearWorkingDirInputSchema, gitClearWorkingDirLogic } from './logic.js';
6
+ import { BaseErrorCode } from "../../../types-global/errors.js"; // Keep direct import for types-global
7
+ import { requestContextService } from "../../../utils/index.js";
8
+ import { GitClearWorkingDirInputSchema, gitClearWorkingDirLogic, } from "./logic.js";
9
9
  let _clearWorkingDirectory;
10
10
  let _getSessionId;
11
11
  /**
@@ -17,9 +17,9 @@ let _getSessionId;
17
17
  export function initializeGitClearWorkingDirStateAccessors(clearFn, getFn) {
18
18
  _clearWorkingDirectory = clearFn;
19
19
  _getSessionId = getFn; // Can reuse the getter from the set tool
20
- logger.info('State accessors initialized for git_clear_working_dir tool registration.');
20
+ logger.info("State accessors initialized for git_clear_working_dir tool registration.");
21
21
  }
22
- const TOOL_NAME = 'git_clear_working_dir';
22
+ const TOOL_NAME = "git_clear_working_dir";
23
23
  const TOOL_DESCRIPTION = "Clears the session-specific working directory previously set by `git_set_working_dir`. Subsequent Git tool calls in this session will require an explicit `path` parameter or will default to the server's current working directory. Returns the result as a JSON object.";
24
24
  /**
25
25
  * Registers the git_clear_working_dir tool with the MCP server.
@@ -29,13 +29,16 @@ const TOOL_DESCRIPTION = "Clears the session-specific working directory previous
29
29
  */
30
30
  export async function registerGitClearWorkingDirTool(server) {
31
31
  if (!_clearWorkingDirectory || !_getSessionId) {
32
- throw new Error('State accessors for git_clear_working_dir must be initialized before registration.');
32
+ throw new Error("State accessors for git_clear_working_dir must be initialized before registration.");
33
33
  }
34
34
  try {
35
35
  server.tool(TOOL_NAME, TOOL_DESCRIPTION, GitClearWorkingDirInputSchema.shape, // Empty shape
36
36
  async (validatedArgs, callContext) => {
37
- const operation = 'tool:git_clear_working_dir';
38
- const requestContext = requestContextService.createRequestContext({ operation, parentContext: callContext });
37
+ const operation = "tool:git_clear_working_dir";
38
+ const requestContext = requestContextService.createRequestContext({
39
+ operation,
40
+ parentContext: callContext,
41
+ });
39
42
  const sessionId = _getSessionId(requestContext);
40
43
  // Define the session-specific clear function
41
44
  const clearWorkingDirectoryForSession = () => {
@@ -51,11 +54,14 @@ export async function registerGitClearWorkingDirTool(server) {
51
54
  const result = await gitClearWorkingDirLogic(validatedArgs, logicContext);
52
55
  // Format the successful result
53
56
  const responseContent = {
54
- type: 'text',
57
+ type: "text",
55
58
  text: JSON.stringify(result, null, 2),
56
- contentType: 'application/json',
59
+ contentType: "application/json",
57
60
  };
58
- logger.info(`Tool ${TOOL_NAME} executed successfully`, { ...logicContext, result });
61
+ logger.info(`Tool ${TOOL_NAME} executed successfully`, {
62
+ ...logicContext,
63
+ result,
64
+ });
59
65
  return { content: [responseContent] };
60
66
  }, {
61
67
  operation,
@@ -2,6 +2,6 @@
2
2
  * @fileoverview Barrel file for the git_clone tool.
3
3
  * Exports the registration function.
4
4
  */
5
- export { registerGitCloneTool } from './registration.js';
5
+ export { registerGitCloneTool } from "./registration.js";
6
6
  // Export types if needed elsewhere, e.g.:
7
7
  // export type { GitCloneInput, GitCloneResult } from './logic.js';