#
tokens: 44808/50000 34/34 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── jest.config.js
├── package.json
├── README.md
├── src
│   ├── caching
│   │   ├── cache.ts
│   │   └── repository-cache.ts
│   ├── common
│   │   └── command-builder.ts
│   ├── errors
│   │   ├── error-handler.ts
│   │   └── error-types.ts
│   ├── git-operations.ts
│   ├── index.ts
│   ├── monitoring
│   │   ├── performance.ts
│   │   └── types.ts
│   ├── operations
│   │   ├── base
│   │   │   ├── base-operation.ts
│   │   │   └── operation-result.ts
│   │   ├── branch
│   │   │   ├── branch-operations.ts
│   │   │   └── branch-types.ts
│   │   ├── remote
│   │   │   ├── remote-operations.ts
│   │   │   └── remote-types.ts
│   │   ├── repository
│   │   │   └── repository-operations.ts
│   │   ├── sync
│   │   │   ├── sync-operations.ts
│   │   │   └── sync-types.ts
│   │   ├── tag
│   │   │   ├── tag-operations.ts
│   │   │   └── tag-types.ts
│   │   └── working-tree
│   │       ├── working-tree-operations.ts
│   │       └── working-tree-types.ts
│   ├── tool-handler.ts
│   ├── types.ts
│   └── utils
│       ├── command.ts
│       ├── logger.ts
│       ├── path.ts
│       ├── paths.ts
│       └── repository.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Dependencies
node_modules/
package-lock.json

# Build output
build/
dist/
*.tsbuildinfo

# Environment variables
.env
.env.local
.env.*.local

# IDE
.vscode/
.idea/
*.swp
*.swo

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# System files
.DS_Store
Thumbs.db

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# Git MCP Server

A Model Context Protocol (MCP) server that provides enhanced Git operations through a standardized interface. This server integrates with the MCP ecosystem to provide Git functionality to AI assistants.

## Features

- **Core Git Operations**: init, clone, status, add, commit, push, pull
- **Branch Management**: list, create, delete, checkout
- **Tag Operations**: list, create, delete
- **Remote Management**: list, add, remove
- **Stash Operations**: list, save, pop
- **Bulk Actions**: Execute multiple Git operations in sequence
- **GitHub Integration**: Built-in GitHub support via Personal Access Token
- **Path Resolution**: Smart path handling with optional default path configuration
- **Error Handling**: Comprehensive error handling with custom error types
- **Repository Caching**: Efficient repository state management
- **Performance Monitoring**: Built-in performance tracking

## Installation

1. Clone the repository:
```bash
git clone https://github.com/yourusername/git-mcp-v2.git
cd git-mcp-v2
```

2. Install dependencies:
```bash
npm install
```

3. Build the project:
```bash
npm run build
```

## Configuration

Add to your MCP settings file:

```json
{
  "mcpServers": {
    "git-v2": {
      "command": "node",
      "args": ["path/to/git-mcp-v2/build/index.js"],
      "env": {
        "GIT_DEFAULT_PATH": "/path/to/default/git/directory",
        "GITHUB_PERSONAL_ACCESS_TOKEN": "your-github-pat"
      }
    }
  }
}
```

## Environment Variables

- `GIT_DEFAULT_PATH`: (Optional) Default path for Git operations
- `GITHUB_PERSONAL_ACCESS_TOKEN`: (Optional) GitHub Personal Access Token for GitHub operations

## Available Tools

### Basic Operations
- `init`: Initialize a new Git repository
- `clone`: Clone a repository
- `status`: Get repository status
- `add`: Stage files
- `commit`: Create a commit
- `push`: Push commits to remote
- `pull`: Pull changes from remote

### Branch Operations
- `branch_list`: List all branches
- `branch_create`: Create a new branch
- `branch_delete`: Delete a branch
- `checkout`: Switch branches or restore working tree files

### Tag Operations
- `tag_list`: List tags
- `tag_create`: Create a tag
- `tag_delete`: Delete a tag

### Remote Operations
- `remote_list`: List remotes
- `remote_add`: Add a remote
- `remote_remove`: Remove a remote

### Stash Operations
- `stash_list`: List stashes
- `stash_save`: Save changes to stash
- `stash_pop`: Apply and remove a stash

### Bulk Operations
- `bulk_action`: Execute multiple Git operations in sequence

## Development

```bash
# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Run linter
npm run lint

# Format code
npm run format
```

## License

MIT

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

```

--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------

```javascript
/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
  preset: 'ts-jest',
  testEnvironment: 'node',
  extensionsToTreatAsEsm: ['.ts'],
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  transform: {
    '^.+\\.tsx?$': [
      'ts-jest',
      {
        useESM: true,
      },
    ],
  },
  coverageDirectory: 'coverage',
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.d.ts',
    '!src/**/index.ts',
    '!src/**/*.types.ts'
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  },
  testMatch: [
    '<rootDir>/tests/**/*.test.ts'
  ],
  setupFilesAfterEnv: [
    '<rootDir>/tests/setup.ts'
  ],
  testPathIgnorePatterns: [
    '/node_modules/',
    '/build/'
  ],
  verbose: true,
  testTimeout: 10000
};

```

--------------------------------------------------------------------------------
/src/monitoring/types.ts:
--------------------------------------------------------------------------------

```typescript
import { GitMcpError } from '../errors/error-types.js';
import { ErrorCategory, ErrorSeverity } from '../errors/error-types.js';
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';

/**
 * Performance monitoring types
 */

/**
 * Performance error context
 */
export interface PerformanceErrorContext {
  currentUsage?: number;
  threshold?: number;
  operation?: string;
  details?: Record<string, any>;
  [key: string]: unknown;  // Index signature for additional properties
}

/**
 * Performance error with context
 */
export class PerformanceError extends GitMcpError {
  constructor(
    message: string,
    context: PerformanceErrorContext
  ) {
    super(
      ErrorCode.InternalError,
      message,
      ErrorSeverity.HIGH,
      ErrorCategory.SYSTEM,
      {
        operation: context.operation || 'performance',
        timestamp: Date.now(),
        severity: ErrorSeverity.HIGH,
        category: ErrorCategory.SYSTEM,
        details: context
      }
    );
    this.name = 'PerformanceError';
  }
}

```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "git-mcp-server",
  "version": "1.0.0",
  "description": "A Model Context Protocol server",
  "private": true,
  "type": "module",
  "bin": {
    "git-mcp-server": "./build/index.js"
  },
  "files": [
    "build"
  ],
  "scripts": {
    "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
    "prepare": "npm run build",
    "watch": "tsc --watch",
    "inspector": "npx @modelcontextprotocol/inspector build/index.js",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "eslint src --ext .ts",
    "format": "prettier --write \"src/**/*.ts\"",
    "clean": "rimraf build coverage"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "1.0.4",
    "simple-git": "^3.27.0"
  },
  "devDependencies": {
    "@types/jest": "^29.5.11",
    "@types/node": "^20.17.10",
    "@typescript-eslint/eslint-plugin": "^6.19.0",
    "@typescript-eslint/parser": "^6.19.0",
    "eslint": "^8.56.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-jest": "^27.6.3",
    "jest": "^29.7.0",
    "prettier": "^3.2.4",
    "rimraf": "^5.0.5",
    "ts-jest": "^29.1.1",
    "typescript": "^5.3.3"
  }
}

```

--------------------------------------------------------------------------------
/src/operations/base/operation-result.ts:
--------------------------------------------------------------------------------

```typescript
import { GitToolContent } from '../../types.js';
import { GitMcpError } from '../../errors/error-types.js';

/**
 * Represents the result of a Git operation with proper type safety
 */
export interface GitOperationResult<T = void> {
  /** Whether the operation was successful */
  success: boolean;
  
  /** Operation-specific data if successful */
  data?: T;
  
  /** Error information if operation failed */
  error?: GitMcpError;
  
  /** Standard MCP tool response content */
  content: GitToolContent[];
  
  /** Additional metadata about the operation */
  meta?: Record<string, unknown>;
}

/**
 * Base interface for all Git operation options
 */
export interface GitOperationOptions {
  /** Operation path override */
  path?: string;
  
  /** Whether to use caching */
  useCache?: boolean;
  
  /** Whether to invalidate cache after operation */
  invalidateCache?: boolean;
}

/**
 * Common result types for Git operations
 */
import { CommandResult as BaseCommandResult } from '../../utils/command.js';

export interface CommandResult extends BaseCommandResult {
  // Extend the base command result with any additional fields we need
}

export interface ListResult {
  items: string[];
  raw: string;
}

export interface StatusResult {
  staged: string[];
  unstaged: string[];
  untracked: string[];
  raw: string;
}

export interface BranchResult {
  current: string;
  branches: string[];
  raw: string;
}

export interface TagResult {
  tags: string[];
  raw: string;
}

export interface RemoteResult {
  remotes: Array<{
    name: string;
    url: string;
    purpose: 'fetch' | 'push';
  }>;
  raw: string;
}

export interface StashResult {
  stashes: Array<{
    index: number;
    message: string;
  }>;
  raw: string;
}

```

--------------------------------------------------------------------------------
/src/operations/tag/tag-types.ts:
--------------------------------------------------------------------------------

```typescript
import { GitOperationOptions } from '../base/operation-result.js';

/**
 * Options for listing tags
 */
export interface TagListOptions extends GitOperationOptions {
  /** Show tag message */
  showMessage?: boolean;
  /** Sort tags by specific key */
  sort?: 'version' | 'creatordate' | 'taggerdate';
  /** Show only tags containing the specified commit */
  contains?: string;
  /** Match tags with pattern */
  pattern?: string;
}

/**
 * Options for creating tags
 */
export interface TagCreateOptions extends GitOperationOptions {
  /** Name of the tag to create */
  name: string;
  /** Tag message (creates annotated tag) */
  message?: string;
  /** Whether to force create even if tag exists */
  force?: boolean;
  /** Create a signed tag */
  sign?: boolean;
  /** Specific commit to tag */
  commit?: string;
}

/**
 * Options for deleting tags
 */
export interface TagDeleteOptions extends GitOperationOptions {
  /** Name of the tag to delete */
  name: string;
  /** Whether to force delete */
  force?: boolean;
  /** Also delete the tag from remotes */
  remote?: boolean;
}

/**
 * Structured tag information
 */
export interface TagInfo {
  /** Tag name */
  name: string;
  /** Whether this is an annotated tag */
  annotated: boolean;
  /** Tag message if annotated */
  message?: string;
  /** Tagger information if annotated */
  tagger?: {
    name: string;
    email: string;
    date: string;
  };
  /** Commit that is tagged */
  commit: string;
  /** Whether this is a signed tag */
  signed: boolean;
}

/**
 * Result of tag listing operation
 */
export interface TagListResult {
  /** List of all tags */
  tags: TagInfo[];
  /** Raw command output */
  raw: string;
}

/**
 * Result of tag creation operation
 */
export interface TagCreateResult {
  /** Name of created tag */
  name: string;
  /** Whether it's an annotated tag */
  annotated: boolean;
  /** Whether it's signed */
  signed: boolean;
  /** Tagged commit */
  commit?: string;
  /** Raw command output */
  raw: string;
}

/**
 * Result of tag deletion operation
 */
export interface TagDeleteResult {
  /** Name of deleted tag */
  name: string;
  /** Whether it was force deleted */
  forced: boolean;
  /** Raw command output */
  raw: string;
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { ToolHandler } from './tool-handler.js';
import { logger } from './utils/logger.js';
import { CommandExecutor } from './utils/command.js';
import { PathResolver } from './utils/paths.js';

async function validateDefaultPath(): Promise<void> {
  const defaultPath = process.env.GIT_DEFAULT_PATH;
  if (!defaultPath) {
    logger.warn('startup', 'GIT_DEFAULT_PATH not set - absolute paths will be required for all operations');
    return;
  }

  try {
    // Validate the default path exists and is accessible
    PathResolver.validatePath(defaultPath, 'startup', {
      mustExist: true,
      mustBeDirectory: true,
      createIfMissing: true
    });
    logger.info('startup', 'Default git path validated', defaultPath);
  } catch (error) {
    logger.error('startup', 'Invalid GIT_DEFAULT_PATH', defaultPath, error as Error);
    throw new McpError(
      ErrorCode.InternalError,
      `Invalid GIT_DEFAULT_PATH: ${(error as Error).message}`
    );
  }
}

async function main() {
  try {
    // Validate git installation first
    await CommandExecutor.validateGitInstallation('startup');
    logger.info('startup', 'Git installation validated');

    // Validate default path if provided
    await validateDefaultPath();

    // Create and configure server
    const server = new Server(
      {
        name: 'git-mcp-server',
        version: '1.0.0',
      },
      {
        capabilities: {
          tools: {},
        },
      }
    );

    // Set up error handling
    server.onerror = (error) => {
      if (error instanceof McpError) {
        logger.error('server', error.message, undefined, error);
      } else {
        logger.error('server', 'Unexpected error', undefined, error as Error);
      }
    };

    // Initialize tool handler
    new ToolHandler(server);

    // Connect server
    const transport = new StdioServerTransport();
    await server.connect(transport);
    logger.info('server', 'Git MCP server running on stdio');

    // Handle shutdown
    process.on('SIGINT', async () => {
      logger.info('server', 'Shutting down server');
      await server.close();
      process.exit(0);
    });

  } catch (error) {
    logger.error('startup', 'Failed to start server', undefined, error as Error);
    process.exit(1);
  }
}

main().catch((error) => {
  console.error('Fatal error:', error);
  process.exit(1);
});

```

--------------------------------------------------------------------------------
/src/operations/remote/remote-types.ts:
--------------------------------------------------------------------------------

```typescript
import { GitOperationOptions } from '../base/operation-result.js';

/**
 * Options for listing remotes
 */
export interface RemoteListOptions extends GitOperationOptions {
  /** Show remote URLs */
  verbose?: boolean;
}

/**
 * Options for adding remotes
 */
export interface RemoteAddOptions extends GitOperationOptions {
  /** Name of the remote */
  name: string;
  /** URL of the remote */
  url: string;
  /** Whether to fetch immediately */
  fetch?: boolean;
  /** Tags to fetch (--tags, --no-tags) */
  tags?: boolean;
  /** Mirror mode (--mirror=fetch or --mirror=push) */
  mirror?: 'fetch' | 'push';
}

/**
 * Options for removing remotes
 */
export interface RemoteRemoveOptions extends GitOperationOptions {
  /** Name of the remote */
  name: string;
}

/**
 * Options for updating remote URLs
 */
export interface RemoteSetUrlOptions extends GitOperationOptions {
  /** Name of the remote */
  name: string;
  /** New URL for the remote */
  url: string;
  /** Whether this is a push URL */
  pushUrl?: boolean;
  /** Add URL instead of changing existing URLs */
  add?: boolean;
  /** Delete URL instead of changing it */
  delete?: boolean;
}

/**
 * Options for pruning remotes
 */
export interface RemotePruneOptions extends GitOperationOptions {
  /** Name of the remote */
  name: string;
  /** Whether to show what would be done */
  dryRun?: boolean;
}

/**
 * Represents a remote configuration
 */
export interface RemoteConfig {
  /** Remote name */
  name: string;
  /** Fetch URL */
  fetchUrl: string;
  /** Push URL (if different from fetch) */
  pushUrl?: string;
  /** Remote branches tracked */
  branches?: string[];
  /** Whether tags are fetched */
  fetchTags?: boolean;
  /** Mirror configuration */
  mirror?: 'fetch' | 'push';
}

/**
 * Result of remote listing operation
 */
export interface RemoteListResult {
  /** List of remotes */
  remotes: RemoteConfig[];
  /** Raw command output */
  raw: string;
}

/**
 * Result of remote add operation
 */
export interface RemoteAddResult {
  /** Added remote configuration */
  remote: RemoteConfig;
  /** Raw command output */
  raw: string;
}

/**
 * Result of remote remove operation
 */
export interface RemoteRemoveResult {
  /** Name of removed remote */
  name: string;
  /** Raw command output */
  raw: string;
}

/**
 * Result of remote set-url operation
 */
export interface RemoteSetUrlResult {
  /** Updated remote configuration */
  remote: RemoteConfig;
  /** Raw command output */
  raw: string;
}

/**
 * Result of remote prune operation
 */
export interface RemotePruneResult {
  /** Name of pruned remote */
  name: string;
  /** Branches that were pruned */
  prunedBranches: string[];
  /** Raw command output */
  raw: string;
}

```

--------------------------------------------------------------------------------
/src/operations/working-tree/working-tree-types.ts:
--------------------------------------------------------------------------------

```typescript
import { GitOperationOptions } from '../base/operation-result.js';

/**
 * Options for adding files to staging
 */
export interface AddOptions extends GitOperationOptions {
  /** Files to stage */
  files: string[];
  /** Whether to add all files (including untracked) */
  all?: boolean;
  /** Whether to add only updates to already tracked files */
  update?: boolean;
  /** Whether to ignore removal of files */
  ignoreRemoval?: boolean;
  /** Whether to add files with errors */
  force?: boolean;
  /** Whether to only show what would be added */
  dryRun?: boolean;
}

/**
 * Options for committing changes
 */
export interface CommitOptions extends GitOperationOptions {
  /** Commit message */
  message: string;
  /** Whether to allow empty commits */
  allowEmpty?: boolean;
  /** Whether to amend the previous commit */
  amend?: boolean;
  /** Whether to skip pre-commit hooks */
  noVerify?: boolean;
  /** Author of the commit (in format: "Name <email>") */
  author?: string;
  /** Files to commit (if not specified, commits all staged changes) */
  files?: string[];
}

/**
 * Options for checking status
 */
export interface StatusOptions extends GitOperationOptions {
  /** Whether to show untracked files */
  showUntracked?: boolean;
  /** Whether to ignore submodules */
  ignoreSubmodules?: boolean;
  /** Whether to show ignored files */
  showIgnored?: boolean;
  /** Whether to show branch info */
  showBranch?: boolean;
}

/**
 * Represents a file change in the working tree
 */
export interface FileChange {
  /** Path of the file */
  path: string;
  /** Type of change */
  type: 'added' | 'modified' | 'deleted' | 'renamed' | 'copied' | 'untracked' | 'ignored';
  /** Original path for renamed files */
  originalPath?: string;
  /** Whether the change is staged */
  staged: boolean;
  /** Raw status code from Git */
  raw: string;
}

/**
 * Result of add operation
 */
export interface AddResult {
  /** Files that were staged */
  staged: string[];
  /** Files that were not staged (with reasons) */
  notStaged?: Array<{
    path: string;
    reason: string;
  }>;
  /** Raw command output */
  raw: string;
}

/**
 * Result of commit operation
 */
export interface CommitResult {
  /** Commit hash */
  hash: string;
  /** Number of files changed */
  filesChanged: number;
  /** Number of insertions */
  insertions: number;
  /** Number of deletions */
  deletions: number;
  /** Whether it was an amend */
  amended: boolean;
  /** Raw command output */
  raw: string;
}

/**
 * Result of status operation
 */
export interface StatusResult {
  /** Current branch name */
  branch: string;
  /** Whether the working tree is clean */
  clean: boolean;
  /** Staged changes */
  staged: FileChange[];
  /** Unstaged changes */
  unstaged: FileChange[];
  /** Untracked files */
  untracked: FileChange[];
  /** Ignored files (if requested) */
  ignored?: FileChange[];
  /** Raw command output */
  raw: string;
}

```

--------------------------------------------------------------------------------
/src/operations/branch/branch-types.ts:
--------------------------------------------------------------------------------

