@cyanheads/git-mcp-server 2.0.2 → 2.0.3
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.
- package/README.md +45 -85
- package/dist/config/index.js +16 -18
- package/dist/index.js +80 -30
- package/dist/mcp-server/server.js +247 -523
- package/dist/mcp-server/tools/gitAdd/logic.js +9 -6
- package/dist/mcp-server/tools/gitAdd/registration.js +7 -4
- package/dist/mcp-server/tools/gitBranch/logic.js +23 -12
- package/dist/mcp-server/tools/gitBranch/registration.js +8 -5
- package/dist/mcp-server/tools/gitCheckout/logic.js +92 -44
- package/dist/mcp-server/tools/gitCheckout/registration.js +8 -5
- package/dist/mcp-server/tools/gitCherryPick/logic.js +10 -7
- package/dist/mcp-server/tools/gitCherryPick/registration.js +8 -5
- package/dist/mcp-server/tools/gitClean/logic.js +9 -6
- package/dist/mcp-server/tools/gitClean/registration.js +8 -5
- package/dist/mcp-server/tools/gitClearWorkingDir/logic.js +3 -2
- package/dist/mcp-server/tools/gitClearWorkingDir/registration.js +7 -4
- package/dist/mcp-server/tools/gitClone/logic.js +8 -5
- package/dist/mcp-server/tools/gitClone/registration.js +7 -4
- package/dist/mcp-server/tools/gitCommit/logic.js +98 -20
- package/dist/mcp-server/tools/gitCommit/registration.js +22 -15
- package/dist/mcp-server/tools/gitDiff/logic.js +9 -6
- package/dist/mcp-server/tools/gitDiff/registration.js +8 -5
- package/dist/mcp-server/tools/gitFetch/logic.js +10 -7
- package/dist/mcp-server/tools/gitFetch/registration.js +8 -5
- package/dist/mcp-server/tools/gitInit/index.js +2 -2
- package/dist/mcp-server/tools/gitInit/logic.js +9 -6
- package/dist/mcp-server/tools/gitInit/registration.js +66 -12
- package/dist/mcp-server/tools/gitLog/logic.js +53 -16
- package/dist/mcp-server/tools/gitLog/registration.js +8 -5
- package/dist/mcp-server/tools/gitMerge/logic.js +9 -6
- package/dist/mcp-server/tools/gitMerge/registration.js +8 -5
- package/dist/mcp-server/tools/gitPull/logic.js +11 -8
- package/dist/mcp-server/tools/gitPull/registration.js +7 -4
- package/dist/mcp-server/tools/gitPush/logic.js +12 -9
- package/dist/mcp-server/tools/gitPush/registration.js +7 -4
- package/dist/mcp-server/tools/gitRebase/logic.js +9 -6
- package/dist/mcp-server/tools/gitRebase/registration.js +8 -5
- package/dist/mcp-server/tools/gitRemote/logic.js +4 -5
- package/dist/mcp-server/tools/gitRemote/registration.js +2 -4
- package/dist/mcp-server/tools/gitReset/logic.js +5 -6
- package/dist/mcp-server/tools/gitReset/registration.js +2 -4
- package/dist/mcp-server/tools/gitSetWorkingDir/logic.js +5 -6
- package/dist/mcp-server/tools/gitSetWorkingDir/registration.js +22 -13
- package/dist/mcp-server/tools/gitShow/logic.js +5 -6
- package/dist/mcp-server/tools/gitShow/registration.js +3 -5
- package/dist/mcp-server/tools/gitStash/logic.js +5 -6
- package/dist/mcp-server/tools/gitStash/registration.js +3 -5
- package/dist/mcp-server/tools/gitStatus/logic.js +5 -6
- package/dist/mcp-server/tools/gitStatus/registration.js +2 -4
- package/dist/mcp-server/tools/gitTag/logic.js +3 -4
- package/dist/mcp-server/tools/gitTag/registration.js +2 -4
- package/dist/mcp-server/transports/authentication/authMiddleware.js +145 -0
- package/dist/mcp-server/transports/httpTransport.js +432 -0
- package/dist/mcp-server/transports/stdioTransport.js +87 -0
- package/dist/types-global/errors.js +2 -2
- package/dist/utils/index.js +12 -11
- package/dist/utils/{errorHandler.js → internal/errorHandler.js} +18 -8
- package/dist/utils/internal/index.js +3 -0
- package/dist/utils/internal/logger.js +254 -0
- package/dist/utils/{requestContext.js → internal/requestContext.js} +2 -3
- package/dist/utils/metrics/index.js +1 -0
- package/dist/utils/{tokenCounter.js → metrics/tokenCounter.js} +3 -3
- package/dist/utils/parsing/dateParser.js +62 -0
- package/dist/utils/parsing/index.js +2 -0
- package/dist/utils/{jsonParser.js → parsing/jsonParser.js} +3 -2
- package/dist/utils/{idGenerator.js → security/idGenerator.js} +4 -5
- package/dist/utils/security/index.js +3 -0
- package/dist/utils/{rateLimiter.js → security/rateLimiter.js} +7 -10
- package/dist/utils/{sanitization.js → security/sanitization.js} +4 -3
- package/package.json +12 -9
- package/dist/types-global/mcp.js +0 -59
- package/dist/types-global/tool.js +0 -1
- package/dist/utils/logger.js +0 -266
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { exec } from 'child_process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
5
|
+
import { logger } from '../../../utils/index.js';
|
|
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
|
|
8
|
+
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
9
|
+
import { sanitization } from '../../../utils/index.js';
|
|
7
10
|
const execAsync = promisify(exec);
|
|
8
11
|
// Define the input schema for the git_add tool using Zod
|
|
9
12
|
export const GitAddInputSchema = z.object({
|
|
10
|
-
path: z.string().min(1).optional().default('.').describe("Path to the Git repository. Defaults to the
|
|
13
|
+
path: z.string().min(1).optional().default('.').describe("Path to the Git repository. Defaults to the directory set via `git_set_working_dir` for the session; set 'git_set_working_dir' if not set."),
|
|
11
14
|
files: z.union([
|
|
12
15
|
z.string().min(1),
|
|
13
16
|
z.array(z.string().min(1))
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
4
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
5
|
+
// Import utils from barrel (requestContextService from ../utils/internal/requestContext.js)
|
|
6
|
+
import { requestContextService } from '../../../utils/index.js';
|
|
4
7
|
// Import the result type along with the function and input schema
|
|
5
|
-
import { addGitFiles, GitAddInputSchema } from './logic.js';
|
|
6
8
|
import { BaseErrorCode } from '../../../types-global/errors.js'; // Import BaseErrorCode
|
|
9
|
+
import { addGitFiles, GitAddInputSchema } from './logic.js';
|
|
7
10
|
let _getWorkingDirectory;
|
|
8
11
|
let _getSessionId;
|
|
9
12
|
/**
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { exec } from 'child_process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
5
|
+
import { logger } from '../../../utils/index.js';
|
|
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
|
|
8
|
+
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
9
|
+
import { sanitization } from '../../../utils/index.js';
|
|
7
10
|
const execAsync = promisify(exec);
|
|
8
11
|
// Define the BASE input schema for the git_branch tool using Zod
|
|
9
12
|
export const GitBranchBaseSchema = z.object({
|
|
10
|
-
path: z.string().min(1).optional().default('.').describe("Path to the local Git repository.
|
|
13
|
+
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."),
|
|
11
14
|
mode: z.enum(['list', 'create', 'delete', 'rename', 'show-current']).describe("The branch operation to perform: 'list', 'create', 'delete', 'rename', 'show-current'."),
|
|
12
|
-
branchName: z.string().min(1).optional().describe("The name of the branch. Required for 'create', 'delete', 'rename' modes."),
|
|
13
|
-
newBranchName: z.string().min(1).optional().describe("The new name for the branch. Required for 'rename' mode."),
|
|
14
|
-
startPoint: z.string().min(1).optional().describe("Optional commit hash, tag, or existing branch name to start the new branch from. Used only in 'create' mode. Defaults to HEAD."),
|
|
15
|
+
branchName: z.string().min(1).optional().describe("The name of the branch (e.g., 'feat/new-login', 'main'). Required for 'create', 'delete', 'rename' modes."),
|
|
16
|
+
newBranchName: z.string().min(1).optional().describe("The new name for the branch (e.g., 'fix/typo-in-readme'). Required for 'rename' mode."),
|
|
17
|
+
startPoint: z.string().min(1).optional().describe("Optional commit hash, tag, or existing branch name (e.g., 'main', 'v1.0.0', 'commit-hash') to start the new branch from. Used only in 'create' mode. Defaults to HEAD."),
|
|
15
18
|
force: z.boolean().default(false).describe("Force the operation. Use -D for delete, -M for rename, -f for create (if branch exists). Use with caution, as forcing operations can lead to data loss."),
|
|
16
19
|
all: z.boolean().default(false).describe("List both local and remote-tracking branches. Used only in 'list' mode."),
|
|
17
20
|
remote: z.boolean().default(false).describe("Act on remote-tracking branches. Used with 'list' (-r) or 'delete' (-r)."),
|
|
@@ -80,12 +83,20 @@ export async function gitBranchLogic(input, context) {
|
|
|
80
83
|
.map(line => {
|
|
81
84
|
const isCurrent = line.startsWith('* ');
|
|
82
85
|
const trimmedLine = line.replace(/^\*?\s+/, ''); // Remove leading '*' and spaces
|
|
86
|
+
// Determine isRemote based on the raw trimmed line BEFORE splitting
|
|
87
|
+
const isRemote = trimmedLine.startsWith('remotes/');
|
|
83
88
|
const parts = trimmedLine.split(/\s+/);
|
|
84
|
-
const name = parts[0];
|
|
85
|
-
const isRemote = name.startsWith('remotes/');
|
|
89
|
+
const name = parts[0]; // This might be 'remotes/origin/main' or just 'main'
|
|
86
90
|
const commitHash = parts[1] || undefined; // Verbose gives hash
|
|
87
91
|
const commitSubject = parts.slice(2).join(' ') || undefined; // Verbose gives subject
|
|
88
|
-
|
|
92
|
+
// Return the correct name (without 'remotes/' prefix if it was remote) and the isRemote flag
|
|
93
|
+
return {
|
|
94
|
+
name: isRemote ? name.split('/').slice(2).join('/') : name, // e.g., 'origin/main' or 'main'
|
|
95
|
+
isCurrent,
|
|
96
|
+
isRemote, // Use the flag determined before splitting
|
|
97
|
+
commitHash,
|
|
98
|
+
commitSubject
|
|
99
|
+
};
|
|
89
100
|
});
|
|
90
101
|
const currentBranch = branches.find(b => b.isCurrent)?.name;
|
|
91
102
|
result = { success: true, mode: 'list', branches, currentBranch };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
4
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
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 { GitBranchBaseSchema, gitBranchLogic } from './logic.js';
|
|
6
9
|
let _getWorkingDirectory;
|
|
7
10
|
let _getSessionId;
|
|
8
11
|
/**
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { exec } from 'child_process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
5
|
+
import { logger } from '../../../utils/index.js';
|
|
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
|
|
8
|
+
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
9
|
+
import { sanitization } from '../../../utils/index.js';
|
|
7
10
|
const execAsync = promisify(exec);
|
|
8
11
|
// Define the input schema for the git_checkout tool using Zod
|
|
9
12
|
export const GitCheckoutInputSchema = z.object({
|
|
10
|
-
path: z.string().min(1).optional().default('.').describe("Path to the Git repository. Defaults to the session
|
|
11
|
-
branchOrPath: z.string().min(1).describe("The branch name, commit hash, tag, or file path(s) to checkout."),
|
|
12
|
-
newBranch: z.string().optional().describe("Create a new branch named <new_branch> and start it at <branchOrPath>."),
|
|
13
|
+
path: z.string().min(1).optional().default('.').describe("Path to the Git repository. Defaults to the directory set via `git_set_working_dir` for the session; set 'git_set_working_dir' if not set."),
|
|
14
|
+
branchOrPath: z.string().min(1).describe("The branch name (e.g., 'main'), commit hash, tag, or file path(s) (e.g., './src/file.ts') to checkout."),
|
|
15
|
+
newBranch: z.string().optional().describe("Create a new branch named <new_branch> (e.g., 'feat/new-feature') and start it at <branchOrPath>."),
|
|
13
16
|
force: z.boolean().optional().default(false).describe("Force checkout even if there are uncommitted changes (use with caution, discards local changes)."),
|
|
14
17
|
// Add other relevant git checkout options as needed (e.g., --track, -b for new branch shorthand)
|
|
15
18
|
});
|
|
@@ -72,52 +75,53 @@ export async function checkoutGit(input, context) {
|
|
|
72
75
|
let currentBranch = undefined;
|
|
73
76
|
let newBranchCreated = !!input.newBranch;
|
|
74
77
|
let filesRestored = undefined;
|
|
78
|
+
let isDetachedHead = false;
|
|
79
|
+
let isFileCheckout = false;
|
|
80
|
+
// --- Initial analysis of checkout output ---
|
|
75
81
|
// Extract previous branch if available
|
|
76
82
|
const prevBranchMatch = stderr.match(/Switched to.*? from ['"]?(.*?)['"]?/);
|
|
77
83
|
if (prevBranchMatch) {
|
|
78
84
|
previousBranch = prevBranchMatch[1];
|
|
79
85
|
}
|
|
80
|
-
//
|
|
81
|
-
if (stderr.includes('Switched to branch')) {
|
|
82
|
-
const currentBranchMatch = stderr.match(/Switched to branch ['"]?(.*?)['"]?/);
|
|
83
|
-
if (currentBranchMatch)
|
|
84
|
-
currentBranch = currentBranchMatch[1];
|
|
85
|
-
message = `Switched to branch '${currentBranch || input.branchOrPath}'.`;
|
|
86
|
-
}
|
|
87
|
-
else if (stderr.includes('Switched to a new branch')) {
|
|
86
|
+
// Determine primary outcome from stderr/stdout
|
|
87
|
+
if (stderr.includes('Switched to a new branch')) {
|
|
88
88
|
const currentBranchMatch = stderr.match(/Switched to a new branch ['"]?(.*?)['"]?/);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
currentBranch = currentBranchMatch ? currentBranchMatch[1] : input.newBranch; // Use matched or input
|
|
90
|
+
message = `Switched to new branch '${currentBranch}'.`;
|
|
91
|
+
newBranchCreated = true;
|
|
92
|
+
}
|
|
93
|
+
else if (stderr.includes('Switched to branch')) {
|
|
94
|
+
const currentBranchMatch = stderr.match(/Switched to branch ['"]?(.*?)['"]?/);
|
|
95
|
+
currentBranch = currentBranchMatch ? currentBranchMatch[1] : input.branchOrPath; // Use matched or input
|
|
96
|
+
message = `Switched to branch '${currentBranch}'.`;
|
|
93
97
|
}
|
|
94
98
|
else if (stderr.includes('Already on')) {
|
|
95
99
|
const currentBranchMatch = stderr.match(/Already on ['"]?(.*?)['"]?/);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const statusResult = await execAsync(`git -C "${targetPath}" branch --show-current`);
|
|
108
|
-
currentBranch = statusResult.stdout.trim();
|
|
100
|
+
currentBranch = currentBranchMatch ? currentBranchMatch[1] : input.branchOrPath; // Use matched or input
|
|
101
|
+
message = `Already on '${currentBranch}'.`;
|
|
102
|
+
}
|
|
103
|
+
else if (stderr.includes('Updated N path') || stdout.includes('Updated N path') || stderr.includes('Your branch is up to date with')) { // Checking out files or confirming current state
|
|
104
|
+
// Check if the input looks like file paths rather than a branch/commit
|
|
105
|
+
// This is heuristic - might need refinement if branch names look like paths
|
|
106
|
+
if (input.branchOrPath.includes('/') || input.branchOrPath.includes('.')) {
|
|
107
|
+
isFileCheckout = true;
|
|
108
|
+
message = `Restored or checked path(s): ${input.branchOrPath}`;
|
|
109
|
+
filesRestored = input.branchOrPath.split('\n').map(p => p.trim()).filter(p => p.length > 0);
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
else {
|
|
112
|
+
// Assume it was just confirming the current branch state
|
|
113
|
+
message = stderr.trim() || stdout.trim() || `Checked out ${input.branchOrPath}.`;
|
|
112
114
|
}
|
|
113
115
|
}
|
|
114
116
|
else if (stderr.includes('Previous HEAD position was') && stderr.includes('HEAD is now at')) { // Detached HEAD
|
|
115
117
|
message = `Checked out commit ${input.branchOrPath} (Detached HEAD state).`;
|
|
116
|
-
currentBranch = 'Detached HEAD';
|
|
118
|
+
currentBranch = 'Detached HEAD';
|
|
119
|
+
isDetachedHead = true;
|
|
117
120
|
}
|
|
118
|
-
else if (stderr.includes('Note: switching to')) { //
|
|
121
|
+
else if (stderr.includes('Note: switching to') || stderr.includes('Note: checking out')) { // Other detached HEAD variants
|
|
119
122
|
message = `Checked out ${input.branchOrPath} (Detached HEAD state).`;
|
|
120
123
|
currentBranch = 'Detached HEAD';
|
|
124
|
+
isDetachedHead = true;
|
|
121
125
|
}
|
|
122
126
|
else if (message.includes('fatal:')) {
|
|
123
127
|
success = false;
|
|
@@ -125,19 +129,63 @@ export async function checkoutGit(input, context) {
|
|
|
125
129
|
logger.error(`Git checkout command indicated failure: ${message}`, { ...context, operation, stdout, stderr });
|
|
126
130
|
}
|
|
127
131
|
else if (!message && !stdout && !stderr) {
|
|
128
|
-
message = 'Checkout command executed,
|
|
129
|
-
logger.
|
|
130
|
-
|
|
132
|
+
message = 'Checkout command executed silently.'; // Assume success, will verify branch below
|
|
133
|
+
logger.info(message, { ...context, operation });
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Some other message, treat as informational for now
|
|
137
|
+
message = stderr.trim() || stdout.trim();
|
|
138
|
+
logger.info(`Git checkout produced message: ${message}`, { ...context, operation });
|
|
139
|
+
}
|
|
140
|
+
// --- Get definitive current branch IF checkout was successful AND not file checkout/detached HEAD ---
|
|
141
|
+
if (success && !isFileCheckout && !isDetachedHead) {
|
|
131
142
|
try {
|
|
143
|
+
logger.debug('Attempting to get current branch via git branch --show-current', { ...context, operation });
|
|
132
144
|
const statusResult = await execAsync(`git -C "${targetPath}" branch --show-current`);
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
const definitiveCurrentBranch = statusResult.stdout.trim();
|
|
146
|
+
if (definitiveCurrentBranch) {
|
|
147
|
+
currentBranch = definitiveCurrentBranch;
|
|
148
|
+
logger.info(`Confirmed current branch: ${currentBranch}`, { ...context, operation });
|
|
149
|
+
// Refine message if it wasn't specific before
|
|
150
|
+
if (message.startsWith('Checkout command executed silently') || message.startsWith('Checked out ')) {
|
|
151
|
+
message = `Checked out '${currentBranch}'.`;
|
|
152
|
+
}
|
|
153
|
+
else if (message.startsWith('Already on') && !message.includes(`'${currentBranch}'`)) {
|
|
154
|
+
message = `Already on '${currentBranch}'.`; // Update if initial parse was wrong
|
|
155
|
+
}
|
|
156
|
+
else if (message.startsWith('Switched to branch') && !message.includes(`'${currentBranch}'`)) {
|
|
157
|
+
message = `Switched to branch '${currentBranch}'.`; // Update if initial parse was wrong
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// Command succeeded but returned empty - might be detached HEAD after all?
|
|
162
|
+
logger.warning('git branch --show-current returned empty, possibly detached HEAD?', { ...context, operation });
|
|
163
|
+
// Keep potentially parsed 'Detached HEAD' or fallback to input if needed
|
|
164
|
+
currentBranch = currentBranch || 'Unknown (possibly detached)';
|
|
165
|
+
if (!message.includes('Detached HEAD'))
|
|
166
|
+
message += ' (Could not confirm branch name).';
|
|
167
|
+
}
|
|
135
168
|
}
|
|
136
169
|
catch (statusError) {
|
|
137
|
-
logger.warning('Could not determine current branch after
|
|
170
|
+
logger.warning('Could not determine current branch after checkout', { ...context, operation, error: statusError.message });
|
|
171
|
+
// Keep potentially parsed 'Detached HEAD' or fallback to input if needed
|
|
172
|
+
currentBranch = currentBranch || 'Unknown (error checking)';
|
|
173
|
+
if (!message.includes('Detached HEAD'))
|
|
174
|
+
message += ' (Error checking branch name).';
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (success && isFileCheckout) {
|
|
178
|
+
// If it was a file checkout, still try to get the branch name for context
|
|
179
|
+
try {
|
|
180
|
+
const statusResult = await execAsync(`git -C "${targetPath}" branch --show-current`);
|
|
181
|
+
currentBranch = statusResult.stdout.trim() || 'Unknown (possibly detached)';
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
currentBranch = 'Unknown (error checking)';
|
|
138
185
|
}
|
|
186
|
+
logger.info(`Current branch after file checkout: ${currentBranch}`, { ...context, operation });
|
|
139
187
|
}
|
|
140
|
-
logger.info(`${operation} completed`, { ...context, operation, path: targetPath, success, message });
|
|
188
|
+
logger.info(`${operation} completed`, { ...context, operation, path: targetPath, success, message, currentBranch });
|
|
141
189
|
return { success, message, previousBranch, currentBranch, newBranchCreated, filesRestored };
|
|
142
190
|
}
|
|
143
191
|
catch (error) {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
2
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
4
|
+
import { logger } from '../../../utils/index.js';
|
|
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 { checkoutGit, GitCheckoutInputSchema } from './logic.js';
|
|
6
9
|
let _getWorkingDirectory;
|
|
7
10
|
let _getSessionId;
|
|
8
11
|
/**
|
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { exec } from 'child_process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
5
|
+
import { logger } from '../../../utils/index.js';
|
|
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
|
|
8
|
+
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
9
|
+
import { sanitization } from '../../../utils/index.js';
|
|
7
10
|
const execAsync = promisify(exec);
|
|
8
11
|
// Define the input schema for the git_cherry-pick tool using Zod
|
|
9
12
|
export const GitCherryPickInputSchema = z.object({
|
|
10
|
-
path: z.string().min(1).optional().default('.').describe("Path to the local Git repository.
|
|
13
|
+
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."),
|
|
11
14
|
commitRef: z.string().min(1).describe("The commit reference(s) to cherry-pick (e.g., 'hash1', 'hash1..hash3', 'branchName~3..branchName')."),
|
|
12
15
|
mainline: z.number().int().min(1).optional().describe("Specify the parent number (starting from 1) when cherry-picking a merge commit."),
|
|
13
|
-
strategy: z.enum(['recursive', 'resolve', 'ours', 'theirs', 'octopus', 'subtree']).optional().describe("Specifies
|
|
16
|
+
strategy: z.enum(['recursive', 'resolve', 'ours', 'theirs', 'octopus', 'subtree']).optional().describe("Specifies a merge strategy *option* (passed via -X)."),
|
|
14
17
|
noCommit: z.boolean().default(false).describe("Apply the changes but do not create a commit."),
|
|
15
18
|
signoff: z.boolean().default(false).describe("Add a Signed-off-by line to the commit message."),
|
|
16
19
|
// Add options for conflict handling? (e.g., --continue, --abort, --skip) - Maybe separate tool or mode?
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
4
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
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
9
|
let _getWorkingDirectory;
|
|
7
10
|
let _getSessionId;
|
|
8
11
|
/**
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { exec } from 'child_process';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
5
|
+
import { logger } from '../../../utils/index.js';
|
|
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
|
|
8
|
+
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
9
|
+
import { sanitization } from '../../../utils/index.js';
|
|
7
10
|
const execAsync = promisify(exec);
|
|
8
11
|
// Define the input schema for the git_clean tool using Zod
|
|
9
12
|
// No refinements needed here, but the 'force' check is critical in the logic
|
|
10
13
|
export const GitCleanInputSchema = z.object({
|
|
11
|
-
path: z.string().min(1).optional().default('.').describe("Path to the local Git repository.
|
|
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."),
|
|
12
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."),
|
|
13
16
|
dryRun: z.boolean().default(false).describe("Show what would be deleted without actually deleting (-n flag)."),
|
|
14
17
|
directories: z.boolean().default(false).describe("Remove untracked directories in addition to files (-d flag)."),
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
2
|
+
import { logger } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
4
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
5
|
+
// Import utils from barrel (requestContextService from ../utils/internal/requestContext.js)
|
|
6
|
+
import { requestContextService } from '../../../utils/index.js';
|
|
4
7
|
// Import the schema and types
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
8
|
+
import { BaseErrorCode } from '../../../types-global/errors.js'; // Keep direct import for types-global
|
|
9
|
+
import { GitCleanInputSchema, gitCleanLogic } from './logic.js';
|
|
7
10
|
let _getWorkingDirectory;
|
|
8
11
|
let _getSessionId;
|
|
9
12
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
3
|
-
import {
|
|
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';
|
|
4
5
|
// Define the Zod schema for input validation (no arguments needed)
|
|
5
6
|
export const GitClearWorkingDirInputSchema = z.object({});
|
|
6
7
|
/**
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
2
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
4
|
+
import { logger } from '../../../utils/index.js';
|
|
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';
|
|
4
8
|
import { GitClearWorkingDirInputSchema, gitClearWorkingDirLogic } from './logic.js';
|
|
5
|
-
import { BaseErrorCode } from '../../../types-global/errors.js';
|
|
6
9
|
let _clearWorkingDirectory;
|
|
7
10
|
let _getSessionId;
|
|
8
11
|
/**
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { promisify } from 'util';
|
|
3
1
|
import { exec } from 'child_process';
|
|
4
2
|
import fs from 'fs/promises';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
6
|
+
import { logger } from '../../../utils/index.js';
|
|
7
|
+
// Import utils from barrel (RequestContext from ../utils/internal/requestContext.js)
|
|
8
|
+
import { BaseErrorCode, McpError } from '../../../types-global/errors.js'; // Keep direct import for types-global
|
|
9
|
+
// Import utils from barrel (sanitization from ../utils/security/sanitization.js)
|
|
10
|
+
import { sanitization } from '../../../utils/index.js';
|
|
8
11
|
const execAsync = promisify(exec);
|
|
9
12
|
// Define the input schema for the git_clone tool using Zod
|
|
10
13
|
export const GitCloneInputSchema = z.object({
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
// Import utils from barrel (ErrorHandler from ../utils/internal/errorHandler.js)
|
|
2
|
+
import { ErrorHandler } from '../../../utils/index.js';
|
|
3
|
+
// Import utils from barrel (logger from ../utils/internal/logger.js)
|
|
4
|
+
import { logger } from '../../../utils/index.js';
|
|
5
|
+
// Import utils from barrel (requestContextService from ../utils/internal/requestContext.js)
|
|
6
|
+
import { requestContextService } from '../../../utils/index.js';
|
|
4
7
|
import { GitCloneInputSchema, gitCloneLogic } from './logic.js';
|
|
5
|
-
import { BaseErrorCode } from '../../../types-global/errors.js';
|
|
8
|
+
import { BaseErrorCode } from '../../../types-global/errors.js'; // Keep direct import for types-global
|
|
6
9
|
const TOOL_NAME = 'git_clone';
|
|
7
10
|
const TOOL_DESCRIPTION = 'Clones a Git repository from a given URL into a specified absolute directory path. Supports cloning specific branches and setting clone depth.';
|
|
8
11
|
/**
|