```typescript
import { GitOperationOptions } from '../base/operation-result.js';

/**
 * Options for listing branches
 */
export interface BranchListOptions extends GitOperationOptions {
  /** Show remote branches */
  remotes?: boolean;
  /** Show all branches (local and remote) */
  all?: boolean;
  /** Show only branches containing the specified commit */
  contains?: string;
  /** Show only branches merged into the specified commit */
  merged?: string;
  /** Show only branches not merged into the specified commit */
  noMerged?: string;
}

/**
 * Options for creating branches
 */
export interface BranchCreateOptions extends GitOperationOptions {
  /** Name of the branch to create */
  name: string;
  /** Whether to force create even if branch exists */
  force?: boolean;
  /** Set up tracking mode (true = --track, false = --no-track) */
  track?: boolean;
  /** Set upstream for push/pull */
  setUpstream?: boolean;
  /** Start point (commit/branch) for the new branch */
  startPoint?: string;
}

/**
 * Options for deleting branches
 */
export interface BranchDeleteOptions extends GitOperationOptions {
  /** Name of the branch to delete */
  name: string;
  /** Whether to force delete even if not merged */
  force?: boolean;
  /** Also delete the branch from remotes */
  remote?: boolean;
}

/**
 * Options for checking out branches
 */
export interface CheckoutOptions extends GitOperationOptions {
  /** Branch/commit/tag to check out */
  target: string;
  /** Whether to force checkout even with local changes */
  force?: boolean;
  /** Create a new branch and check it out */
  newBranch?: string;
  /** Track the remote branch */
  track?: boolean;
}

/**
 * Structured branch information
 */
export interface BranchInfo {
  /** Branch name */
  name: string;
  /** Whether this is the current branch */
  current: boolean;
  /** Remote tracking branch if any */
  tracking?: string;
  /** Whether the branch is ahead/behind tracking branch */
  status?: {
    ahead: number;
    behind: number;
  };
  /** Whether this is a remote branch */
  remote: boolean;
  /** Latest commit hash */
  commit?: string;
  /** Latest commit message */
  message?: string;
}

/**
 * Result of branch listing operation
 */
export interface BranchListResult {
  /** Current branch name */
  current: string;
  /** List of all branches */
  branches: BranchInfo[];
  /** Raw command output */
  raw: string;
}

/**
 * Result of branch creation operation
 */
export interface BranchCreateResult {
  /** Name of created branch */
  name: string;
  /** Starting point of the branch */
  startPoint?: string;
  /** Whether tracking was set up */
  tracking?: string;
  /** Raw command output */
  raw: string;
}

/**
 * Result of branch deletion operation
 */
export interface BranchDeleteResult {
  /** Name of deleted branch */
  name: string;
  /** Whether it was force deleted */
  forced: boolean;
  /** Raw command output */
  raw: string;
}

/**
 * Result of checkout operation
 */
export interface CheckoutResult {
  /** Target that was checked out */
  target: string;
  /** Whether a new branch was created */
  newBranch?: string;
  /** Previous HEAD position */
  previousHead?: string;
  /** Raw command output */
  raw: string;
}

```

--------------------------------------------------------------------------------
/src/operations/sync/sync-types.ts:
--------------------------------------------------------------------------------

```typescript
import { GitOperationOptions } from '../base/operation-result.js';

/**
 * Options for push operations
 */
export interface PushOptions extends GitOperationOptions {
  /** Remote to push to */
  remote?: string;
  /** Branch to push */
  branch: string;
  /** Whether to force push */
  force?: boolean;
  /** Whether to force push with lease */
  forceWithLease?: boolean;
  /** Whether to push all branches */
  all?: boolean;
  /** Whether to push tags */
  tags?: boolean;
  /** Whether to skip pre-push hooks */
  noVerify?: boolean;
  /** Whether to set upstream for branch */
  setUpstream?: boolean;
  /** Whether to delete remote branches that were deleted locally */
  prune?: boolean;
}

/**
 * Options for pull operations
 */
export interface PullOptions extends GitOperationOptions {
  /** Remote to pull from */
  remote?: string;
  /** Branch to pull */
  branch: string;
  /** Whether to rebase instead of merge */
  rebase?: boolean;
  /** Whether to automatically stash/unstash changes */
  autoStash?: boolean;
  /** Whether to allow unrelated histories */
  allowUnrelated?: boolean;
  /** Whether to fast-forward only */
  ff?: 'only' | 'no' | true;
  /** Strategy to use when merging */
  strategy?: 'recursive' | 'resolve' | 'octopus' | 'ours' | 'subtree';
  /** Strategy options */
  strategyOption?: string[];
}

/**
 * Options for fetch operations
 */
export interface FetchOptions extends GitOperationOptions {
  /** Remote to fetch from */
  remote?: string;
  /** Whether to fetch all remotes */
  all?: boolean;
  /** Whether to prune remote branches */
  prune?: boolean;
  /** Whether to prune tags */
  pruneTags?: boolean;
  /** Whether to fetch tags */
  tags?: boolean;
  /** Whether to fetch only tags */
  tagsOnly?: boolean;
  /** Whether to force fetch tags */
  forceTags?: boolean;
  /** Depth of history to fetch */
  depth?: number;
  /** Whether to update submodules */
  recurseSubmodules?: boolean | 'on-demand';
  /** Whether to show progress */
  progress?: boolean;
}

/**
 * Result of push operation
 */
export interface PushResult {
  /** Remote that was pushed to */
  remote: string;
  /** Branch that was pushed */
  branch: string;
  /** Whether force push was used */
  forced: boolean;
  /** New remote ref */
  newRef?: string;
  /** Old remote ref */
  oldRef?: string;
  /** Summary of changes */
  summary: {
    created?: string[];
    deleted?: string[];
    updated?: string[];
    rejected?: string[];
  };
  /** Raw command output */
  raw: string;
}

/**
 * Result of pull operation
 */
export interface PullResult {
  /** Remote that was pulled from */
  remote: string;
  /** Branch that was pulled */
  branch: string;
  /** Whether rebase was used */
  rebased: boolean;
  /** Files changed */
  filesChanged: number;
  /** Number of insertions */
  insertions: number;
  /** Number of deletions */
  deletions: number;
  /** Summary of changes */
  summary: {
    merged?: string[];
    conflicts?: string[];
  };
  /** Raw command output */
  raw: string;
}

/**
 * Result of fetch operation
 */
export interface FetchResult {
  /** Remote that was fetched from */
  remote?: string;
  /** Summary of changes */
  summary: {
    branches?: Array<{
      name: string;
      oldRef?: string;
      newRef: string;
    }>;
    tags?: Array<{
      name: string;
      oldRef?: string;
      newRef: string;
    }>;
    pruned?: string[];
  };
  /** Raw command output */
  raw: string;
}

```

--------------------------------------------------------------------------------
/src/operations/repository/repository-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { BaseGitOperation } from '../base/base-operation.js';
import { GitOperationOptions, CommandResult } from '../base/operation-result.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { PathValidator } from '../../utils/path.js';

/**
 * Options for repository initialization
 */
export interface InitOptions extends GitOperationOptions {
  /** Whether to create a bare repository */
  bare?: boolean;
  /** Initial branch name */
  initialBranch?: string;
}

/**
 * Options for repository cloning
 */
export interface CloneOptions extends GitOperationOptions {
  /** Repository URL to clone from */
  url: string;
  /** Whether to create a bare repository */
  bare?: boolean;
  /** Depth of history to clone */
  depth?: number;
  /** Branch to clone */
  branch?: string;
}

/**
 * Handles Git repository initialization
 */
export class InitOperation extends BaseGitOperation<InitOptions> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.init();
    
    if (this.options.bare) {
      command.flag('bare');
    }
    
    if (this.options.initialBranch) {
      command.option('initial-branch', this.options.initialBranch);
    }
    
    return command;
  }

  protected parseResult(result: CommandResult): void {
    // Init doesn't return any structured data
  }

  protected getCacheConfig() {
    return {
      command: 'init'
    };
  }

  protected validateOptions(): void {
    const path = this.options.path || process.env.GIT_DEFAULT_PATH;
    if (!path) {
      throw ErrorHandler.handleValidationError(
        new Error('Path must be provided when GIT_DEFAULT_PATH is not set'),
        { operation: this.context.operation }
      );
    }

    // Validate path exists or can be created
    PathValidator.validatePath(path, {
      mustExist: false,
      allowDirectory: true
    });
  }
}

/**
 * Handles Git repository cloning
 */
export class CloneOperation extends BaseGitOperation<CloneOptions> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.clone()
      .arg(this.options.url)
      .arg(this.options.path || '.');
    
    if (this.options.bare) {
      command.flag('bare');
    }
    
    if (this.options.depth) {
      command.option('depth', this.options.depth.toString());
    }
    
    if (this.options.branch) {
      command.option('branch', this.options.branch);
    }
    
    return command;
  }

  protected parseResult(result: CommandResult): void {
    // Clone doesn't return any structured data
  }

  protected getCacheConfig() {
    return {
      command: 'clone'
    };
  }

  protected validateOptions(): void {
    if (!this.options.url) {
      throw ErrorHandler.handleValidationError(
        new Error('URL is required for clone operation'),
        { operation: this.context.operation }
      );
    }

    const path = this.options.path || process.env.GIT_DEFAULT_PATH;
    if (!path) {
      throw ErrorHandler.handleValidationError(
        new Error('Path must be provided when GIT_DEFAULT_PATH is not set'),
        { operation: this.context.operation }
      );
    }

    // Validate path exists or can be created
    PathValidator.validatePath(path, {
      mustExist: false,
      allowDirectory: true
    });

    if (this.options.depth !== undefined && this.options.depth <= 0) {
      throw ErrorHandler.handleValidationError(
        new Error('Depth must be a positive number'),
        { operation: this.context.operation }
      );
    }
  }
}

```

--------------------------------------------------------------------------------
/src/utils/logger.ts:
--------------------------------------------------------------------------------

```typescript
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { resolve, relative } from 'path';

export enum LogLevel {
  DEBUG = 'DEBUG',
  INFO = 'INFO',
  WARN = 'WARN',
  ERROR = 'ERROR'
}

interface LogEntry {
  timestamp: string;
  level: LogLevel;
  operation: string;
  message: string;
  path?: string;
  error?: Error;
  context?: Record<string, any>;
}

export class Logger {
  private static instance: Logger;
  private entries: LogEntry[] = [];
  private readonly cwd: string;

  private constructor() {
    this.cwd = process.cwd();
  }

  static getInstance(): Logger {
    if (!Logger.instance) {
      Logger.instance = new Logger();
    }
    return Logger.instance;
  }

  private formatPath(path: string): string {
    const absolutePath = resolve(this.cwd, path);
    return relative(this.cwd, absolutePath);
  }

  private createEntry(
    level: LogLevel,
    operation: string,
    message: string,
    path?: string,
    error?: Error,
    context?: Record<string, any>
  ): LogEntry {
    return {
      timestamp: new Date().toISOString(),
      level,
      operation,
      message,
      path: path ? this.formatPath(path) : undefined,
      error,
      context,
    };
  }

  private log(entry: LogEntry): void {
    this.entries.push(entry);
    let logMessage = `[${entry.timestamp}] ${entry.level} - ${entry.operation}: ${entry.message}`;
    
    if (entry.path) {
      logMessage += `\n  Path: ${entry.path}`;
    }
    
    if (entry.context) {
      logMessage += `\n  Context: ${JSON.stringify(entry.context, null, 2)}`;
    }
    
    if (entry.error) {
      if (entry.error instanceof McpError) {
        logMessage += `\n  Error: ${entry.error.message}`;
      } else {
        logMessage += `\n  Error: ${entry.error.stack || entry.error.message}`;
      }
    }

    console.error(logMessage);
  }

  debug(operation: string, message: string, path?: string, context?: Record<string, any>): void {
    this.log(this.createEntry(LogLevel.DEBUG, operation, message, path, undefined, context));
  }

  info(operation: string, message: string, path?: string, context?: Record<string, any>): void {
    this.log(this.createEntry(LogLevel.INFO, operation, message, path, undefined, context));
  }

  warn(operation: string, message: string, path?: string, error?: Error, context?: Record<string, any>): void {
    this.log(this.createEntry(LogLevel.WARN, operation, message, path, error, context));
  }

  error(operation: string, message: string, path?: string, error?: Error, context?: Record<string, any>): void {
    this.log(this.createEntry(LogLevel.ERROR, operation, message, path, error, context));
  }

  getEntries(): LogEntry[] {
    return [...this.entries];
  }

  getEntriesForOperation(operation: string): LogEntry[] {
    return this.entries.filter(entry => entry.operation === operation);
  }

  getEntriesForPath(path: string): LogEntry[] {
    const searchPath = this.formatPath(path);
    return this.entries.filter(entry => entry.path === searchPath);
  }

  clear(): void {
    this.entries = [];
  }

  // Helper methods for common operations
  logCommand(operation: string, command: string, path?: string, context?: Record<string, any>): void {
    this.debug(operation, `Executing command: ${command}`, path, context);
  }

  logCommandResult(operation: string, result: string, path?: string, context?: Record<string, any>): void {
    this.debug(operation, `Command result: ${result}`, path, context);
  }

  logPathValidation(operation: string, path: string, context?: Record<string, any>): void {
    this.debug(operation, `Validating path: ${path}`, path, context);
  }

  logGitOperation(operation: string, details: string, path?: string, context?: Record<string, any>): void {
    this.info(operation, details, path, context);
  }

  logError(operation: string, error: Error, path?: string, context?: Record<string, any>): void {
    this.error(operation, 'Operation failed', path, error, context);
  }
}

// Export a singleton instance
export const logger = Logger.getInstance();

```

--------------------------------------------------------------------------------
/src/common/command-builder.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Provides a fluent interface for building Git commands with proper option handling
 */
export class GitCommandBuilder {
  private command: string[] = ['git'];
  private options: Map<string, string | boolean> = new Map();

  /**
   * Create a new GitCommandBuilder for a specific Git command
   */
  constructor(command: string) {
    this.command.push(command);
  }

  /**
   * Add a positional argument to the command
   */
  arg(value: string): this {
    this.command.push(this.escapeArg(value));
    return this;
  }

  /**
   * Add multiple positional arguments
   */
  args(...values: string[]): this {
    values.forEach(value => this.arg(value));
    return this;
  }

  /**
   * Add a flag option (--flag)
   */
  flag(name: string): this {
    this.options.set(name, true);
    return this;
  }

  /**
   * Add a value option (--option=value)
   */
  option(name: string, value: string): this {
    this.options.set(name, value);
    return this;
  }

  /**
   * Add a force flag (--force)
   */
  withForce(): this {
    return this.flag('force');
  }

  /**
   * Add a no-verify flag (--no-verify)
   */
  withNoVerify(): this {
    return this.flag('no-verify');
  }

  /**
   * Add a tags flag (--tags)
   */
  withTags(): this {
    return this.flag('tags');
  }

  /**
   * Add a track flag (--track)
   */
  withTrack(): this {
    return this.flag('track');
  }

  /**
   * Add a no-track flag (--no-track)
   */
  withNoTrack(): this {
    return this.flag('no-track');
  }

  /**
   * Add a set-upstream flag (--set-upstream)
   */
  withSetUpstream(): this {
    return this.flag('set-upstream');
  }

  /**
   * Add an annotated flag (-a)
   */
  withAnnotated(): this {
    return this.flag('a');
  }

  /**
   * Add a sign flag (-s)
   */
  withSign(): this {
    return this.flag('s');
  }

  /**
   * Add an include-untracked flag (--include-untracked)
   */
  withIncludeUntracked(): this {
    return this.flag('include-untracked');
  }

  /**
   * Add a keep-index flag (--keep-index)
   */
  withKeepIndex(): this {
    return this.flag('keep-index');
  }

  /**
   * Add an all flag (--all)
   */
  withAll(): this {
    return this.flag('all');
  }

  /**
   * Add a message option (-m "message")
   */
  withMessage(message: string): this {
    return this.option('m', message);
  }

  /**
   * Build the final command string
   */
  toString(): string {
    const parts = [...this.command];

    // Add options in sorted order for consistency
    Array.from(this.options.entries())
      .sort(([a], [b]) => a.localeCompare(b))
      .forEach(([name, value]) => {
        if (name.length === 1) {
          // Short option (-m "value")
          parts.push(`-${name}`);
          if (typeof value === 'string') {
            parts.push(this.escapeArg(value));
          }
        } else {
          // Long option
          if (value === true) {
            // Flag (--force)
            parts.push(`--${name}`);
          } else if (typeof value === 'string') {
            // Value option (--option=value)
            parts.push(`--${name}=${this.escapeArg(value)}`);
          }
        }
      });

    return parts.join(' ');
  }

  /**
   * Create common Git commands
   */
  static init(): GitCommandBuilder {
    return new GitCommandBuilder('init');
  }

  static clone(): GitCommandBuilder {
    return new GitCommandBuilder('clone');
  }

  static add(): GitCommandBuilder {
    return new GitCommandBuilder('add');
  }

  static commit(): GitCommandBuilder {
    return new GitCommandBuilder('commit');
  }

  static push(): GitCommandBuilder {
    return new GitCommandBuilder('push');
  }

  static pull(): GitCommandBuilder {
    return new GitCommandBuilder('pull');
  }

  static branch(): GitCommandBuilder {
    return new GitCommandBuilder('branch');
  }

  static checkout(): GitCommandBuilder {
    return new GitCommandBuilder('checkout');
  }

  static tag(): GitCommandBuilder {
    return new GitCommandBuilder('tag');
  }

  static remote(): GitCommandBuilder {
    return new GitCommandBuilder('remote');
  }

  static stash(): GitCommandBuilder {
    return new GitCommandBuilder('stash');
  }

  static status(): GitCommandBuilder {
    return new GitCommandBuilder('status');
  }

  static fetch(): GitCommandBuilder {
    return new GitCommandBuilder('fetch');
  }

  /**
   * Escape command arguments that contain spaces or special characters
   */
  private escapeArg(arg: string): string {
    if (arg.includes(' ') || arg.includes('"') || arg.includes('\'')) {
      // Escape quotes and wrap in quotes
      return `"${arg.replace(/"/g, '\\"')}"`;
    }
    return arg;
  }
}

```

--------------------------------------------------------------------------------
/src/operations/base/base-operation.ts:
--------------------------------------------------------------------------------

```typescript
import { CommandExecutor } from '../../utils/command.js';
import { PathValidator } from '../../utils/path.js';
import { logger } from '../../utils/logger.js';
import { repositoryCache } from '../../caching/repository-cache.js';
import { RepoStateType } from '../../caching/repository-cache.js';
import { GitToolContext, GitToolResult } from '../../types.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { GitOperationOptions, GitOperationResult, CommandResult } from './operation-result.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { GitMcpError } from '../../errors/error-types.js';

/**
 * Base class for all Git operations providing common functionality
 */
export abstract class BaseGitOperation<TOptions extends GitOperationOptions, TResult = void> {
  protected constructor(
    protected readonly context: GitToolContext,
    protected readonly options: TOptions
  ) {}

  /**
   * Execute the Git operation with proper error handling and caching
   */
  public async execute(): Promise<GitOperationResult<TResult>> {
    try {
      // Validate options before proceeding
      this.validateOptions();

      // Get resolved path
      const path = this.getResolvedPath();

      // Execute operation with caching if enabled
      const result = await this.executeWithCache(path);

      // Format the result
      return await this.formatResult(result);
    } catch (error: unknown) {
      return this.handleError(error);
    }
  }

  /**
   * Build the Git command for this operation
   */
  protected abstract buildCommand(): GitCommandBuilder | Promise<GitCommandBuilder>;

  /**
   * Parse the command result into operation-specific format
   */
  protected abstract parseResult(result: CommandResult): TResult | Promise<TResult>;

  /**
   * Get cache configuration for this operation
   */
  protected abstract getCacheConfig(): {
    command: string;
    stateType?: RepoStateType;
  };

  /**
   * Validate operation-specific options
   */
  protected abstract validateOptions(): void;

  /**
   * Execute the Git command with caching if enabled
   */
  private async executeWithCache(path: string): Promise<CommandResult> {
    const { command, stateType } = this.getCacheConfig();
    const action = () => this.executeCommand(path);

    if (this.options.useCache && path) {
      if (stateType) {
        // Use state cache
        return await repositoryCache.getState(
          path,
          stateType,
          command,
          action
        );
      } else {
        // Use command cache
        return await repositoryCache.getCommandResult(
          path,
          command,
          action
        );
      }
    }

    // Execute without caching
    return await action();
  }

  /**
   * Execute the Git command
   */
  private async executeCommand(path: string): Promise<CommandResult> {
    const builder = await Promise.resolve(this.buildCommand());
    const command = builder.toString();
    return await CommandExecutor.executeGitCommand(
      command,
      this.context.operation,
      path
    );
  }

  /**
   * Format the operation result into standard GitToolResult
   */
  private async formatResult(result: CommandResult): Promise<GitOperationResult<TResult>> {
    return {
      success: true,
      data: await Promise.resolve(this.parseResult(result)),
      content: [{
        type: 'text',
        text: CommandExecutor.formatOutput(result)
      }]
    };
  }

  /**
   * Handle operation errors
   */
  private handleError(error: unknown): GitOperationResult<TResult> {
    if (error instanceof GitMcpError) {
      return {
        success: false,
        error,
        content: [{
          type: 'text',
          text: error.message
        }]
      };
    }

    const wrappedError = ErrorHandler.handleOperationError(
      error instanceof Error ? error : new Error('Unknown error'),
      {
        operation: this.context.operation,
        path: this.options.path,
        command: this.getCacheConfig().command
      }
    );

    return {
      success: false,
      error: wrappedError,
      content: [{
        type: 'text',
        text: wrappedError.message
      }]
    };
  }

  /**
   * Get resolved path with proper validation
   */
  protected getResolvedPath(): string {
    const path = this.options.path || process.env.GIT_DEFAULT_PATH;
    if (!path) {
      throw ErrorHandler.handleValidationError(
        new Error('Path must be provided when GIT_DEFAULT_PATH is not set'),
        { operation: this.context.operation }
      );
    }

    const { path: repoPath } = PathValidator.validateGitRepo(path);
    return repoPath;
  }

  /**
   * Invalidate cache if needed
   */
  protected invalidateCache(path: string): void {
    if (this.options.invalidateCache) {
      const { command, stateType } = this.getCacheConfig();
      if (stateType) {
        repositoryCache.invalidateState(path, stateType);
      }
      repositoryCache.invalidateCommand(path, command);
    }
  }
}

```

--------------------------------------------------------------------------------
/src/operations/tag/tag-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { BaseGitOperation } from '../base/base-operation.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { CommandResult } from '../base/operation-result.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { RepositoryValidator } from '../../utils/repository.js';
import { CommandExecutor } from '../../utils/command.js';
import { RepoStateType } from '../../caching/repository-cache.js';
import {
  TagListOptions,
  TagCreateOptions,
  TagDeleteOptions,
  TagListResult,
  TagCreateResult,
  TagDeleteResult,
  TagInfo
} from './tag-types.js';

/**
 * Handles Git tag listing operations
 */
export class TagListOperation extends BaseGitOperation<TagListOptions, TagListResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.tag();

    // Add format option for parsing
    command.option('format', '%(refname:strip=2)|%(objecttype)|%(subject)|%(taggername)|%(taggeremail)|%(taggerdate)|%(objectname)');

    if (this.options.showMessage) {
      command.flag('n');
    }

    if (this.options.sort) {
      command.option('sort', this.options.sort);
    }

    if (this.options.contains) {
      command.option('contains', this.options.contains);
    }

    if (this.options.pattern) {
      command.arg(this.options.pattern);
    }

    return command;
  }

  protected parseResult(result: CommandResult): TagListResult {
    const tags: TagInfo[] = [];

    // Parse each line of output
    result.stdout.split('\n').filter(Boolean).forEach(line => {
      const [name, type, message, taggerName, taggerEmail, taggerDate, commit] = line.split('|');
      
      const tag: TagInfo = {
        name,
        annotated: type === 'tag',
        commit,
        signed: message?.includes('-----BEGIN PGP SIGNATURE-----') || false
      };

      if (tag.annotated) {
        tag.message = message;
        if (taggerName && taggerEmail && taggerDate) {
          tag.tagger = {
            name: taggerName,
            email: taggerEmail.replace(/[<>]/g, ''),
            date: taggerDate
          };
        }
      }

      tags.push(tag);
    });

    return {
      tags,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'tag',
      stateType: RepoStateType.TAG
    };
  }

  protected validateOptions(): void {
    // No specific validation needed for listing
  }
}

/**
 * Handles Git tag creation operations
 */
export class TagCreateOperation extends BaseGitOperation<TagCreateOptions, TagCreateResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.tag();

    if (this.options.message) {
      command.withAnnotated();
      command.withMessage(this.options.message);
    }

    if (this.options.force) {
      command.withForce();
    }

    if (this.options.sign) {
      command.withSign();
    }

    command.arg(this.options.name);

    if (this.options.commit) {
      command.arg(this.options.commit);
    }

    return command;
  }

  protected parseResult(result: CommandResult): TagCreateResult {
    const signed = result.stdout.includes('-----BEGIN PGP SIGNATURE-----');
    
    return {
      name: this.options.name,
      annotated: Boolean(this.options.message),
      signed,
      commit: this.options.commit,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'tag_create',
      stateType: RepoStateType.TAG
    };
  }

  protected validateOptions(): void {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Tag name is required'),
        { operation: this.context.operation }
      );
    }
  }
}

/**
 * Handles Git tag deletion operations
 */
export class TagDeleteOperation extends BaseGitOperation<TagDeleteOptions, TagDeleteResult> {
  protected async buildCommand(): Promise<GitCommandBuilder> {
    const command = GitCommandBuilder.tag();

    command.flag('d');
    if (this.options.force) {
      command.withForce();
    }

    command.arg(this.options.name);

    if (this.options.remote) {
      // Get remote name from configuration
      const remotes = await RepositoryValidator.getRemotes(
        this.getResolvedPath(),
        this.context.operation
      );

      // Push deletion to all remotes
      for (const remote of remotes) {
        await CommandExecutor.executeGitCommand(
          `push ${remote} :refs/tags/${this.options.name}`,
          this.context.operation,
          this.getResolvedPath()
        );
      }
    }

    return command;
  }

  protected parseResult(result: CommandResult): TagDeleteResult {
    return {
      name: this.options.name,
      forced: this.options.force || false,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'tag_delete',
      stateType: RepoStateType.TAG
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Tag name is required'),
        { operation: this.context.operation }
      );
    }

    // Ensure tag exists
    await RepositoryValidator.validateTagExists(
      this.getResolvedPath(),
      this.options.name,
      this.context.operation
    );
  }
}

```

--------------------------------------------------------------------------------
/src/caching/repository-cache.ts:
--------------------------------------------------------------------------------

```typescript
import { RepositoryStateCache, CommandResultCache } from './cache.js';
import { logger } from '../utils/logger.js';
import { PerformanceMonitor } from '../monitoring/performance.js';

/**
 * Repository state types
 */
export enum RepoStateType {
  BRANCH = 'branch',
  STATUS = 'status',
  REMOTE = 'remote',
  TAG = 'tag',
  STASH = 'stash'
}

/**
 * Repository state manager with caching
 */
export class RepositoryCacheManager {
  private static instance: RepositoryCacheManager;
  private stateCache: RepositoryStateCache;
  private commandCache: CommandResultCache;
  private performanceMonitor: PerformanceMonitor;

  private constructor() {
    this.stateCache = new RepositoryStateCache();
    this.commandCache = new CommandResultCache();
    this.performanceMonitor = PerformanceMonitor.getInstance();
  }

  /**
   * Get singleton instance
   */
  static getInstance(): RepositoryCacheManager {
    if (!RepositoryCacheManager.instance) {
      RepositoryCacheManager.instance = new RepositoryCacheManager();
    }
    return RepositoryCacheManager.instance;
  }

  /**
   * Get repository state from cache or execute command
   */
  async getState(
    repoPath: string,
    stateType: RepoStateType,
    command: string,
    executor: () => Promise<any>
  ): Promise<any> {
    const cacheKey = this.getStateKey(repoPath, stateType);
    const cachedState = this.stateCache.get(cacheKey);

    if (cachedState !== undefined) {
      logger.debug(
        'cache',
        `Cache hit for repository state: ${stateType}`,
        repoPath,
        { command }
      );
      return cachedState;
    }

    // Start timing the operation
    const startTime = performance.now();

    try {
      const result = await executor();
      const duration = performance.now() - startTime;

      // Record performance metrics
      this.performanceMonitor.recordCommandExecution(command, duration, {
        repoPath,
        stateType,
        cached: false
      });

      // Cache the result
      this.stateCache.set(cacheKey, result);

      return result;
    } catch (error) {
      const duration = performance.now() - startTime;
      this.performanceMonitor.recordCommandExecution(command, duration, {
        repoPath,
        stateType,
        cached: false,
        error: true
      });
      throw error;
    }
  }

  /**
   * Get command result from cache or execute command
   */
  async getCommandResult(
    repoPath: string,
    command: string,
    executor: () => Promise<any>
  ): Promise<any> {
    const cacheKey = CommandResultCache.generateKey(command, repoPath);
    const cachedResult = this.commandCache.get(cacheKey);

    if (cachedResult !== undefined) {
      logger.debug(
        'cache',
        `Cache hit for command result`,
        repoPath,
        { command }
      );
      return cachedResult;
    }

    // Start timing the operation
    const startTime = performance.now();

    try {
      const result = await executor();
      const duration = performance.now() - startTime;

      // Record performance metrics
      this.performanceMonitor.recordCommandExecution(command, duration, {
        repoPath,
        cached: false
      });

      // Cache the result
      this.commandCache.set(cacheKey, result);

      return result;
    } catch (error) {
      const duration = performance.now() - startTime;
      this.performanceMonitor.recordCommandExecution(command, duration, {
        repoPath,
        cached: false,
        error: true
      });
      throw error;
    }
  }

  /**
   * Invalidate repository state cache
   */
  invalidateState(repoPath: string, stateType?: RepoStateType): void {
    if (stateType) {
      const cacheKey = this.getStateKey(repoPath, stateType);
      this.stateCache.delete(cacheKey);
      logger.debug(
        'cache',
        `Invalidated repository state cache`,
        repoPath,
        { stateType }
      );
    } else {
      // Invalidate all state types for this repository
      Object.values(RepoStateType).forEach(type => {
        const cacheKey = this.getStateKey(repoPath, type);
        this.stateCache.delete(cacheKey);
      });
      logger.debug(
        'cache',
        `Invalidated all repository state cache`,
        repoPath
      );
    }
  }

  /**
   * Invalidate command result cache
   */
  invalidateCommand(repoPath: string, command?: string): void {
    if (command) {
      const cacheKey = CommandResultCache.generateKey(command, repoPath);
      this.commandCache.delete(cacheKey);
      logger.debug(
        'cache',
        `Invalidated command result cache`,
        repoPath,
        { command }
      );
    } else {
      // Clear all command results for this repository
      // Note: This is a bit inefficient as it clears all commands for all repos
      // A better solution would be to store repo-specific commands separately
      this.commandCache.clear();
      logger.debug(
        'cache',
        `Invalidated all command result cache`,
        repoPath
      );
    }
  }

  /**
   * Get cache statistics
   */
  getStats(): Record<string, any> {
    return {
      state: this.stateCache.getStats(),
      command: this.commandCache.getStats()
    };
  }

  /**
   * Generate cache key for repository state
   */
  private getStateKey(repoPath: string, stateType: RepoStateType): string {
    return `${repoPath}:${stateType}`;
  }
}

// Export singleton instance
export const repositoryCache = RepositoryCacheManager.getInstance();

```

--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------

```typescript
import { ExecOptions } from 'child_process';

export enum ErrorCode {
  InvalidParams = 'InvalidParams',
  InternalError = 'InternalError',
  InvalidState = 'InvalidState'
}

export interface GitOptions {
  /**
   * Absolute path to the working directory
   * Example: /Users/username/projects/my-repo
   */
  cwd?: string;
  execOptions?: ExecOptions;
}

export interface GitToolContent {
  type: string;
  text: string;
}

export interface GitToolResult {
  content: GitToolContent[];
  _meta?: Record<string, unknown>;
}

export interface GitToolContext {
  operation: string;
  path?: string;
  options?: GitOptions;
}

// Base interface for operations that require a path
export interface BasePathOptions {
  /**
   * MUST be an absolute path to the repository
   * Example: /Users/username/projects/my-repo
   * If not provided, will use GIT_DEFAULT_PATH from environment
   */
  path?: string;
}

// Tool-specific interfaces
export interface InitOptions extends GitOptions, BasePathOptions {}

export interface CloneOptions extends GitOptions, BasePathOptions {
  /**
   * URL of the repository to clone
   */
  url: string;
}

export interface AddOptions extends GitOptions, BasePathOptions {
  /**
   * Array of absolute paths to files to stage
   * Example: /Users/username/projects/my-repo/src/file.js
   */
  files: string[];
}

export interface CommitOptions extends GitOptions, BasePathOptions {
  message: string;
}

export interface PushPullOptions extends GitOptions, BasePathOptions {
  remote?: string;
  branch: string;
  force?: boolean;  // Allow force push/pull
  noVerify?: boolean;  // Skip pre-push/pre-pull hooks
  tags?: boolean;  // Include tags
}

export interface BranchOptions extends GitOptions, BasePathOptions {
  name: string;
  force?: boolean;  // Allow force operations
  track?: boolean;  // Set up tracking mode
  setUpstream?: boolean;  // Set upstream for push/pull
}

export interface CheckoutOptions extends GitOptions, BasePathOptions {
  target: string;
}

export interface TagOptions extends GitOptions, BasePathOptions {
  name: string;
  message?: string;
  force?: boolean;  // Allow force operations
  annotated?: boolean;  // Create an annotated tag
  sign?: boolean;  // Create a signed tag
}

export interface RemoteOptions extends GitOptions, BasePathOptions {
  name: string;
  url?: string;
  force?: boolean;  // Allow force operations
  mirror?: boolean;  // Mirror all refs
  tags?: boolean;  // Include tags
}

export interface StashOptions extends GitOptions, BasePathOptions {
  message?: string;
  index?: number;
  includeUntracked?: boolean;  // Include untracked files
  keepIndex?: boolean;  // Keep staged changes
  all?: boolean;  // Include ignored files
}

// New bulk action interfaces
export interface BulkActionStage {
  type: 'stage';
  files?: string[]; // If not provided, stages all files
}

export interface BulkActionCommit {
  type: 'commit';
  message: string;
}

export interface BulkActionPush {
  type: 'push';
  remote?: string;
  branch: string;
}

export type BulkAction = BulkActionStage | BulkActionCommit | BulkActionPush;

export interface BulkActionOptions extends GitOptions, BasePathOptions {
  actions: BulkAction[];
}

// Type guard functions
export function isAbsolutePath(path: string): boolean {
  return path.startsWith('/');
}

export function validatePath(path?: string): boolean {
  return !path || isAbsolutePath(path);
}

export function isInitOptions(obj: any): obj is InitOptions {
  return obj && validatePath(obj.path);
}

export function isCloneOptions(obj: any): obj is CloneOptions {
  return obj && 
    typeof obj.url === 'string' &&
    validatePath(obj.path);
}

export function isAddOptions(obj: any): obj is AddOptions {
  return obj && 
    validatePath(obj.path) && 
    Array.isArray(obj.files) &&
    obj.files.every((f: any) => typeof f === 'string' && isAbsolutePath(f));
}

export function isCommitOptions(obj: any): obj is CommitOptions {
  return obj && 
    validatePath(obj.path) && 
    typeof obj.message === 'string';
}

export function isPushPullOptions(obj: any): obj is PushPullOptions {
  return obj && 
    validatePath(obj.path) && 
    typeof obj.branch === 'string';
}

export function isBranchOptions(obj: any): obj is BranchOptions {
  return obj && 
    validatePath(obj.path) && 
    typeof obj.name === 'string';
}

export function isCheckoutOptions(obj: any): obj is CheckoutOptions {
  return obj && 
    validatePath(obj.path) && 
    typeof obj.target === 'string';
}

export function isTagOptions(obj: any): obj is TagOptions {
  return obj && 
    validatePath(obj.path) && 
    typeof obj.name === 'string';
}

export function isRemoteOptions(obj: any): obj is RemoteOptions {
  return obj && 
    validatePath(obj.path) && 
    typeof obj.name === 'string';
}

export function isStashOptions(obj: any): obj is StashOptions {
  return obj && validatePath(obj.path);
}

export function isPathOnly(obj: any): obj is BasePathOptions {
  return obj && validatePath(obj.path);
}

export function isBulkActionOptions(obj: any): obj is BulkActionOptions {
  if (!obj || !validatePath(obj.path) || !Array.isArray(obj.actions)) {
    return false;
  }

  return obj.actions.every((action: any) => {
    if (!action || typeof action.type !== 'string') {
      return false;
    }

    switch (action.type) {
      case 'stage':
        return !action.files || (Array.isArray(action.files) && 
          action.files.every((f: any) => typeof f === 'string' && isAbsolutePath(f)));
      case 'commit':
        return typeof action.message === 'string';
      case 'push':
        return typeof action.branch === 'string';
      default:
        return false;
    }
  });
}

```

--------------------------------------------------------------------------------
/src/utils/paths.ts:
--------------------------------------------------------------------------------

```typescript
import { resolve, isAbsolute, normalize, relative, join, dirname } from 'path';
import { existsSync, statSync, mkdirSync } from 'fs';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { logger } from './logger.js';

export interface PathInfo {
  original: string;
  absolute: string;
  relative: string;
  exists: boolean;
  isDirectory?: boolean;
  isFile?: boolean;
  isGitRepo?: boolean;
  parent: string;
}

export class PathResolver {
  private static readonly CWD = process.cwd();

  private static createDirectory(path: string, operation: string): void {
    try {
      mkdirSync(path, { recursive: true });
      logger.info(operation, `Created directory: ${path}`);
    } catch (error) {
      logger.error(operation, `Failed to create directory: ${path}`, path, error as Error);
      throw new McpError(
        ErrorCode.InternalError,
        `Failed to create directory: ${(error as Error).message}`
      );
    }
  }

  private static getStats(path: string): { exists: boolean; isDirectory?: boolean; isFile?: boolean } {
    if (!existsSync(path)) {
      return { exists: false };
    }

    try {
      const stats = statSync(path);
      return {
        exists: true,
        isDirectory: stats.isDirectory(),
        isFile: stats.isFile(),
      };
    } catch {
      return { exists: true };
    }
  }

  private static validateAbsolutePath(path: string, operation: string): void {
    if (!isAbsolute(path)) {
      const error = new McpError(
        ErrorCode.InvalidParams,
        `Path must be absolute. Received: ${path}\nExample: /Users/username/projects/my-repo`
      );
      logger.error(operation, 'Invalid path format', path, error);
      throw error;
    }
  }

  static getPathInfo(path: string, operation: string): PathInfo {
    logger.debug(operation, 'Resolving path info', path);

    // Validate absolute path
    this.validateAbsolutePath(path, operation);

    // Normalize the path
    const absolutePath = normalize(path);
    const relativePath = relative(this.CWD, absolutePath);
    const parentPath = dirname(absolutePath);

    // Get path stats
    const stats = this.getStats(absolutePath);
    const isGitRepo = stats.isDirectory ? existsSync(join(absolutePath, '.git')) : false;

    const pathInfo: PathInfo = {
      original: path,
      absolute: absolutePath,
      relative: relativePath,
      exists: stats.exists,
      isDirectory: stats.isDirectory,
      isFile: stats.isFile,
      isGitRepo,
      parent: parentPath,
    };

    logger.debug(operation, 'Path info resolved', path, pathInfo);
    return pathInfo;
  }

  static validatePath(path: string, operation: string, options: {
    mustExist?: boolean;
    mustBeDirectory?: boolean;
    mustBeFile?: boolean;
    mustBeGitRepo?: boolean;
    createIfMissing?: boolean;
  } = {}): PathInfo {
    const {
      mustExist = false,
      mustBeDirectory = false,
      mustBeFile = false,
      mustBeGitRepo = false,
      createIfMissing = false,
    } = options;

    logger.debug(operation, 'Validating path with options', path, options);

    // Get path info (includes absolute path validation)
    const pathInfo = this.getPathInfo(path, operation);

    // Create directory if needed
    if (!pathInfo.exists && (createIfMissing || mustBeDirectory)) {
      this.createDirectory(pathInfo.absolute, operation);
      return this.getPathInfo(path, operation);
    }

    // Handle existence requirements
    if (mustExist && !pathInfo.exists) {
      const error = new McpError(
        ErrorCode.InvalidParams,
        `Path does not exist: ${pathInfo.absolute}`
      );
      logger.error(operation, 'Path validation failed', path, error);
      throw error;
    }

    // Validate directory requirement
    if (mustBeDirectory && !pathInfo.isDirectory) {
      const error = new McpError(
        ErrorCode.InvalidParams,
        `Path is not a directory: ${pathInfo.absolute}`
      );
      logger.error(operation, 'Path validation failed', path, error);
      throw error;
    }

    // Validate file requirement
    if (mustBeFile && !pathInfo.isFile) {
      const error = new McpError(
        ErrorCode.InvalidParams,
        `Path is not a file: ${pathInfo.absolute}`
      );
      logger.error(operation, 'Path validation failed', path, error);
      throw error;
    }

    // Validate git repo requirement
    if (mustBeGitRepo && !pathInfo.isGitRepo) {
      const error = new McpError(
        ErrorCode.InvalidParams,
        `Path is not a git repository: ${pathInfo.absolute}`
      );
      logger.error(operation, 'Path validation failed', path, error);
      throw error;
    }

    logger.debug(operation, 'Path validation successful', path, pathInfo);
    return pathInfo;
  }

  static validateFilePaths(paths: string[], operation: string): PathInfo[] {
    logger.debug(operation, 'Validating multiple file paths', undefined, { paths });

    return paths.map(path => {
      // Validate absolute path
      this.validateAbsolutePath(path, operation);

      const pathInfo = this.validatePath(path, operation, {
        mustExist: true,
        mustBeFile: true,
      });
      return pathInfo;
    });
  }

  static validateGitRepo(path: string, operation: string): PathInfo {
    // Validate absolute path
    this.validateAbsolutePath(path, operation);

    return this.validatePath(path, operation, {
      mustExist: true,
      mustBeDirectory: true,
      mustBeGitRepo: true,
    });
  }

  static ensureDirectory(path: string, operation: string): PathInfo {
    // Validate absolute path
    this.validateAbsolutePath(path, operation);

    return this.validatePath(path, operation, {
      createIfMissing: true,
      mustBeDirectory: true,
    });
  }
}

```

--------------------------------------------------------------------------------
/src/utils/command.ts:
--------------------------------------------------------------------------------

```typescript
import { ExecException, exec, ExecOptions } from 'child_process';
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import { logger } from './logger.js';
import { PathResolver } from './paths.js';
import { ErrorHandler } from '../errors/error-handler.js';
import { ErrorCategory, ErrorSeverity, GitMcpError } from '../errors/error-types.js';

export interface CommandResult {
  stdout: string;
  stderr: string;
  command: string;
  workingDir?: string;
}

/**
 * Formats a command error message with detailed context
 */
function formatCommandError(error: ExecException, result: Partial<CommandResult>): string {
  let message = `Command failed with exit code ${error.code}`;
  
  if (result.command) {
    message += `\nCommand: ${result.command}`;
  }
  
  if (result.workingDir) {
    message += `\nWorking Directory: ${result.workingDir}`;
  }
  
  if (result.stdout) {
    message += `\nOutput: ${result.stdout}`;
  }
  
  if (result.stderr) {
    message += `\nError: ${result.stderr}`;
  }
  
  return message;
}

/**
 * Creates a command error with appropriate category and severity
 */
function createCommandError(
  error: ExecException,
  result: Partial<CommandResult>,
  operation: string
): GitMcpError {
  const message = formatCommandError(error, result);
  const context = {
    operation,
    path: result.workingDir,
    command: result.command,
    details: {
      exitCode: error.code,
      stdout: result.stdout,
      stderr: result.stderr
    }
  };

  // Determine error category and severity based on error code and context
  const errorCode = error.code?.toString() || '';

  // System errors
  if (errorCode === 'ENOENT') {
    return ErrorHandler.handleSystemError(error, context);
  }

  // Security errors
  if (errorCode === 'EACCES') {
    return ErrorHandler.handleSecurityError(error, context);
  }

  // Validation errors
  if (errorCode === 'ENOTDIR' || errorCode === 'ENOTEMPTY') {
    return ErrorHandler.handleValidationError(error, context);
  }

  // Git-specific error codes
  const numericCode = typeof error.code === 'number' ? error.code : 
                     typeof error.code === 'string' ? parseInt(error.code, 10) : 
                     null;
  
  if (numericCode !== null) {
    switch (numericCode) {
      case 128: // Repository not found or invalid
        return ErrorHandler.handleRepositoryError(error, context);
      case 129: // Invalid command or argument
        return ErrorHandler.handleValidationError(error, context);
      case 130: // User interrupt
        return ErrorHandler.handleOperationError(error, context);
      default:
        return ErrorHandler.handleOperationError(error, context);
    }
  }

  // Default to operation error for unknown cases
  return ErrorHandler.handleOperationError(error, context);
}

export class CommandExecutor {
  static async execute(
    command: string,
    operation: string,
    workingDir?: string,
    options: ExecOptions = {}
  ): Promise<CommandResult> {
    // Validate and resolve working directory if provided
    if (workingDir) {
      const pathInfo = PathResolver.validatePath(workingDir, operation, {
        mustExist: true,
        mustBeDirectory: true,
      });
      workingDir = pathInfo.absolute;
    }

    // Log command execution
    logger.logCommand(operation, command, workingDir);

    // Prepare execution options
    const execOptions: ExecOptions = {
      ...options,
      cwd: workingDir,
      maxBuffer: 10 * 1024 * 1024, // 10MB buffer
    };

    return new Promise((resolve, reject) => {
      exec(command, execOptions, (error, stdout, stderr) => {
        const result: CommandResult = {
          command,
          workingDir,
          stdout: stdout.trim(),
          stderr: stderr.trim(),
        };

        // Log command result
        if (error) {
          reject(createCommandError(error, result, operation));
          return;
        }

        logger.logCommandResult(operation, result.stdout, workingDir, {
          stderr: result.stderr,
        });
        resolve(result);
      });
    });
  }

  static formatOutput(result: CommandResult): string {
    let output = '';
    
    if (result.stdout) {
      output += result.stdout;
    }
    
    if (result.stderr) {
      if (output) output += '\n';
      output += result.stderr;
    }
    
    return output.trim();
  }

  static async executeGitCommand(
    command: string,
    operation: string,
    workingDir?: string,
    options: ExecOptions = {}
  ): Promise<CommandResult> {
    // Add git environment variables
    const gitOptions: ExecOptions = {
      ...options,
      env: {
        ...process.env,
        ...options.env,
        GIT_TERMINAL_PROMPT: '0', // Disable git terminal prompts
        GIT_ASKPASS: 'echo', // Prevent password prompts
      },
    };

    try {
      return await this.execute(`git ${command}`, operation, workingDir, gitOptions);
    } catch (error) {
      if (error instanceof GitMcpError) {
        // Add git-specific context to error
        logger.error(operation, 'Git command failed', workingDir, error, {
          command: `git ${command}`,
          gitConfig: await this.execute('git config --list', operation, workingDir)
            .then(result => result.stdout)
            .catch(() => 'Unable to get git config'),
        });
      }
      throw error;
    }
  }

  static async validateGitInstallation(operation: string): Promise<void> {
    try {
      const result = await this.execute('git --version', operation);
      logger.info(operation, 'Git installation validated', undefined, {
        version: result.stdout,
      });
    } catch (error) {
      const mcpError = new McpError(
        ErrorCode.InternalError,
        'Git is not installed or not accessible'
      );
      logger.error(operation, 'Git installation validation failed', undefined, mcpError);
      throw mcpError;
    }
  }
}

```

--------------------------------------------------------------------------------
/src/caching/cache.ts:
--------------------------------------------------------------------------------

```typescript
import { logger } from '../utils/logger.js';
import { PerformanceMonitor } from '../monitoring/performance.js';

/**
 * Cache entry with metadata
 */
interface CacheEntry<T> {
  value: T;
  timestamp: number;
  ttl: number;
  hits: number;
  lastAccess: number;
}

/**
 * Cache configuration
 */
interface CacheConfig {
  defaultTTL: number;        // Default time-to-live in milliseconds
  maxSize: number;          // Maximum number of entries
  cleanupInterval: number;  // Cleanup interval in milliseconds
}

/**
 * Default cache configuration
 */
const DEFAULT_CONFIG: CacheConfig = {
  defaultTTL: 5 * 60 * 1000,  // 5 minutes
  maxSize: 1000,              // 1000 entries
  cleanupInterval: 60 * 1000  // 1 minute
};

/**
 * Generic cache implementation with performance monitoring
 */
export class Cache<T> {
  private entries: Map<string, CacheEntry<T>> = new Map();
  private config: CacheConfig;
  private performanceMonitor: PerformanceMonitor;
  private readonly cacheType: string;

  constructor(cacheType: string, config: Partial<CacheConfig> = {}) {
    this.config = { ...DEFAULT_CONFIG, ...config };
    this.cacheType = cacheType;
    this.performanceMonitor = PerformanceMonitor.getInstance();
    this.startCleanup();
  }

  /**
   * Set a cache entry
   */
  set(key: string, value: T, ttl: number = this.config.defaultTTL): void {
    // Check cache size limit
    if (this.entries.size >= this.config.maxSize) {
      this.evictOldest();
    }

    this.entries.set(key, {
      value,
      timestamp: Date.now(),
      ttl,
      hits: 0,
      lastAccess: Date.now()
    });

    logger.debug(
      'cache',
      `Set cache entry: ${key}`,
      undefined,
      { cacheType: this.cacheType }
    );
  }

  /**
   * Get a cache entry
   */
  get(key: string): T | undefined {
    const entry = this.entries.get(key);
    
    if (!entry) {
      this.performanceMonitor.recordCacheAccess(false, this.cacheType);
      return undefined;
    }

    // Check if entry is expired
    if (this.isExpired(entry)) {
      this.entries.delete(key);
      this.performanceMonitor.recordCacheAccess(false, this.cacheType);
      return undefined;
    }

    // Update entry metadata
    entry.hits++;
    entry.lastAccess = Date.now();
    this.performanceMonitor.recordCacheAccess(true, this.cacheType);

    logger.debug(
      'cache',
      `Cache hit: ${key}`,
      undefined,
      { cacheType: this.cacheType, hits: entry.hits }
    );

    return entry.value;
  }

  /**
   * Delete a cache entry
   */
  delete(key: string): void {
    this.entries.delete(key);
    logger.debug(
      'cache',
      `Deleted cache entry: ${key}`,
      undefined,
      { cacheType: this.cacheType }
    );
  }

  /**
   * Clear all cache entries
   */
  clear(): void {
    this.entries.clear();
    logger.info(
      'cache',
      'Cleared cache',
      undefined,
      { cacheType: this.cacheType }
    );
  }

  /**
   * Get cache statistics
   */
  getStats(): Record<string, any> {
    const now = Date.now();
    let totalHits = 0;
    let totalSize = 0;
    let oldestTimestamp = now;
    let newestTimestamp = 0;

    this.entries.forEach(entry => {
      totalHits += entry.hits;
      totalSize++;
      oldestTimestamp = Math.min(oldestTimestamp, entry.timestamp);
      newestTimestamp = Math.max(newestTimestamp, entry.timestamp);
    });

    return {
      size: totalSize,
      maxSize: this.config.maxSize,
      totalHits,
      oldestEntry: oldestTimestamp === now ? null : oldestTimestamp,
      newestEntry: newestTimestamp === 0 ? null : newestTimestamp,
      hitRate: this.performanceMonitor.getCacheHitRate(this.cacheType)
    };
  }

  /**
   * Check if a cache entry exists and is valid
   */
  has(key: string): boolean {
    const entry = this.entries.get(key);
    if (!entry) return false;
    if (this.isExpired(entry)) {
      this.entries.delete(key);
      return false;
    }
    return true;
  }

  /**
   * Update cache configuration
   */
  updateConfig(config: Partial<CacheConfig>): void {
    this.config = {
      ...this.config,
      ...config
    };
    logger.info(
      'cache',
      'Updated cache configuration',
      undefined,
      { cacheType: this.cacheType, config: this.config }
    );
  }

  /**
   * Get current configuration
   */
  getConfig(): CacheConfig {
    return { ...this.config };
  }

  /**
   * Check if a cache entry is expired
   */
  private isExpired(entry: CacheEntry<T>): boolean {
    return Date.now() - entry.timestamp > entry.ttl;
  }

  /**
   * Evict the least recently used entry
   */
  private evictOldest(): void {
    let oldestKey: string | undefined;
    let oldestAccess = Date.now();

    this.entries.forEach((entry, key) => {
      if (entry.lastAccess < oldestAccess) {
        oldestAccess = entry.lastAccess;
        oldestKey = key;
      }
    });

    if (oldestKey) {
      this.entries.delete(oldestKey);
      logger.debug(
        'cache',
        `Evicted oldest entry: ${oldestKey}`,
        undefined,
        { cacheType: this.cacheType }
      );
    }
  }

  /**
   * Start periodic cache cleanup
   */
  private startCleanup(): void {
    setInterval(() => {
      const now = Date.now();
      let expiredCount = 0;

      this.entries.forEach((entry, key) => {
        if (now - entry.timestamp > entry.ttl) {
          this.entries.delete(key);
          expiredCount++;
        }
      });

      if (expiredCount > 0) {
        logger.debug(
          'cache',
          `Cleaned up ${expiredCount} expired entries`,
          undefined,
          { cacheType: this.cacheType }
        );
      }
    }, this.config.cleanupInterval);
  }
}

/**
 * Repository state cache
 */
export class RepositoryStateCache extends Cache<any> {
  constructor() {
    super('repository_state', {
      defaultTTL: 30 * 1000,  // 30 seconds
      maxSize: 100            // 100 entries
    });
  }
}

/**
 * Command result cache
 */
export class CommandResultCache extends Cache<any> {
  constructor() {
    super('command_result', {
      defaultTTL: 5 * 60 * 1000,  // 5 minutes
      maxSize: 500                // 500 entries
    });
  }

  /**
   * Generate cache key for a command
   */
  static generateKey(command: string, workingDir?: string): string {
    return `${workingDir || ''}:${command}`;
  }
}

```

--------------------------------------------------------------------------------
/src/errors/error-handler.ts:
--------------------------------------------------------------------------------

```typescript
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import {
  ErrorCategory,
  ErrorSeverity,
  ErrorCategoryType,
  ErrorSeverityType,
  GitMcpError,
  ErrorContext
} from './error-types.js';
import { logger } from '../utils/logger.js';

/**
 * Maps error categories to appropriate MCP error codes
 */
function getMcpErrorCode(category: ErrorCategoryType, severity: ErrorSeverityType): ErrorCode {
  switch (category) {
    case ErrorCategory.VALIDATION:
      return ErrorCode.InvalidParams;
    case ErrorCategory.SYSTEM:
    case ErrorCategory.OPERATION:
    case ErrorCategory.NETWORK:
    case ErrorCategory.SECURITY:
      return ErrorCode.InternalError;
    case ErrorCategory.REPOSITORY:
      // For repository state errors, use InvalidParams if it's a configuration issue,
      // otherwise use InternalError
      return severity === ErrorSeverity.MEDIUM ? ErrorCode.InvalidParams : ErrorCode.InternalError;
    case ErrorCategory.CONFIGURATION:
      return ErrorCode.InvalidParams;
    default:
      return ErrorCode.InternalError;
  }
}

/**
 * Handles and logs errors with appropriate context and recovery steps
 */
export class ErrorHandler {
  /**
   * Creates a GitMcpError with appropriate context and logs it
   */
  static handleError(
    error: Error | GitMcpError,
    category: ErrorCategoryType,
    severity: ErrorSeverityType,
    context: Partial<ErrorContext>
  ): GitMcpError {
    // If it's already a GitMcpError, just log and return it
    if (error instanceof GitMcpError) {
      this.logError(error);
      return error;
    }

    // Create new GitMcpError with context
    const errorContext: Partial<ErrorContext> = {
      ...context,
      stackTrace: error.stack,
      timestamp: Date.now()
    };

    const gitError = new GitMcpError(
      getMcpErrorCode(category, severity),
      error.message,
      severity,
      category,
      errorContext
    );

    this.logError(gitError);
    return gitError;
  }

  /**
   * Logs error with full context and recovery steps
   */
  private static logError(error: GitMcpError): void {
    const errorInfo = {
      name: error.name,
      message: error.message,
      severity: error.severity,
      category: error.category,
      context: error.context,
      recoverySteps: error.getRecoverySteps()
    };

    // Log based on severity
    switch (error.severity) {
      case ErrorSeverity.CRITICAL:
        logger.error(
          error.context.operation,
          `CRITICAL: ${error.message}`,
          error.context.path,
          error,
          errorInfo
        );
        break;
      case ErrorSeverity.HIGH:
        logger.error(
          error.context.operation,
          `HIGH: ${error.message}`,
          error.context.path,
          error,
          errorInfo
        );
        break;
      case ErrorSeverity.MEDIUM:
        logger.warn(
          error.context.operation,
          `MEDIUM: ${error.message}`,
          error.context.path,
          error,
          errorInfo
        );
        break;
      case ErrorSeverity.LOW:
        logger.warn(
          error.context.operation,
          `LOW: ${error.message}`,
          error.context.path,
          error,
          errorInfo
        );
        break;
    }
  }

  /**
   * Creates and handles a system error
   */
  static handleSystemError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.SYSTEM, ErrorSeverity.CRITICAL, context);
  }

  /**
   * Creates and handles a validation error
   */
  static handleValidationError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.VALIDATION, ErrorSeverity.HIGH, context);
  }

  /**
   * Creates and handles an operation error
   */
  static handleOperationError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.OPERATION, ErrorSeverity.HIGH, context);
  }

  /**
   * Creates and handles a repository error
   */
  static handleRepositoryError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.REPOSITORY, ErrorSeverity.HIGH, context);
  }

  /**
   * Creates and handles a network error
   */
  static handleNetworkError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.NETWORK, ErrorSeverity.HIGH, context);
  }

  /**
   * Creates and handles a configuration error
   */
  static handleConfigError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.CONFIGURATION, ErrorSeverity.MEDIUM, context);
  }

  /**
   * Creates and handles a security error
   */
  static handleSecurityError(error: Error, context: Partial<ErrorContext>): GitMcpError {
    return this.handleError(error, ErrorCategory.SECURITY, ErrorSeverity.CRITICAL, context);
  }

  /**
   * Determines if an error is retryable based on its category and severity
   */
  static isRetryable(error: GitMcpError): boolean {
    // Never retry validation or security errors
    if (
      error.category === ErrorCategory.VALIDATION ||
      error.category === ErrorCategory.SECURITY ||
      error.severity === ErrorSeverity.CRITICAL
    ) {
      return false;
    }

    // Network errors are usually retryable
    if (error.category === ErrorCategory.NETWORK) {
      return true;
    }

    // Repository and operation errors are retryable for non-critical severities
    if (
      (error.category === ErrorCategory.REPOSITORY ||
       error.category === ErrorCategory.OPERATION) &&
      [ErrorSeverity.HIGH, ErrorSeverity.MEDIUM, ErrorSeverity.LOW].includes(error.severity as any)
    ) {
      return true;
    }

    return false;
  }

  /**
   * Gets suggested retry delay in milliseconds based on error type
   */
  static getRetryDelay(error: GitMcpError): number {
    if (!this.isRetryable(error)) {
      return 0;
    }

    switch (error.category) {
      case ErrorCategory.NETWORK:
        return 1000; // 1 second for network issues
      case ErrorCategory.REPOSITORY:
        return 500;  // 500ms for repository issues
      case ErrorCategory.OPERATION:
        return 200;  // 200ms for operation issues
      default:
        return 1000; // Default 1 second
    }
  }
}

```

--------------------------------------------------------------------------------
/src/operations/branch/branch-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { BaseGitOperation } from '../base/base-operation.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { CommandResult } from '../base/operation-result.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { RepositoryValidator } from '../../utils/repository.js';
import { RepoStateType } from '../../caching/repository-cache.js';
import {
  BranchListOptions,
  BranchCreateOptions,
  BranchDeleteOptions,
  CheckoutOptions,
  BranchListResult,
  BranchCreateResult,
  BranchDeleteResult,
  CheckoutResult,
  BranchInfo
} from './branch-types.js';

/**
 * Handles Git branch listing operations
 */
export class BranchListOperation extends BaseGitOperation<BranchListOptions, BranchListResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.branch();

    // Add format option for parsing
    command.option('format', '%(refname:short)|%(upstream:short)|%(objectname:short)|%(subject)');

    if (this.options.remotes) {
      command.flag('remotes');
    }
    if (this.options.all) {
      command.flag('all');
    }
    if (this.options.contains) {
      command.option('contains', this.options.contains);
    }
    if (this.options.merged) {
      command.option('merged', this.options.merged);
    }
    if (this.options.noMerged) {
      command.option('no-merged', this.options.noMerged);
    }

    return command;
  }

  protected parseResult(result: CommandResult): BranchListResult {
    const branches: BranchInfo[] = [];
    let current = '';

    // Parse each line of output
    result.stdout.split('\n').filter(Boolean).forEach(line => {
      const [name, tracking, commit, message] = line.split('|');
      const isCurrent = name.startsWith('* ');
      const cleanName = name.replace('* ', '');
      
      const branch: BranchInfo = {
        name: cleanName,
        current: isCurrent,
        tracking: tracking || undefined,
        remote: cleanName.includes('origin/'),
        commit: commit || undefined,
        message: message || undefined
      };

      if (isCurrent) {
        current = cleanName;
      }

      branches.push(branch);
    });

    return {
      current,
      branches,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'branch',
      stateType: RepoStateType.BRANCH
    };
  }

  protected validateOptions(): void {
    // No specific validation needed for listing
  }
}

/**
 * Handles Git branch creation operations
 */
export class BranchCreateOperation extends BaseGitOperation<BranchCreateOptions, BranchCreateResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.branch()
      .arg(this.options.name);

    if (this.options.startPoint) {
      command.arg(this.options.startPoint);
    }

    if (this.options.force) {
      command.withForce();
    }

    if (this.options.track) {
      command.withTrack();
    } else {
      command.withNoTrack();
    }

    if (this.options.setUpstream) {
      command.withSetUpstream();
    }

    return command;
  }

  protected parseResult(result: CommandResult): BranchCreateResult {
    return {
      name: this.options.name,
      startPoint: this.options.startPoint,
      tracking: result.stdout.includes('set up to track') ? 
        result.stdout.match(/track\s+([^\s]+)/)?.[1] : undefined,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'branch_create',
      stateType: RepoStateType.BRANCH
    };
  }

  protected validateOptions(): void {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Branch name is required'),
        { operation: this.context.operation }
      );
    }
  }
}

/**
 * Handles Git branch deletion operations
 */
export class BranchDeleteOperation extends BaseGitOperation<BranchDeleteOptions, BranchDeleteResult> {
  protected async buildCommand(): Promise<GitCommandBuilder> {
    const command = GitCommandBuilder.branch();

    // Use -D for force delete, -d for safe delete
    command.flag(this.options.force ? 'D' : 'd')
      .arg(this.options.name);

    if (this.options.remote) {
      // Get remote name from branch if it's a remote branch
      const remoteName = this.options.name.split('/')[0];
      if (remoteName) {
        await RepositoryValidator.validateRemoteConfig(
          this.getResolvedPath(),
          remoteName,
          this.context.operation
        );
      }
      command.flag('r');
    }

    return command;
  }

  protected parseResult(result: CommandResult): BranchDeleteResult {
    return {
      name: this.options.name,
      forced: this.options.force || false,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'branch_delete',
      stateType: RepoStateType.BRANCH
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Branch name is required'),
        { operation: this.context.operation }
      );
    }

    // Ensure branch exists
    await RepositoryValidator.validateBranchExists(
      this.getResolvedPath(),
      this.options.name,
      this.context.operation
    );

    // Cannot delete current branch
    const currentBranch = await RepositoryValidator.getCurrentBranch(
      this.getResolvedPath(),
      this.context.operation
    );
    if (currentBranch === this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error(`Cannot delete the currently checked out branch: ${this.options.name}`),
        { operation: this.context.operation }
      );
    }
  }

}

/**
 * Handles Git checkout operations
 */
export class CheckoutOperation extends BaseGitOperation<CheckoutOptions, CheckoutResult> {
  protected async buildCommand(): Promise<GitCommandBuilder> {
    const command = GitCommandBuilder.checkout();

    if (this.options.newBranch) {
      command.flag('b').arg(this.options.newBranch);
      if (this.options.track) {
        command.withTrack();
      }
    }

    command.arg(this.options.target);

    if (this.options.force) {
      command.withForce();
    }

    return command;
  }

  protected parseResult(result: CommandResult): CheckoutResult {
    const previousHead = result.stdout.match(/HEAD is now at ([a-f0-9]+)/)?.[1];
    const newBranch = result.stdout.includes('Switched to a new branch') ? 
      this.options.newBranch : undefined;

    return {
      target: this.options.target,
      newBranch,
      previousHead,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'checkout',
      stateType: RepoStateType.BRANCH
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.target) {
      throw ErrorHandler.handleValidationError(
        new Error('Checkout target is required'),
        { operation: this.context.operation }
      );
    }

    // Ensure working tree is clean unless force is specified
    if (!this.options.force) {
      await RepositoryValidator.ensureClean(
        this.getResolvedPath(),
        this.context.operation
      );
    }
  }

}

```

--------------------------------------------------------------------------------
/src/errors/error-types.ts:
--------------------------------------------------------------------------------

```typescript
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';

/**
 * Error severity levels for categorizing errors and determining appropriate responses
 */
export const ErrorSeverity = {
  CRITICAL: 'CRITICAL', // System-level failures requiring immediate attention
  HIGH: 'HIGH',        // Operation-blocking errors that need urgent handling
  MEDIUM: 'MEDIUM',    // Non-blocking errors that should be addressed
  LOW: 'LOW'          // Minor issues that can be handled gracefully
} as const;

export type ErrorSeverityType = typeof ErrorSeverity[keyof typeof ErrorSeverity];

/**
 * Error categories for better error handling and reporting
 */
export const ErrorCategory = {
  SYSTEM: 'SYSTEM',           // System-level errors (file system, process, etc.)
  VALIDATION: 'VALIDATION',   // Input validation errors
  OPERATION: 'OPERATION',     // Git operation errors
  REPOSITORY: 'REPOSITORY',   // Repository state errors
  NETWORK: 'NETWORK',         // Network-related errors
  CONFIGURATION: 'CONFIG',    // Configuration errors
  SECURITY: 'SECURITY'        // Security-related errors
} as const;

export type ErrorCategoryType = typeof ErrorCategory[keyof typeof ErrorCategory];

/**
 * Extended error context for better error tracking and debugging
 */
export interface ErrorContext {
  operation: string;           // Operation being performed
  path?: string;              // Path being operated on
  command?: string;           // Git command being executed
  timestamp: number;          // Error occurrence timestamp
  severity: ErrorSeverityType;    // Error severity level
  category: ErrorCategoryType;    // Error category
  details?: {
    currentUsage?: number;
    threshold?: number;
    command?: string;
    exitCode?: number | string;
    stdout?: string;
    stderr?: string;
    config?: string;
    tool?: string;
    args?: unknown;
    [key: string]: unknown;
  }; // Additional error-specific details
  recoverySteps?: string[];   // Suggested recovery steps
  stackTrace?: string;        // Error stack trace
}

/**
 * Base class for all Git MCP server errors
 */
export class GitMcpError extends McpError {
  readonly severity: ErrorSeverityType;
  readonly category: ErrorCategoryType;
  readonly context: ErrorContext;

  constructor(
    code: ErrorCode,
    message: string,
    severity: ErrorSeverityType,
    category: ErrorCategoryType,
    context: Partial<ErrorContext>
  ) {
    super(code, message);
    this.name = 'GitMcpError';
    this.severity = severity;
    this.category = category;
    this.context = {
      operation: context.operation || 'unknown',
      timestamp: Date.now(),
      severity,
      category,
      ...context
    };
  }

  /**
   * Get recovery steps based on error type and context
   */
  getRecoverySteps(): string[] {
    return this.context.recoverySteps || this.getDefaultRecoverySteps();
  }

  /**
   * Get default recovery steps based on error category
   */
  private getDefaultRecoverySteps(): string[] {
    switch (this.category) {
      case ErrorCategory.SYSTEM:
        return [
          'Check system permissions and access rights',
          'Verify file system access',
          'Check available disk space',
          'Ensure required dependencies are installed'
        ];
      case ErrorCategory.VALIDATION:
        return [
          'Verify input parameters are correct',
          'Check path formatting and permissions',
          'Ensure all required fields are provided'
        ];
      case ErrorCategory.OPERATION:
        return [
          'Verify Git command syntax',
          'Check repository state',
          'Ensure working directory is clean',
          'Try running git status for more information'
        ];
      case ErrorCategory.REPOSITORY:
        return [
          'Verify repository exists and is accessible',
          'Check repository permissions',
          'Ensure .git directory is intact',
          'Try reinitializing the repository'
        ];
      case ErrorCategory.NETWORK:
        return [
          'Check network connectivity',
          'Verify remote repository access',
          'Check authentication credentials',
          'Try using git remote -v to verify remote configuration'
        ];
      case ErrorCategory.CONFIGURATION:
        return [
          'Check Git configuration',
          'Verify environment variables',
          'Ensure required settings are configured',
          'Try git config --list to view current configuration'
        ];
      case ErrorCategory.SECURITY:
        return [
          'Check file and directory permissions',
          'Verify authentication credentials',
          'Ensure secure connection to remote',
          'Review security settings'
        ];
      default:
        return [
          'Check operation parameters',
          'Verify system state',
          'Review error message details',
          'Contact support if issue persists'
        ];
    }
  }

  /**
   * Format error for logging
   */
  toJSON(): Record<string, any> {
    return {
      name: this.name,
      message: this.message,
      code: this.code,
      severity: this.severity,
      category: this.category,
      context: this.context,
      recoverySteps: this.getRecoverySteps(),
      stack: this.stack
    };
  }
}

/**
 * System-level errors
 */
export class SystemError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InternalError,
      message,
      ErrorSeverity.CRITICAL,
      ErrorCategory.SYSTEM,
      context
    );
    this.name = 'SystemError';
  }
}

/**
 * Validation errors
 */
export class ValidationError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InvalidParams,
      message,
      ErrorSeverity.HIGH,
      ErrorCategory.VALIDATION,
      context
    );
    this.name = 'ValidationError';
  }
}

/**
 * Git operation errors
 */
export class OperationError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InternalError,
      message,
      ErrorSeverity.HIGH,
      ErrorCategory.OPERATION,
      context
    );
    this.name = 'OperationError';
  }
}

/**
 * Repository state errors
 */
export class RepositoryError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InternalError,
      message,
      ErrorSeverity.HIGH,
      ErrorCategory.REPOSITORY,
      context
    );
    this.name = 'RepositoryError';
  }
}

/**
 * Network-related errors
 */
export class NetworkError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InternalError,
      message,
      ErrorSeverity.HIGH,
      ErrorCategory.NETWORK,
      context
    );
    this.name = 'NetworkError';
  }
}

/**
 * Configuration errors
 */
export class ConfigurationError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InvalidParams,
      message,
      ErrorSeverity.MEDIUM,
      ErrorCategory.CONFIGURATION,
      context
    );
    this.name = 'ConfigurationError';
  }
}

/**
 * Security-related errors
 */
export class SecurityError extends GitMcpError {
  constructor(message: string, context: Partial<ErrorContext>) {
    super(
      ErrorCode.InternalError,
      message,
      ErrorSeverity.CRITICAL,
      ErrorCategory.SECURITY,
      context
    );
    this.name = 'SecurityError';
  }
}

```

--------------------------------------------------------------------------------
/src/operations/working-tree/working-tree-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { BaseGitOperation } from '../base/base-operation.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { CommandResult } from '../base/operation-result.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { RepositoryValidator } from '../../utils/repository.js';
import { CommandExecutor } from '../../utils/command.js';
import { RepoStateType } from '../../caching/repository-cache.js';
import {
  AddOptions,
  CommitOptions,
  StatusOptions,
  AddResult,
  CommitResult,
  StatusResult,
  FileChange
} from './working-tree-types.js';

/**
 * Handles Git add operations
 */
export class AddOperation extends BaseGitOperation<AddOptions, AddResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.add();

    if (this.options.all) {
      command.flag('all');
    }

    if (this.options.update) {
      command.flag('update');
    }

    if (this.options.ignoreRemoval) {
      command.flag('no-all');
    }

    if (this.options.force) {
      command.withForce();
    }

    if (this.options.dryRun) {
      command.flag('dry-run');
    }

    // Add files
    this.options.files.forEach(file => command.arg(file));

    return command;
  }

  protected parseResult(result: CommandResult): AddResult {
    const staged: string[] = [];
    const notStaged: Array<{ path: string; reason: string }> = [];

    // Parse output to determine which files were staged
    result.stdout.split('\n').forEach(line => {
      const match = line.match(/^add '(.+)'$/);
      if (match) {
        staged.push(match[1]);
      } else if (line.includes('error:')) {
        const errorMatch = line.match(/error: (.+?) '(.+?)'/);
        if (errorMatch) {
          notStaged.push({
            path: errorMatch[2],
            reason: errorMatch[1]
          });
        }
      }
    });

    return {
      staged,
      notStaged: notStaged.length > 0 ? notStaged : undefined,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'add',
      stateType: RepoStateType.STATUS
    };
  }

  protected validateOptions(): void {
    if (!this.options.files || this.options.files.length === 0) {
      throw ErrorHandler.handleValidationError(
        new Error('At least one file must be specified'),
        { operation: this.context.operation }
      );
    }
  }
}

/**
 * Handles Git commit operations
 */
export class CommitOperation extends BaseGitOperation<CommitOptions, CommitResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.commit();

    command.withMessage(this.options.message);

    if (this.options.allowEmpty) {
      command.flag('allow-empty');
    }

    if (this.options.amend) {
      command.flag('amend');
    }

    if (this.options.noVerify) {
      command.withNoVerify();
    }

    if (this.options.author) {
      command.option('author', this.options.author);
    }

    // Add specific files if provided
    if (this.options.files) {
      this.options.files.forEach(file => command.arg(file));
    }

    return command;
  }

  protected parseResult(result: CommandResult): CommitResult {
    const hash = result.stdout.match(/\[.+?(\w+)\]/)?.[1] || '';
    const stats = result.stdout.match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);

    return {
      hash,
      filesChanged: stats ? parseInt(stats[1], 10) : 0,
      insertions: stats && stats[2] ? parseInt(stats[2], 10) : 0,
      deletions: stats && stats[3] ? parseInt(stats[3], 10) : 0,
      amended: this.options.amend || false,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'commit',
      stateType: RepoStateType.STATUS
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.message && !this.options.amend) {
      throw ErrorHandler.handleValidationError(
        new Error('Commit message is required unless amending'),
        { operation: this.context.operation }
      );
    }

    // Verify there are staged changes unless allowing empty commits
    if (!this.options.allowEmpty) {
      const statusResult = await CommandExecutor.executeGitCommand(
        'status --porcelain',
        this.context.operation,
        this.getResolvedPath()
      );
      
      if (!statusResult.stdout.trim()) {
        throw ErrorHandler.handleValidationError(
          new Error('No changes to commit'),
          { operation: this.context.operation }
        );
      }
    }
  }
}

/**
 * Handles Git status operations
 */
export class StatusOperation extends BaseGitOperation<StatusOptions, StatusResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.status();

    // Use porcelain format for consistent parsing
    command.flag('porcelain');
    command.flag('z'); // Use NUL character as separator

    if (this.options.showUntracked) {
      command.flag('untracked-files');
    }

    if (this.options.ignoreSubmodules) {
      command.option('ignore-submodules', 'all');
    }

    if (this.options.showIgnored) {
      command.flag('ignored');
    }

    if (this.options.showBranch) {
      command.flag('branch');
    }

    return command;
  }

  protected async parseResult(result: CommandResult): Promise<StatusResult> {
    const staged: FileChange[] = [];
    const unstaged: FileChange[] = [];
    const untracked: FileChange[] = [];
    const ignored: FileChange[] = [];

    // Get current branch
    const branchResult = await CommandExecutor.executeGitCommand(
      'rev-parse --abbrev-ref HEAD',
      this.context.operation,
      this.getResolvedPath()
    );
    const branch = branchResult.stdout.trim();

    // Parse status output
    const entries = result.stdout.split('\0').filter(Boolean);
    for (const entry of entries) {
      const [status, ...pathParts] = entry.split(' ');
      const path = pathParts.join(' ');

      const change: FileChange = {
        path,
        type: this.parseChangeType(status),
        staged: status[0] !== ' ' && status[0] !== '?',
        raw: status
      };

      // Handle renamed files
      if (change.type === 'renamed') {
        const [oldPath, newPath] = path.split(' -> ');
        change.path = newPath;
        change.originalPath = oldPath;
      }

      // Categorize the change
      if (status === '??') {
        untracked.push(change);
      } else if (status === '!!') {
        ignored.push(change);
      } else if (change.staged) {
        staged.push(change);
      } else {
        unstaged.push(change);
      }
    }

    return {
      branch,
      clean: staged.length === 0 && unstaged.length === 0 && untracked.length === 0,
      staged,
      unstaged,
      untracked,
      ignored: this.options.showIgnored ? ignored : undefined,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'status',
      stateType: RepoStateType.STATUS
    };
  }

  protected validateOptions(): void {
    // No specific validation needed for status
  }

  private parseChangeType(status: string): FileChange['type'] {
    const index = status[0];
    const worktree = status[1];

    if (status === '??') return 'untracked';
    if (status === '!!') return 'ignored';
    if (index === 'R' || worktree === 'R') return 'renamed';
    if (index === 'C' || worktree === 'C') return 'copied';
    if (index === 'A' || worktree === 'A') return 'added';
    if (index === 'D' || worktree === 'D') return 'deleted';
    return 'modified';
  }
}

```

--------------------------------------------------------------------------------
/src/utils/path.ts:
--------------------------------------------------------------------------------

```typescript
import { resolve, isAbsolute, normalize } from 'path';
import { existsSync, statSync, readdirSync } from 'fs';
import { ErrorHandler } from '../errors/error-handler.js';
import { GitMcpError } from '../errors/error-types.js';

export interface PathValidationOptions {
  mustExist?: boolean;
  allowDirectory?: boolean;
  allowPattern?: boolean;
  cwd?: string;
  operation?: string;
}

export class PathValidator {
  static validatePath(path: string, options: PathValidationOptions = {}): string {
    const { 
      mustExist = true, 
      allowDirectory = true, 
      cwd = process.cwd(),
      operation = 'path_validation'
    } = options;

    try {
      if (!path || typeof path !== 'string') {
        throw new Error('Path must be a non-empty string');
      }

      // Convert to absolute path if relative
      const absolutePath = isAbsolute(path) ? normalize(path) : resolve(cwd, path);

      // Check existence if required
      if (mustExist && !existsSync(absolutePath)) {
        throw new Error(`Path does not exist: ${path}`);
      }

      // If path exists and is not a pattern, validate type
      if (existsSync(absolutePath)) {
        const stats = statSync(absolutePath);
        if (!allowDirectory && stats.isDirectory()) {
          throw new Error(`Path is a directory when file expected: ${path}`);
        }
      }

      return absolutePath;
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { options }
      });
    }
  }

  static validateGitRepo(path: string, operation = 'validate_repo'): { path: string; hasEmbeddedRepo: boolean } {
    try {
      const absolutePath = this.validatePath(path, { allowDirectory: true, operation });
      const gitPath = resolve(absolutePath, '.git');

      if (!existsSync(gitPath)) {
        throw new Error(`Not a git repository: ${path}`);
      }

      if (!statSync(gitPath).isDirectory()) {
        throw new Error(`Invalid git repository: ${path}`);
      }

      // Check for embedded repositories
      let hasEmbeddedRepo = false;
      const checkEmbeddedRepos = (dir: string) => {
        const entries = readdirSync(dir, { withFileTypes: true });
        for (const entry of entries) {
          if (entry.isDirectory()) {
            const fullPath = resolve(dir, entry.name);
            if (entry.name === '.git' && fullPath !== gitPath) {
              hasEmbeddedRepo = true;
              break;
            }
            if (entry.name !== '.git' && entry.name !== 'node_modules') {
              checkEmbeddedRepos(fullPath);
            }
          }
        }
      };
      checkEmbeddedRepos(absolutePath);

      return { path: absolutePath, hasEmbeddedRepo };
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { gitPath: resolve(path, '.git') }
      });
    }
  }

  static validatePaths(paths: string[], options: PathValidationOptions = {}): string[] {
    const { 
      allowPattern = false, 
      cwd = process.cwd(),
      operation = 'validate_paths'
    } = options;

    try {
      if (!Array.isArray(paths)) {
        throw new Error('Paths must be an array');
      }

      return paths.map(path => {
        if (!path || typeof path !== 'string') {
          throw new Error('Each path must be a non-empty string');
        }

        // If patterns are allowed and path contains wildcards, return as-is
        if (allowPattern && /[*?[\]]/.test(path)) {
          return path;
        }

        // For relative paths starting with '.', make them relative to the repository root
        if (path.startsWith('.')) {
          // Just return the path as-is to let Git handle it relative to the repo root
          return path;
        }

        // Convert to absolute path if relative
        return isAbsolute(path) ? normalize(path) : resolve(cwd, path);
      });
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { paths, options }
      });
    }
  }

  static validateBranchName(branch: string, operation = 'validate_branch'): void {
    try {
      if (!branch || typeof branch !== 'string') {
        throw new Error('Branch name must be a non-empty string');
      }

      // Git branch naming rules
      if (!/^(?!\/|\.|\.\.|@|\{|\}|\[|\]|\\)[\x21-\x7E]+(?<!\.lock|[/.])$/.test(branch)) {
        throw new Error('Invalid branch name format');
      }
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { branch }
      });
    }
  }

  static validateRemoteName(name: string, operation = 'validate_remote'): void {
    try {
      if (!name || typeof name !== 'string') {
        throw new Error('Remote name must be a non-empty string');
      }

      // Git remote naming rules
      if (!/^[a-zA-Z0-9][a-zA-Z0-9-]*$/.test(name)) {
        throw new Error('Invalid remote name format');
      }
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { remoteName: name }
      });
    }
  }

  static validateRemoteUrl(url: string, operation = 'validate_remote_url'): void {
    try {
      if (!url || typeof url !== 'string') {
        throw new Error('Remote URL must be a non-empty string');
      }

      // Basic URL format validation for git URLs
      const gitUrlPattern = /^(git|https?|ssh):\/\/|^git@|^[a-zA-Z0-9_-]+:/;
      if (!gitUrlPattern.test(url)) {
        throw new Error('Invalid git remote URL format');
      }

      // Additional security checks for URLs
      const securityPattern = /[<>'";&|]/;
      if (securityPattern.test(url)) {
        throw new Error('Remote URL contains invalid characters');
      }
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { 
          url,
          allowedProtocols: ['git', 'https', 'ssh']
        }
      });
    }
  }

  static validateTagName(tag: string, operation = 'validate_tag'): void {
    try {
      if (!tag || typeof tag !== 'string') {
        throw new Error('Tag name must be a non-empty string');
      }

      // Git tag naming rules
      if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(tag)) {
        throw new Error('Invalid tag name format');
      }

      // Additional validation for semantic versioning tags
      if (tag.startsWith('v') && !/^v\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(tag)) {
        throw new Error('Invalid semantic version tag format');
      }
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { 
          tag,
          semanticVersioning: tag.startsWith('v')
        }
      });
    }
  }

  /**
   * Validates a commit message format
   */
  static validateCommitMessage(message: string, operation = 'validate_commit'): void {
    try {
      if (!message || typeof message !== 'string') {
        throw new Error('Commit message must be a non-empty string');
      }

      // Basic commit message format validation
      if (message.length > 72) {
        throw new Error('Commit message exceeds maximum length of 72 characters');
      }

      // Check for conventional commit format if it appears to be one
      const conventionalPattern = /^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .+/;
      if (message.match(/^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)/) && !conventionalPattern.test(message)) {
        throw new Error('Invalid conventional commit format');
      }
    } catch (error: unknown) {
      throw ErrorHandler.handleValidationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { 
          message,
          isConventionalCommit: message.match(/^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)/) !== null
        }
      });
    }
  }
}

```

--------------------------------------------------------------------------------
/src/utils/repository.ts:
--------------------------------------------------------------------------------

```typescript
import { existsSync } from 'fs';
import { join } from 'path';
import { CommandExecutor } from './command.js';
import { ErrorHandler } from '../errors/error-handler.js';
import { GitMcpError } from '../errors/error-types.js';

export class RepositoryValidator {
  /**
   * Get list of configured remotes
   */
  static async getRemotes(path: string, operation: string): Promise<string[]> {
    const result = await CommandExecutor.executeGitCommand(
      'remote',
      operation,
      path
    );
    return result.stdout.split('\n').filter(Boolean);
  }

  static async validateLocalRepo(path: string, operation: string): Promise<void> {
    try {
      const gitDir = join(path, '.git');
      if (!existsSync(gitDir)) {
        throw new Error('Not a git repository');
      }
    } catch (error: unknown) {
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { gitDir: join(path, '.git') }
      });
    }
  }

  static async validateRemoteRepo(remote: string, operation: string): Promise<void> {
    try {
      await CommandExecutor.execute(`git ls-remote ${remote}`, operation);
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        details: { 
          remote,
          action: 'validate_remote_repo'
        }
      });
    }
  }

  static async validateBranchExists(path: string, branch: string, operation: string): Promise<void> {
    try {
      await CommandExecutor.execute(
        `git show-ref --verify --quiet refs/heads/${branch}`,
        operation,
        path
      );
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          branch,
          action: 'validate_branch_exists'
        }
      });
    }
  }

  static async validateRemoteBranchExists(path: string, remote: string, branch: string, operation: string): Promise<void> {
    try {
      await CommandExecutor.execute(
        `git show-ref --verify --quiet refs/remotes/${remote}/${branch}`,
        operation,
        path
      );
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          remote,
          branch,
          action: 'validate_remote_branch_exists'
        }
      });
    }
  }

  static async getCurrentBranch(path: string, operation: string): Promise<string> {
    try {
      const result = await CommandExecutor.execute('git rev-parse --abbrev-ref HEAD', operation, path);
      return result.stdout.trim();
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          action: 'get_current_branch',
          command: 'git rev-parse --abbrev-ref HEAD'
        }
      });
    }
  }

  static async ensureClean(path: string, operation: string): Promise<void> {
    let statusResult;
    try {
      statusResult = await CommandExecutor.execute('git status --porcelain', operation, path);
      if (statusResult.stdout.trim()) {
        throw new Error('Working directory is not clean. Please commit or stash your changes.');
      }
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          action: 'ensure_clean',
          status: statusResult?.stdout || 'unknown'
        }
      });
    }
  }

  static async validateRemoteConfig(path: string, remote: string, operation: string): Promise<void> {
    let remoteResult;
    try {
      remoteResult = await CommandExecutor.execute(`git remote get-url ${remote}`, operation, path);
      if (!remoteResult.stdout.trim()) {
        throw new Error(`Remote ${remote} is not configured`);
      }
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          remote,
          action: 'validate_remote_config',
          remoteUrl: remoteResult?.stdout || 'unknown'
        }
      });
    }
  }

  static async validateCommitExists(path: string, commit: string, operation: string): Promise<void> {
    try {
      await CommandExecutor.execute(`git cat-file -e ${commit}^{commit}`, operation, path);
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          commit,
          action: 'validate_commit_exists'
        }
      });
    }
  }

  static async validateTagExists(path: string, tag: string, operation: string): Promise<void> {
    try {
      await CommandExecutor.execute(`git show-ref --tags --quiet refs/tags/${tag}`, operation, path);
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          tag,
          action: 'validate_tag_exists'
        }
      });
    }
  }

  /**
   * Validates repository configuration
   */
  static async validateRepositoryConfig(path: string, operation: string): Promise<void> {
    let configResult;
    try {
      // Check core configuration
      configResult = await CommandExecutor.execute('git config --list', operation, path);
      const config = new Map<string, string>(
        configResult.stdout
          .split('\n')
          .filter(line => line)
          .map(line => {
            const [key, ...values] = line.split('=');
            return [key, values.join('=')] as [string, string];
          })
      );

      // Required configurations
      const requiredConfigs = [
        ['core.repositoryformatversion', '0'],
        ['core.filemode', 'true'],
        ['core.bare', 'false']
      ];

      for (const [key, value] of requiredConfigs) {
        if (config.get(key) !== value) {
          throw new Error(`Invalid repository configuration: ${key}=${config.get(key) || 'undefined'}`);
        }
      }

      // Check repository integrity
      await CommandExecutor.execute('git fsck --full', operation, path);

    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          action: 'validate_repository_config',
          config: configResult?.stdout || 'unknown'
        }
      });
    }
  }

  /**
   * Checks if a repository has any uncommitted changes
   */
  static async hasUncommittedChanges(path: string, operation: string): Promise<boolean> {
    try {
      const result = await CommandExecutor.execute('git status --porcelain', operation, path);
      return result.stdout.trim().length > 0;
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          action: 'check_uncommitted_changes'
        }
      });
    }
  }

  /**
   * Gets the repository's current state information
   */
  static async getRepositoryState(path: string, operation: string): Promise<{
    branch: string;
    isClean: boolean;
    hasStashed: boolean;
    remotes: string[];
    lastCommit: string;
  }> {
    try {
      const [branch, isClean, stashList, remoteList, lastCommit] = await Promise.all([
        this.getCurrentBranch(path, operation),
        this.hasUncommittedChanges(path, operation).then(changes => !changes),
        CommandExecutor.execute('git stash list', operation, path),
        CommandExecutor.execute('git remote', operation, path),
        CommandExecutor.execute('git log -1 --format=%H', operation, path)
      ]);

      return {
        branch,
        isClean,
        hasStashed: stashList.stdout.trim().length > 0,
        remotes: remoteList.stdout.trim().split('\n').filter(Boolean),
        lastCommit: lastCommit.stdout.trim()
      };
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleRepositoryError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        details: { 
          action: 'get_repository_state'
        }
      });
    }
  }
}

```

--------------------------------------------------------------------------------
/src/operations/remote/remote-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { BaseGitOperation } from '../base/base-operation.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { CommandResult } from '../base/operation-result.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { RepositoryValidator } from '../../utils/repository.js';
import { CommandExecutor } from '../../utils/command.js';
import { RepoStateType } from '../../caching/repository-cache.js';
import {
  RemoteListOptions,
  RemoteAddOptions,
  RemoteRemoveOptions,
  RemoteSetUrlOptions,
  RemotePruneOptions,
  RemoteListResult,
  RemoteAddResult,
  RemoteRemoveResult,
  RemoteSetUrlResult,
  RemotePruneResult,
  RemoteConfig
} from './remote-types.js';

/**
 * Handles Git remote listing operations
 */
export class RemoteListOperation extends BaseGitOperation<RemoteListOptions, RemoteListResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.remote();

    if (this.options.verbose) {
      command.flag('verbose');
    }

    return command;
  }

  protected async parseResult(result: CommandResult): Promise<RemoteListResult> {
    const remotes: RemoteConfig[] = [];
    const lines = result.stdout.split('\n').filter(Boolean);

    for (const line of lines) {
      const [name, url, purpose] = line.split(/\s+/);
      
      // Find or create remote config
      let remote = remotes.find(r => r.name === name);
      if (!remote) {
        remote = {
          name,
          fetchUrl: url
        };
        remotes.push(remote);
      }

      // Set URL based on purpose
      if (purpose === '(push)') {
        remote.pushUrl = url;
      }

      // Get additional configuration if verbose
      if (this.options.verbose) {
        const configResult = await CommandExecutor.executeGitCommand(
          `config --get-regexp ^remote\\.${name}\\.`,
          this.context.operation,
          this.getResolvedPath()
        );

        configResult.stdout.split('\n').filter(Boolean).forEach(configLine => {
          const [key, value] = configLine.split(' ');
          const configKey = key.split('.')[2];

          switch (configKey) {
            case 'tagopt':
              remote!.fetchTags = value === '--tags';
              break;
            case 'mirror':
              remote!.mirror = value as 'fetch' | 'push';
              break;
            case 'fetch':
              if (!remote!.branches) remote!.branches = [];
              const branch = value.match(/refs\/heads\/(.+):refs\/remotes\/.+/)?.[1];
              if (branch) remote!.branches.push(branch);
              break;
          }
        });
      }
    }

    return {
      remotes,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'remote',
      stateType: RepoStateType.REMOTE
    };
  }

  protected validateOptions(): void {
    // No specific validation needed for listing
  }
}

/**
 * Handles Git remote add operations
 */
export class RemoteAddOperation extends BaseGitOperation<RemoteAddOptions, RemoteAddResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.remote()
      .arg('add');

    if (this.options.fetch) {
      command.flag('fetch');
    }

    if (typeof this.options.tags === 'boolean') {
      command.flag(this.options.tags ? 'tags' : 'no-tags');
    }

    if (this.options.mirror) {
      command.option('mirror', this.options.mirror);
    }

    command.arg(this.options.name)
      .arg(this.options.url);

    return command;
  }

  protected async parseResult(result: CommandResult): Promise<RemoteAddResult> {
    // Get full remote configuration
    const listOperation = new RemoteListOperation(this.context, { verbose: true });
    const listResult = await listOperation.execute();
    const remotes = listResult.data?.remotes;
    if (!remotes) {
      throw ErrorHandler.handleOperationError(
        new Error('Failed to get remote list'),
        { operation: this.context.operation }
      );
    }
    const remote = remotes.find(r => r.name === this.options.name);

    if (!remote) {
      throw ErrorHandler.handleOperationError(
        new Error(`Failed to get configuration for remote ${this.options.name}`),
        { operation: this.context.operation }
      );
    }

    return {
      remote,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'remote_add',
      stateType: RepoStateType.REMOTE
    };
  }

  protected validateOptions(): void {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Remote name is required'),
        { operation: this.context.operation }
      );
    }

    if (!this.options.url) {
      throw ErrorHandler.handleValidationError(
        new Error('Remote URL is required'),
        { operation: this.context.operation }
      );
    }
  }
}

/**
 * Handles Git remote remove operations
 */
export class RemoteRemoveOperation extends BaseGitOperation<RemoteRemoveOptions, RemoteRemoveResult> {
  protected buildCommand(): GitCommandBuilder {
    return GitCommandBuilder.remote()
      .arg('remove')
      .arg(this.options.name);
  }

  protected parseResult(result: CommandResult): RemoteRemoveResult {
    return {
      name: this.options.name,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'remote_remove',
      stateType: RepoStateType.REMOTE
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Remote name is required'),
        { operation: this.context.operation }
      );
    }

    // Ensure remote exists
    await RepositoryValidator.validateRemoteConfig(
      this.getResolvedPath(),
      this.options.name,
      this.context.operation
    );
  }
}

/**
 * Handles Git remote set-url operations
 */
export class RemoteSetUrlOperation extends BaseGitOperation<RemoteSetUrlOptions, RemoteSetUrlResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.remote()
      .arg('set-url');

    if (this.options.pushUrl) {
      command.flag('push');
    }

    if (this.options.add) {
      command.flag('add');
    }

    if (this.options.delete) {
      command.flag('delete');
    }

    command.arg(this.options.name)
      .arg(this.options.url);

    return command;
  }

  protected async parseResult(result: CommandResult): Promise<RemoteSetUrlResult> {
    // Get full remote configuration
    const listOperation = new RemoteListOperation(this.context, { verbose: true });
    const listResult = await listOperation.execute();
    const remotes = listResult.data?.remotes;
    if (!remotes) {
      throw ErrorHandler.handleOperationError(
        new Error('Failed to get remote list'),
        { operation: this.context.operation }
      );
    }
    const remote = remotes.find(r => r.name === this.options.name);

    if (!remote) {
      throw ErrorHandler.handleOperationError(
        new Error(`Failed to get configuration for remote ${this.options.name}`),
        { operation: this.context.operation }
      );
    }

    return {
      remote,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'remote_set_url',
      stateType: RepoStateType.REMOTE
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Remote name is required'),
        { operation: this.context.operation }
      );
    }

    if (!this.options.url) {
      throw ErrorHandler.handleValidationError(
        new Error('Remote URL is required'),
        { operation: this.context.operation }
      );
    }

    // Ensure remote exists
    await RepositoryValidator.validateRemoteConfig(
      this.getResolvedPath(),
      this.options.name,
      this.context.operation
    );
  }
}

/**
 * Handles Git remote prune operations
 */
export class RemotePruneOperation extends BaseGitOperation<RemotePruneOptions, RemotePruneResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.remote()
      .arg('prune');

    if (this.options.dryRun) {
      command.flag('dry-run');
    }

    command.arg(this.options.name);

    return command;
  }

  protected parseResult(result: CommandResult): RemotePruneResult {
    const prunedBranches = result.stdout
      .split('\n')
      .filter(line => line.includes('* [pruned] '))
      .map(line => line.match(/\* \[pruned\] (.+)/)?.[1] || '');

    return {
      name: this.options.name,
      prunedBranches,
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'remote_prune',
      stateType: RepoStateType.REMOTE
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.name) {
      throw ErrorHandler.handleValidationError(
        new Error('Remote name is required'),
        { operation: this.context.operation }
      );
    }

    // Ensure remote exists
    await RepositoryValidator.validateRemoteConfig(
      this.getResolvedPath(),
      this.options.name,
      this.context.operation
    );
  }
}

```

--------------------------------------------------------------------------------
/src/monitoring/performance.ts:
--------------------------------------------------------------------------------

```typescript
import { logger } from '../utils/logger.js';
import { ErrorHandler } from '../errors/error-handler.js';
import { PerformanceError } from './types.js';
import { ErrorCategory, ErrorSeverity } from '../errors/error-types.js';

/**
 * Performance metric types
 */
export enum MetricType {
  OPERATION_DURATION = 'operation_duration',
  MEMORY_USAGE = 'memory_usage',
  COMMAND_EXECUTION = 'command_execution',
  CACHE_HIT = 'cache_hit',
  CACHE_MISS = 'cache_miss',
  RESOURCE_USAGE = 'resource_usage'
}

/**
 * Performance metric data structure
 */
export interface Metric {
  type: MetricType;
  value: number;
  timestamp: number;
  labels: Record<string, string>;
  context?: Record<string, any>;
}

/**
 * Resource usage thresholds
 */
export interface ResourceThresholds {
  memory: {
    warning: number;   // MB
    critical: number;  // MB
  };
  cpu: {
    warning: number;   // Percentage
    critical: number;  // Percentage
  };
  operations: {
    warning: number;   // Operations per second
    critical: number;  // Operations per second
  };
}

/**
 * Default resource thresholds
 */
const DEFAULT_THRESHOLDS: ResourceThresholds = {
  memory: {
    warning: 1024,    // 1GB
    critical: 2048    // 2GB
  },
  cpu: {
    warning: 70,      // 70%
    critical: 90      // 90%
  },
  operations: {
    warning: 100,     // 100 ops/sec
    critical: 200     // 200 ops/sec
  }
};

/**
 * Performance monitoring system
 */
export class PerformanceMonitor {
  private static instance: PerformanceMonitor;
  private metrics: Metric[] = [];
  private thresholds: ResourceThresholds;
  private operationTimers: Map<string, number> = new Map();
  private readonly METRICS_RETENTION = 3600; // 1 hour in seconds
  private readonly METRICS_CLEANUP_INTERVAL = 300; // 5 minutes in seconds

  private constructor() {
    this.thresholds = DEFAULT_THRESHOLDS;
    this.startMetricsCleanup();
  }

  /**
   * Get singleton instance
   */
  static getInstance(): PerformanceMonitor {
    if (!PerformanceMonitor.instance) {
      PerformanceMonitor.instance = new PerformanceMonitor();
    }
    return PerformanceMonitor.instance;
  }

  /**
   * Start operation timing
   */
  startOperation(operation: string): void {
    this.operationTimers.set(operation, performance.now());
  }

  /**
   * End operation timing and record metric
   */
  endOperation(operation: string, context?: Record<string, any>): void {
    const startTime = this.operationTimers.get(operation);
    if (!startTime) {
      logger.warn(operation, 'No start time found for operation timing', undefined, new Error('Missing operation start time'));
      return;
    }

    const duration = performance.now() - startTime;
    this.operationTimers.delete(operation);

    this.recordMetric({
      type: MetricType.OPERATION_DURATION,
      value: duration,
      timestamp: Date.now(),
      labels: { operation },
      context
    });
  }

  /**
   * Record command execution metric
   */
  recordCommandExecution(command: string, duration: number, context?: Record<string, any>): void {
    this.recordMetric({
      type: MetricType.COMMAND_EXECUTION,
      value: duration,
      timestamp: Date.now(),
      labels: { command },
      context
    });
  }

  /**
   * Record memory usage metric
   */
  recordMemoryUsage(context?: Record<string, any>): void {
    const memoryUsage = process.memoryUsage();
    const memoryUsageMB = memoryUsage.heapUsed / 1024 / 1024; // Convert to MB
    
    // Record heap usage
    this.recordMetric({
      type: MetricType.MEMORY_USAGE,
      value: memoryUsageMB,
      timestamp: Date.now(),
      labels: { type: 'heap' },
      context: {
        ...context,
        heapTotal: memoryUsage.heapTotal / 1024 / 1024,
        external: memoryUsage.external / 1024 / 1024,
        rss: memoryUsage.rss / 1024 / 1024
      }
    });

    // Check thresholds
    this.checkMemoryThresholds(memoryUsageMB);
  }

  /**
   * Record resource usage metric
   */
  recordResourceUsage(
    resource: string,
    value: number,
    context?: Record<string, any>
  ): void {
    this.recordMetric({
      type: MetricType.RESOURCE_USAGE,
      value,
      timestamp: Date.now(),
      labels: { resource },
      context
    });
  }

  /**
   * Record cache hit/miss
   */
  recordCacheAccess(hit: boolean, cacheType: string, context?: Record<string, any>): void {
    this.recordMetric({
      type: hit ? MetricType.CACHE_HIT : MetricType.CACHE_MISS,
      value: 1,
      timestamp: Date.now(),
      labels: { cacheType },
      context
    });
  }

  /**
   * Get metrics for a specific type and time range
   */
  getMetrics(
    type: MetricType,
    startTime: number,
    endTime: number = Date.now()
  ): Metric[] {
    return this.metrics.filter(metric => 
      metric.type === type &&
      metric.timestamp >= startTime &&
      metric.timestamp <= endTime
    );
  }

  /**
   * Calculate operation rate (operations per second)
   */
  getOperationRate(operation: string, windowSeconds: number = 60): number {
    const now = Date.now();
    const startTime = now - (windowSeconds * 1000);
    
    const operationMetrics = this.getMetrics(
      MetricType.OPERATION_DURATION,
      startTime,
      now
    ).filter(metric => metric.labels.operation === operation);

    return operationMetrics.length / windowSeconds;
  }

  /**
   * Get average operation duration
   */
  getAverageOperationDuration(
    operation: string,
    windowSeconds: number = 60
  ): number {
    const now = Date.now();
    const startTime = now - (windowSeconds * 1000);
    
    const operationMetrics = this.getMetrics(
      MetricType.OPERATION_DURATION,
      startTime,
      now
    ).filter(metric => metric.labels.operation === operation);

    if (operationMetrics.length === 0) return 0;

    const totalDuration = operationMetrics.reduce(
      (sum, metric) => sum + metric.value,
      0
    );
    return totalDuration / operationMetrics.length;
  }

  /**
   * Get cache hit rate
   */
  getCacheHitRate(cacheType: string, windowSeconds: number = 60): number {
    const now = Date.now();
    const startTime = now - (windowSeconds * 1000);
    
    const hits = this.getMetrics(MetricType.CACHE_HIT, startTime, now)
      .filter(metric => metric.labels.cacheType === cacheType).length;
    
    const misses = this.getMetrics(MetricType.CACHE_MISS, startTime, now)
      .filter(metric => metric.labels.cacheType === cacheType).length;

    const total = hits + misses;
    return total === 0 ? 0 : hits / total;
  }

  /**
   * Update resource thresholds
   */
  updateThresholds(thresholds: Partial<ResourceThresholds>): void {
    this.thresholds = {
      ...this.thresholds,
      ...thresholds
    };
  }

  /**
   * Get current thresholds
   */
  getThresholds(): ResourceThresholds {
    return { ...this.thresholds };
  }

  /**
   * Private helper to record a metric
   */
  private recordMetric(metric: Metric): void {
    this.metrics.push(metric);

    // Log high severity metrics
    if (
      metric.type === MetricType.MEMORY_USAGE ||
      metric.type === MetricType.RESOURCE_USAGE
    ) {
      const metricError = new PerformanceError(
        `Recorded ${metric.type} metric`,
        {
          details: {
            value: metric.value,
            labels: metric.labels,
            context: metric.context
          },
          operation: metric.labels.operation || 'performance'
        }
      );
      logger.info(
        metric.labels.operation || 'performance',
        `Recorded ${metric.type} metric`,
        undefined,
        metricError
      );
    }
  }

  /**
   * Check memory usage against thresholds
   */
  private checkMemoryThresholds(memoryUsageMB: number): void {
    if (memoryUsageMB >= this.thresholds.memory.critical) {
      const error = new PerformanceError(
        `Critical memory usage: ${memoryUsageMB.toFixed(2)}MB`,
        {
          details: {
            currentUsage: memoryUsageMB,
            threshold: this.thresholds.memory.critical
          },
          operation: 'memory_monitor',
          severity: ErrorSeverity.CRITICAL,
          category: ErrorCategory.SYSTEM
        }
      );
      ErrorHandler.handleSystemError(error, {
        operation: 'memory_monitor',
        severity: ErrorSeverity.CRITICAL,
        category: ErrorCategory.SYSTEM
      });
    } else if (memoryUsageMB >= this.thresholds.memory.warning) {
      const warningError = new PerformanceError(
        `High memory usage: ${memoryUsageMB.toFixed(2)}MB`,
        {
          details: {
            currentUsage: memoryUsageMB,
            threshold: this.thresholds.memory.warning
          },
          operation: 'memory_monitor'
        }
      );
      logger.warn(
        'memory_monitor',
        `High memory usage: ${memoryUsageMB.toFixed(2)}MB`,
        undefined,
        warningError
      );
    }
  }

  /**
   * Start periodic metrics cleanup
   */
  private startMetricsCleanup(): void {
    setInterval(() => {
      const cutoffTime = Date.now() - (this.METRICS_RETENTION * 1000);
      this.metrics = this.metrics.filter(metric => metric.timestamp >= cutoffTime);
    }, this.METRICS_CLEANUP_INTERVAL * 1000);
  }

  /**
   * Get current performance statistics
   */
  getStatistics(): Record<string, any> {
    const now = Date.now();
    const oneMinuteAgo = now - 60000;
    const fiveMinutesAgo = now - 300000;

    return {
      memory: {
        current: process.memoryUsage().heapUsed / 1024 / 1024,
        trend: this.getMetrics(MetricType.MEMORY_USAGE, fiveMinutesAgo)
          .map(m => ({ timestamp: m.timestamp, value: m.value }))
      },
      operations: {
        last1m: this.metrics
          .filter(m => 
            m.type === MetricType.OPERATION_DURATION &&
            m.timestamp >= oneMinuteAgo
          ).length,
        last5m: this.metrics
          .filter(m => 
            m.type === MetricType.OPERATION_DURATION &&
            m.timestamp >= fiveMinutesAgo
          ).length
      },
      cache: {
        hitRate1m: this.getCacheHitRate('all', 60),
        hitRate5m: this.getCacheHitRate('all', 300)
      },
      commandExecutions: {
        last1m: this.metrics
          .filter(m => 
            m.type === MetricType.COMMAND_EXECUTION &&
            m.timestamp >= oneMinuteAgo
          ).length,
        last5m: this.metrics
          .filter(m => 
            m.type === MetricType.COMMAND_EXECUTION &&
            m.timestamp >= fiveMinutesAgo
          ).length
      }
    };
  }
}

```

--------------------------------------------------------------------------------
/src/operations/sync/sync-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { BaseGitOperation } from '../base/base-operation.js';
import { GitCommandBuilder } from '../../common/command-builder.js';
import { CommandResult } from '../base/operation-result.js';
import { ErrorHandler } from '../../errors/error-handler.js';
import { RepositoryValidator } from '../../utils/repository.js';
import { CommandExecutor } from '../../utils/command.js';
import { RepoStateType } from '../../caching/repository-cache.js';
import {
  PushOptions,
  PullOptions,
  FetchOptions,
  PushResult,
  PullResult,
  FetchResult
} from './sync-types.js';

/**
 * Handles Git push operations
 */
export class PushOperation extends BaseGitOperation<PushOptions, PushResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.push();

    if (this.options.remote) {
      command.arg(this.options.remote);
    }

    if (this.options.branch) {
      command.arg(this.options.branch);
    }

    if (this.options.force) {
      command.withForce();
    }

    if (this.options.forceWithLease) {
      command.flag('force-with-lease');
    }

    if (this.options.all) {
      command.flag('all');
    }

    if (this.options.tags) {
      command.flag('tags');
    }

    if (this.options.noVerify) {
      command.withNoVerify();
    }

    if (this.options.setUpstream) {
      command.withSetUpstream();
    }

    if (this.options.prune) {
      command.flag('prune');
    }

    return command;
  }

  protected parseResult(result: CommandResult): PushResult {
    const summary = {
      created: [] as string[],
      deleted: [] as string[],
      updated: [] as string[],
      rejected: [] as string[]
    };

    // Parse push output
    result.stdout.split('\n').forEach(line => {
      if (line.startsWith('To ')) return; // Skip remote URL line

      const match = line.match(/^\s*([a-f0-9]+)\.\.([a-f0-9]+)\s+(\S+)\s+->\s+(\S+)/);
      if (match) {
        const [, oldRef, newRef, localRef, remoteRef] = match;
        summary.updated.push(remoteRef);
      } else if (line.includes('[new branch]')) {
        const branchMatch = line.match(/\[new branch\]\s+(\S+)\s+->\s+(\S+)/);
        if (branchMatch) {
          summary.created.push(branchMatch[2]);
        }
      } else if (line.includes('[deleted]')) {
        const deleteMatch = line.match(/\[deleted\]\s+(\S+)/);
        if (deleteMatch) {
          summary.deleted.push(deleteMatch[1]);
        }
      } else if (line.includes('! [rejected]')) {
        const rejectMatch = line.match(/\! \[rejected\]\s+(\S+)/);
        if (rejectMatch) {
          summary.rejected.push(rejectMatch[1]);
        }
      }
    });

    return {
      remote: this.options.remote || 'origin',
      branch: this.options.branch,
      forced: this.options.force || false,
      summary: {
        created: summary.created.length > 0 ? summary.created : undefined,
        deleted: summary.deleted.length > 0 ? summary.deleted : undefined,
        updated: summary.updated.length > 0 ? summary.updated : undefined,
        rejected: summary.rejected.length > 0 ? summary.rejected : undefined
      },
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'push',
      stateType: RepoStateType.REMOTE
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.branch && !this.options.all) {
      throw ErrorHandler.handleValidationError(
        new Error('Either branch or --all must be specified'),
        { operation: this.context.operation }
      );
    }

    if (this.options.remote) {
      await RepositoryValidator.validateRemoteConfig(
        this.getResolvedPath(),
        this.options.remote,
        this.context.operation
      );
    }

    if (this.options.branch) {
      await RepositoryValidator.validateBranchExists(
        this.getResolvedPath(),
        this.options.branch,
        this.context.operation
      );
    }
  }
}

/**
 * Handles Git pull operations
 */
export class PullOperation extends BaseGitOperation<PullOptions, PullResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.pull();

    if (this.options.remote) {
      command.arg(this.options.remote);
    }

    if (this.options.branch) {
      command.arg(this.options.branch);
    }

    if (this.options.rebase) {
      command.flag('rebase');
    }

    if (this.options.autoStash) {
      command.flag('autostash');
    }

    if (this.options.allowUnrelated) {
      command.flag('allow-unrelated-histories');
    }

    if (this.options.ff === 'only') {
      command.flag('ff-only');
    } else if (this.options.ff === 'no') {
      command.flag('no-ff');
    }

    if (this.options.strategy) {
      command.option('strategy', this.options.strategy);
    }

    if (this.options.strategyOption) {
      this.options.strategyOption.forEach(opt => {
        command.option('strategy-option', opt);
      });
    }

    return command;
  }

  protected parseResult(result: CommandResult): PullResult {
    const summary = {
      merged: [] as string[],
      conflicts: [] as string[]
    };

    let filesChanged = 0;
    let insertions = 0;
    let deletions = 0;

    // Parse pull output
    result.stdout.split('\n').forEach(line => {
      if (line.includes('|')) {
        // Parse merge stats
        const statsMatch = line.match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);
        if (statsMatch) {
          filesChanged = parseInt(statsMatch[1], 10);
          insertions = statsMatch[2] ? parseInt(statsMatch[2], 10) : 0;
          deletions = statsMatch[3] ? parseInt(statsMatch[3], 10) : 0;
        }
      } else if (line.includes('Fast-forward') || line.includes('Merge made by')) {
        // Track merged files
        const mergeMatch = line.match(/([^/]+)$/);
        if (mergeMatch) {
          summary.merged.push(mergeMatch[1]);
        }
      } else if (line.includes('CONFLICT')) {
        // Track conflicts
        const conflictMatch = line.match(/CONFLICT \(.+?\): (.+)/);
        if (conflictMatch) {
          summary.conflicts.push(conflictMatch[1]);
        }
      }
    });

    return {
      remote: this.options.remote || 'origin',
      branch: this.options.branch,
      rebased: this.options.rebase || false,
      filesChanged,
      insertions,
      deletions,
      summary: {
        merged: summary.merged.length > 0 ? summary.merged : undefined,
        conflicts: summary.conflicts.length > 0 ? summary.conflicts : undefined
      },
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'pull',
      stateType: RepoStateType.REMOTE
    };
  }

  protected async validateOptions(): Promise<void> {
    if (!this.options.branch) {
      throw ErrorHandler.handleValidationError(
        new Error('Branch must be specified'),
        { operation: this.context.operation }
      );
    }

    if (this.options.remote) {
      await RepositoryValidator.validateRemoteConfig(
        this.getResolvedPath(),
        this.options.remote,
        this.context.operation
      );
    }

    // Ensure working tree is clean unless autostash is enabled
    if (!this.options.autoStash) {
      await RepositoryValidator.ensureClean(
        this.getResolvedPath(),
        this.context.operation
      );
    }
  }
}

/**
 * Handles Git fetch operations
 */
export class FetchOperation extends BaseGitOperation<FetchOptions, FetchResult> {
  protected buildCommand(): GitCommandBuilder {
    const command = GitCommandBuilder.fetch();

    if (this.options.remote && !this.options.all) {
      command.arg(this.options.remote);
    }

    if (this.options.all) {
      command.flag('all');
    }

    if (this.options.prune) {
      command.flag('prune');
    }

    if (this.options.pruneTags) {
      command.flag('prune-tags');
    }

    if (this.options.tags) {
      command.flag('tags');
    }

    if (this.options.tagsOnly) {
      command.flag('tags').flag('no-recurse-submodules');
    }

    if (this.options.forceTags) {
      command.flag('force').flag('tags');
    }

    if (this.options.depth) {
      command.option('depth', this.options.depth.toString());
    }

    if (typeof this.options.recurseSubmodules !== 'undefined') {
      if (typeof this.options.recurseSubmodules === 'boolean') {
        command.flag(this.options.recurseSubmodules ? 'recurse-submodules' : 'no-recurse-submodules');
      } else {
        command.option('recurse-submodules', this.options.recurseSubmodules);
      }
    }

    if (this.options.progress) {
      command.flag('progress');
    }

    return command;
  }

  protected parseResult(result: CommandResult): FetchResult {
    const summary = {
      branches: [] as Array<{ name: string; oldRef?: string; newRef: string }>,
      tags: [] as Array<{ name: string; oldRef?: string; newRef: string }>,
      pruned: [] as string[]
    };

    // Parse fetch output
    result.stdout.split('\n').forEach(line => {
      if (line.includes('->')) {
        // Parse branch/tag updates
        const match = line.match(/([a-f0-9]+)\.\.([a-f0-9]+)\s+(\S+)\s+->\s+(\S+)/);
        if (match) {
          const [, oldRef, newRef, localRef, remoteRef] = match;
          if (remoteRef.includes('refs/tags/')) {
            summary.tags.push({
              name: remoteRef.replace('refs/tags/', ''),
              oldRef,
              newRef
            });
          } else {
            summary.branches.push({
              name: remoteRef.replace('refs/remotes/', ''),
              oldRef,
              newRef
            });
          }
        }
      } else if (line.includes('[pruned]')) {
        // Parse pruned refs
        const pruneMatch = line.match(/\[pruned\] (.+)/);
        if (pruneMatch) {
          summary.pruned.push(pruneMatch[1]);
        }
      }
    });

    return {
      remote: this.options.remote,
      summary: {
        branches: summary.branches.length > 0 ? summary.branches : undefined,
        tags: summary.tags.length > 0 ? summary.tags : undefined,
        pruned: summary.pruned.length > 0 ? summary.pruned : undefined
      },
      raw: result.stdout
    };
  }

  protected getCacheConfig() {
    return {
      command: 'fetch',
      stateType: RepoStateType.REMOTE
    };
  }

  protected async validateOptions(): Promise<void> {
    if (this.options.remote && !this.options.all) {
      await RepositoryValidator.validateRemoteConfig(
        this.getResolvedPath(),
        this.options.remote,
        this.context.operation
      );
    }

    if (this.options.depth !== undefined && this.options.depth <= 0) {
      throw ErrorHandler.handleValidationError(
        new Error('Depth must be a positive number'),
        { operation: this.context.operation }
      );
    }
  }
}

```

--------------------------------------------------------------------------------
/src/tool-handler.ts:
--------------------------------------------------------------------------------

```typescript
import {
  CallToolRequestSchema,
  ErrorCode,
  ListToolsRequestSchema,
  McpError,
} from '@modelcontextprotocol/sdk/types.js';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { GitOperations } from './git-operations.js';
import { logger } from './utils/logger.js';
import { ErrorHandler } from './errors/error-handler.js';
import { GitMcpError } from './errors/error-types.js';
import {
  isInitOptions,
  isCloneOptions,
  isAddOptions,
  isCommitOptions,
  isPushPullOptions,
  isBranchOptions,
  isCheckoutOptions,
  isTagOptions,
  isRemoteOptions,
  isStashOptions,
  isPathOnly,
  isBulkActionOptions,
  BasePathOptions,
} from './types.js';

const PATH_DESCRIPTION = `MUST be an absolute path (e.g., /Users/username/projects/my-repo)`;
const FILE_PATH_DESCRIPTION = `MUST be an absolute path (e.g., /Users/username/projects/my-repo/src/file.js)`;

export class ToolHandler {
  private static readonly TOOL_PREFIX = 'git_mcp_server';

  constructor(private server: Server) {
    this.setupHandlers();
  }

  private getOperationName(toolName: string): string {
    return `${ToolHandler.TOOL_PREFIX}.${toolName}`;
  }

  private validateArguments<T extends BasePathOptions>(operation: string, args: unknown, validator: (obj: any) => obj is T): T {
    if (!args || !validator(args)) {
      throw ErrorHandler.handleValidationError(
        new Error(`Invalid arguments for operation: ${operation}`),
        { 
          operation,
          details: { args }
        }
      );
    }

    // If path is not provided, use default path from environment
    if (!args.path && process.env.GIT_DEFAULT_PATH) {
      args.path = process.env.GIT_DEFAULT_PATH;
      logger.info(operation, 'Using default git path', args.path);
    }

    return args;
  }

  private setupHandlers(): void {
    this.setupToolDefinitions();
    this.setupToolExecutor();
  }

  private setupToolDefinitions(): void {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'init',
          description: 'Initialize a new Git repository',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to initialize the repository in. ${PATH_DESCRIPTION}`,
              },
            },
            required: [],
          },
        },
        {
          name: 'clone',
          description: 'Clone a repository',
          inputSchema: {
            type: 'object',
            properties: {
              url: {
                type: 'string',
                description: 'URL of the repository to clone',
              },
              path: {
                type: 'string',
                description: `Path to clone into. ${PATH_DESCRIPTION}`,
              },
            },
            required: ['url'],
          },
        },
        {
          name: 'status',
          description: 'Get repository status',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
            },
            required: [],
          },
        },
        {
          name: 'add',
          description: 'Stage files',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              files: {
                type: 'array',
                items: {
                  type: 'string',
                  description: FILE_PATH_DESCRIPTION,
                },
                description: 'Files to stage',
              },
            },
            required: ['files'],
          },
        },
        {
          name: 'commit',
          description: 'Create a commit',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              message: {
                type: 'string',
                description: 'Commit message',
              },
            },
            required: ['message'],
          },
        },
        {
          name: 'push',
          description: 'Push commits to remote',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              remote: {
                type: 'string',
                description: 'Remote name',
                default: 'origin',
              },
              branch: {
                type: 'string',
                description: 'Branch name',
              },
              force: {
                type: 'boolean',
                description: 'Force push changes',
                default: false
              },
              noVerify: {
                type: 'boolean',
                description: 'Skip pre-push hooks',
                default: false
              },
              tags: {
                type: 'boolean',
                description: 'Push all tags',
                default: false
              }
            },
            required: ['branch'],
          },
        },
        {
          name: 'pull',
          description: 'Pull changes from remote',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              remote: {
                type: 'string',
                description: 'Remote name',
                default: 'origin',
              },
              branch: {
                type: 'string',
                description: 'Branch name',
              },
            },
            required: ['branch'],
          },
        },
        {
          name: 'branch_list',
          description: 'List all branches',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
            },
            required: [],
          },
        },
        {
          name: 'branch_create',
          description: 'Create a new branch',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              name: {
                type: 'string',
                description: 'Branch name',
              },
              force: {
                type: 'boolean',
                description: 'Force create branch even if it exists',
                default: false
              },
              track: {
                type: 'boolean',
                description: 'Set up tracking mode',
                default: true
              },
              setUpstream: {
                type: 'boolean',
                description: 'Set upstream for push/pull',
                default: false
              }
            },
            required: ['name'],
          },
        },
        {
          name: 'branch_delete',
          description: 'Delete a branch',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              name: {
                type: 'string',
                description: 'Branch name',
              },
            },
            required: ['name'],
          },
        },
        {
          name: 'checkout',
          description: 'Switch branches or restore working tree files',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              target: {
                type: 'string',
                description: 'Branch name, commit hash, or file path',
              },
            },
            required: ['target'],
          },
        },
        {
          name: 'tag_list',
          description: 'List tags',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
            },
            required: [],
          },
        },
        {
          name: 'tag_create',
          description: 'Create a tag',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              name: {
                type: 'string',
                description: 'Tag name',
              },
              message: {
                type: 'string',
                description: 'Tag message',
              },
              force: {
                type: 'boolean',
                description: 'Force create tag even if it exists',
                default: false
              },
              annotated: {
                type: 'boolean',
                description: 'Create an annotated tag',
                default: true
              },
              sign: {
                type: 'boolean',
                description: 'Create a signed tag',
                default: false
              }
            },
            required: ['name'],
          },
        },
        {
          name: 'tag_delete',
          description: 'Delete a tag',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              name: {
                type: 'string',
                description: 'Tag name',
              },
            },
            required: ['name'],
          },
        },
        {
          name: 'remote_list',
          description: 'List remotes',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
            },
            required: [],
          },
        },
        {
          name: 'remote_add',
          description: 'Add a remote',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              name: {
                type: 'string',
                description: 'Remote name',
              },
              url: {
                type: 'string',
                description: 'Remote URL',
              },
            },
            required: ['name', 'url'],
          },
        },
        {
          name: 'remote_remove',
          description: 'Remove a remote',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              name: {
                type: 'string',
                description: 'Remote name',
              },
            },
            required: ['name'],
          },
        },
        {
          name: 'stash_list',
          description: 'List stashes',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
            },
            required: [],
          },
        },
        {
          name: 'stash_save',
          description: 'Save changes to stash',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              message: {
                type: 'string',
                description: 'Stash message',
              },
              includeUntracked: {
                type: 'boolean',
                description: 'Include untracked files',
                default: false
              },
              keepIndex: {
                type: 'boolean',
                description: 'Keep staged changes',
                default: false
              },
              all: {
                type: 'boolean',
                description: 'Include ignored files',
                default: false
              }
            },
            required: [],
          },
        },
        {
          name: 'stash_pop',
          description: 'Apply and remove a stash',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              index: {
                type: 'number',
                description: 'Stash index',
                default: 0,
              },
            },
            required: [],
          },
        },
        // New bulk action tool
        {
          name: 'bulk_action',
          description: 'Execute multiple Git operations in sequence. This is the preferred way to execute multiple operations.',
          inputSchema: {
            type: 'object',
            properties: {
              path: {
                type: 'string',
                description: `Path to repository. ${PATH_DESCRIPTION}`,
              },
              actions: {
                type: 'array',
                description: 'Array of Git operations to execute in sequence',
                items: {
                  type: 'object',
                  oneOf: [
                    {
                      type: 'object',
                      properties: {
                        type: { const: 'stage' },
                        files: {
                          type: 'array',
                          items: {
                            type: 'string',
                            description: FILE_PATH_DESCRIPTION,
                          },
                          description: 'Files to stage. If not provided, stages all changes.',
                        },
                      },
                      required: ['type'],
                    },
                    {
                      type: 'object',
                      properties: {
                        type: { const: 'commit' },
                        message: {
                          type: 'string',
                          description: 'Commit message',
                        },
                      },
                      required: ['type', 'message'],
                    },
                    {
                      type: 'object',
                      properties: {
                        type: { const: 'push' },
                        remote: {
                          type: 'string',
                          description: 'Remote name',
                          default: 'origin',
                        },
                        branch: {
                          type: 'string',
                          description: 'Branch name',
                        },
                      },
                      required: ['type', 'branch'],
                    },
                  ],
                },
                minItems: 1,
              },
            },
            required: ['actions'],
          },
        },
      ],
    }));
  }

  private setupToolExecutor(): void {
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const operation = this.getOperationName(request.params.name);
      const args = request.params.arguments;
      const context = { operation, path: args?.path as string | undefined };

      try {
        switch (request.params.name) {
          case 'init': {
            const validArgs = this.validateArguments(operation, args, isInitOptions);
            return await GitOperations.init(validArgs, context);
          }

          case 'clone': {
            const validArgs = this.validateArguments(operation, args, isCloneOptions);
            return await GitOperations.clone(validArgs, context);
          }

          case 'status': {
            const validArgs = this.validateArguments(operation, args, isPathOnly);
            return await GitOperations.status(validArgs, context);
          }

          case 'add': {
            const validArgs = this.validateArguments(operation, args, isAddOptions);
            return await GitOperations.add(validArgs, context);
          }

          case 'commit': {
            const validArgs = this.validateArguments(operation, args, isCommitOptions);
            return await GitOperations.commit(validArgs, context);
          }

          case 'push': {
            const validArgs = this.validateArguments(operation, args, isPushPullOptions);
            return await GitOperations.push(validArgs, context);
          }

          case 'pull': {
            const validArgs = this.validateArguments(operation, args, isPushPullOptions);
            return await GitOperations.pull(validArgs, context);
          }

          case 'branch_list': {
            const validArgs = this.validateArguments(operation, args, isPathOnly);
            return await GitOperations.branchList(validArgs, context);
          }

          case 'branch_create': {
            const validArgs = this.validateArguments(operation, args, isBranchOptions);
            return await GitOperations.branchCreate(validArgs, context);
          }

          case 'branch_delete': {
            const validArgs = this.validateArguments(operation, args, isBranchOptions);
            return await GitOperations.branchDelete(validArgs, context);
          }

          case 'checkout': {
            const validArgs = this.validateArguments(operation, args, isCheckoutOptions);
            return await GitOperations.checkout(validArgs, context);
          }

          case 'tag_list': {
            const validArgs = this.validateArguments(operation, args, isPathOnly);
            return await GitOperations.tagList(validArgs, context);
          }

          case 'tag_create': {
            const validArgs = this.validateArguments(operation, args, isTagOptions);
            return await GitOperations.tagCreate(validArgs, context);
          }

          case 'tag_delete': {
            const validArgs = this.validateArguments(operation, args, isTagOptions);
            return await GitOperations.tagDelete(validArgs, context);
          }

          case 'remote_list': {
            const validArgs = this.validateArguments(operation, args, isPathOnly);
            return await GitOperations.remoteList(validArgs, context);
          }

          case 'remote_add': {
            const validArgs = this.validateArguments(operation, args, isRemoteOptions);
            return await GitOperations.remoteAdd(validArgs, context);
          }

          case 'remote_remove': {
            const validArgs = this.validateArguments(operation, args, isRemoteOptions);
            return await GitOperations.remoteRemove(validArgs, context);
          }

          case 'stash_list': {
            const validArgs = this.validateArguments(operation, args, isPathOnly);
            return await GitOperations.stashList(validArgs, context);
          }

          case 'stash_save': {
            const validArgs = this.validateArguments(operation, args, isStashOptions);
            return await GitOperations.stashSave(validArgs, context);
          }

          case 'stash_pop': {
            const validArgs = this.validateArguments(operation, args, isStashOptions);
            return await GitOperations.stashPop(validArgs, context);
          }

          case 'bulk_action': {
            const validArgs = this.validateArguments(operation, args, isBulkActionOptions);
            return await GitOperations.executeBulkActions(validArgs, context);
          }

          default:
            throw ErrorHandler.handleValidationError(
              new Error(`Unknown tool: ${request.params.name}`),
              { operation }
            );
        }
      } catch (error: unknown) {
        // If it's already a GitMcpError or McpError, rethrow it
        if (error instanceof GitMcpError || error instanceof McpError) {
          throw error;
        }

        // Otherwise, wrap it in an appropriate error type
        throw ErrorHandler.handleOperationError(
          error instanceof Error ? error : new Error('Unknown error'),
          {
            operation,
            path: context.path,
            details: { tool: request.params.name }
          }
        );
      }
    });
  }
}

```

--------------------------------------------------------------------------------
/src/git-operations.ts:
--------------------------------------------------------------------------------

```typescript
import { CommandExecutor } from './utils/command.js';
import { PathValidator } from './utils/path.js';
import { RepositoryValidator } from './utils/repository.js';
import { logger } from './utils/logger.js';
import { repositoryCache } from './caching/repository-cache.js';
import { RepoStateType } from './caching/repository-cache.js';
import {
  GitToolResult,
  GitToolContext,
  InitOptions,
  CloneOptions,
  AddOptions,
  CommitOptions,
  PushPullOptions,
  BranchOptions,
  CheckoutOptions,
  TagOptions,
  RemoteOptions,
  StashOptions,
  BasePathOptions,
  BulkActionOptions,
  BulkAction,
} from './types.js';
import { resolve } from 'path';
import { existsSync } from 'fs';
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { ErrorHandler } from './errors/error-handler.js';
import { GitMcpError } from './errors/error-types.js';

export class GitOperations {
  private static async executeOperation<T>(
    operation: string,
    path: string | undefined,
    action: () => Promise<T>,
    options: {
      useCache?: boolean;
      stateType?: RepoStateType;
      command?: string;
      invalidateCache?: boolean;
    } = {}
  ): Promise<T> {
    try {
      logger.info(operation, 'Starting git operation', path);

      let result: T;
      if (options.useCache && path && options.stateType && options.command) {
        // Use cache for repository state operations
        result = await repositoryCache.getState(
          path,
          options.stateType,
          options.command,
          action
        );
      } else if (options.useCache && path && options.command) {
        // Use cache for command results
        result = await repositoryCache.getCommandResult(
          path,
          options.command,
          action
        );
      } else {
        // Execute without caching
        result = await action();
      }

      // Invalidate cache if needed
      if (options.invalidateCache && path) {
        if (options.stateType) {
          repositoryCache.invalidateState(path, options.stateType);
        }
        if (options.command) {
          repositoryCache.invalidateCommand(path, options.command);
        }
      }

      logger.info(operation, 'Operation completed successfully', path);
      return result;
    } catch (error: unknown) {
      if (error instanceof GitMcpError) throw error;
      throw ErrorHandler.handleOperationError(error instanceof Error ? error : new Error('Unknown error'), {
        operation,
        path,
        command: options.command || 'git operation'
      });
    }
  }

  private static getPath(options: BasePathOptions): string {
    if (!options.path && !process.env.GIT_DEFAULT_PATH) {
      throw ErrorHandler.handleValidationError(
        new Error('Path must be provided when GIT_DEFAULT_PATH is not set'),
        { operation: 'get_path' }
      );
    }
    return options.path || process.env.GIT_DEFAULT_PATH!;
  }

  static async init(options: InitOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const pathInfo = PathValidator.validatePath(path, { mustExist: false, allowDirectory: true });
        const result = await CommandExecutor.executeGitCommand(
          'init',
          context.operation,
          pathInfo
        );

        return {
          content: [{
            type: 'text',
            text: `Repository initialized successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'init',
        invalidateCache: true // Invalidate all caches for this repo
      }
    );
  }

  static async clone(options: CloneOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const pathInfo = PathValidator.validatePath(path, { mustExist: false, allowDirectory: true });
        const result = await CommandExecutor.executeGitCommand(
          `clone ${options.url} ${pathInfo}`,
          context.operation
        );

        return {
          content: [{
            type: 'text',
            text: `Repository cloned successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'clone',
        invalidateCache: true // Invalidate all caches for this repo
      }
    );
  }

  static async status(options: BasePathOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(path);
        const result = await CommandExecutor.executeGitCommand(
          'status',
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: CommandExecutor.formatOutput(result)
          }]
        };
      },
      {
        useCache: true,
        stateType: RepoStateType.STATUS,
        command: 'status'
      }
    );
  }

  static async add({ path, files }: AddOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        
        // Handle each file individually to avoid path issues
        for (const file of files) {
          await CommandExecutor.executeGitCommand(
            `add "${file}"`,
            context.operation,
            repoPath
          );
        }

        return {
          content: [{
            type: 'text',
            text: 'Files staged successfully'
          }]
        };
      },
      {
        command: 'add',
        invalidateCache: true, // Invalidate status cache
        stateType: RepoStateType.STATUS
      }
    );
  }

  static async commit({ path, message }: CommitOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        
        // Verify there are staged changes
        const statusResult = await CommandExecutor.executeGitCommand(
          'status --porcelain',
          context.operation,
          repoPath
        );
        
        if (!statusResult.stdout.trim()) {
          return {
            content: [{
              type: 'text',
              text: 'No changes to commit'
            }],
            isError: true
          };
        }

        const result = await CommandExecutor.executeGitCommand(
          `commit -m "${message}"`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Changes committed successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'commit',
        invalidateCache: true, // Invalidate status and branch caches
        stateType: RepoStateType.STATUS
      }
    );
  }

  static async push({ path, remote = 'origin', branch, force, noVerify, tags }: PushPullOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        await RepositoryValidator.validateRemoteConfig(repoPath, remote, context.operation);
        await RepositoryValidator.validateBranchExists(repoPath, branch, context.operation);
        
        const result = await CommandExecutor.executeGitCommand(
          `push ${remote} ${branch}${force ? ' --force' : ''}${noVerify ? ' --no-verify' : ''}${tags ? ' --tags' : ''}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Changes pushed successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'push',
        invalidateCache: true, // Invalidate remote cache
        stateType: RepoStateType.REMOTE
      }
    );
  }

  static async executeBulkActions(options: BulkActionOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        const results: string[] = [];

        for (const action of options.actions) {
          try {
            switch (action.type) {
              case 'stage': {
                const files = action.files || ['.'];
                const addResult = await this.add({ path: repoPath, files }, context);
                results.push(addResult.content[0].text);
                break;
              }
              case 'commit': {
                const commitResult = await this.commit({ path: repoPath, message: action.message }, context);
                results.push(commitResult.content[0].text);
                break;
              }
              case 'push': {
                const pushResult = await this.push({ 
                  path: repoPath, 
                  remote: action.remote, 
                  branch: action.branch 
                }, context);
                results.push(pushResult.content[0].text);
                break;
              }
            }
          } catch (error: unknown) {
            const errorMessage = error instanceof Error ? error.message : 'Unknown error';
            results.push(`Failed to execute ${action.type}: ${errorMessage}`);
            if (error instanceof Error) {
              logger.error(context.operation, `Bulk action ${action.type} failed`, repoPath, error);
            }
          }
        }

        return {
          content: [{
            type: 'text',
            text: results.join('\n\n')
          }]
        };
      },
      {
        command: 'bulk_action',
        invalidateCache: true // Invalidate all caches
      }
    );
  }

  static async pull({ path, remote = 'origin', branch }: PushPullOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        await RepositoryValidator.validateRemoteConfig(repoPath, remote, context.operation);
        
        const result = await CommandExecutor.executeGitCommand(
          `pull ${remote} ${branch}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Changes pulled successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'pull',
        invalidateCache: true // Invalidate all caches
      }
    );
  }

  static async branchList(options: BasePathOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(path);
        const result = await CommandExecutor.executeGitCommand(
          'branch -a',
          context.operation,
          repoPath
        );

        const output = result.stdout.trim();
        return {
          content: [{
            type: 'text',
            text: output || 'No branches found'
          }]
        };
      },
      {
        useCache: true,
        stateType: RepoStateType.BRANCH,
        command: 'branch -a'
      }
    );
  }

  static async branchCreate({ path, name, force, track, setUpstream }: BranchOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        PathValidator.validateBranchName(name);
        
        const result = await CommandExecutor.executeGitCommand(
          `checkout -b ${name}${force ? ' --force' : ''}${track ? ' --track' : ' --no-track'}${setUpstream ? ' --set-upstream' : ''}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Branch '${name}' created successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'branch_create',
        invalidateCache: true, // Invalidate branch cache
        stateType: RepoStateType.BRANCH
      }
    );
  }

  static async branchDelete({ path, name }: BranchOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        PathValidator.validateBranchName(name);
        await RepositoryValidator.validateBranchExists(repoPath, name, context.operation);
        
        const currentBranch = await RepositoryValidator.getCurrentBranch(repoPath, context.operation);
        if (currentBranch === name) {
          throw ErrorHandler.handleValidationError(
            new Error(`Cannot delete the currently checked out branch: ${name}`),
            { operation: context.operation, path: repoPath }
          );
        }
        
        const result = await CommandExecutor.executeGitCommand(
          `branch -D ${name}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Branch '${name}' deleted successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'branch_delete',
        invalidateCache: true, // Invalidate branch cache
        stateType: RepoStateType.BRANCH
      }
    );
  }

  static async checkout({ path, target }: CheckoutOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        await RepositoryValidator.ensureClean(repoPath, context.operation);
        
        const result = await CommandExecutor.executeGitCommand(
          `checkout ${target}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Switched to '${target}' successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'checkout',
        invalidateCache: true, // Invalidate branch and status caches
        stateType: RepoStateType.BRANCH
      }
    );
  }

  static async tagList(options: BasePathOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(path);
        const result = await CommandExecutor.executeGitCommand(
          'tag -l',
          context.operation,
          repoPath
        );

        const output = result.stdout.trim();
        return {
          content: [{
            type: 'text',
            text: output || 'No tags found'
          }]
        };
      },
      {
        useCache: true,
        stateType: RepoStateType.TAG,
        command: 'tag -l'
      }
    );
  }

  static async tagCreate({ path, name, message }: TagOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        PathValidator.validateTagName(name);
        
        let command = `tag ${name}`;
        if (typeof message === 'string' && message.length > 0) {
          command = `tag -a ${name} -m "${message}"`;
        }

        const result = await CommandExecutor.executeGitCommand(
          command,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Tag '${name}' created successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'tag_create',
        invalidateCache: true, // Invalidate tag cache
        stateType: RepoStateType.TAG
      }
    );
  }

  static async tagDelete({ path, name }: TagOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        PathValidator.validateTagName(name);
        await RepositoryValidator.validateTagExists(repoPath, name, context.operation);
        
        const result = await CommandExecutor.executeGitCommand(
          `tag -d ${name}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Tag '${name}' deleted successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'tag_delete',
        invalidateCache: true, // Invalidate tag cache
        stateType: RepoStateType.TAG
      }
    );
  }

  static async remoteList(options: BasePathOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(path);
        const result = await CommandExecutor.executeGitCommand(
          'remote -v',
          context.operation,
          repoPath
        );

        const output = result.stdout.trim();
        return {
          content: [{
            type: 'text',
            text: output || 'No remotes configured'
          }]
        };
      },
      {
        useCache: true,
        stateType: RepoStateType.REMOTE,
        command: 'remote -v'
      }
    );
  }

  static async remoteAdd({ path, name, url }: RemoteOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        PathValidator.validateRemoteName(name);
        if (!url) {
          throw ErrorHandler.handleValidationError(
            new Error('URL is required when adding a remote'),
            { operation: context.operation, path: repoPath }
          );
        }
        PathValidator.validateRemoteUrl(url);
        
        const result = await CommandExecutor.executeGitCommand(
          `remote add ${name} ${url}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Remote '${name}' added successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'remote_add',
        invalidateCache: true, // Invalidate remote cache
        stateType: RepoStateType.REMOTE
      }
    );
  }

  static async remoteRemove({ path, name }: RemoteOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        PathValidator.validateRemoteName(name);
        
        const result = await CommandExecutor.executeGitCommand(
          `remote remove ${name}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Remote '${name}' removed successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'remote_remove',
        invalidateCache: true, // Invalidate remote cache
        stateType: RepoStateType.REMOTE
      }
    );
  }

  static async stashList(options: BasePathOptions, context: GitToolContext): Promise<GitToolResult> {
    const path = this.getPath(options);
    return await this.executeOperation(
      context.operation,
      path,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(path);
        const result = await CommandExecutor.executeGitCommand(
          'stash list',
          context.operation,
          repoPath
        );

        const output = result.stdout.trim();
        return {
          content: [{
            type: 'text',
            text: output || 'No stashes found'
          }]
        };
      },
      {
        useCache: true,
        stateType: RepoStateType.STASH,
        command: 'stash list'
      }
    );
  }

  static async stashSave({ path, message, includeUntracked, keepIndex, all }: StashOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        let command = 'stash';
        if (typeof message === 'string' && message.length > 0) {
          command += ` save "${message}"`;
        }
        if (includeUntracked) {
          command += ' --include-untracked';
        }
        if (keepIndex) {
          command += ' --keep-index';
        }
        if (all) {
          command += ' --all';
        }
        const result = await CommandExecutor.executeGitCommand(
          command,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Changes stashed successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'stash_save',
        invalidateCache: true, // Invalidate stash and status caches
        stateType: RepoStateType.STASH
      }
    );
  }

  static async stashPop({ path, index = 0 }: StashOptions, context: GitToolContext): Promise<GitToolResult> {
    const resolvedPath = this.getPath({ path });
    return await this.executeOperation(
      context.operation,
      resolvedPath,
      async () => {
        const { path: repoPath } = PathValidator.validateGitRepo(resolvedPath);
        const result = await CommandExecutor.executeGitCommand(
          `stash pop stash@{${index}}`,
          context.operation,
          repoPath
        );

        return {
          content: [{
            type: 'text',
            text: `Stash applied successfully\n${CommandExecutor.formatOutput(result)}`
          }]
        };
      },
      {
        command: 'stash_pop',
        invalidateCache: true, // Invalidate stash and status caches
        stateType: RepoStateType.STASH
      }
    );
  }
}

```