#
tokens: 49939/50000 139/195 files (page 1/4)
lines: off (toggle) GitHub
raw markdown copy
This is page 1 of 4. Use http://codebase.md/stefan-nitu/mcp-xcode-server?page={x} to view the full context.

# Directory Structure

```
├── .claude
│   └── settings.local.json
├── .github
│   └── workflows
│       └── ci.yml
├── .gitignore
├── .vscode
│   └── settings.json
├── CLAUDE.md
├── CONTRIBUTING.md
├── docs
│   ├── ARCHITECTURE.md
│   ├── ERROR-HANDLING.md
│   └── TESTING-PHILOSOPHY.md
├── examples
│   └── screenshot-demo.js
├── jest.config.cjs
├── jest.e2e.config.cjs
├── LICENSE
├── package-lock.json
├── package.json
├── README.md
├── scripts
│   └── xcode-sync.swift
├── src
│   ├── application
│   │   └── ports
│   │       ├── ArtifactPorts.ts
│   │       ├── BuildPorts.ts
│   │       ├── CommandPorts.ts
│   │       ├── ConfigPorts.ts
│   │       ├── LoggingPorts.ts
│   │       ├── MappingPorts.ts
│   │       ├── OutputFormatterPorts.ts
│   │       ├── OutputParserPorts.ts
│   │       └── SimulatorPorts.ts
│   ├── cli.ts
│   ├── config.ts
│   ├── domain
│   │   ├── errors
│   │   │   └── DomainError.ts
│   │   ├── services
│   │   │   └── PlatformDetector.ts
│   │   ├── shared
│   │   │   └── Result.ts
│   │   └── tests
│   │       └── unit
│   │           └── PlatformDetector.unit.test.ts
│   ├── features
│   │   ├── app-management
│   │   │   ├── controllers
│   │   │   │   └── InstallAppController.ts
│   │   │   ├── domain
│   │   │   │   ├── InstallRequest.ts
│   │   │   │   └── InstallResult.ts
│   │   │   ├── factories
│   │   │   │   └── InstallAppControllerFactory.ts
│   │   │   ├── index.ts
│   │   │   ├── infrastructure
│   │   │   │   └── AppInstallerAdapter.ts
│   │   │   ├── tests
│   │   │   │   ├── e2e
│   │   │   │   │   ├── InstallAppController.e2e.test.ts
│   │   │   │   │   └── InstallAppMCP.e2e.test.ts
│   │   │   │   ├── integration
│   │   │   │   │   └── InstallAppController.integration.test.ts
│   │   │   │   └── unit
│   │   │   │       ├── AppInstallerAdapter.unit.test.ts
│   │   │   │       ├── InstallAppController.unit.test.ts
│   │   │   │       ├── InstallAppUseCase.unit.test.ts
│   │   │   │       ├── InstallRequest.unit.test.ts
│   │   │   │       └── InstallResult.unit.test.ts
│   │   │   └── use-cases
│   │   │       └── InstallAppUseCase.ts
│   │   ├── build
│   │   │   ├── controllers
│   │   │   │   └── BuildXcodeController.ts
│   │   │   ├── domain
│   │   │   │   ├── BuildDestination.ts
│   │   │   │   ├── BuildIssue.ts
│   │   │   │   ├── BuildRequest.ts
│   │   │   │   ├── BuildResult.ts
│   │   │   │   └── PlatformInfo.ts
│   │   │   ├── factories
│   │   │   │   └── BuildXcodeControllerFactory.ts
│   │   │   ├── index.ts
│   │   │   ├── infrastructure
│   │   │   │   ├── BuildArtifactLocatorAdapter.ts
│   │   │   │   ├── BuildDestinationMapperAdapter.ts
│   │   │   │   ├── XcbeautifyFormatterAdapter.ts
│   │   │   │   ├── XcbeautifyOutputParserAdapter.ts
│   │   │   │   └── XcodeBuildCommandAdapter.ts
│   │   │   ├── tests
│   │   │   │   ├── e2e
│   │   │   │   │   ├── BuildXcodeController.e2e.test.ts
│   │   │   │   │   └── BuildXcodeMCP.e2e.test.ts
│   │   │   │   ├── integration
│   │   │   │   │   └── BuildXcodeController.integration.test.ts
│   │   │   │   └── unit
│   │   │   │       ├── BuildArtifactLocatorAdapter.unit.test.ts
│   │   │   │       ├── BuildDestinationMapperAdapter.unit.test.ts
│   │   │   │       ├── BuildIssue.unit.test.ts
│   │   │   │       ├── BuildProjectUseCase.unit.test.ts
│   │   │   │       ├── BuildRequest.unit.test.ts
│   │   │   │       ├── BuildResult.unit.test.ts
│   │   │   │       ├── BuildXcodeController.unit.test.ts
│   │   │   │       ├── BuildXcodePresenter.unit.test.ts
│   │   │   │       ├── PlatformInfo.unit.test.ts
│   │   │   │       ├── XcbeautifyFormatterAdapter.unit.test.ts
│   │   │   │       ├── XcbeautifyOutputParserAdapter.unit.test.ts
│   │   │   │       └── XcodeBuildCommandAdapter.unit.test.ts
│   │   │   └── use-cases
│   │   │       └── BuildProjectUseCase.ts
│   │   └── simulator
│   │       ├── controllers
│   │       │   ├── BootSimulatorController.ts
│   │       │   ├── ListSimulatorsController.ts
│   │       │   └── ShutdownSimulatorController.ts
│   │       ├── domain
│   │       │   ├── BootRequest.ts
│   │       │   ├── BootResult.ts
│   │       │   ├── ListSimulatorsRequest.ts
│   │       │   ├── ListSimulatorsResult.ts
│   │       │   ├── ShutdownRequest.ts
│   │       │   ├── ShutdownResult.ts
│   │       │   └── SimulatorState.ts
│   │       ├── factories
│   │       │   ├── BootSimulatorControllerFactory.ts
│   │       │   ├── ListSimulatorsControllerFactory.ts
│   │       │   └── ShutdownSimulatorControllerFactory.ts
│   │       ├── index.ts
│   │       ├── infrastructure
│   │       │   ├── SimulatorControlAdapter.ts
│   │       │   └── SimulatorLocatorAdapter.ts
│   │       ├── tests
│   │       │   ├── e2e
│   │       │   │   ├── BootSimulatorController.e2e.test.ts
│   │       │   │   ├── BootSimulatorMCP.e2e.test.ts
│   │       │   │   ├── ListSimulatorsController.e2e.test.ts
│   │       │   │   ├── ListSimulatorsMCP.e2e.test.ts
│   │       │   │   ├── ShutdownSimulatorController.e2e.test.ts
│   │       │   │   └── ShutdownSimulatorMCP.e2e.test.ts
│   │       │   ├── integration
│   │       │   │   ├── BootSimulatorController.integration.test.ts
│   │       │   │   ├── ListSimulatorsController.integration.test.ts
│   │       │   │   └── ShutdownSimulatorController.integration.test.ts
│   │       │   └── unit
│   │       │       ├── BootRequest.unit.test.ts
│   │       │       ├── BootResult.unit.test.ts
│   │       │       ├── BootSimulatorController.unit.test.ts
│   │       │       ├── BootSimulatorUseCase.unit.test.ts
│   │       │       ├── ListSimulatorsController.unit.test.ts
│   │       │       ├── ListSimulatorsUseCase.unit.test.ts
│   │       │       ├── ShutdownRequest.unit.test.ts
│   │       │       ├── ShutdownResult.unit.test.ts
│   │       │       ├── ShutdownSimulatorUseCase.unit.test.ts
│   │       │       ├── SimulatorControlAdapter.unit.test.ts
│   │       │       └── SimulatorLocatorAdapter.unit.test.ts
│   │       └── use-cases
│   │           ├── BootSimulatorUseCase.ts
│   │           ├── ListSimulatorsUseCase.ts
│   │           └── ShutdownSimulatorUseCase.ts
│   ├── index.ts
│   ├── infrastructure
│   │   ├── repositories
│   │   │   └── DeviceRepository.ts
│   │   ├── services
│   │   │   └── DependencyChecker.ts
│   │   └── tests
│   │       └── unit
│   │           ├── DependencyChecker.unit.test.ts
│   │           └── DeviceRepository.unit.test.ts
│   ├── logger.ts
│   ├── presentation
│   │   ├── decorators
│   │   │   └── DependencyCheckingDecorator.ts
│   │   ├── formatters
│   │   │   ├── ErrorFormatter.ts
│   │   │   └── strategies
│   │   │       ├── BuildIssuesStrategy.ts
│   │   │       ├── DefaultErrorStrategy.ts
│   │   │       ├── ErrorFormattingStrategy.ts
│   │   │       └── OutputFormatterErrorStrategy.ts
│   │   ├── interfaces
│   │   │   ├── IDependencyChecker.ts
│   │   │   ├── MCPController.ts
│   │   │   └── MCPResponse.ts
│   │   ├── presenters
│   │   │   └── BuildXcodePresenter.ts
│   │   └── tests
│   │       └── unit
│   │           ├── BuildIssuesStrategy.unit.test.ts
│   │           ├── DefaultErrorStrategy.unit.test.ts
│   │           ├── DependencyCheckingDecorator.unit.test.ts
│   │           └── ErrorFormatter.unit.test.ts
│   ├── shared
│   │   ├── domain
│   │   │   ├── AppPath.ts
│   │   │   ├── DeviceId.ts
│   │   │   ├── Platform.ts
│   │   │   └── ProjectPath.ts
│   │   ├── index.ts
│   │   ├── infrastructure
│   │   │   ├── ConfigProviderAdapter.ts
│   │   │   └── ShellCommandExecutorAdapter.ts
│   │   └── tests
│   │       ├── mocks
│   │       │   ├── promisifyExec.ts
│   │       │   ├── selectiveExecMock.ts
│   │       │   └── xcodebuildHelpers.ts
│   │       ├── skipped
│   │       │   ├── cli.e2e.test.skip
│   │       │   ├── hook-e2e.test.skip
│   │       │   ├── hook-path.e2e.test.skip
│   │       │   └── hook.test.skip
│   │       ├── types
│   │       │   └── execTypes.ts
│   │       ├── unit
│   │       │   ├── AppPath.unit.test.ts
│   │       │   ├── ConfigProviderAdapter.unit.test.ts
│   │       │   ├── ProjectPath.unit.test.ts
│   │       │   └── ShellCommandExecutorAdapter.unit.test.ts
│   │       └── utils
│   │           ├── gitResetTestArtifacts.ts
│   │           ├── mockHelpers.ts
│   │           ├── TestEnvironmentCleaner.ts
│   │           ├── TestErrorInjector.ts
│   │           ├── testHelpers.ts
│   │           ├── TestProjectManager.ts
│   │           └── TestSimulatorManager.ts
│   ├── types.ts
│   ├── utils
│   │   ├── devices
│   │   │   ├── Devices.ts
│   │   │   ├── SimulatorApps.ts
│   │   │   ├── SimulatorBoot.ts
│   │   │   ├── SimulatorDevice.ts
│   │   │   ├── SimulatorInfo.ts
│   │   │   ├── SimulatorReset.ts
│   │   │   └── SimulatorUI.ts
│   │   ├── errors
│   │   │   ├── index.ts
│   │   │   └── xcbeautify-parser.ts
│   │   ├── index.ts
│   │   ├── LogManager.ts
│   │   ├── LogManagerInstance.ts
│   │   └── projects
│   │       ├── SwiftBuild.ts
│   │       ├── SwiftPackage.ts
│   │       ├── SwiftPackageInfo.ts
│   │       ├── Xcode.ts
│   │       ├── XcodeArchive.ts
│   │       ├── XcodeBuild.ts
│   │       ├── XcodeErrors.ts
│   │       ├── XcodeInfo.ts
│   │       └── XcodeProject.ts
│   └── utils.ts
├── test_artifacts
│   ├── Test.xcworkspace
│   │   ├── contents.xcworkspacedata
│   │   └── xcuserdata
│   │       └── stefan.xcuserdatad
│   │           └── UserInterfaceState.xcuserstate
│   ├── TestProjectSwiftTesting
│   │   ├── TestProjectSwiftTesting
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   ├── Item.swift
│   │   │   ├── TestProjectSwiftTesting.entitlements
│   │   │   └── TestProjectSwiftTestingApp.swift
│   │   ├── TestProjectSwiftTesting.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   ├── project.xcworkspace
│   │   │   │   ├── contents.xcworkspacedata
│   │   │   │   └── xcuserdata
│   │   │   │       └── stefan.xcuserdatad
│   │   │   │           └── UserInterfaceState.xcuserstate
│   │   │   └── xcuserdata
│   │   │       └── stefan.xcuserdatad
│   │   │           └── xcschemes
│   │   │               └── xcschememanagement.plist
│   │   ├── TestProjectSwiftTestingTests
│   │   │   └── TestProjectSwiftTestingTests.swift
│   │   └── TestProjectSwiftTestingUITests
│   │       ├── TestProjectSwiftTestingUITests.swift
│   │       └── TestProjectSwiftTestingUITestsLaunchTests.swift
│   ├── TestProjectWatchOS
│   │   ├── TestProjectWatchOS
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   └── TestProjectWatchOSApp.swift
│   │   ├── TestProjectWatchOS Watch App
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   └── TestProjectWatchOSApp.swift
│   │   ├── TestProjectWatchOS Watch AppTests
│   │   │   └── TestProjectWatchOS_Watch_AppTests.swift
│   │   ├── TestProjectWatchOS Watch AppUITests
│   │   │   ├── TestProjectWatchOS_Watch_AppUITests.swift
│   │   │   └── TestProjectWatchOS_Watch_AppUITestsLaunchTests.swift
│   │   ├── TestProjectWatchOS.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   └── project.xcworkspace
│   │   │       └── contents.xcworkspacedata
│   │   ├── TestProjectWatchOSTests
│   │   │   └── TestProjectWatchOSTests.swift
│   │   └── TestProjectWatchOSUITests
│   │       ├── TestProjectWatchOSUITests.swift
│   │       └── TestProjectWatchOSUITestsLaunchTests.swift
│   ├── TestProjectXCTest
│   │   ├── TestProjectXCTest
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   ├── Item.swift
│   │   │   ├── TestProjectXCTest.entitlements
│   │   │   └── TestProjectXCTestApp.swift
│   │   ├── TestProjectXCTest.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   ├── project.xcworkspace
│   │   │   │   ├── contents.xcworkspacedata
│   │   │   │   └── xcuserdata
│   │   │   │       └── stefan.xcuserdatad
│   │   │   │           └── UserInterfaceState.xcuserstate
│   │   │   └── xcuserdata
│   │   │       └── stefan.xcuserdatad
│   │   │           └── xcschemes
│   │   │               └── xcschememanagement.plist
│   │   ├── TestProjectXCTestTests
│   │   │   └── TestProjectXCTestTests.swift
│   │   └── TestProjectXCTestUITests
│   │       ├── TestProjectXCTestUITests.swift
│   │       └── TestProjectXCTestUITestsLaunchTests.swift
│   ├── TestSwiftPackageSwiftTesting
│   │   ├── .gitignore
│   │   ├── Package.swift
│   │   ├── Sources
│   │   │   ├── TestSwiftPackageSwiftTesting
│   │   │   │   └── TestSwiftPackageSwiftTesting.swift
│   │   │   └── TestSwiftPackageSwiftTestingExecutable
│   │   │       └── main.swift
│   │   └── Tests
│   │       └── TestSwiftPackageSwiftTestingTests
│   │           └── TestSwiftPackageSwiftTestingTests.swift
│   └── TestSwiftPackageXCTest
│       ├── .gitignore
│       ├── Package.swift
│       ├── Sources
│       │   ├── TestSwiftPackageXCTest
│       │   │   └── TestSwiftPackageXCTest.swift
│       │   └── TestSwiftPackageXCTestExecutable
│       │       └── main.swift
│       └── Tests
│           └── TestSwiftPackageXCTestTests
│               └── TestSwiftPackageXCTestTests.swift
├── tsconfig.json
└── XcodeProjectModifier
    ├── Package.resolved
    ├── Package.swift
    └── Sources
        └── XcodeProjectModifier
            └── main.swift
```

# Files

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageSwiftTesting/.gitignore:
--------------------------------------------------------------------------------

```
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageXCTest/.gitignore:
--------------------------------------------------------------------------------

```
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc

```

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

```
node_modules/
dist/
coverage/
DerivedData/
*.log
.DS_Store
.env
.env.local
.env.*.local
*.xcuserdata
*.xcworkspace/xcuserdata/
*.xcodeproj/xcuserdata/
/build/
*.app
*.ipa
*.dSYM.zip
*.dSYM

# Swift Package Manager
.build/
.swiftpm/

# XcodeProjectModifier build artifacts
XcodeProjectModifier/.build/
XcodeProjectModifier/.swiftpm/

# Test artifacts
test-results*.log
test_artifacts/**/*.xcuserstate
test_artifacts/**/*.xcuserdatad/
test_artifacts/**/xcuserdata/

# Temporary files
*.tmp
.tmp/
/tmp/
```

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

```markdown
# MCP Xcode Server

[![CI](https://github.com/stefan-nitu/mcp-xcode-server/actions/workflows/ci.yml/badge.svg)](https://github.com/stefan-nitu/mcp-xcode-server/actions/workflows/ci.yml)

A Model Context Protocol (MCP) server that enables AI assistants to build, test, run, and manage Apple platform projects through natural language interactions.

## Version: 0.6.0

## Purpose

This MCP server bridges the gap between AI assistants and Apple's development ecosystem. It allows AI tools like Claude to directly execute Xcode and Swift Package Manager commands, enabling automated development workflows without manual intervention. The server is designed for token efficiency, providing concise output while maintaining comprehensive error reporting and debugging capabilities.

## Why Use MCP Xcode Server?

### Key Advantages

- **AI-Native Development**: Enables AI assistants to build, test, and run iOS/macOS apps directly
- **Token Efficiency**: Optimized output shows only essential information (errors, warnings, test results)
- **Smart Error Handling**: Parses build errors and provides actionable suggestions
- **Visual Debugging**: Capture simulator screenshots to verify UI changes
- **Automatic Simulator Management**: Intelligently reuses running simulators to save time
- **Xcode Integration**: Auto-syncs file operations with Xcode projects via hooks
- **Persistent Logging**: All operations saved to `~/.mcp-xcode-server/logs/` for debugging
- **Multi-Platform**: Supports iOS, macOS, tvOS, watchOS, and visionOS from a single interface

### Use Cases

- **Automated Testing**: AI can run your test suites and analyze failures
- **Build Verification**: Quickly verify code changes compile across platforms
- **UI Development**: Build and screenshot apps to verify visual changes
- **Dependency Management**: Add, update, or remove Swift packages programmatically
- **Cross-Platform Development**: Test the same code on multiple Apple platforms
- **CI/CD Integration**: Automate build and test workflows through natural language

## Limitations

### What It Can't Do

- **No SwiftUI Previews**: Xcode's live preview requires the full IDE
- **No Interactive UI Testing**: Cannot simulate user interactions (taps, swipes)
- **No Physical Devices**: Simulator-only for iOS/tvOS/watchOS/visionOS
- **No Debugging**: No breakpoints, step-through debugging, or LLDB access
- **No Xcode UI Features**: Project configuration, storyboard editing require Xcode
- **Platform Requirements**: Requires macOS 14+, Xcode 16+, iOS 17+ simulators

### When You Still Need Xcode

- Designing UI with Interface Builder or SwiftUI previews
- Debugging with breakpoints and variable inspection
- Profiling with Instruments
- Managing certificates and provisioning profiles
- Testing on physical devices
- Using Xcode-specific features (Playgrounds, AR tools, etc.)

## Core Features

### Build & Test Automation
- Build and run Xcode projects/workspaces
- Execute Swift Package Manager packages
- Run XCTest and Swift Testing suites
- **Xcode projects**: Support for custom build configurations (Debug, Release, Beta, Staging, etc.)
- **Swift packages**: Standard SPM configurations (Debug/Release only - SPM limitation)

### Simulator Management
- List and boot simulators for any Apple platform
- Capture screenshots for visual verification
- Install/uninstall apps
- Retrieve device logs with filtering

### Error Intelligence
- **Compile Errors**: Shows file, line, column with error message
- **Scheme Errors**: Suggests using `list_schemes` tool
- **Code Signing**: Identifies certificate and provisioning issues
- **Dependencies**: Detects missing modules and version conflicts

### File Sync Hooks
- Automatically syncs file operations with Xcode projects
- Intelligently assigns files to correct build phases (Sources, Resources, etc.)
- Respects `.no-xcode-sync` opt-out files
- Maintains proper group structure in Xcode

## Installation

### Prerequisites

- macOS 14.0 or later
- Xcode 16.0 or later
- Node.js 18+
- Xcode Command Line Tools
- Simulators for target platforms

### Quick Setup

```bash
# Install globally
npm install -g mcp-xcode-server

# Run interactive setup
mcp-xcode-server setup
```

The setup wizard will:
- Configure the MCP server for Claude
- Optionally set up Xcode sync hooks
- Build necessary helper tools

### Manual Configuration

Add to `~/.claude.json` (global) or `.claude/settings.json` (project):

```json
{
  "mcpServers": {
    "mcp-xcode-server": {
      "type": "stdio",
      "command": "mcp-xcode-server",
      "args": ["serve"],
      "env": {}
    }
  }
}
```

## Available Tools

### Building

- **`build_xcode`**: Build Xcode projects/workspaces (supports custom configurations)
- **`build_swift_package`**: Build Swift packages (Debug/Release only per SPM spec)
- **`run_xcode`**: Build and run on simulator/macOS
- **`run_swift_package`**: Execute Swift package executables

### Testing

- **`test_xcode`**: Run XCTest/Swift Testing suites
- **`test_swift_package`**: Test Swift packages
- Supports test filtering by class/method

### Project Information

- **`list_schemes`**: Get available Xcode schemes
- **`get_project_info`**: Comprehensive project details
- **`list_targets`**: List all build targets
- **`get_build_settings`**: Get scheme configuration

### Simulator Management

- **`list_simulators`**: Show available devices
- **`boot_simulator`**: Start a simulator
- **`shutdown_simulator`**: Stop a simulator
- **`view_simulator_screen`**: Capture screenshot

### App Management

- **`install_app`**: Install app on simulator
- **`uninstall_app`**: Remove app by bundle ID
- **`get_device_logs`**: Retrieve filtered device logs

### Distribution

- **`archive_project`**: Create .xcarchive
- **`export_ipa`**: Export IPA from archive

### Maintenance

- **`clean_build`**: Clean build artifacts/DerivedData
- **`manage_dependencies`**: Add/remove/update Swift packages

## Platform Support

| Platform | Simulator Required | Default Device | Min Version |
|----------|-------------------|----------------|-------------|
| iOS | Yes | iPhone 16 Pro | iOS 17+ |
| macOS | No | Host machine | macOS 14+ |
| tvOS | Yes | Apple TV | tvOS 17+ |
| watchOS | Yes | Apple Watch Series 10 | watchOS 10+ |
| visionOS | Yes | Apple Vision Pro | visionOS 1.0+ |

## Architecture

The server follows Clean/Hexagonal Architecture with SOLID principles:

### Core Structure
```
src/
├── features/         # Feature-based vertical slices
│   ├── build/       # Build feature
│   │   ├── domain/  # Build domain objects
│   │   ├── use-cases/
│   │   ├── infrastructure/
│   │   ├── controllers/
│   │   └── factories/
│   ├── simulator/   # Simulator management
│   │   └── ...same structure...
│   └── app-management/ # App installation
│       └── ...same structure...
├── shared/          # Cross-feature shared code
│   ├── domain/      # Shared value objects
│   └── infrastructure/
├── application/     # Application layer ports
│   └── ports/       # Interface definitions
├── presentation/    # MCP presentation layer
│   ├── interfaces/  # MCP contracts
│   └── formatters/  # Output formatting
└── infrastructure/  # Shared infrastructure
    ├── repositories/
    └── services/
```

### Key Design Principles
- **Clean Architecture**: Dependency rule - inner layers know nothing about outer layers
- **Domain-Driven Design**: Rich domain models with embedded validation
- **Type Safety**: Full TypeScript with domain primitives and parse-don't-validate pattern
- **Security First**: Path validation, command injection protection at boundaries
- **Error Recovery**: Typed domain errors with graceful handling and helpful suggestions

## Logging

All operations are logged to `~/.mcp-xcode-server/logs/`:
- Daily folders (e.g., `2025-01-27/`)
- 7-day automatic retention
- Full xcodebuild/swift output preserved
- Symlinks to latest logs for easy access

## Development

```bash
# Build
npm run build

# Test
npm test              # All tests
npm run test:unit    # Unit tests only
npm run test:e2e     # End-to-end tests
npm run test:coverage # With coverage

# Development
npm run dev          # Build and run
```

## Contributing

Contributions welcome! Please ensure:
- Tests pass (`npm test`)
- Code follows SOLID principles
- New tools include tests
- Documentation updated

## License

MIT

## Support

- Report issues: [GitHub Issues](https://github.com/yourusername/mcp-xcode-server/issues)
- Documentation: [MCP Protocol](https://modelcontextprotocol.io)
```

--------------------------------------------------------------------------------
/CLAUDE.md:
--------------------------------------------------------------------------------

```markdown
# MANDATORY INITIALIZATION - DO THIS IMMEDIATELY

## ⚠️ STOP - READ THIS FIRST ⚠️

**YOU MUST READ THESE DOCUMENTS IMMEDIATELY UPON STARTING ANY CONVERSATION ABOUT THIS PROJECT.**
**DO NOT WAIT TO BE ASKED. DO NOT PROCEED WITHOUT READING THEM FIRST.**

### Required Documents (READ NOW):
1. `docs/TESTING-PHILOSOPHY.md` - Critical testing patterns and approaches
2. `docs/ARCHITECTURE.md` - Clean/Hexagonal Architecture structure
3. `docs/ERROR-HANDLING.md` - Error handling patterns and presentation conventions

### Verification Checklist:
- [ ] I have read `docs/TESTING-PHILOSOPHY.md` completely
- [ ] I have read `docs/ARCHITECTURE.md` completely
- [ ] I have read `docs/ERROR-HANDLING.md` completely
- [ ] I understand the testing philosophy (integration focus, proper mocking, behavior testing)
- [ ] I understand the architecture layers (Domain, Application, Infrastructure, Presentation)
- [ ] I understand error handling patterns (typed errors, emoji prefixes, separation of concerns)

If you haven't read these documents yet, STOP and read them now using the Read tool.
Only after reading all three documents should you proceed to help the user.

## Project Context

This is an MCP (Model Context Protocol) server for Xcode operations. The codebase follows:
- Clean/Hexagonal Architecture principles
- Integration-focused testing (60% integration, 25% unit, 10% E2E, 5% static)
- Parse-don't-validate pattern with domain validation
- Domain primitives over primitive types
- Type-safe enum comparisons (always use `SimulatorState.Booted`, never `'Booted'`)
```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
# Contributing to MCP Apple Simulator

## Branching Strategy

We use **GitHub Flow** - a simple, effective branching model:

### Branches
- **`main`** - Always stable, production-ready code. Every commit should be deployable.
- **`feature/*`** - Feature branches for new functionality
- **`fix/*`** - Bug fix branches
- **`docs/*`** - Documentation updates

### Workflow

1. **Create a feature branch** from main:
   ```bash
   git checkout main
   git pull origin main
   git checkout -b feature/your-feature-name
   ```

2. **Make your changes** and commit:
   ```bash
   git add .
   git commit -m "feat: add new simulator tool"
   ```

3. **Push and create a Pull Request**:
   ```bash
   git push origin feature/your-feature-name
   ```

4. **After review and CI passes**, merge to main

### Commit Message Convention

We use conventional commits:
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation changes
- `test:` - Test additions or changes
- `refactor:` - Code refactoring
- `chore:` - Maintenance tasks

### Why No Develop Branch?

We intentionally don't use a `develop` branch because:
- **Simplicity** - Fewer branches to manage
- **No sync issues** - No divergence between develop and main
- **Continuous deployment** - Every merge to main is ready for users
- **Local tool** - Users update when they want, not on a release schedule

### Pull Request Guidelines

1. **All tests must pass** - Run `npm test` locally first
2. **Update documentation** - If adding features, update README
3. **Small, focused PRs** - Easier to review and less likely to conflict
4. **Clean commit history** - Squash commits if needed

### Testing

Before submitting a PR:
```bash
npm run build          # Build TypeScript
npm run test:unit      # Run unit tests
npm run test:coverage  # Check coverage (aim for >75%)
```

### Code Style

- TypeScript strict mode enabled
- No `any` types without good reason
- Follow existing patterns in the codebase
- Use dependency injection for testability

### Questions?

Open an issue for discussion before making large changes.
```

--------------------------------------------------------------------------------
/scripts/xcode-sync.swift:
--------------------------------------------------------------------------------

```swift

```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
{
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTesting/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTest/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTesting/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "colors" : [
    {
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch App/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "colors" : [
    {
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "colors" : [
    {
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTest/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "colors" : [
    {
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

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

```typescript
import { exec } from 'child_process';
import { promisify } from 'util';

/**
 * Promisified version of exec for async/await usage
 */
export const execAsync = promisify(exec);
```

--------------------------------------------------------------------------------
/src/presentation/formatters/strategies/ErrorFormattingStrategy.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Strategy interface for formatting different types of errors
 */
export interface ErrorFormattingStrategy {
  canFormat(error: any): boolean;
  format(error: any): string;
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "images" : [
    {
      "idiom" : "universal",
      "platform" : "watchos",
      "size" : "1024x1024"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageXCTest/Sources/TestSwiftPackageXCTest/TestSwiftPackageXCTest.swift:
--------------------------------------------------------------------------------

```swift
// The Swift Programming Language
// https://docs.swift.org/swift-book

public struct TestSwiftPackageXCTest {
    public let text = "Hello, TestSwiftPackageXCTest!"
    
    public init() {}
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageSwiftTesting/Sources/TestSwiftPackageSwiftTesting/TestSwiftPackageSwiftTesting.swift:
--------------------------------------------------------------------------------

```swift
// The Swift Programming Language
// https://docs.swift.org/swift-book

public struct TestSwiftPackageSwiftTesting {
    public let text = "Hello, TestSwiftPackageSwiftTesting!"
    
    public init() {}
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTest/Item.swift:
--------------------------------------------------------------------------------

```swift
//
//  Item.swift
//  TestProjectXCTest
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import Foundation
import SwiftData

@Model
final class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTesting/Item.swift:
--------------------------------------------------------------------------------

```swift
//
//  Item.swift
//  TestProjectSwiftTesting
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import Foundation
import SwiftData

@Model
final class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS/TestProjectWatchOSApp.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOSApp.swift
//  TestProjectWatchOS
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import SwiftUI

@main
struct TestProjectWatchOSApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

```

--------------------------------------------------------------------------------
/src/application/ports/ArtifactPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Port interfaces for build artifact management
 * 
 * These ports define how the application layer locates
 * and manages build artifacts (apps, frameworks, etc.)
 */

export interface IAppLocator {
  findApp(derivedDataPath: string): Promise<string | undefined>;
}
```

--------------------------------------------------------------------------------
/src/shared/tests/mocks/xcodebuildHelpers.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Checks if a command is an xcodebuild command
 */
export function isXcodebuildCommand(cmd: string): boolean {
  return cmd.startsWith('xcodebuild') || 
         cmd.includes(' xcodebuild ') || 
         cmd.includes('|xcodebuild') || 
         cmd.includes('&& xcodebuild');
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch App/TestProjectWatchOSApp.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOSApp.swift
//  TestProjectWatchOS Watch App
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import SwiftUI

@main
struct TestProjectWatchOS_Watch_AppApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

```

--------------------------------------------------------------------------------
/src/presentation/interfaces/MCPResponse.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * MCP Framework Response Model
 * 
 * Defines the response format expected by the MCP (Model Context Protocol) framework.
 * This is a presentation layer contract for formatting output to the MCP client.
 */
export interface MCPResponse {
  content: Array<{
    type: string;
    text: string;
  }>;
}
```

--------------------------------------------------------------------------------
/src/shared/tests/types/execTypes.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Node.js exec error with stdout/stderr attached
 * This is how Node.js exec actually behaves - it attaches stdout/stderr to the error
 */
export interface NodeExecError extends Error {
  code?: number;
  stdout?: string;
  stderr?: string;
}

/**
 * Mock call type for exec function  
 */
export type ExecMockCall = [string, ...unknown[]];
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOSTests/TestProjectWatchOSTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOSTests.swift
//  TestProjectWatchOSTests
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import Testing
@testable import TestProjectWatchOS

struct TestProjectWatchOSTests {

    @Test func example() async throws {
        // Write your test here and use APIs like `#expect(...)` to check expected conditions.
    }

}

```

--------------------------------------------------------------------------------
/src/application/ports/OutputFormatterPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Port for formatting build output
 * This allows us to swap between different formatters (xcbeautify, raw, custom)
 */
export interface IOutputFormatter {
  /**
   * Format raw build output into a more readable format
   * @param rawOutput The raw output from xcodebuild
   * @returns Formatted output
   */
  format(rawOutput: string): Promise<string>;
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch AppTests/TestProjectWatchOS_Watch_AppTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOS_Watch_AppTests.swift
//  TestProjectWatchOS Watch AppTests
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import Testing
@testable import TestProjectWatchOS_Watch_App

struct TestProjectWatchOS_Watch_AppTests {

    @Test func example() async throws {
        // Write your test here and use APIs like `#expect(...)` to check expected conditions.
    }

}

```

--------------------------------------------------------------------------------
/src/application/ports/LoggingPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Interface for log management operations
 * Cross-cutting concern used by multiple use cases
 */
export interface ILogManager {
  saveLog(
    operation: 'build' | 'test' | 'run' | 'archive' | 'clean',
    content: string,
    projectName?: string,
    metadata?: Record<string, any>
  ): string;
  
  saveDebugData(
    operation: string,
    data: any,
    projectName?: string
  ): string;
}
```

--------------------------------------------------------------------------------
/src/domain/shared/Result.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Generic Result type for operations that can fail
 * Used throughout the domain layer to avoid throwing
 */
export type Result<T, E = Error> =
  | { success: true; value: T }
  | { success: false; error: E };

export const Result = {
  ok<T>(value: T): Result<T, never> {
    return { success: true, value };
  },

  fail<E>(error: E): Result<never, E> {
    return { success: false, error };
  }
};
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS/ContentView.swift:
--------------------------------------------------------------------------------

```swift
//
//  ContentView.swift
//  TestProjectWatchOS
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch App/ContentView.swift:
--------------------------------------------------------------------------------

```swift
//
//  ContentView.swift
//  TestProjectWatchOS Watch App
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

```

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

```typescript
// Domain Value Objects
export { Platform } from './domain/Platform.js';
export { DeviceId } from './domain/DeviceId.js';
export { ProjectPath } from './domain/ProjectPath.js';
export { AppPath } from './domain/AppPath.js';

// Infrastructure
export { ShellCommandExecutorAdapter } from './infrastructure/ShellCommandExecutorAdapter.js';
export { ConfigProviderAdapter } from './infrastructure/ConfigProviderAdapter.js';
```

--------------------------------------------------------------------------------
/src/application/ports/OutputParserPorts.ts:
--------------------------------------------------------------------------------

```typescript
import { BuildIssue } from '../../features/build/domain/BuildIssue.js';

/**
 * Port interface for parsing build output
 * This is an application-level abstraction
 */

export interface ParsedOutput {
  issues: BuildIssue[];
}

export interface IOutputParser {
  /**
   * Parse build output and extract issues (errors/warnings)
   * Only parses - no formatting or adding messages
   */
  parseBuildOutput(output: string): ParsedOutput;
}
```

--------------------------------------------------------------------------------
/src/features/app-management/index.ts:
--------------------------------------------------------------------------------

```typescript
// Controllers
export { InstallAppController } from './controllers/InstallAppController.js';

// Use Cases
export { InstallAppUseCase } from './use-cases/InstallAppUseCase.js';

// Factories
export { InstallAppControllerFactory } from './factories/InstallAppControllerFactory.js';

// Domain
export { InstallRequest } from './domain/InstallRequest.js';

// Infrastructure
export { AppInstallerAdapter } from './infrastructure/AppInstallerAdapter.js';
```

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

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "node",
    "lib": ["ES2022"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
```

--------------------------------------------------------------------------------
/src/features/simulator/domain/BootRequest.ts:
--------------------------------------------------------------------------------

```typescript
import { DeviceId } from '../../../shared/domain/DeviceId.js';

/**
 * Value object representing a request to boot a simulator
 *
 * Encapsulates the device identifier (can be UUID or name)
 */
export class BootRequest {
  private constructor(
    public readonly deviceId: string
  ) {
    Object.freeze(this);
  }

  /**
   * Create a boot request from a DeviceId
   */
  static create(deviceId: DeviceId): BootRequest {
    return new BootRequest(deviceId.toString());
  }
}
```

--------------------------------------------------------------------------------
/src/presentation/interfaces/IDependencyChecker.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Represents a missing dependency
 */
export interface MissingDependency {
  readonly name: string;
  readonly installCommand?: string;
}

/**
 * Checks for system dependencies required by MCP tools
 */
export interface IDependencyChecker {
  /**
   * Check if the specified dependencies are available
   * @param dependencies List of dependency names to check
   * @returns List of missing dependencies
   */
  check(dependencies: string[]): Promise<MissingDependency[]>;
}
```

--------------------------------------------------------------------------------
/.claude/settings.local.json:
--------------------------------------------------------------------------------

```json
{
  "permissions": {
    "allow": [
      "Bash(npm test:*)",
      "WebSearch",
      "Bash(npm run build:*)",
      "Bash(npm run test:coverage:*)",
      "WebFetch(domain:gist.github.com)",
      "WebFetch(domain:github.com)",
      "Bash(npm run test:e2e:*)",
      "Bash(npm run:*)",
      "Bash(npx jest:*)",
      "Bash(timeout 60 npx jest:*)",
      "Bash(grep:*)",
      "WebFetch(domain:docs.anthropic.com)",
      "Bash(xcodebuild:*)"
    ],
    "deny": [],
    "ask": []
  }
}
```

--------------------------------------------------------------------------------
/src/application/ports/CommandPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Port interfaces for command execution
 * 
 * These are general infrastructure ports that can be used
 * by any use case that needs to execute external commands.
 */

export interface ExecutionResult {
  stdout: string;
  stderr: string;
  exitCode: number;
}

export interface ExecutionOptions {
  maxBuffer?: number;
  timeout?: number;
  shell?: string;
}

export interface ICommandExecutor {
  execute(
    command: string,
    options?: ExecutionOptions
  ): Promise<ExecutionResult>;
}
```

--------------------------------------------------------------------------------
/src/features/simulator/domain/ShutdownRequest.ts:
--------------------------------------------------------------------------------

```typescript
import { DeviceId } from '../../../shared/domain/DeviceId.js';

/**
 * Value object representing a request to shutdown a simulator
 *
 * Encapsulates the device identifier (can be UUID or name)
 */
export class ShutdownRequest {
  private constructor(
    public readonly deviceId: string
  ) {
    Object.freeze(this);
  }

  /**
   * Create a shutdown request from a DeviceId
   */
  static create(deviceId: DeviceId): ShutdownRequest {
    return new ShutdownRequest(deviceId.toString());
  }
}
```

--------------------------------------------------------------------------------
/src/application/ports/MappingPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Port interfaces for mapping between domain and infrastructure concepts
 */

import { BuildDestination } from '../../features/build/domain/BuildDestination.js';

/**
 * Maps BuildDestination to xcodebuild-specific options
 */
export interface IBuildDestinationMapper {
  /**
   * Map a domain BuildDestination to xcodebuild destination string and settings
   */
  toXcodeBuildOptions(destination: BuildDestination): Promise<{
    destination: string;
    additionalSettings?: string[];
  }>;
}
```

--------------------------------------------------------------------------------
/src/presentation/formatters/strategies/OutputFormatterErrorStrategy.ts:
--------------------------------------------------------------------------------

```typescript
import { OutputFormatterError } from '../../../features/build/domain/BuildResult.js';
import { ErrorFormattingStrategy } from './ErrorFormattingStrategy.js';

/**
 * Formats output formatter errors (e.g., xcbeautify not installed)
 */
export class OutputFormatterErrorStrategy implements ErrorFormattingStrategy {
  canFormat(error: any): boolean {
    return error instanceof OutputFormatterError;
  }
  
  format(error: OutputFormatterError): string {
    return `xcbeautify failed: ${error.stderr}`;
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/domain/ListSimulatorsRequest.ts:
--------------------------------------------------------------------------------

```typescript
import { Platform } from '../../../shared/domain/Platform.js';
import { SimulatorState } from './SimulatorState.js';

/**
 * Value object for list simulators request
 */
export class ListSimulatorsRequest {
  constructor(
    public readonly platform?: Platform,
    public readonly state?: SimulatorState,
    public readonly name?: string
  ) {}

  static create(
    platform?: Platform,
    state?: SimulatorState,
    name?: string
  ): ListSimulatorsRequest {
    return new ListSimulatorsRequest(platform, state, name);
  }
}
```

--------------------------------------------------------------------------------
/src/application/ports/BuildPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Port interfaces specific to build operations
 * 
 * These ports define how the application layer
 * interacts with build-specific infrastructure.
 */

// Options for the build command builder (infrastructure concerns)
export interface BuildCommandOptions {
  scheme: string;
  configuration?: string;
  destination: string;  // Already mapped destination string
  additionalSettings?: string[];
  derivedDataPath?: string;
}

export interface IBuildCommand {
  build(
    projectPath: string,
    isWorkspace: boolean,
    options: BuildCommandOptions
  ): string;
}
```

--------------------------------------------------------------------------------
/XcodeProjectModifier/Package.swift:
--------------------------------------------------------------------------------

```swift
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "XcodeProjectModifier",
    platforms: [.macOS(.v10_15)],
    dependencies: [
        .package(url: "https://github.com/tuist/XcodeProj.git", from: "8.0.0"),
        .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0")
    ],
    targets: [
        .executableTarget(
            name: "XcodeProjectModifier",
            dependencies: [
                "XcodeProj",
                .product(name: "ArgumentParser", package: "swift-argument-parser")
            ]
        )
    ]
)
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "images" : [
    {
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "tinted"
        }
      ],
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageXCTest/Tests/TestSwiftPackageXCTestTests/TestSwiftPackageXCTestTests.swift:
--------------------------------------------------------------------------------

```swift
import XCTest
@testable import TestSwiftPackageXCTest

final class LegacyTests: XCTestCase {
    func testExample() throws {
        let spm = TestSwiftPackageXCTest()
        XCTAssertEqual(spm.text, "Hello, TestSwiftPackageXCTest!")
    }
    
    func testFailingTest() async throws {
        // This test is designed to fail for MCP testing
        XCTFail("Test MCP failing test reporting")
    }
    
    func testAnotherFailure() async throws {
        // Another failing test to verify multiple failures are handled
        XCTAssertEqual(42, 100, "Expected 42 to equal 100 but it doesn't")
    }
}

```

--------------------------------------------------------------------------------
/src/application/ports/ConfigPorts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Port interface for configuration access
 * This is an application-level abstraction
 */

export interface IConfigProvider {
  /**
   * Get the path for DerivedData
   * @param projectPath Optional project path to generate project-specific derived data path
   */
  getDerivedDataPath(projectPath?: string): string;
  
  /**
   * Get timeout for build operations in milliseconds
   */
  getBuildTimeout(): number;
  
  /**
   * Check if xcbeautify is enabled
   */
  isXcbeautifyEnabled(): boolean;
  
  /**
   * Get any custom build settings
   */
  getCustomBuildSettings(): Record<string, string>;
}
```

--------------------------------------------------------------------------------
/src/config.ts:
--------------------------------------------------------------------------------

```typescript
import { homedir } from 'os';
import path from 'path';

/**
 * Configuration for MCP Xcode Server
 */
export const config = {
  /**
   * Base path for MCP-Xcode DerivedData
   * Uses Xcode's standard location but in MCP-Xcode subfolder
   */
  derivedDataBasePath: path.join(homedir(), 'Library', 'Developer', 'Xcode', 'DerivedData', 'MCP-Xcode'),
  
  /**
   * Get DerivedData path for a specific project
   */
  getDerivedDataPath(projectPath: string): string {
    const projectName = path.basename(projectPath, path.extname(projectPath));
    return path.join(this.derivedDataBasePath, projectName);
  }
};
```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageSwiftTesting/Sources/TestSwiftPackageSwiftTestingExecutable/main.swift:
--------------------------------------------------------------------------------

```swift
import Foundation

// Simple executable for testing
print("TestSwiftPackageSwiftTesting Executable Running")
print("Arguments: \(CommandLine.arguments)")
print("Current Date: \(Date())")

// Test argument handling
if CommandLine.arguments.count > 1 {
    print("Received \(CommandLine.arguments.count - 1) arguments:")
    for (index, arg) in CommandLine.arguments.dropFirst().enumerated() {
        print("  Arg \(index + 1): \(arg)")
    }
}

// Test exit codes
if CommandLine.arguments.contains("--fail") {
    print("Error: Requested failure via --fail flag")
    exit(1)
}

print("Execution completed successfully")

```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageXCTest/Sources/TestSwiftPackageXCTestExecutable/main.swift:
--------------------------------------------------------------------------------

```swift
import Foundation

// Simple executable for testing
print("TestSwiftPackageXCTestExecutable Executable Running")
print("Arguments: \(CommandLine.arguments)")
print("Current Date: \(Date())")

// Test argument handling
if CommandLine.arguments.count > 1 {
    print("Received \(CommandLine.arguments.count - 1) arguments:")
    for (index, arg) in CommandLine.arguments.dropFirst().enumerated() {
        print("  Arg \(index + 1): \(arg)")
    }
}

// Test exit codes
if CommandLine.arguments.contains("--fail") {
    print("Error: Requested failure via --fail flag")
    exit(1)
}

print("Execution completed successfully")

```

--------------------------------------------------------------------------------
/src/features/app-management/infrastructure/AppInstallerAdapter.ts:
--------------------------------------------------------------------------------

```typescript
import { IAppInstaller } from '../../../application/ports/SimulatorPorts.js';
import { ICommandExecutor } from '../../../application/ports/CommandPorts.js';

/**
 * Installs apps on simulators using xcrun simctl
 */
export class AppInstallerAdapter implements IAppInstaller {
  constructor(private executor: ICommandExecutor) {}

  async installApp(appPath: string, simulatorId: string): Promise<void> {
    const result = await this.executor.execute(
      `xcrun simctl install "${simulatorId}" "${appPath}"`
    );
    
    if (result.exitCode !== 0) {
      throw new Error(result.stderr || 'Failed to install app');
    }
  }
}
```

--------------------------------------------------------------------------------
/src/presentation/formatters/strategies/DefaultErrorStrategy.ts:
--------------------------------------------------------------------------------

```typescript
import { ErrorFormattingStrategy } from './ErrorFormattingStrategy.js';

/**
 * Default strategy for plain error messages
 */
export class DefaultErrorStrategy implements ErrorFormattingStrategy {
  canFormat(_error: any): boolean {
    return true; // Always can format as fallback
  }
  
  format(error: any): string {
    if (error && error.message) {
      // Clean up common prefixes
      let message = error.message;
      message = message.replace(/^Error:\s*/i, '');
      message = message.replace(/^Invalid arguments:\s*/i, '');
      message = message.replace(/^Validation failed:\s*/i, '');
      return message;
    }
    return 'An error occurred';
  }
}
```

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

```typescript
/**
 * Type definitions for Apple Simulator MCP Server
 */

// Re-export Platform from domain for backward compatibility
// TODO: Update all imports to use domain directly
export { Platform } from './shared/domain/Platform.js';

export interface SimulatorDevice {
  udid: string;
  name: string;
  state: 'Booted' | 'Shutdown' | 'Creating' | 'Booting' | 'ShuttingDown';
  deviceTypeIdentifier: string;
  runtime: string;
  isAvailable?: boolean;
}

export interface TestResult {
  success: boolean;
  output: string;
  errors?: string;
  testCount?: number;
  failureCount?: number;
}

export interface Tool {
  execute(args: any): Promise<any>;
  getToolDefinition(): any;
}
```

--------------------------------------------------------------------------------
/jest.e2e.config.cjs:
--------------------------------------------------------------------------------

```
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testTimeout: 120000,
  transform: {
    '^.+\\.ts$': ['ts-jest', {
      tsconfig: {
        module: 'commonjs',
        esModuleInterop: true,
        allowSyntheticDefaultImports: true,
      },
    }],
  },
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  testMatch: [
    '**/*.e2e.test.ts'
  ],
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.d.ts',
    '!src/**/*.test.ts',
    '!src/**/tests/**/*',
    '!src/__tests__/**/*',
    '!src/index.ts',
  ],
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html'],
};
```

--------------------------------------------------------------------------------
/src/infrastructure/repositories/DeviceRepository.ts:
--------------------------------------------------------------------------------

```typescript
import { ICommandExecutor } from '../../application/ports/CommandPorts.js';

export interface RawDevice {
  udid: string;
  name: string;
  state: string;
  isAvailable: boolean;
  deviceTypeIdentifier?: string;
  dataPath?: string;
  dataPathSize?: number;
  logPath?: string;
}

export interface DeviceList {
  [runtime: string]: RawDevice[];
}

/**
 * Repository for accessing simulator device information
 */
export class DeviceRepository {
  constructor(private executor: ICommandExecutor) {}

  async getAllDevices(): Promise<DeviceList> {
    const result = await this.executor.execute('xcrun simctl list devices --json');
    const data = JSON.parse(result.stdout);
    return data.devices as DeviceList;
  }
}
```

--------------------------------------------------------------------------------
/jest.config.cjs:
--------------------------------------------------------------------------------

```
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testTimeout: 10000,
  transform: {
    '^.+\\.ts$': ['ts-jest', {
      tsconfig: {
        module: 'commonjs',
        esModuleInterop: true,
        allowSyntheticDefaultImports: true,
      },
    }],
  },
  moduleNameMapper: {
    '^(\\.{1,2}/.*)\\.js$': '$1',
  },
  testMatch: [
    '**/*.unit.test.ts',
    '**/*.integration.test.ts'
  ],
  collectCoverageFrom: [
    'src/**/*.ts',
    '!src/**/*.d.ts',
    '!src/**/*.test.ts',
    '!src/**/tests/**/*',
    '!src/__tests__/**/*',
    '!src/index.ts',
  ],
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html'],
};
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTest/TestProjectXCTestApp.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectXCTestApp.swift
//  TestProjectXCTest
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import SwiftUI
import SwiftData

@main
struct TestProjectXCTestApp: App {
    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            Item.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(sharedModelContainer)
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTesting/TestProjectSwiftTestingApp.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectSwiftTestingApp.swift
//  TestProjectSwiftTesting
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import SwiftUI
import SwiftData

@main
struct TestProjectSwiftTestingApp: App {
    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            Item.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(sharedModelContainer)
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTestingTests/TestProjectSwiftTestingTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectSwiftTestingTests.swift
//  TestProjectSwiftTestingTests
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import Testing

struct TestProjectSwiftTestingTests {

    @Test func example() async throws {
        // Write your test here and use APIs like `#expect(...)` to check expected conditions.
        #expect(true)
    }
    
    @Test func testFailingTest() async throws {
        // This test intentionally fails to test failure reporting
        #expect(false, "This test is designed to fail for testing MCP failure reporting")
    }
    
    @Test func testAnotherFailure() async throws {
        // Another failing test to verify multiple failures are handled
        let result = 42
        #expect(result == 100, "Expected result to be 100 but got \(result)")
    }

}

```

--------------------------------------------------------------------------------
/src/shared/tests/mocks/promisifyExec.ts:
--------------------------------------------------------------------------------

```typescript
import type { ExecOptions, ExecException } from 'child_process';

type ExecCallback = (error: ExecException | null, stdout: string, stderr: string) => void;
type ExecFunction = (command: string, options: ExecOptions, callback: ExecCallback) => void;

/**
 * Creates a promisified version of exec that matches Node's util.promisify behavior
 * Returns {stdout, stderr} on success, attaches them to error on failure
 */
export function createPromisifiedExec(execFn: ExecFunction) {
  return (cmd: string, options?: ExecOptions) => 
    new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
      execFn(cmd, options || {}, (error, stdout, stderr) => {
        if (error) {
          Object.assign(error, { stdout, stderr });
          reject(error);
        } else {
          resolve({ stdout, stderr });
        }
      });
    });
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTestUITests/TestProjectXCTestUITestsLaunchTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectXCTestUITestsLaunchTests.swift
//  TestProjectXCTestUITests
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import XCTest

final class TestProjectXCTestUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    @MainActor
    func testLaunch() throws {
        let app = XCUIApplication()
        app.launch()

        // Insert steps here to perform after app launch but before taking a screenshot,
        // such as logging into a test account or navigating somewhere in the app

        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "Launch Screen"
        attachment.lifetime = .keepAlways
        add(attachment)
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOSUITests/TestProjectWatchOSUITestsLaunchTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOSUITestsLaunchTests.swift
//  TestProjectWatchOSUITests
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import XCTest

final class TestProjectWatchOSUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    @MainActor
    func testLaunch() throws {
        let app = XCUIApplication()
        app.launch()

        // Insert steps here to perform after app launch but before taking a screenshot,
        // such as logging into a test account or navigating somewhere in the app

        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "Launch Screen"
        attachment.lifetime = .keepAlways
        add(attachment)
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTestingUITests/TestProjectSwiftTestingUITestsLaunchTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectSwiftTestingUITestsLaunchTests.swift
//  TestProjectSwiftTestingUITests
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import XCTest

final class TestProjectSwiftTestingUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    @MainActor
    func testLaunch() throws {
        let app = XCUIApplication()
        app.launch()

        // Insert steps here to perform after app launch but before taking a screenshot,
        // such as logging into a test account or navigating somewhere in the app

        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "Launch Screen"
        attachment.lifetime = .keepAlways
        add(attachment)
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch AppUITests/TestProjectWatchOS_Watch_AppUITestsLaunchTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOS_Watch_AppUITestsLaunchTests.swift
//  TestProjectWatchOS Watch AppUITests
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import XCTest

final class TestProjectWatchOS_Watch_AppUITestsLaunchTests: XCTestCase {

    override class var runsForEachTargetApplicationUIConfiguration: Bool {
        true
    }

    override func setUpWithError() throws {
        continueAfterFailure = false
    }

    @MainActor
    func testLaunch() throws {
        let app = XCUIApplication()
        app.launch()

        // Insert steps here to perform after app launch but before taking a screenshot,
        // such as logging into a test account or navigating somewhere in the app

        let attachment = XCTAttachment(screenshot: app.screenshot())
        attachment.name = "Launch Screen"
        attachment.lifetime = .keepAlways
        add(attachment)
    }
}

```

--------------------------------------------------------------------------------
/src/features/simulator/factories/ListSimulatorsControllerFactory.ts:
--------------------------------------------------------------------------------

```typescript
import { ListSimulatorsController } from '../controllers/ListSimulatorsController.js';
import { ListSimulatorsUseCase } from '../use-cases/ListSimulatorsUseCase.js';
import { DeviceRepository } from '../../../infrastructure/repositories/DeviceRepository.js';
import { ShellCommandExecutorAdapter } from '../../../shared/infrastructure/ShellCommandExecutorAdapter.js';
import { exec } from 'child_process';
import { promisify } from 'util';

/**
 * Factory for creating ListSimulatorsController with all dependencies
 */
export class ListSimulatorsControllerFactory {
  static create(): ListSimulatorsController {
    const execAsync = promisify(exec);
    const executor = new ShellCommandExecutorAdapter(execAsync);
    const deviceRepository = new DeviceRepository(executor);
    const useCase = new ListSimulatorsUseCase(deviceRepository);

    return new ListSimulatorsController(useCase);
  }
}
```

--------------------------------------------------------------------------------
/src/domain/services/PlatformDetector.ts:
--------------------------------------------------------------------------------

```typescript
import { Platform } from '../../shared/domain/Platform.js';
import { BuildDestination } from '../../features/build/domain/BuildDestination.js';

/**
 * Domain Service: Detects platform from build destination
 * 
 * Pure domain logic - no external dependencies
 * Used to determine which platform a build destination targets
 */
export class PlatformDetector {
  /**
   * Extract platform from a build destination
   */
  static fromDestination(destination: BuildDestination): Platform {
    if (destination.startsWith('iOS')) return Platform.iOS;
    if (destination.startsWith('macOS')) return Platform.macOS;
    if (destination.startsWith('tvOS')) return Platform.tvOS;
    if (destination.startsWith('watchOS')) return Platform.watchOS;
    if (destination.startsWith('visionOS')) return Platform.visionOS;
    
    // Default to iOS if unknown (shouldn't happen with proper validation)
    return Platform.iOS;
  }
}
```

--------------------------------------------------------------------------------
/src/presentation/interfaces/MCPController.ts:
--------------------------------------------------------------------------------

```typescript
import { MCPResponse } from './MCPResponse.js';

/**
 * Interface for MCP Tool Controllers
 *
 * All MCP controllers must implement this interface to ensure
 * consistent tool definition and execution patterns
 */
export interface MCPController {
  /** MCP tool name (e.g., 'build_xcode', 'install_app') */
  readonly name: string;
  
  /** Human-readable description of what the tool does */
  readonly description: string;
  
  /** JSON Schema for input validation */
  readonly inputSchema: object;
  
  /**
   * Get the complete MCP tool definition
   * Used by the MCP server to register the tool
   */
  getToolDefinition(): {
    name: string;
    description: string;
    inputSchema: object;
  };
  
  /**
   * Execute the tool with given arguments
   * @param args - Unknown input that will be validated
   * @returns MCP-formatted response with content array
   */
  execute(args: unknown): Promise<MCPResponse>;
}
```

--------------------------------------------------------------------------------
/src/utils/projects/XcodeErrors.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Error types for Xcode operations
 */
export enum XcodeErrorType {
  ProjectNotFound = 'PROJECT_NOT_FOUND',
  InvalidProjectType = 'INVALID_PROJECT_TYPE',
  UnknownError = 'UNKNOWN_ERROR'
}

/**
 * Custom error class for Xcode operations
 */
export class XcodeError extends Error {
  constructor(
    public readonly type: XcodeErrorType,
    public readonly path: string,
    message?: string
  ) {
    super(message || XcodeError.getDefaultMessage(type, path));
    this.name = 'XcodeError';
  }

  private static getDefaultMessage(type: XcodeErrorType, path: string): string {
    switch (type) {
      case XcodeErrorType.ProjectNotFound:
        return `No Xcode project or Swift package found at: ${path}`;
      case XcodeErrorType.InvalidProjectType:
        return `Invalid project type at: ${path}`;
      case XcodeErrorType.UnknownError:
        return `Unknown error opening project at: ${path}`;
    }
  }
}
```

--------------------------------------------------------------------------------
/src/utils/devices/SimulatorReset.ts:
--------------------------------------------------------------------------------

```typescript
import { execAsync } from '../../utils.js';
import { createModuleLogger } from '../../logger.js';

const logger = createModuleLogger('SimulatorReset');

/**
 * Utility class for resetting simulator state
 * Single responsibility: Reset a simulator (erase all content and settings)
 */
export class SimulatorReset {
  /**
   * Reset a simulator by erasing all content and settings
   * Equivalent to "Device > Erase All Content and Settings" in Simulator app
   */
  async reset(deviceId: string): Promise<void> {
    try {
      logger.info({ deviceId }, 'Resetting simulator - erasing all content and settings');
      await execAsync(`xcrun simctl erase "${deviceId}"`);
      logger.debug({ deviceId }, 'Successfully reset simulator');
    } catch (error: any) {
      logger.error({ error: error.message, deviceId }, 'Failed to reset simulator');
      throw new Error(`Failed to reset simulator: ${error.message}`);
    }
  }
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageSwiftTesting/Tests/TestSwiftPackageSwiftTestingTests/TestSwiftPackageSwiftTestingTests.swift:
--------------------------------------------------------------------------------

```swift
import Testing
@testable import TestSwiftPackageSwiftTesting

struct ModernTests {
    @Test func testExample() async throws {
        // Simple test to verify the module can be imported and tested
        let spm = TestSwiftPackageSwiftTesting()
        #expect(spm.text == "Hello, TestSwiftPackageSwiftTesting!")
    }

    @Test func testFailingTest() async throws {
        // This test is designed to fail for MCP testing
        #expect(1 == 2, """
            Test MCP failing test reporting.
            This is a multi-line message to test
            how Swift Testing handles longer error descriptions.
            Line 4 of the message.
            Line 5 with special characters: @#$%^&*()
            """)
    }
    
    @Test func testAnotherFailure() async throws {
        // Another failing test to verify multiple failures are handled
        let result = 42
        #expect(result == 100, "Expected result to be 100 but got \(result)")
    }
}

```

--------------------------------------------------------------------------------
/src/presentation/formatters/ErrorFormatter.ts:
--------------------------------------------------------------------------------

```typescript
import { ErrorFormattingStrategy } from './strategies/ErrorFormattingStrategy.js';
import { BuildIssuesStrategy } from './strategies/BuildIssuesStrategy.js';
import { OutputFormatterErrorStrategy } from './strategies/OutputFormatterErrorStrategy.js';
import { DefaultErrorStrategy } from './strategies/DefaultErrorStrategy.js';

/**
 * Main error formatter that uses strategies
 */
export class ErrorFormatter {
  private static strategies: ErrorFormattingStrategy[] = [
    new BuildIssuesStrategy(),
    new OutputFormatterErrorStrategy(),
    new DefaultErrorStrategy() // Must be last - catches all other errors
  ];
  
  /**
   * Format any error into a user-friendly message
   */
  static format(error: Error | any): string {
    for (const strategy of this.strategies) {
      if (strategy.canFormat(error)) {
        return strategy.format(error);
      }
    }
    
    // Shouldn't reach here due to DefaultErrorStrategy
    return 'Unknown error';
  }
}
```

--------------------------------------------------------------------------------
/src/features/app-management/domain/InstallRequest.ts:
--------------------------------------------------------------------------------

```typescript
import { AppPath } from '../../../shared/domain/AppPath.js';
import { DeviceId } from '../../../shared/domain/DeviceId.js';

/**
 * Domain Value Object: Represents an app installation request
 *
 * Contains all the data needed to install an app:
 * - What: appPath (the .app bundle to install)
 * - Where: simulatorId (optional - uses booted simulator if not specified)
 */
export class InstallRequest {
  private constructor(
    public readonly appPath: AppPath,
    public readonly simulatorId?: DeviceId
  ) {}

  /**
   * Create an InstallRequest from raw inputs
   * Validates the inputs and creates an immutable request object
   */
  static create(
    appPath: unknown,
    simulatorId?: unknown
  ): InstallRequest {
    // Validate app path using AppPath value object
    const validatedAppPath = AppPath.create(appPath);

    // Validate simulator ID if provided
    const validatedDeviceId = DeviceId.createOptional(simulatorId);

    return new InstallRequest(validatedAppPath, validatedDeviceId);
  }
}
```

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

```typescript
// Export device management
export { Devices, devices } from './devices/Devices.js';
export { SimulatorDevice } from './devices/SimulatorDevice.js';

// Export individual simulator components for testing
export { SimulatorBoot } from './devices/SimulatorBoot.js';
export { SimulatorReset } from './devices/SimulatorReset.js';
export { SimulatorApps } from './devices/SimulatorApps.js';
export { SimulatorUI } from './devices/SimulatorUI.js';
export { SimulatorInfo } from './devices/SimulatorInfo.js';

// Export Xcode project management
export { Xcode, xcode } from './projects/Xcode.js';
export { XcodeProject } from './projects/XcodeProject.js';
export { SwiftPackage } from './projects/SwiftPackage.js';

// Export Xcode components for testing
export { XcodeBuild } from './projects/XcodeBuild.js';
export { XcodeArchive } from './projects/XcodeArchive.js';
export { XcodeInfo } from './projects/XcodeInfo.js';
export { SwiftBuild } from './projects/SwiftBuild.js';
export { SwiftPackageInfo } from './projects/SwiftPackageInfo.js';
```

--------------------------------------------------------------------------------
/src/domain/errors/DomainError.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Base domain error classes that ensure consistent error messages
 * Each domain object can extend these for type-safe, consistent errors
 */

export abstract class DomainError extends Error {
  constructor(message: string) {
    super(message);
    this.name = this.constructor.name;
  }
}

// Common validation error patterns with consistent messages
export abstract class DomainEmptyError extends DomainError {
  constructor(fieldDisplayName: string) {
    super(`${fieldDisplayName} cannot be empty`);
  }
}

export abstract class DomainRequiredError extends DomainError {
  constructor(fieldDisplayName: string) {
    super(`${fieldDisplayName} is required`);
  }
}

export abstract class DomainInvalidTypeError extends DomainError {
  constructor(fieldDisplayName: string, expectedType: string) {
    super(`${fieldDisplayName} must be a ${expectedType}`);
  }
}

export abstract class DomainInvalidFormatError extends DomainError {
  // This one varies by context, so just pass the message
  constructor(message: string) {
    super(message);
  }
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageXCTest/Package.swift:
--------------------------------------------------------------------------------

```swift
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "TestSwiftPackageXCTest",
    products: [
        // Products define the executables and libraries a package produces, making them visible to other packages.
        .library(
            name: "TestSwiftPackageXCTest",
            targets: ["TestSwiftPackageXCTest"]),
        .executable(
            name: "TestSwiftPackageXCTestExecutable",
            targets: ["TestSwiftPackageXCTestExecutable"])
    ],
    targets: [
        // Targets are the basic building blocks of a package, defining a module or a test suite.
        // Targets can depend on other targets in this package and products from dependencies.
        .target(
            name: "TestSwiftPackageXCTest"),
        .executableTarget(
            name: "TestSwiftPackageXCTestExecutable"),
        .testTarget(
            name: "TestSwiftPackageXCTestTests",
            dependencies: ["TestSwiftPackageXCTest"]
        ),
    ]
)

```

--------------------------------------------------------------------------------
/src/features/simulator/domain/ListSimulatorsResult.ts:
--------------------------------------------------------------------------------

```typescript
import { Platform } from '../../../shared/domain/Platform.js';
import { SimulatorState } from './SimulatorState.js';

export interface SimulatorInfo {
  udid: string;
  name: string;
  state: SimulatorState;
  platform: string;
  runtime: string;
}

// Base class for all list simulators errors
export abstract class ListSimulatorsError extends Error {}

// Specific error types
export class SimulatorListParseError extends ListSimulatorsError {
  constructor() {
    super('Failed to parse simulator list: not valid JSON');
    this.name = 'SimulatorListParseError';
  }
}

/**
 * Result of listing simulators operation
 */
export class ListSimulatorsResult {
  private constructor(
    public readonly simulators: SimulatorInfo[],
    public readonly error?: Error
  ) {}

  static success(simulators: SimulatorInfo[]): ListSimulatorsResult {
    return new ListSimulatorsResult(simulators);
  }

  static failed(error: Error): ListSimulatorsResult {
    return new ListSimulatorsResult([], error);
  }

  get isSuccess(): boolean {
    return !this.error;
  }

  get count(): number {
    return this.simulators.length;
  }
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestSwiftPackageSwiftTesting/Package.swift:
--------------------------------------------------------------------------------

```swift
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "TestSwiftPackageSwiftTesting",
    products: [
        // Products define the executables and libraries a package produces, making them visible to other packages.
        .library(
            name: "TestSwiftPackageSwiftTesting",
            targets: ["TestSwiftPackageSwiftTesting"]),
        .executable(
            name: "TestSwiftPackageSwiftTestingExecutable",
            targets: ["TestSwiftPackageSwiftTestingExecutable"])
    ],
    targets: [
        // Targets are the basic building blocks of a package, defining a module or a test suite.
        // Targets can depend on other targets in this package and products from dependencies.
        .target(
            name: "TestSwiftPackageSwiftTesting"),
        .executableTarget(
            name: "TestSwiftPackageSwiftTestingExecutable"),
        .testTarget(
            name: "TestSwiftPackageSwiftTestingTests",
            dependencies: ["TestSwiftPackageSwiftTesting"]
        ),
    ]
)

```

--------------------------------------------------------------------------------
/src/features/simulator/infrastructure/SimulatorControlAdapter.ts:
--------------------------------------------------------------------------------

```typescript
import { ISimulatorControl } from '../../../application/ports/SimulatorPorts.js';
import { ICommandExecutor } from '../../../application/ports/CommandPorts.js';

/**
 * Controls simulator lifecycle using xcrun simctl
 */
export class SimulatorControlAdapter implements ISimulatorControl {
  constructor(private executor: ICommandExecutor) {}

  async boot(simulatorId: string): Promise<void> {
    const result = await this.executor.execute(`xcrun simctl boot "${simulatorId}"`);
    
    // Already booted is not an error
    if (result.exitCode !== 0 && 
        !result.stderr.includes('Unable to boot device in current state: Booted')) {
      // Throw raw error - presentation layer will format it
      throw new Error(result.stderr);
    }
  }

  async shutdown(simulatorId: string): Promise<void> {
    const result = await this.executor.execute(`xcrun simctl shutdown "${simulatorId}"`);
    
    // Already shutdown is not an error
    if (result.exitCode !== 0 && 
        !result.stderr.includes('Unable to shutdown device in current state: Shutdown')) {
      // Throw raw error - presentation layer will format it
      throw new Error(result.stderr);
    }
  }
}
```

--------------------------------------------------------------------------------
/src/application/ports/SimulatorPorts.ts:
--------------------------------------------------------------------------------

```typescript
import { SimulatorState } from '../../features/simulator/domain/SimulatorState.js';

/**
 * Port interfaces for simulator operations
 * 
 * Focused, single-responsibility interfaces following ISP
 */

export interface ISimulatorLocator {
  /**
   * Find a simulator by ID or name
   * Returns null if not found
   */
  findSimulator(idOrName: string): Promise<SimulatorInfo | null>;
  
  /**
   * Find first booted simulator
   * Returns null if none are booted
   * If multiple are booted, returns one (implementation-defined which)
   */
  findBootedSimulator(): Promise<SimulatorInfo | null>;
}

export interface ISimulatorControl {
  /**
   * Boot a simulator
   */
  boot(simulatorId: string): Promise<void>;
  
  /**
   * Shutdown a simulator
   */
  shutdown(simulatorId: string): Promise<void>;
}

export interface IAppInstaller {
  /**
   * Install an app bundle on a specific simulator
   * Throws if installation fails
   */
  installApp(appPath: string, simulatorId: string): Promise<void>;
}

/**
 * Simulator information snapshot
 * Includes current state at time of query (not cached)
 */
export interface SimulatorInfo {
  readonly id: string;
  readonly name: string;
  readonly state: SimulatorState;
  readonly platform: string;
  readonly runtime: string;
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTestUITests/TestProjectXCTestUITests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectXCTestUITests.swift
//  TestProjectXCTestUITests
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import XCTest

final class TestProjectXCTestUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    @MainActor
    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    @MainActor
    func testLaunchPerformance() throws {
        // This measures how long it takes to launch your application.
        measure(metrics: [XCTApplicationLaunchMetric()]) {
            XCUIApplication().launch()
        }
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOSUITests/TestProjectWatchOSUITests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOSUITests.swift
//  TestProjectWatchOSUITests
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import XCTest

final class TestProjectWatchOSUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    @MainActor
    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    @MainActor
    func testLaunchPerformance() throws {
        // This measures how long it takes to launch your application.
        measure(metrics: [XCTApplicationLaunchMetric()]) {
            XCUIApplication().launch()
        }
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTestingUITests/TestProjectSwiftTestingUITests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectSwiftTestingUITests.swift
//  TestProjectSwiftTestingUITests
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import XCTest

final class TestProjectSwiftTestingUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    @MainActor
    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    @MainActor
    func testLaunchPerformance() throws {
        // This measures how long it takes to launch your application.
        measure(metrics: [XCTApplicationLaunchMetric()]) {
            XCUIApplication().launch()
        }
    }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectWatchOS/TestProjectWatchOS Watch AppUITests/TestProjectWatchOS_Watch_AppUITests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectWatchOS_Watch_AppUITests.swift
//  TestProjectWatchOS Watch AppUITests
//
//  Created by Stefan Dragos Nitu on 22/08/2025.
//

import XCTest

final class TestProjectWatchOS_Watch_AppUITests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.

        // In UI tests it is usually best to stop immediately when a failure occurs.
        continueAfterFailure = false

        // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    @MainActor
    func testExample() throws {
        // UI tests must launch the application that they test.
        let app = XCUIApplication()
        app.launch()

        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    @MainActor
    func testLaunchPerformance() throws {
        // This measures how long it takes to launch your application.
        measure(metrics: [XCTApplicationLaunchMetric()]) {
            XCUIApplication().launch()
        }
    }
}

```

--------------------------------------------------------------------------------
/src/shared/infrastructure/ShellCommandExecutorAdapter.ts:
--------------------------------------------------------------------------------

```typescript
import { ExecOptions } from 'child_process';
import { createModuleLogger } from '../../logger.js';
import { ICommandExecutor, ExecutionResult, ExecutionOptions } from '../../application/ports/CommandPorts.js';

const logger = createModuleLogger('ShellCommandExecutor');

/**
 * Executes shell commands via child process
 * Single Responsibility: Execute shell commands and return results
 */
export class ShellCommandExecutorAdapter implements ICommandExecutor {
  constructor(
    private readonly execAsync: (
      command: string, 
      options: ExecOptions
    ) => Promise<{ stdout: string; stderr: string }>
  ) {}
  
  /**
   * Execute a command and return the result
   */
  async execute(command: string, options: ExecutionOptions = {}): Promise<ExecutionResult> {
    const {
      maxBuffer = 50 * 1024 * 1024, // 50MB default
      timeout = 300000, // 5 minute default
      shell = '/bin/bash'
    } = options;
    
    logger.debug({ command }, 'Executing command');
    
    try {
      const { stdout, stderr } = await this.execAsync(command, {
        maxBuffer,
        timeout,
        shell
      });
      
      return {
        stdout,
        stderr,
        exitCode: 0
      };
    } catch (error: any) {
      // Even on failure, return the output
      return {
        stdout: error.stdout || '',
        stderr: error.stderr || '',
        exitCode: error.code || 1
      };
    }
  }
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTesting/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "images" : [
    {
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "tinted"
        }
      ],
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "16x16"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "16x16"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "32x32"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "32x32"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "128x128"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "128x128"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "256x256"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "256x256"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "512x512"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "512x512"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTest/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------

```json
{
  "images" : [
    {
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "tinted"
        }
      ],
      "idiom" : "universal",
      "platform" : "ios",
      "size" : "1024x1024"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "16x16"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "16x16"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "32x32"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "32x32"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "128x128"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "128x128"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "256x256"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "256x256"
    },
    {
      "idiom" : "mac",
      "scale" : "1x",
      "size" : "512x512"
    },
    {
      "idiom" : "mac",
      "scale" : "2x",
      "size" : "512x512"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

```

--------------------------------------------------------------------------------
/src/presentation/formatters/strategies/BuildIssuesStrategy.ts:
--------------------------------------------------------------------------------

```typescript
import { BuildIssue } from '../../../features/build/domain/BuildIssue.js';
import { ErrorFormattingStrategy } from './ErrorFormattingStrategy.js';

/**
 * Formats build issues (errors and warnings)
 */
export class BuildIssuesStrategy implements ErrorFormattingStrategy {
  canFormat(error: any): boolean {
    return !!(error && error.issues && Array.isArray(error.issues) && 
             error.issues.some((i: any) => i instanceof BuildIssue));
  }
  
  format(error: any): string {
    // Filter to only actual BuildIssue instances
    const issues = (error.issues as any[]).filter(i => i instanceof BuildIssue);
    const errors = issues.filter(i => i.type === 'error');
    const warnings = issues.filter(i => i.type === 'warning');
    
    let message = '';
    if (errors.length > 0) {
      message += `❌ Errors (${errors.length}):\n`;
      message += errors.slice(0, 5).map(e => `  • ${e.toString()}`).join('\n');
      if (errors.length > 5) {
        message += `\n  ... and ${errors.length - 5} more errors`;
      }
    }
    
    if (warnings.length > 0) {
      if (message) message += '\n\n';
      message += `⚠️ Warnings (${warnings.length}):\n`;
      message += warnings.slice(0, 3).map(w => `  • ${w.toString()}`).join('\n');
      if (warnings.length > 3) {
        message += `\n  ... and ${warnings.length - 3} more warnings`;
      }
    }
    
    return message || error.message || 'Build failed';
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/index.ts:
--------------------------------------------------------------------------------

```typescript
// Controllers
export { BootSimulatorController } from './controllers/BootSimulatorController.js';
export { ShutdownSimulatorController } from './controllers/ShutdownSimulatorController.js';
export { ListSimulatorsController } from './controllers/ListSimulatorsController.js';

// Use Cases
export { BootSimulatorUseCase } from './use-cases/BootSimulatorUseCase.js';
export { ShutdownSimulatorUseCase } from './use-cases/ShutdownSimulatorUseCase.js';
export { ListSimulatorsUseCase } from './use-cases/ListSimulatorsUseCase.js';

// Factories
export { BootSimulatorControllerFactory } from './factories/BootSimulatorControllerFactory.js';
export { ShutdownSimulatorControllerFactory } from './factories/ShutdownSimulatorControllerFactory.js';
export { ListSimulatorsControllerFactory } from './factories/ListSimulatorsControllerFactory.js';

// Domain
export { BootRequest } from './domain/BootRequest.js';
export { ShutdownRequest } from './domain/ShutdownRequest.js';
export { ListSimulatorsRequest } from './domain/ListSimulatorsRequest.js';
export { SimulatorState } from './domain/SimulatorState.js';
export {
  BootResult,
  BootOutcome,
  SimulatorNotFoundError,
  BootCommandFailedError,
  SimulatorBusyError
} from './domain/BootResult.js';

// Infrastructure
export { SimulatorControlAdapter } from './infrastructure/SimulatorControlAdapter.js';
export { SimulatorLocatorAdapter } from './infrastructure/SimulatorLocatorAdapter.js';
```

--------------------------------------------------------------------------------
/src/presentation/decorators/DependencyCheckingDecorator.ts:
--------------------------------------------------------------------------------

```typescript
import { MCPController } from '../interfaces/MCPController.js';
import { MCPResponse } from '../interfaces/MCPResponse.js';
import { IDependencyChecker } from '../interfaces/IDependencyChecker.js';

/**
 * Decorator that checks dependencies before executing the controller
 *
 * Follows the Decorator pattern to add dependency checking behavior
 * without modifying the original controller
 */
export class DependencyCheckingDecorator implements MCPController {
  // Delegate properties to decoratee
  get name(): string { return this.decoratee.name; }
  get description(): string { return this.decoratee.description; }
  get inputSchema(): object { return this.decoratee.inputSchema; }

  constructor(
    private readonly decoratee: MCPController,
    private readonly requiredDependencies: string[],
    private readonly dependencyChecker: IDependencyChecker
  ) {}

  async execute(args: unknown): Promise<MCPResponse> {
    // Check dependencies first
    const missing = await this.dependencyChecker.check(this.requiredDependencies);

    if (missing.length > 0) {
      // Dependencies missing - return error without executing
      let text = '❌ Missing required dependencies:\n';
      for (const dep of missing) {
        text += `\n  • ${dep.name}`;
        if (dep.installCommand) {
          text += `: ${dep.installCommand}`;
        }
      }

      return {
        content: [{ type: 'text', text }]
      };
    }

    // All dependencies available - delegate to actual controller
    return this.decoratee.execute(args);
  }

  getToolDefinition() {
    // Delegate to decoratee
    return this.decoratee.getToolDefinition();
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/domain/ShutdownResult.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Domain entity representing the result of a shutdown operation
 */

// Error types specific to shutdown operations
export abstract class ShutdownError extends Error {}

export class SimulatorNotFoundError extends ShutdownError {
  constructor(public readonly deviceId: string) {
    super(deviceId);
    this.name = 'SimulatorNotFoundError';
  }
}

export class ShutdownCommandFailedError extends ShutdownError {
  constructor(public readonly stderr: string) {
    super(stderr);
    this.name = 'ShutdownCommandFailedError';
  }
}

// Possible outcomes of a shutdown operation
export enum ShutdownOutcome {
  Shutdown = 'shutdown',
  AlreadyShutdown = 'already_shutdown',
  Failed = 'failed'
}

// Diagnostics information about the shutdown operation
interface ShutdownDiagnostics {
  simulatorId?: string;
  simulatorName?: string;
  error?: Error;
}

export class ShutdownResult {
  private constructor(
    public readonly outcome: ShutdownOutcome,
    public readonly diagnostics: ShutdownDiagnostics
  ) {}
  
  static shutdown(simulatorId: string, simulatorName: string): ShutdownResult {
    return new ShutdownResult(
      ShutdownOutcome.Shutdown,
      { simulatorId, simulatorName }
    );
  }
  
  static alreadyShutdown(simulatorId: string, simulatorName: string): ShutdownResult {
    return new ShutdownResult(
      ShutdownOutcome.AlreadyShutdown,
      { simulatorId, simulatorName }
    );
  }
  
  static failed(simulatorId: string | undefined, simulatorName: string | undefined, error: Error): ShutdownResult {
    return new ShutdownResult(
      ShutdownOutcome.Failed,
      { simulatorId, simulatorName, error }
    );
  }
}
```

--------------------------------------------------------------------------------
/src/infrastructure/services/DependencyChecker.ts:
--------------------------------------------------------------------------------

```typescript
import { IDependencyChecker, MissingDependency } from '../../presentation/interfaces/IDependencyChecker.js';
import { ICommandExecutor } from '../../application/ports/CommandPorts.js';

/**
 * Checks for system dependencies using shell commands
 */
export class DependencyChecker implements IDependencyChecker {
  private readonly dependencyMap: Record<string, { checkCommand: string; installCommand?: string }> = {
    'xcodebuild': {
      checkCommand: 'which xcodebuild',
      installCommand: 'Install Xcode from the App Store'
    },
    'xcrun': {
      checkCommand: 'which xcrun',
      installCommand: 'Install Xcode Command Line Tools: xcode-select --install'
    },
    'xcbeautify': {
      checkCommand: 'which xcbeautify',
      installCommand: 'brew install xcbeautify'
    }
  };

  constructor(
    private readonly executor: ICommandExecutor
  ) {}

  async check(dependencies: string[]): Promise<MissingDependency[]> {
    const missing: MissingDependency[] = [];

    for (const dep of dependencies) {
      const config = this.dependencyMap[dep];
      if (!config) {
        // Unknown dependency - just check with 'which'
        const result = await this.executor.execute(`which ${dep}`, {
          shell: '/bin/bash'
        });

        if (result.exitCode !== 0) {
          missing.push({ name: dep });
        }
        continue;
      }

      // Check using configured command
      const result = await this.executor.execute(config.checkCommand, {
        shell: '/bin/bash'
      });

      if (result.exitCode !== 0) {
        missing.push({
          name: dep,
          installCommand: config.installCommand
        });
      }
    }

    return missing;
  }
}
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTest/ContentView.swift:
--------------------------------------------------------------------------------

```swift
//
//  ContentView.swift
//  TestProjectXCTest
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]

    var body: some View {
        NavigationSplitView {
            List {
                ForEach(items) { item in
                    NavigationLink {
                        Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
                    } label: {
                        Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
                    }
                }
                .onDelete(perform: deleteItems)
            }
#if os(macOS)
            .navigationSplitViewColumnWidth(min: 180, ideal: 200)
#endif
            .toolbar {
#if os(iOS)
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
#endif
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            Text("Select an item")
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(timestamp: Date())
            modelContext.insert(newItem)
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                modelContext.delete(items[index])
            }
        }
    }
}

#Preview {
    ContentView()
        .modelContainer(for: Item.self, inMemory: true)
}

```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectSwiftTesting/TestProjectSwiftTesting/ContentView.swift:
--------------------------------------------------------------------------------

```swift
//
//  ContentView.swift
//  TestProjectSwiftTesting
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]

    var body: some View {
        NavigationSplitView {
            List {
                ForEach(items) { item in
                    NavigationLink {
                        Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
                    } label: {
                        Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
                    }
                }
                .onDelete(perform: deleteItems)
            }
#if os(macOS)
            .navigationSplitViewColumnWidth(min: 180, ideal: 200)
#endif
            .toolbar {
#if os(iOS)
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
#endif
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            Text("Select an item")
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(timestamp: Date())
            modelContext.insert(newItem)
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                modelContext.delete(items[index])
            }
        }
    }
}

#Preview {
    ContentView()
        .modelContainer(for: Item.self, inMemory: true)
}

```

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

```json
{
  "name": "mcp-xcode-server",
  "version": "0.6.0",
  "description": "MCP server for Xcode - build, test, run, and manage Apple platform projects (iOS, macOS, tvOS, watchOS, visionOS)",
  "main": "dist/index.js",
  "type": "module",
  "bin": {
    "mcp-xcode-server": "dist/cli.js"
  },
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js",
    "dev": "tsc && node dist/index.js",
    "test": "jest && jest --config jest.e2e.config.cjs --runInBand",
    "test:coverage": "jest --coverage",
    "test:unit": "jest '*.unit.test.ts'",
    "test:integration": "jest '*.integration.test.ts'",
    "test:e2e": "jest --config jest.e2e.config.cjs --runInBand",
    "postinstall": "cd XcodeProjectModifier && swift build -c release",
    "build:modifier": "cd XcodeProjectModifier && swift build -c release"
  },
  "keywords": [
    "mcp",
    "apple",
    "ios",
    "macos",
    "tvos",
    "watchos",
    "visionos",
    "simulator",
    "xcode",
    "spm",
    "swift"
  ],
  "author": "Stefan",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/yourusername/mcp-xcode-server.git"
  },
  "bugs": {
    "url": "https://github.com/yourusername/mcp-xcode-server/issues"
  },
  "homepage": "https://github.com/yourusername/mcp-xcode-server#readme",
  "files": [
    "dist/**/*",
    "XcodeProjectModifier/**/*",
    "README.md",
    "LICENSE"
  ],
  "engines": {
    "node": ">=18.0.0"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.17.3",
    "commander": "^12.0.0",
    "fast-xml-parser": "^5.2.5",
    "pino": "^9.9.0",
    "pino-pretty": "^13.1.1"
  },
  "devDependencies": {
    "@types/jest": "^30.0.0",
    "@types/node": "^20.11.0",
    "jest": "^30.1.1",
    "regexp-tree": "^0.1.27",
    "ts-jest": "^29.4.1",
    "typescript": "^5.3.3"
  }
}

```

--------------------------------------------------------------------------------
/src/shared/domain/Platform.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Domain Value Object: Platform enum
 * Represents the supported Apple platforms
 */
export enum Platform {
  iOS = 'iOS',
  macOS = 'macOS',
  tvOS = 'tvOS',
  watchOS = 'watchOS',
  visionOS = 'visionOS'
}

/**
 * Platform validation and parsing utilities
 */
export namespace Platform {
  /**
   * Parse a string into a Platform enum value
   * @throws Error if the string is not a valid platform
   */
  export function parse(value: unknown): Platform {
    // Type check
    if (typeof value !== 'string') {
      throw new InvalidTypeError(value);
    }

    // Check if valid platform - filter out namespace functions
    const validPlatforms = Object.values(Platform).filter(v => typeof v === 'string') as string[];
    if (!validPlatforms.includes(value)) {
      throw new InvalidPlatformError(value, validPlatforms);
    }

    return value as Platform;
  }

  /**
   * Parse a string into a Platform enum value or return undefined
   */
  export function parseOptional(value: unknown): Platform | undefined {
    if (value === undefined || value === null) {
      return undefined;
    }
    return parse(value);
  }

  // Error classes
  export class InvalidTypeError extends Error {
    constructor(public readonly providedValue: unknown) {
      const validValues = Object.values(Platform).filter(v => typeof v === 'string') as string[];
      super(`Platform must be a string (one of: ${validValues.join(', ')}), got ${typeof providedValue}`);
      this.name = 'Platform.InvalidTypeError';
    }
  }

  export class InvalidPlatformError extends Error {
    constructor(
      public readonly providedValue: unknown,
      public readonly validValues: string[]
    ) {
      super(`Invalid platform: ${providedValue}. Valid values are: ${validValues.join(', ')}`);
      this.name = 'Platform.InvalidPlatformError';
    }
  }
}
```

--------------------------------------------------------------------------------
/src/shared/tests/mocks/selectiveExecMock.ts:
--------------------------------------------------------------------------------

```typescript
import type { ExecOptions, ChildProcess } from 'child_process';
import type { NodeExecError } from '../types/execTypes.js';

type ExecCallback = (error: NodeExecError | null, stdout: string, stderr: string) => void;
type ExecFunction = {
  (command: string, callback: ExecCallback): ChildProcess;
  (command: string, options: ExecOptions, callback: ExecCallback): ChildProcess;
};

export interface MockResponse {
  error?: NodeExecError;
  stdout?: string;
  stderr?: string;
}

/**
 * Creates a selective exec mock that only mocks specific commands
 * and delegates others to the real exec implementation
 */
export function createSelectiveExecMock(
  commandFilter: (cmd: string) => boolean,
  getMockResponse: () => MockResponse | undefined,
  actualExec: ExecFunction
) {
  return (cmd: string, ...args: unknown[]) => {
    // Handle both (cmd, callback) and (cmd, options, callback) signatures
    const callback = typeof args[0] === 'function' ? args[0] as ExecCallback : args[1] as ExecCallback;
    const options = typeof args[0] === 'function' ? {} : args[0] as ExecOptions;
    
    if (commandFilter(cmd)) {
      const response = getMockResponse();
      if (response) {
        process.nextTick(() => {
          if (response.error) {
            callback(response.error, response.stdout || '', response.stderr || '');
          } else {
            callback(null, response.stdout || '', response.stderr || '');
          }
        });
      } else {
        process.nextTick(() => {
          const error = new Error(`No mock response configured for: ${cmd}`) as NodeExecError;
          error.code = 1;
          error.stdout = '';
          error.stderr = '';
          callback(error, '', '');
        });
      }
      return;
    }
    
    // Delegate to real exec for other commands
    return actualExec(cmd, options, callback);
  };
}
```

--------------------------------------------------------------------------------
/src/features/simulator/domain/SimulatorState.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Simulator state enum
 * Values match xcrun simctl output exactly for direct comparison
 */
export enum SimulatorState {
  Booted = 'Booted',
  Booting = 'Booting',
  Shutdown = 'Shutdown',
  ShuttingDown = 'Shutting Down'
}

/**
 * SimulatorState validation and parsing utilities
 */
export namespace SimulatorState {
  /**
   * Parse a string into a SimulatorState enum value
   * @throws Error if the string is not a valid state
   */
  export function parse(value: unknown): SimulatorState {
    // Type check
    if (typeof value !== 'string') {
      throw new InvalidTypeError(value);
    }

    // Check if valid state - filter out namespace functions
    const validStates = Object.values(SimulatorState).filter(v => typeof v === 'string') as string[];
    if (!validStates.includes(value)) {
      throw new InvalidStateError(value, validStates);
    }

    return value as SimulatorState;
  }

  /**
   * Parse a string into a SimulatorState enum value or return undefined
   */
  export function parseOptional(value: unknown): SimulatorState | undefined {
    if (value === undefined || value === null) {
      return undefined;
    }
    return parse(value);
  }

  // Error classes
  export class InvalidTypeError extends Error {
    constructor(public readonly providedValue: unknown) {
      const validValues = Object.values(SimulatorState).filter(v => typeof v === 'string') as string[];
      super(`Simulator state must be a string (one of: ${validValues.join(', ')}), got ${typeof providedValue}`);
      this.name = 'SimulatorState.InvalidTypeError';
    }
  }

  export class InvalidStateError extends Error {
    constructor(
      public readonly providedValue: unknown,
      public readonly validValues: string[]
    ) {
      super(`Invalid simulator state: ${providedValue}. Valid values are: ${validValues.join(', ')}`);
      this.name = 'SimulatorState.InvalidStateError';
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/factories/BootSimulatorControllerFactory.ts:
--------------------------------------------------------------------------------

```typescript
import { exec } from 'child_process';
import { promisify } from 'util';
import { BootSimulatorUseCase } from '../use-cases/BootSimulatorUseCase.js';
import { BootSimulatorController } from '../controllers/BootSimulatorController.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';
import { SimulatorLocatorAdapter } from '../infrastructure/SimulatorLocatorAdapter.js';
import { SimulatorControlAdapter } from '../infrastructure/SimulatorControlAdapter.js';
import { ShellCommandExecutorAdapter } from '../../../shared/infrastructure/ShellCommandExecutorAdapter.js';
import { DependencyCheckingDecorator } from '../../../presentation/decorators/DependencyCheckingDecorator.js';
import { DependencyChecker } from '../../../infrastructure/services/DependencyChecker.js';

/**
 * Factory class for creating BootSimulatorController with all dependencies
 * This is the composition root for the boot simulator functionality
 */
export class BootSimulatorControllerFactory {
  static create(): MCPController {
    // Create the shell executor that all adapters will use
    const execAsync = promisify(exec);
    const executor = new ShellCommandExecutorAdapter(execAsync);

    // Create infrastructure adapters
    const simulatorLocator = new SimulatorLocatorAdapter(executor);
    const simulatorControl = new SimulatorControlAdapter(executor);

    // Create the use case with all dependencies
    const useCase = new BootSimulatorUseCase(
      simulatorLocator,
      simulatorControl
    );

    // Create the controller
    const controller = new BootSimulatorController(useCase);

    // Create dependency checker
    const dependencyChecker = new DependencyChecker(executor);

    // Wrap with dependency checking decorator
    const decoratedController = new DependencyCheckingDecorator(
      controller,
      ['xcrun'],  // simctl is part of xcrun
      dependencyChecker
    );

    return decoratedController;
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/tests/unit/BootRequest.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from '@jest/globals';
import { BootRequest } from '../../domain/BootRequest.js';
import { DeviceId } from '../../../../shared/domain/DeviceId.js';

describe('BootRequest', () => {
  describe('create', () => {
    it('should create a valid boot request with simulator UUID', () => {
      // Arrange
      const deviceIdString = 'ABC123-DEF456-789';
      const deviceId = DeviceId.create(deviceIdString);

      // Act
      const request = BootRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe(deviceIdString);
    });

    it('should create a valid boot request with simulator name', () => {
      // Arrange
      const deviceName = 'iPhone 15 Pro';
      const deviceId = DeviceId.create(deviceName);

      // Act
      const request = BootRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe(deviceName);
    });

    it('should throw error for empty device ID', () => {
      // Arrange
      const emptyId = '';

      // Act & Assert
      expect(() => DeviceId.create(emptyId)).toThrow('Device ID cannot be empty');
    });

    it('should throw error for whitespace-only device ID', () => {
      // Arrange
      const whitespaceId = '   ';

      // Act & Assert
      expect(() => DeviceId.create(whitespaceId)).toThrow('Device ID cannot be whitespace only');
    });

    it('should be immutable', () => {
      // Arrange
      const deviceId = DeviceId.create('ABC123');
      const request = BootRequest.create(deviceId);

      // Act & Assert
      expect(() => {
        (request as any).deviceId = 'changed';
      }).toThrow();
    });

    it('should trim whitespace from device ID', () => {
      // Arrange
      const idWithSpaces = '  iPhone 15  ';
      const deviceId = DeviceId.create(idWithSpaces);

      // Act
      const request = BootRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe('iPhone 15');
    });
  });
});
```

--------------------------------------------------------------------------------
/src/shared/tests/utils/gitResetTestArtifacts.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Utility to reset test artifacts using git
 * This ensures consistent cleanup across all test utilities
 */

import { execSync } from 'child_process';
import { resolve } from 'path';
import { createModuleLogger } from '../../../logger.js';

const logger = createModuleLogger('GitResetTestArtifacts');

/**
 * Reset test_artifacts directory to pristine git state
 * @param path - Optional specific path within test_artifacts to reset
 */
export function gitResetTestArtifacts(path?: string): void {
  const targetPath = path || 'test_artifacts/';
  
  try {
    // Remove untracked files and directories (build artifacts)
    execSync(`git clean -fdx ${targetPath}`, { 
      cwd: resolve(process.cwd()),
      stdio: 'pipe'
    });
    
    // First unstage any staged changes
    execSync(`git reset HEAD ${targetPath}`, { 
      cwd: resolve(process.cwd()),
      stdio: 'pipe'
    });
    
    // Then reset any modified tracked files
    execSync(`git checkout -- ${targetPath}`, { 
      cwd: resolve(process.cwd()),
      stdio: 'pipe'
    });
    
    logger.debug({ path: targetPath }, 'Reset test artifacts using git');
  } catch (error) {
    logger.error({ error, path: targetPath }, 'Failed to reset test artifacts');
    // Don't throw - cleanup should be best effort
  }
}

/**
 * Reset a specific file within test_artifacts
 * @param filePath - Path to the file relative to project root
 */
export function gitResetFile(filePath: string): void {
  try {
    // Only reset if the file is within test_artifacts
    if (!filePath.includes('test_artifacts')) {
      logger.warn({ filePath }, 'Attempting to reset file outside test_artifacts - skipping');
      return;
    }
    
    execSync(`git checkout -- ${filePath}`, { 
      cwd: resolve(process.cwd()),
      stdio: 'pipe'
    });
    
    logger.debug({ filePath }, 'Reset file using git');
  } catch (error) {
    logger.warn({ error, filePath }, 'Failed to reset file - may be untracked');
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/factories/ShutdownSimulatorControllerFactory.ts:
--------------------------------------------------------------------------------

```typescript
import { exec } from 'child_process';
import { promisify } from 'util';
import { ShutdownSimulatorUseCase } from '../use-cases/ShutdownSimulatorUseCase.js';
import { ShutdownSimulatorController } from '../controllers/ShutdownSimulatorController.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';
import { SimulatorLocatorAdapter } from '../infrastructure/SimulatorLocatorAdapter.js';
import { SimulatorControlAdapter } from '../infrastructure/SimulatorControlAdapter.js';
import { ShellCommandExecutorAdapter } from '../../../shared/infrastructure/ShellCommandExecutorAdapter.js';
import { DependencyCheckingDecorator } from '../../../presentation/decorators/DependencyCheckingDecorator.js';
import { DependencyChecker } from '../../../infrastructure/services/DependencyChecker.js';

/**
 * Factory class for creating ShutdownSimulatorController with all dependencies
 * This is the composition root for the shutdown simulator functionality
 */
export class ShutdownSimulatorControllerFactory {
  static create(): MCPController {
    // Create the shell executor that all adapters will use
    const execAsync = promisify(exec);
    const executor = new ShellCommandExecutorAdapter(execAsync);

    // Create infrastructure adapters
    const simulatorLocator = new SimulatorLocatorAdapter(executor);
    const simulatorControl = new SimulatorControlAdapter(executor);

    // Create the use case with all dependencies
    const useCase = new ShutdownSimulatorUseCase(
      simulatorLocator,
      simulatorControl
    );

    // Create the controller
    const controller = new ShutdownSimulatorController(useCase);

    // Create dependency checker
    const dependencyChecker = new DependencyChecker(executor);

    // Wrap with dependency checking decorator
    const decoratedController = new DependencyCheckingDecorator(
      controller,
      ['xcrun'],  // simctl is part of xcrun
      dependencyChecker
    );

    return decoratedController;
  }
}
```

--------------------------------------------------------------------------------
/src/shared/domain/DeviceId.ts:
--------------------------------------------------------------------------------

```typescript
import { DomainEmptyError, DomainInvalidTypeError } from '../../domain/errors/DomainError.js';

/**
 * Value object for a device identifier
 * Can be either a device UDID or a device name
 * Works for both simulators and physical devices
 */
export class DeviceId {
  private constructor(private readonly value: string) {}

  static create(id: unknown): DeviceId {
    // Required check
    if (id === undefined || id === null) {
      throw new DeviceId.RequiredError();
    }

    // Type checking
    if (typeof id !== 'string') {
      throw new DeviceId.InvalidTypeError(id);
    }

    // Empty check
    if (id === '') {
      throw new DeviceId.EmptyError(id);
    }

    // Whitespace-only check
    if (id.trim() === '') {
      throw new DeviceId.WhitespaceOnlyError(id);
    }

    return new DeviceId(id.trim());
  }

  static createOptional(id: unknown): DeviceId | undefined {
    if (id === undefined || id === null) {
      return undefined;
    }
    return DeviceId.create(id);
  }

  toString(): string {
    return this.value;
  }

  equals(other: DeviceId): boolean {
    return this.value === other.value;
  }
}

// Nested error classes under DeviceId namespace
export namespace DeviceId {
  export class RequiredError extends Error {
    constructor() {
      super('Device ID is required');
      this.name = 'DeviceId.RequiredError';
    }
  }

  export class InvalidTypeError extends DomainInvalidTypeError {
    constructor(public readonly providedValue: unknown) {
      super('Device ID', 'string');
      this.name = 'DeviceId.InvalidTypeError';
    }
  }

  export class EmptyError extends DomainEmptyError {
    constructor(public readonly providedValue: unknown) {
      super('Device ID');
      this.name = 'DeviceId.EmptyError';
    }
  }

  export class WhitespaceOnlyError extends Error {
    constructor(public readonly providedValue: unknown) {
      super('Device ID cannot be whitespace only');
      this.name = 'DeviceId.WhitespaceOnlyError';
    }
  }
}
```

--------------------------------------------------------------------------------
/src/shared/infrastructure/ConfigProviderAdapter.ts:
--------------------------------------------------------------------------------

```typescript
import { IConfigProvider } from '../../application/ports/ConfigPorts.js';
import { homedir } from 'os';
import path from 'path';

/**
 * Infrastructure adapter for configuration access
 * Implements the IConfigProvider port
 * 
 * Self-contained with no external dependencies.
 * Configuration values come from:
 * 1. Environment variables (when available)
 * 2. System defaults (e.g., user home directory)
 * 3. Hardcoded defaults as fallback
 */
export class ConfigProviderAdapter implements IConfigProvider {
  private readonly derivedDataBasePath: string;
  
  constructor() {
    // Read from environment or use default
    // This is an infrastructure concern - reading from the environment
    this.derivedDataBasePath = process.env.MCP_XCODE_DERIVED_DATA_PATH ||
      path.join(homedir(), 'Library', 'Developer', 'Xcode', 'DerivedData', 'MCP-Xcode');
  }
  
  getDerivedDataPath(projectPath?: string): string {
    // If we have a project path, use it for the derived data path
    if (projectPath) {
      const projectName = path.basename(projectPath, path.extname(projectPath));
      return path.join(this.derivedDataBasePath, projectName);
    }
    // Otherwise return the base path
    return this.derivedDataBasePath;
  }
  
  getBuildTimeout(): number {
    // Read from environment or use default (10 minutes)
    const timeout = process.env.MCP_XCODE_BUILD_TIMEOUT;
    return timeout ? parseInt(timeout, 10) : 600000;
  }
  
  isXcbeautifyEnabled(): boolean {
    // Read from environment or default to true
    const enabled = process.env.MCP_XCODE_XCBEAUTIFY_ENABLED;
    return enabled ? enabled.toLowerCase() === 'true' : true;
  }
  
  getCustomBuildSettings(): Record<string, string> {
    // Could read from environment as JSON or return empty
    const settings = process.env.MCP_XCODE_CUSTOM_BUILD_SETTINGS;
    if (settings) {
      try {
        return JSON.parse(settings);
      } catch {
        // Invalid JSON, return empty
        return {};
      }
    }
    return {};
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/use-cases/ShutdownSimulatorUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { ShutdownRequest } from '../domain/ShutdownRequest.js';
import { ShutdownResult, SimulatorNotFoundError, ShutdownCommandFailedError } from '../domain/ShutdownResult.js';
import { SimulatorState } from '../domain/SimulatorState.js';
import { ISimulatorLocator, ISimulatorControl } from '../../../application/ports/SimulatorPorts.js';

export interface IShutdownSimulatorUseCase {
  execute(request: ShutdownRequest): Promise<ShutdownResult>;
}

/**
 * Use Case: Shutdown a simulator
 * 
 * Orchestrates finding the target simulator and shutting it down if needed
 */
export class ShutdownSimulatorUseCase implements IShutdownSimulatorUseCase {
  constructor(
    private simulatorLocator: ISimulatorLocator,
    private simulatorControl: ISimulatorControl
  ) {}

  async execute(request: ShutdownRequest): Promise<ShutdownResult> {
    // Find the simulator
    const simulator = await this.simulatorLocator.findSimulator(request.deviceId);
    
    if (!simulator) {
      return ShutdownResult.failed(
        request.deviceId,
        '',  // No name available since simulator wasn't found
        new SimulatorNotFoundError(request.deviceId)
      );
    }
    
    // Check simulator state
    if (simulator.state === SimulatorState.Shutdown) {
      return ShutdownResult.alreadyShutdown(
        simulator.id,
        simulator.name
      );
    }
    
    // Handle ShuttingDown state - simulator is already shutting down
    if (simulator.state === SimulatorState.ShuttingDown) {
      return ShutdownResult.alreadyShutdown(
        simulator.id,
        simulator.name
      );
    }
    
    // Shutdown the simulator (handles Booted and Booting states)
    try {
      await this.simulatorControl.shutdown(simulator.id);
      
      return ShutdownResult.shutdown(
        simulator.id,
        simulator.name
      );
    } catch (error: any) {
      return ShutdownResult.failed(
        simulator.id,
        simulator.name,
        new ShutdownCommandFailedError(error.stderr || error.message || '')
      );
    }
  }
}
```

--------------------------------------------------------------------------------
/src/presentation/tests/unit/ErrorFormatter.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { ErrorFormatter } from '../../formatters/ErrorFormatter.js';
import { BuildIssue } from '../../../features/build/domain/BuildIssue.js';

describe('ErrorFormatter', () => {
  describe('strategy delegation', () => {
    it('should delegate error with BuildIssues to BuildIssuesStrategy', () => {
      const error = {
        issues: [
          BuildIssue.error('Test error')
        ]
      };
      
      const result = ErrorFormatter.format(error);
      
      // Should return formatted result
      expect(result).toBeDefined();
      expect(typeof result).toBe('string');
      expect(result.length).toBeGreaterThan(0);
    });

    it('should delegate plain Error to DefaultErrorStrategy', () => {
      const error = new Error('Plain error message');
      
      const result = ErrorFormatter.format(error);
      
      // Should return formatted result
      expect(result).toBeDefined();
      expect(typeof result).toBe('string');
      expect(result.length).toBeGreaterThan(0);
    });

    it('should delegate unknown objects to DefaultErrorStrategy', () => {
      const error = { someField: 'value' };
      
      const result = ErrorFormatter.format(error);
      
      // Should return formatted result (DefaultErrorStrategy handles everything)
      expect(result).toBeDefined();
      expect(typeof result).toBe('string');
      expect(result.length).toBeGreaterThan(0);
    });

    it('should handle null by delegating to DefaultErrorStrategy', () => {
      const result = ErrorFormatter.format(null);
      
      // DefaultErrorStrategy should handle null
      expect(result).toBeDefined();
      expect(typeof result).toBe('string');
      expect(result.length).toBeGreaterThan(0);
    });

    it('should handle undefined by delegating to DefaultErrorStrategy', () => {
      const result = ErrorFormatter.format(undefined);
      
      // DefaultErrorStrategy should handle undefined
      expect(result).toBeDefined();
      expect(typeof result).toBe('string');
      expect(result.length).toBeGreaterThan(0);
    });
  });
});
```

--------------------------------------------------------------------------------
/test_artifacts/TestProjectXCTest/TestProjectXCTestTests/TestProjectXCTestTests.swift:
--------------------------------------------------------------------------------

```swift
//
//  TestProjectXCTestTests.swift
//  TestProjectXCTestTests
//
//  Created by Stefan Dragos Nitu on 17/08/2025.
//

import XCTest

final class TestProjectXCTestTests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
        // Any test you write for XCTest can be annotated as throws and async.
        // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
        // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
    }

    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        measure {
            // Put the code you want to measure the time of here.
        }
    }
    
    func testTargetForFilter() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
        // Any test you write for XCTest can be annotated as throws and async.
        // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
        // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
    }
    
    func testFailingTest() throws {
        XCTFail("Test MCP failing test reporting")
    }
    
    func testAnotherFailure() throws {
        // Another failing test to verify multiple failures are handled
        let result = 42
        XCTAssertEqual(result, 100, "Expected result to be 100 but got \(result)")
    }

}

```

--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------

```yaml
name: CI

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: macos-latest
    
    strategy:
      matrix:
        node-version: [18.x, 20.x, 22.x]
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
    
    - name: Install dependencies
      run: npm ci
    
    - name: Build TypeScript
      run: npm run build
    
    - name: Run unit tests with coverage
      run: npm run test:unit -- --coverage

    - name: Run integration tests with coverage
      run: npm run test:integration -- --coverage

    - name: Upload coverage reports
      uses: codecov/codecov-action@v4
      if: matrix.node-version == '20.x'
      with:
        files: ./coverage/lcov.info
        flags: unittests
        name: codecov-umbrella
        fail_ci_if_error: false

  e2e-test:
    runs-on: macos-15
    needs: test

    steps:
    - uses: actions/checkout@v4
    
    - name: Use Node.js 20.x
      uses: actions/setup-node@v4
      with:
        node-version: '20.x'

    - name: Install dependencies
      run: |
        echo "Installing system dependencies..."
        which xcbeautify || brew install xcbeautify
        which xcbeautify
        echo "Installing Node.js dependencies..."
        npm ci
    
    - name: Build TypeScript
      run: npm run build
    
    - name: Run E2E tests
      run: npm run test:e2e
      timeout-minutes: 90
    
    - name: Upload test logs
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: e2e-test-logs
        path: |
          ~/.mcp-xcode-server/logs/
        retention-days: 7
        if-no-files-found: warn

  lint:
    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v4

    - name: Use Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20.x'

    - name: Install dependencies
      run: npm ci

    - name: Check TypeScript
      run: npx tsc --noEmit

    - name: Build
      run: npm run build
```

--------------------------------------------------------------------------------
/src/features/app-management/factories/InstallAppControllerFactory.ts:
--------------------------------------------------------------------------------

```typescript
import { exec } from 'child_process';
import { promisify } from 'util';
import { InstallAppUseCase } from '../use-cases/InstallAppUseCase.js';
import { InstallAppController } from '../controllers/InstallAppController.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';
import { SimulatorLocatorAdapter } from '../../simulator/infrastructure/SimulatorLocatorAdapter.js';
import { SimulatorControlAdapter } from '../../simulator/infrastructure/SimulatorControlAdapter.js';
import { AppInstallerAdapter } from '../infrastructure/AppInstallerAdapter.js';
import { ShellCommandExecutorAdapter } from '../../../shared/infrastructure/ShellCommandExecutorAdapter.js';
import { LogManagerInstance } from '../../../utils/LogManagerInstance.js';
import { DependencyCheckingDecorator } from '../../../presentation/decorators/DependencyCheckingDecorator.js';
import { DependencyChecker } from '../../../infrastructure/services/DependencyChecker.js';

/**
 * Factory class for creating InstallAppController with all dependencies
 * This is the composition root for the install app functionality
 */
export class InstallAppControllerFactory {
  static create(): MCPController {
    // Create the shell executor that all adapters will use
    const execAsync = promisify(exec);
    const executor = new ShellCommandExecutorAdapter(execAsync);

    // Create infrastructure adapters
    const simulatorLocator = new SimulatorLocatorAdapter(executor);
    const simulatorControl = new SimulatorControlAdapter(executor);
    const appInstaller = new AppInstallerAdapter(executor);
    const logManager = new LogManagerInstance();

    // Create the use case with all dependencies
    const useCase = new InstallAppUseCase(
      simulatorLocator,
      simulatorControl,
      appInstaller,
      logManager
    );

    // Create the controller
    const controller = new InstallAppController(useCase);

    // Create dependency checker
    const dependencyChecker = new DependencyChecker(executor);

    // Wrap with dependency checking decorator
    const decoratedController = new DependencyCheckingDecorator(
      controller,
      ['xcrun'],  // simctl is part of xcrun
      dependencyChecker
    );

    return decoratedController;
  }
}
```

--------------------------------------------------------------------------------
/src/shared/domain/ProjectPath.ts:
--------------------------------------------------------------------------------

```typescript
import { existsSync } from 'fs';
import path from 'path';
import { DomainEmptyError, DomainInvalidTypeError, DomainInvalidFormatError, DomainRequiredError } from '../../domain/errors/DomainError.js';

/**
 * Value Object: Represents a validated project path
 * Ensures the path exists and is a valid Xcode project or workspace
 */
export class ProjectPath {
  private constructor(private readonly value: string) {}

  static create(pathString: unknown): ProjectPath {
    // Required check (for undefined/null)
    if (pathString === undefined || pathString === null) {
      throw new ProjectPath.RequiredError();
    }

    // Type checking
    if (typeof pathString !== 'string') {
      throw new ProjectPath.InvalidTypeError(pathString);
    }

    // Empty check
    if (pathString.trim() === '') {
      throw new ProjectPath.EmptyError(pathString);
    }

    const trimmed = pathString.trim();

    // Format validation
    const ext = path.extname(trimmed);
    if (ext !== '.xcodeproj' && ext !== '.xcworkspace') {
      throw new ProjectPath.InvalidFormatError(trimmed);
    }

    // Runtime check - this stays as a regular Error since it's not validation
    if (!existsSync(trimmed)) {
      throw new Error(`Project path does not exist: ${trimmed}`);
    }

    return new ProjectPath(trimmed);
  }
  
  toString(): string {
    return this.value;
  }
  
  get name(): string {
    return path.basename(this.value, path.extname(this.value));
  }
  
  get isWorkspace(): boolean {
    return path.extname(this.value) === '.xcworkspace';
  }
}

// Nested error classes under ProjectPath namespace
export namespace ProjectPath {
  export class RequiredError extends DomainRequiredError {
    constructor() {
      super('Project path');
      this.name = 'ProjectPath.RequiredError';
    }
  }

  export class InvalidTypeError extends DomainInvalidTypeError {
    constructor(public readonly providedValue: unknown) {
      super('Project path', 'string');
      this.name = 'ProjectPath.InvalidTypeError';
    }
  }

  export class EmptyError extends DomainEmptyError {
    constructor(public readonly providedValue: unknown) {
      super('Project path');
      this.name = 'ProjectPath.EmptyError';
    }
  }

  export class InvalidFormatError extends DomainInvalidFormatError {
    constructor(public readonly path: string) {
      super('Project path must be an .xcodeproj or .xcworkspace file');
      this.name = 'ProjectPath.InvalidFormatError';
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/use-cases/BootSimulatorUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { BootRequest } from '../domain/BootRequest.js';
import { BootResult, SimulatorNotFoundError, BootCommandFailedError, SimulatorBusyError } from '../domain/BootResult.js';
import { SimulatorState } from '../domain/SimulatorState.js';
import { ISimulatorLocator, ISimulatorControl } from '../../../application/ports/SimulatorPorts.js';

export interface IBootSimulatorUseCase {
  execute(request: BootRequest): Promise<BootResult>;
}

/**
 * Use Case: Boot a simulator
 * 
 * Orchestrates finding the target simulator and booting it if needed
 */
export class BootSimulatorUseCase implements IBootSimulatorUseCase {
  constructor(
    private simulatorLocator: ISimulatorLocator,
    private simulatorControl: ISimulatorControl
  ) {}

  async execute(request: BootRequest): Promise<BootResult> {
    // Find the simulator
    const simulator = await this.simulatorLocator.findSimulator(request.deviceId);
    
    if (!simulator) {
      return BootResult.failed(
        request.deviceId,
        '',  // No name available since simulator wasn't found
        new SimulatorNotFoundError(request.deviceId)
      );
    }
    
    // Check simulator state
    if (simulator.state === SimulatorState.Booted) {
      return BootResult.alreadyBooted(
        simulator.id,
        simulator.name,
        {
          platform: simulator.platform,
          runtime: simulator.runtime
        }
      );
    }
    
    // Handle Booting state - simulator is already in the process of booting
    if (simulator.state === SimulatorState.Booting) {
      return BootResult.alreadyBooted(
        simulator.id,
        simulator.name,
        {
          platform: simulator.platform,
          runtime: simulator.runtime
        }
      );
    }
    
    // Handle ShuttingDown state - can't boot while shutting down
    if (simulator.state === SimulatorState.ShuttingDown) {
      return BootResult.failed(
        simulator.id,
        simulator.name,
        new SimulatorBusyError(SimulatorState.ShuttingDown)
      );
    }
    
    // Boot the simulator (handles Shutdown state)
    try {
      await this.simulatorControl.boot(simulator.id);
      
      return BootResult.booted(
        simulator.id,
        simulator.name,
        {
          platform: simulator.platform,
          runtime: simulator.runtime
        }
      );
    } catch (error: any) {
      return BootResult.failed(
        simulator.id,
        simulator.name,
        new BootCommandFailedError(error.stderr || error.message || '')
      );
    }
  }
}
```

--------------------------------------------------------------------------------
/src/utils/errors/index.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Export types and functions from xcbeautify parser
 */

export {
  Issue,
  Test,
  XcbeautifyOutput,
  parseXcbeautifyOutput,
  formatParsedOutput
} from './xcbeautify-parser.js';

import { Issue, parseXcbeautifyOutput as parseOutput } from './xcbeautify-parser.js';

// Error handlers for tools
// These return MCP format for tools
export function handleSwiftPackageError(error: unknown, context?: any): { content: { type: string; text: string }[] } {
  const message = error instanceof Error ? error.message : String(error);
  
  // Add ❌ prefix if message doesn't already have xcbeautify formatting
  const formattedMessage = message.includes('❌') || message.includes('⚠️') || message.includes('✅') 
    ? message 
    : `❌ ${message}`;
  
  const contextInfo = context 
    ? Object.entries(context)
        .filter(([_, v]) => v !== undefined)
        .map(([k, v]) => `${k}: ${v}`)
        .join(', ')
    : '';
  
  // Check if error has a logPath property
  const logPath = (error as any)?.logPath;
  const logInfo = logPath ? `\n\n📁 Full logs saved to: ${logPath}` : '';
  
  return {
    content: [{
      type: 'text',
      text: contextInfo ? `${formattedMessage}\n\nContext: ${contextInfo}${logInfo}` : `${formattedMessage}${logInfo}`
    }]
  };
}

export function handleXcodeError(error: unknown, context?: any): { content: { type: string; text: string }[] } {
  const message = error instanceof Error ? error.message : String(error);
  
  // Add ❌ prefix if message doesn't already have xcbeautify formatting
  const formattedMessage = message.includes('❌') || message.includes('⚠️') || message.includes('✅') 
    ? message 
    : `❌ ${message}`;
  
  const contextInfo = context 
    ? Object.entries(context)
        .filter(([_, v]) => v !== undefined)
        .map(([k, v]) => `${k}: ${v}`)
        .join(', ')
    : '';
  
  // Check if error has a logPath property
  const logPath = (error as any)?.logPath;
  const logInfo = logPath ? `\n\n📁 Full logs saved to: ${logPath}` : '';
  
  return {
    content: [{
      type: 'text',
      text: contextInfo ? `${formattedMessage}\n\nContext: ${contextInfo}${logInfo}` : `${formattedMessage}${logInfo}`
    }]
  };
}

// Backward compatibility for tests
export function parseBuildErrors(output: string): Issue[] {
  const { errors, warnings } = parseOutput(output);
  return [...errors, ...warnings];
}

export function formatBuildErrors(errors: Issue[]): string {
  return errors.map(e => `${e.file ? `${e.file}:${e.line}:${e.column} - ` : ''}${e.message}`).join('\n');
}
```

--------------------------------------------------------------------------------
/examples/screenshot-demo.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node

/**
 * Demo script showing how to use the view_simulator_screen tool
 * to capture and view the current simulator screen
 */

import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js';
import { writeFileSync } from 'fs';

async function main() {
  // Create MCP client
  const transport = new StdioClientTransport({
    command: 'node',
    args: ['../dist/index.js'],
    cwd: process.cwd(),
  });
  
  const client = new Client({
    name: 'screenshot-demo',
    version: '1.0.0',
  }, {
    capabilities: {}
  });
  
  console.log('Connecting to MCP server...');
  await client.connect(transport);
  
  try {
    // List available simulators
    console.log('Listing simulators...');
    const listResponse = await client.request({
      method: 'tools/call',
      params: {
        name: 'list_simulators',
        arguments: {
          platform: 'iOS'
        }
      }
    }, CallToolResultSchema);
    
    const devices = JSON.parse(listResponse.content[0].text);
    console.log(`Found ${devices.length} iOS simulators`);
    
    const bootedDevice = devices.find(d => d.state === 'Booted');
    if (!bootedDevice) {
      console.log('No booted simulator found. Please boot a simulator first.');
      return;
    }
    
    console.log(`Using booted simulator: ${bootedDevice.name}`);
    
    // Capture the screen
    console.log('Capturing simulator screen...');
    const screenshotResponse = await client.request({
      method: 'tools/call',
      params: {
        name: 'view_simulator_screen',
        arguments: {
          deviceId: bootedDevice.udid
        }
      }
    }, CallToolResultSchema);
    
    // The response contains the image data
    const imageContent = screenshotResponse.content[0];
    if (imageContent.type === 'image') {
      console.log(`Screenshot captured! Image size: ${imageContent.data.length} bytes (base64)`);
      
      // Save to file for demonstration
      const buffer = Buffer.from(imageContent.data, 'base64');
      const filename = `simulator-screen-${Date.now()}.png`;
      writeFileSync(filename, buffer);
      console.log(`Screenshot saved to: ${filename}`);
      
      // In a real MCP client like Claude Code, the image would be displayed directly
      console.log('In an MCP client, this image would be displayed for viewing and analysis.');
    }
    
  } finally {
    await client.close();
    console.log('Disconnected from MCP server');
  }
}

main().catch(console.error);
```

--------------------------------------------------------------------------------
/src/features/app-management/domain/InstallResult.ts:
--------------------------------------------------------------------------------

```typescript
import { AppPath } from '../../../shared/domain/AppPath.js';
import { DeviceId } from '../../../shared/domain/DeviceId.js';

/**
 * Domain Entity: Represents the result of an app installation
 *
 * Separates user-facing outcome from internal diagnostics
 */

// User-facing outcome (what happened)
export enum InstallOutcome {
  Succeeded = 'succeeded',
  Failed = 'failed'
}

// Base class for all install-related errors
export abstract class InstallError extends Error {}

// Specific error types
export class AppNotFoundError extends InstallError {
  constructor(public readonly appPath: AppPath) {
    super(appPath.toString());
    this.name = 'AppNotFoundError';
  }
}

export class SimulatorNotFoundError extends InstallError {
  constructor(public readonly simulatorId: DeviceId) {
    super(simulatorId.toString());
    this.name = 'SimulatorNotFoundError';
  }
}

export class NoBootedSimulatorError extends InstallError {
  constructor() {
    super('No booted simulator found');
    this.name = 'NoBootedSimulatorError';
  }
}

export class InstallCommandFailedError extends InstallError {
  constructor(public readonly stderr: string) {
    super(stderr);
    this.name = 'InstallCommandFailedError';
  }
}

// Internal diagnostics (why/how it happened)
export interface InstallDiagnostics {
  readonly appPath: AppPath;
  readonly simulatorId?: DeviceId;
  readonly simulatorName?: string;
  readonly bundleId?: string;
  readonly error?: InstallError;
  readonly installedAt: Date;
}

// Complete result combining outcome and diagnostics
export interface InstallResult {
  readonly outcome: InstallOutcome;
  readonly diagnostics: InstallDiagnostics;
}

export const InstallResult = {
  /**
   * Installation succeeded
   */
  succeeded(
    bundleId: string,
    simulatorId: DeviceId,
    simulatorName: string,
    appPath: AppPath,
    diagnostics?: Partial<InstallDiagnostics>
  ): InstallResult {
    return Object.freeze({
      outcome: InstallOutcome.Succeeded,
      diagnostics: Object.freeze({
        bundleId,
        simulatorId,
        simulatorName,
        appPath,
        installedAt: new Date(),
        ...diagnostics
      })
    });
  },

  /**
   * Installation failed
   */
  failed(
    error: InstallError,
    appPath: AppPath,
    simulatorId?: DeviceId,
    simulatorName?: string,
    diagnostics?: Partial<InstallDiagnostics>
  ): InstallResult {
    return Object.freeze({
      outcome: InstallOutcome.Failed,
      diagnostics: Object.freeze({
        error,
        appPath,
        simulatorId,
        simulatorName,
        installedAt: new Date(),
        ...diagnostics
      })
    });
  }
};
```

--------------------------------------------------------------------------------
/src/features/simulator/domain/BootResult.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Domain entity representing the result of a boot simulator operation
 * 
 * Separates user-facing outcome from internal diagnostics
 */

// User-facing outcome (what happened)
export enum BootOutcome {
  Booted = 'booted',              // Successfully booted the simulator
  AlreadyBooted = 'alreadyBooted', // Simulator was already running  
  Failed = 'failed'                // Boot failed
}

// Base class for all boot-related errors
export abstract class BootError extends Error {}

// Specific error types
export class SimulatorNotFoundError extends BootError {
  constructor(public readonly deviceId: string) {
    super(deviceId); // Just store the data
    this.name = 'SimulatorNotFoundError';
  }
}

export class BootCommandFailedError extends BootError {
  constructor(public readonly stderr: string) {
    super(stderr); // Just store the stderr output
    this.name = 'BootCommandFailedError';
  }
}

export class SimulatorBusyError extends BootError {
  constructor(public readonly currentState: string) {
    super(currentState); // Just store the state
    this.name = 'SimulatorBusyError';
  }
}

// Internal diagnostics (why/how it happened)
export interface BootDiagnostics {
  readonly simulatorId: string;
  readonly simulatorName: string;
  readonly error?: BootError;           // Any boot-specific error
  readonly runtime?: string;            // Which iOS version
  readonly platform?: string;           // iOS, tvOS, etc
}

// Complete result combining outcome and diagnostics
export interface BootResult {
  readonly outcome: BootOutcome;
  readonly diagnostics: BootDiagnostics;
}

export const BootResult = {
  /**
   * Simulator was successfully booted
   */
  booted(simulatorId: string, simulatorName: string, diagnostics?: Partial<BootDiagnostics>): BootResult {
    return Object.freeze({
      outcome: BootOutcome.Booted,
      diagnostics: Object.freeze({
        simulatorId,
        simulatorName,
        ...diagnostics
      })
    });
  },

  /**
   * Simulator was already running
   */
  alreadyBooted(simulatorId: string, simulatorName: string, diagnostics?: Partial<BootDiagnostics>): BootResult {
    return Object.freeze({
      outcome: BootOutcome.AlreadyBooted,
      diagnostics: Object.freeze({
        simulatorId,
        simulatorName,
        ...diagnostics
      })
    });
  },

  /**
   * Boot operation failed
   */
  failed(simulatorId: string, simulatorName: string, error: BootError, diagnostics?: Partial<BootDiagnostics>): BootResult {
    return Object.freeze({
      outcome: BootOutcome.Failed,
      diagnostics: Object.freeze({
        simulatorId,
        simulatorName,
        error,
        ...diagnostics
      })
    });
  }
};
```

--------------------------------------------------------------------------------
/src/domain/tests/unit/PlatformDetector.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from '@jest/globals';
import { PlatformDetector } from '../../services/PlatformDetector.js';
import { BuildDestination } from '../../../features/build/domain/BuildDestination.js';
import { Platform } from '../../../shared/domain/Platform.js';

/**
 * Unit tests for PlatformDetector domain service
 * 
 * Testing pure domain logic for platform detection from build destinations
 */
describe('PlatformDetector', () => {
  describe('fromDestination', () => {
    it('should detect iOS platform from iOS destinations', () => {
      // Arrange & Act & Assert
      expect(PlatformDetector.fromDestination(BuildDestination.iOSSimulator)).toBe(Platform.iOS);
      expect(PlatformDetector.fromDestination(BuildDestination.iOSDevice)).toBe(Platform.iOS);
      expect(PlatformDetector.fromDestination(BuildDestination.iOSSimulatorUniversal)).toBe(Platform.iOS);
    });

    it('should detect macOS platform from macOS destinations', () => {
      // Arrange & Act & Assert
      expect(PlatformDetector.fromDestination(BuildDestination.macOS)).toBe(Platform.macOS);
      expect(PlatformDetector.fromDestination(BuildDestination.macOSUniversal)).toBe(Platform.macOS);
    });

    it('should detect tvOS platform from tvOS destinations', () => {
      // Arrange & Act & Assert
      expect(PlatformDetector.fromDestination(BuildDestination.tvOSSimulator)).toBe(Platform.tvOS);
      expect(PlatformDetector.fromDestination(BuildDestination.tvOSDevice)).toBe(Platform.tvOS);
      expect(PlatformDetector.fromDestination(BuildDestination.tvOSSimulatorUniversal)).toBe(Platform.tvOS);
    });

    it('should detect watchOS platform from watchOS destinations', () => {
      // Arrange & Act & Assert
      expect(PlatformDetector.fromDestination(BuildDestination.watchOSSimulator)).toBe(Platform.watchOS);
      expect(PlatformDetector.fromDestination(BuildDestination.watchOSDevice)).toBe(Platform.watchOS);
      expect(PlatformDetector.fromDestination(BuildDestination.watchOSSimulatorUniversal)).toBe(Platform.watchOS);
    });

    it('should detect visionOS platform from visionOS destinations', () => {
      // Arrange & Act & Assert
      expect(PlatformDetector.fromDestination(BuildDestination.visionOSSimulator)).toBe(Platform.visionOS);
      expect(PlatformDetector.fromDestination(BuildDestination.visionOSDevice)).toBe(Platform.visionOS);
      expect(PlatformDetector.fromDestination(BuildDestination.visionOSSimulatorUniversal)).toBe(Platform.visionOS);
    });

    it('should default to iOS for unknown destination patterns', () => {
      // Arrange
      const unknownDestination = 'unknownPlatform' as BuildDestination;
      
      // Act
      const result = PlatformDetector.fromDestination(unknownDestination);
      
      // Assert
      expect(result).toBe(Platform.iOS);
    });
  });
});
```

--------------------------------------------------------------------------------
/src/features/app-management/tests/unit/InstallRequest.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from '@jest/globals';
import { InstallRequest } from '../../domain/InstallRequest.js';

describe('InstallRequest', () => {
  describe('create', () => {
    it('should create valid install request with simulator ID', () => {
      // Arrange & Act
      const request = InstallRequest.create(
        '/path/to/app.app',
        'iPhone-15-Simulator'
      );
      
      // Assert
      expect(request.appPath.toString()).toBe('/path/to/app.app');
      expect(request.simulatorId?.toString()).toBe('iPhone-15-Simulator');
    });

    it('should create valid install request without simulator ID', () => {
      // Arrange & Act
      const request = InstallRequest.create(
        '/path/to/app.app'
      );
      
      // Assert
      expect(request.appPath.toString()).toBe('/path/to/app.app');
      expect(request.simulatorId).toBeUndefined();
    });

    it('should reject empty app path', () => {
      // Arrange & Act & Assert
      expect(() => InstallRequest.create('', 'test-sim'))
        .toThrow('App path cannot be empty');
    });

    it('should reject whitespace-only app path', () => {
      // Arrange & Act & Assert
      expect(() => InstallRequest.create('   ', 'test-sim'))
        .toThrow('App path cannot be empty');
    });

    it('should reject invalid app extension', () => {
      // Arrange & Act & Assert
      expect(() => InstallRequest.create('/path/to/file.txt', 'test-sim'))
        .toThrow('App path must end with .app');
    });

    it('should accept .app bundle path', () => {
      // Arrange & Act
      const request = InstallRequest.create(
        '/path/to/MyApp.app',
        'test-sim'
      );
      
      // Assert
      expect(request.appPath.toString()).toBe('/path/to/MyApp.app');
    });

    it('should trim whitespace from simulator ID', () => {
      // Arrange & Act
      const request = InstallRequest.create(
        '/path/to/app.app',
        '  test-sim  '
      );
      
      // Assert
      expect(request.simulatorId?.toString()).toBe('test-sim');
    });
  });

  describe('validation', () => {
    it('should reject path traversal attempts', () => {
      // Arrange & Act & Assert
      expect(() => InstallRequest.create('../../../etc/passwd.app'))
        .toThrow();
    });

    it('should accept absolute paths', () => {
      // Arrange & Act
      const request = InstallRequest.create(
        '/Users/developer/MyApp.app'
      );
      
      // Assert
      expect(request.appPath.toString()).toBe('/Users/developer/MyApp.app');
    });

    it('should accept relative paths within project', () => {
      // Arrange & Act
      const request = InstallRequest.create(
        './build/Debug/MyApp.app'
      );
      
      // Assert
      expect(request.appPath.toString()).toBe('./build/Debug/MyApp.app');
    });
  });
});
```

--------------------------------------------------------------------------------
/src/features/simulator/tests/unit/ShutdownRequest.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from '@jest/globals';
import { ShutdownRequest } from '../../domain/ShutdownRequest.js';
import { DeviceId } from '../../../../shared/domain/DeviceId.js';

describe('ShutdownRequest', () => {
  describe('create', () => {
    it('should create a valid shutdown request with device ID', () => {
      // Arrange
      const deviceIdString = 'iPhone-15';
      const deviceId = DeviceId.create(deviceIdString);

      // Act
      const request = ShutdownRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe('iPhone-15');
    });

    it('should trim whitespace from device ID', () => {
      // Arrange
      const deviceIdString = '  iPhone-15  ';
      const deviceId = DeviceId.create(deviceIdString);

      // Act
      const request = ShutdownRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe('iPhone-15');
    });

    it('should accept UUID format device ID', () => {
      // Arrange
      const uuid = '550e8400-e29b-41d4-a716-446655440000';
      const deviceId = DeviceId.create(uuid);

      // Act
      const request = ShutdownRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe(uuid);
    });

    it('should throw error for empty device ID', () => {
      // Arrange & Act & Assert
      expect(() => DeviceId.create('')).toThrow('Device ID cannot be empty');
    });

    it('should throw error for null device ID', () => {
      // Arrange & Act & Assert
      expect(() => DeviceId.create(null as any)).toThrow('Device ID is required');
    });

    it('should throw error for undefined device ID', () => {
      // Arrange & Act & Assert
      expect(() => DeviceId.create(undefined as any)).toThrow('Device ID is required');
    });

    it('should throw error for whitespace-only device ID', () => {
      // Arrange & Act & Assert
      expect(() => DeviceId.create('   ')).toThrow('Device ID cannot be whitespace only');
    });

    it('should be immutable', () => {
      // Arrange
      const deviceId = DeviceId.create('iPhone-15');
      const request = ShutdownRequest.create(deviceId);

      // Act & Assert
      expect(() => {
        (request as any).deviceId = 'Changed';
      }).toThrow();
    });

    it('should handle device names with spaces', () => {
      // Arrange
      const deviceName = 'iPhone 15 Pro Max';
      const deviceId = DeviceId.create(deviceName);

      // Act
      const request = ShutdownRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe('iPhone 15 Pro Max');
    });

    it('should handle device names with special characters', () => {
      // Arrange
      const deviceName = "John's iPhone (Work)";
      const deviceId = DeviceId.create(deviceName);

      // Act
      const request = ShutdownRequest.create(deviceId);

      // Assert
      expect(request.deviceId).toBe("John's iPhone (Work)");
    });
  });
});
```

--------------------------------------------------------------------------------
/src/features/simulator/controllers/ListSimulatorsController.ts:
--------------------------------------------------------------------------------

```typescript
import { ListSimulatorsUseCase } from '../use-cases/ListSimulatorsUseCase.js';
import { ListSimulatorsRequest } from '../domain/ListSimulatorsRequest.js';
import { SimulatorState } from '../domain/SimulatorState.js';
import { Platform } from '../../../shared/domain/Platform.js';
import { ErrorFormatter } from '../../../presentation/formatters/ErrorFormatter.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';

/**
 * Controller for the list_simulators MCP tool
 *
 * Lists available simulators with optional filtering
 */
export class ListSimulatorsController implements MCPController {
  readonly name = 'list_simulators';
  readonly description = 'List available iOS simulators';

  constructor(
    private useCase: ListSimulatorsUseCase
  ) {}

  get inputSchema() {
    return {
      type: 'object' as const,
      properties: {
        platform: {
          type: 'string' as const,
          description: 'Filter by platform',
          enum: ['iOS', 'tvOS', 'watchOS', 'visionOS'] as const
        },
        state: {
          type: 'string' as const,
          description: 'Filter by simulator state',
          enum: ['Booted', 'Shutdown'] as const
        },
        name: {
          type: 'string' as const,
          description: 'Filter by device name (partial match, case-insensitive)'
        }
      },
      required: [] as const
    };
  }

  getToolDefinition() {
    return {
      name: this.name,
      description: this.description,
      inputSchema: this.inputSchema
    };
  }

  async execute(args: unknown): Promise<{ content: Array<{ type: string; text: string }> }> {
    try {
      // Cast to expected shape
      const input = args as { platform?: string; state?: string; name?: string };

      // Use the new validation functions
      const platform = Platform.parseOptional(input.platform);
      const state = SimulatorState.parseOptional(input.state);

      const request = ListSimulatorsRequest.create(platform, state, input.name);
      const result = await this.useCase.execute(request);

    if (!result.isSuccess) {
      return {
        content: [{
          type: 'text',
          text: `❌ ${ErrorFormatter.format(result.error!)}`
        }]
      };
    }

    if (result.count === 0) {
      return {
        content: [{
          type: 'text',
          text: '🔍 No simulators found'
        }]
      };
    }

    const lines: string[] = [
      `✅ Found ${result.count} simulator${result.count === 1 ? '' : 's'}`,
      ''
    ];

    for (const simulator of result.simulators) {
      lines.push(`• ${simulator.name} (${simulator.udid}) - ${simulator.state} - ${simulator.runtime}`);
    }

    return {
      content: [{
        type: 'text',
        text: lines.join('\n')
      }]
    };
    } catch (error) {
      return {
        content: [{
          type: 'text',
          text: `❌ ${ErrorFormatter.format(error as Error)}`
        }]
      };
    }
  }

}
```

--------------------------------------------------------------------------------
/src/utils/devices/SimulatorUI.ts:
--------------------------------------------------------------------------------

```typescript
import { execAsync } from '../../utils.js';
import { createModuleLogger } from '../../logger.js';
import { readFileSync, existsSync, unlinkSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';

const logger = createModuleLogger('SimulatorUI');

/**
 * Handles simulator UI operations
 * Single responsibility: GUI operations and screenshots
 */
export class SimulatorUI {
  /**
   * Opens the Simulator app GUI (skipped during tests)
   */
  async open(): Promise<void> {
    // Skip opening GUI during tests
    if (process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID) {
      logger.debug('Skipping Simulator GUI in test environment');
      return;
    }
    
    try {
      await execAsync('open -g -a Simulator');
      logger.debug('Opened Simulator app');
    } catch (error: any) {
      logger.warn({ error: error.message }, 'Failed to open Simulator app');
    }
  }

  /**
   * Capture a screenshot from the simulator
   */
  async screenshot(outputPath: string, deviceId?: string): Promise<void> {
    let command = `xcrun simctl io `;
    if (deviceId) {
      command += `"${deviceId}" `;
    } else {
      command += 'booted ';
    }
    command += `screenshot "${outputPath}"`;

    try {
      await execAsync(command);
      logger.debug({ outputPath, deviceId }, 'Screenshot captured successfully');
    } catch (error: any) {
      logger.error({ error: error.message, outputPath, deviceId }, 'Failed to capture screenshot');
      throw new Error(`Failed to capture screenshot: ${error.message}`);
    }
  }

  /**
   * Capture a screenshot and return as base64
   */
  async screenshotData(deviceId?: string): Promise<{ base64: string; mimeType: string }> {
    // Create a temporary file path
    const tempPath = join(tmpdir(), `simulator-screenshot-${Date.now()}.png`);
    
    try {
      // Capture the screenshot to temp file
      await this.screenshot(tempPath, deviceId);
      
      // Read the file and convert to base64
      const imageData = readFileSync(tempPath);
      const base64 = imageData.toString('base64');
      
      return {
        base64,
        mimeType: 'image/png'
      };
    } finally {
      // Clean up temp file
      if (existsSync(tempPath)) {
        unlinkSync(tempPath);
      }
    }
  }

  /**
   * Set simulator appearance (light/dark mode)
   * May fail on older Xcode versions
   */
  async setAppearance(appearance: 'light' | 'dark', deviceId?: string): Promise<void> {
    let command = `xcrun simctl ui `;
    if (deviceId) {
      command += `"${deviceId}" `;
    } else {
      command += 'booted ';
    }
    command += appearance;

    try {
      await execAsync(command);
      logger.debug({ appearance, deviceId }, 'Appearance set successfully');
    } catch (error: any) {
      // This command may not be available on older Xcode versions
      logger.debug({ error: error.message }, 'Could not set appearance (may not be supported)');
    }
  }
}
```

--------------------------------------------------------------------------------
/src/shared/domain/AppPath.ts:
--------------------------------------------------------------------------------

```typescript
import { DomainEmptyError, DomainInvalidTypeError, DomainInvalidFormatError, DomainRequiredError } from '../../domain/errors/DomainError.js';

/**
 * Value object for an app bundle path
 * Ensures the path ends with .app extension
 */
export class AppPath {
  private constructor(private readonly value: string) {}

  static create(path: unknown): AppPath {
    // Required check (for undefined/null)
    if (path === undefined || path === null) {
      throw new AppPath.RequiredError();
    }

    // Type checking
    if (typeof path !== 'string') {
      throw new AppPath.InvalidTypeError(path);
    }

    // Empty check
    if (path.trim() === '') {
      throw new AppPath.EmptyError(path);
    }

    const trimmed = path.trim();

    // Security checks first (before format validation)
    if (trimmed.includes('..')) {
      throw new AppPath.TraversalError(trimmed);
    }

    if (trimmed.includes('\0')) {
      throw new AppPath.NullCharacterError(trimmed);
    }

    // Format validation
    if (!trimmed.endsWith('.app') && !trimmed.endsWith('.app/')) {
      throw new AppPath.InvalidFormatError(trimmed);
    }

    return new AppPath(trimmed);
  }

  toString(): string {
    return this.value;
  }

  get name(): string {
    // Handle both forward slash and backslash for cross-platform support
    const separatorPattern = /[/\\]/;
    const parts = this.value.split(separatorPattern);
    const lastPart = parts[parts.length - 1];

    // If path ends with /, the last part will be empty, so take the second to last
    return lastPart || parts[parts.length - 2];
  }
}

// Nested error classes under AppPath namespace
export namespace AppPath {
  // All AppPath errors extend DomainError for consistency

  export class RequiredError extends DomainRequiredError {
    constructor() {
      super('App path');
      this.name = 'AppPath.RequiredError';
    }
  }

  export class InvalidTypeError extends DomainInvalidTypeError {
    constructor(public readonly providedValue: unknown) {
      super('App path', 'string');
      this.name = 'AppPath.InvalidTypeError';
    }
  }

  export class EmptyError extends DomainEmptyError {
    constructor(public readonly providedValue: unknown) {
      super('App path');
      this.name = 'AppPath.EmptyError';
    }
  }

  export class InvalidFormatError extends DomainInvalidFormatError {
    constructor(public readonly path: string) {
      super('App path must end with .app');
      this.name = 'AppPath.InvalidFormatError';
    }
  }

  export class TraversalError extends DomainInvalidFormatError {
    constructor(public readonly path: string) {
      super('App path cannot contain directory traversal');
      this.name = 'AppPath.TraversalError';
    }
  }

  export class NullCharacterError extends DomainInvalidFormatError {
    constructor(public readonly path: string) {
      super('App path cannot contain null characters');
      this.name = 'AppPath.NullCharacterError';
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/use-cases/ListSimulatorsUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { ListSimulatorsRequest } from '../domain/ListSimulatorsRequest.js';
import { ListSimulatorsResult, SimulatorInfo, SimulatorListParseError } from '../domain/ListSimulatorsResult.js';
import { DeviceRepository } from '../../../infrastructure/repositories/DeviceRepository.js';
import { Platform } from '../../../shared/domain/Platform.js';
import { SimulatorState } from '../domain/SimulatorState.js';

/**
 * Use case for listing available simulators
 */
export class ListSimulatorsUseCase {
  constructor(
    private readonly deviceRepository: DeviceRepository
  ) {}

  async execute(request: ListSimulatorsRequest): Promise<ListSimulatorsResult> {
    try {
      let allDevices;
      try {
        allDevices = await this.deviceRepository.getAllDevices();
      } catch (error) {
        // JSON parsing errors from the repository
        return ListSimulatorsResult.failed(new SimulatorListParseError());
      }

      const simulatorInfos: SimulatorInfo[] = [];

      for (const [runtime, devices] of Object.entries(allDevices)) {
        const platform = this.extractPlatformFromRuntime(runtime);
        const runtimeVersion = this.extractVersionFromRuntime(runtime);

        for (const device of devices) {
          if (!device.isAvailable) continue;

          const simulatorInfo: SimulatorInfo = {
            udid: device.udid,
            name: device.name,
            state: SimulatorState.parse(device.state),
            platform: platform,
            runtime: `${platform} ${runtimeVersion}`
          };

          if (this.matchesFilter(simulatorInfo, request)) {
            simulatorInfos.push(simulatorInfo);
          }
        }
      }

      return ListSimulatorsResult.success(simulatorInfos);
    } catch (error) {
      return ListSimulatorsResult.failed(
        error instanceof Error ? error : new Error(String(error))
      );
    }
  }

  private matchesFilter(simulator: SimulatorInfo, request: ListSimulatorsRequest): boolean {
    if (request.platform) {
      const platformString = Platform[request.platform];
      if (simulator.platform !== platformString) {
        return false;
      }
    }

    if (request.state && simulator.state !== request.state) {
      return false;
    }

    if (request.name) {
      const nameLower = simulator.name.toLowerCase();
      const filterLower = request.name.toLowerCase();
      if (!nameLower.includes(filterLower)) {
        return false;
      }
    }

    return true;
  }

  private extractPlatformFromRuntime(runtime: string): string {
    if (runtime.includes('iOS')) return 'iOS';
    if (runtime.includes('tvOS')) return 'tvOS';
    if (runtime.includes('watchOS')) return 'watchOS';
    if (runtime.includes('xrOS') || runtime.includes('visionOS')) return 'visionOS';
    if (runtime.includes('macOS')) return 'macOS';
    return 'Unknown';
  }

  private extractVersionFromRuntime(runtime: string): string {
    const match = runtime.match(/(\d+[-.]?\d*(?:[-.]?\d+)?)/);
    return match ? match[1].replace(/-/g, '.') : 'Unknown';
  }

}
```

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

```typescript
/**
 * Structured logging configuration for production
 * Uses Pino for high-performance JSON logging
 */

import pino from 'pino';

// Environment-based configuration
const isDevelopment = process.env.NODE_ENV !== 'production';
const isTest = process.env.NODE_ENV === 'test' || process.env.JEST_WORKER_ID;
const logLevel = process.env.LOG_LEVEL || (isDevelopment ? 'debug' : 'info');

// Create logger instance
export const logger = pino({
  level: logLevel,
  // Use pretty printing in development, JSON in production
  // Disable transport in test environment to avoid thread-stream issues
  transport: (isDevelopment) ? {
    target: 'pino-pretty',
    options: {
      colorize: true,
      ignore: 'pid,hostname',
      translateTime: 'SYS:standard',
      singleLine: false,
      sync: true  // Make pino-pretty synchronous to avoid race conditions
    }
  } : undefined,
  // Add metadata to all logs
  base: {
    service: 'mcp-xcode',
    version: '2.2.0'
  },
  // Redact sensitive information
  redact: {
    paths: ['deviceId', 'udid', '*.password', '*.secret', '*.token'],
    censor: '[REDACTED]'
  },
  // Add timestamp
  timestamp: pino.stdTimeFunctions.isoTime,
  // Serializers for common objects
  serializers: {
    error: pino.stdSerializers.err,
    request: (req: any) => ({
      tool: req.tool,
      platform: req.platform,
      projectPath: req.projectPath?.replace(/\/Users\/[^/]+/, '/Users/[USER]')
    })
  }
});

// Create child loggers for different modules
export const createModuleLogger = (module: string) => {
  const moduleLogger = logger.child({ module });
  
  // In test environment, wrap methods to add test name dynamically
  if (isTest) {
    const methods = ['info', 'error', 'warn', 'debug', 'trace', 'fatal'] as const;
    
    methods.forEach(method => {
      const originalMethod = moduleLogger[method].bind(moduleLogger);
      (moduleLogger as any)[method] = function(obj: any, ...rest: any[]) {
        try {
          // @ts-ignore - expect is only available in test environment
          const testName = global.expect?.getState?.()?.currentTestName;
          if (testName && obj && typeof obj === 'object') {
            // Add test name to the context object
            obj = { ...obj, testName };
          }
        } catch {
          // Ignore if expect is not available
        }
        return originalMethod(obj, ...rest);
      };
    });
  }
  
  return moduleLogger;
};

// Export log levels for use in code
export const LogLevel = {
  FATAL: 'fatal',
  ERROR: 'error',
  WARN: 'warn',
  INFO: 'info',
  DEBUG: 'debug',
  TRACE: 'trace'
} as const;

// Helper for logging tool executions
export const logToolExecution = (toolName: string, args: any, duration?: number) => {
  logger.info({
    event: 'tool_execution',
    tool: toolName,
    args: args,
    duration_ms: duration
  }, `Executed tool: ${toolName}`);
};

// Helper for logging errors with context
export const logError = (error: Error, context: Record<string, any>) => {
  logger.error({
    error,
    ...context
  }, error.message);
};
```

--------------------------------------------------------------------------------
/XcodeProjectModifier/Sources/XcodeProjectModifier/main.swift:
--------------------------------------------------------------------------------

```swift
import Foundation
import XcodeProj
import PathKit
import ArgumentParser

struct XcodeProjectModifier: ParsableCommand {
    @Argument(help: "Path to the .xcodeproj file")
    var projectPath: String
    
    @Argument(help: "Action to perform: add or remove")
    var action: String
    
    @Argument(help: "Path to the file to add/remove")
    var filePath: String
    
    @Argument(help: "Target name")
    var targetName: String
    
    @Option(name: .long, help: "Group path for the file")
    var groupPath: String = ""
    
    func run() throws {
        let project = try XcodeProj(pathString: projectPath)
        let pbxproj = project.pbxproj
        
        guard let target = pbxproj.nativeTargets.first(where: { $0.name == targetName }) else {
            print("Error: Target '\(targetName)' not found")
            throw ExitCode.failure
        }
        
        let fileName = URL(fileURLWithPath: filePath).lastPathComponent
        
        if action == "remove" {
            // Remove file reference
            if let fileRef = pbxproj.fileReferences.first(where: { $0.path == fileName || $0.path == filePath }) {
                pbxproj.delete(object: fileRef)
                print("Removed \(fileName) from project")
            }
        } else if action == "add" {
            // Remove existing reference if it exists
            if let existingRef = pbxproj.fileReferences.first(where: { $0.path == fileName || $0.path == filePath }) {
                pbxproj.delete(object: existingRef)
            }
            
            // Add new file reference
            let fileRef = PBXFileReference(
                sourceTree: .group,
                name: fileName,
                path: filePath
            )
            pbxproj.add(object: fileRef)
            
            // Add to appropriate build phase based on file type
            let fileExtension = URL(fileURLWithPath: filePath).pathExtension.lowercased()
            
            if ["swift", "m", "mm", "c", "cpp", "cc", "cxx"].contains(fileExtension) {
                // Add to sources build phase
                if let sourcesBuildPhase = target.buildPhases.compactMap({ $0 as? PBXSourcesBuildPhase }).first {
                    let buildFile = PBXBuildFile(file: fileRef)
                    pbxproj.add(object: buildFile)
                    sourcesBuildPhase.files?.append(buildFile)
                }
            } else if ["png", "jpg", "jpeg", "gif", "pdf", "json", "plist", "xib", "storyboard", "xcassets"].contains(fileExtension) {
                // Add to resources build phase
                if let resourcesBuildPhase = target.buildPhases.compactMap({ $0 as? PBXResourcesBuildPhase }).first {
                    let buildFile = PBXBuildFile(file: fileRef)
                    pbxproj.add(object: buildFile)
                    resourcesBuildPhase.files?.append(buildFile)
                }
            }
            
            // Add to group
            if let mainGroup = try? pbxproj.rootProject()?.mainGroup {
                mainGroup.children.append(fileRef)
            }
            
            print("Added \(fileName) to project")
        }
        
        try project.write(path: Path(projectPath))
    }
}

XcodeProjectModifier.main()
```

--------------------------------------------------------------------------------
/src/utils/devices/SimulatorApps.ts:
--------------------------------------------------------------------------------

```typescript
import { execAsync } from '../../utils.js';
import { createModuleLogger } from '../../logger.js';
import path from 'path';

const logger = createModuleLogger('SimulatorApps');

/**
 * Handles app management on simulators
 * Single responsibility: Install, uninstall, and launch apps
 */
export class SimulatorApps {
  /**
   * Install an app on the simulator
   */
  async install(appPath: string, deviceId?: string): Promise<void> {
    let command = `xcrun simctl install `;
    if (deviceId) {
      command += `"${deviceId}" `;
    } else {
      command += 'booted ';
    }
    command += `"${appPath}"`;

    try {
      await execAsync(command);
      logger.debug({ appPath, deviceId }, 'App installed successfully');
    } catch (error: any) {
      logger.error({ error: error.message, appPath, deviceId }, 'Failed to install app');
      throw new Error(`Failed to install app: ${error.message}`);
    }
  }

  /**
   * Uninstall an app from the simulator
   */
  async uninstall(bundleId: string, deviceId?: string): Promise<void> {
    // First check if the app exists
    let listCommand = `xcrun simctl listapps `;
    if (deviceId) {
      listCommand += `"${deviceId}"`;
    } else {
      listCommand += 'booted';
    }
    
    try {
      const { stdout: listOutput } = await execAsync(listCommand);
      
      // Check if the bundle ID exists in the output
      if (!listOutput.includes(bundleId)) {
        throw new Error(`App with bundle ID '${bundleId}' is not installed`);
      }
      
      // Now uninstall the app
      let command = `xcrun simctl uninstall `;
      if (deviceId) {
        command += `"${deviceId}" `;
      } else {
        command += 'booted ';
      }
      command += `"${bundleId}"`;
      
      await execAsync(command);
      logger.debug({ bundleId, deviceId }, 'App uninstalled successfully');
    } catch (error: any) {
      logger.error({ error: error.message, bundleId, deviceId }, 'Failed to uninstall app');
      throw new Error(`Failed to uninstall app: ${error.message}`);
    }
  }

  /**
   * Launch an app on the simulator
   * Returns the process ID of the launched app
   */
  async launch(bundleId: string, deviceId?: string): Promise<string> {
    let command = `xcrun simctl launch --terminate-running-process `;
    if (deviceId) {
      command += `"${deviceId}" `;
    } else {
      command += 'booted ';
    }
    command += `"${bundleId}"`;

    try {
      const { stdout } = await execAsync(command);
      const pid = stdout.trim();
      logger.debug({ bundleId, deviceId, pid }, 'App launched successfully');
      return pid;
    } catch (error: any) {
      logger.error({ error: error.message, bundleId, deviceId }, 'Failed to launch app');
      throw new Error(`Failed to launch app: ${error.message}`);
    }
  }

  /**
   * Get bundle ID from an app bundle
   */
  async getBundleId(appPath: string): Promise<string> {
    try {
      const plistPath = path.join(appPath, 'Info.plist');
      const { stdout } = await execAsync(
        `/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${plistPath}"`
      );
      return stdout.trim();
    } catch (error: any) {
      logger.error({ error: error.message, appPath }, 'Failed to get bundle ID');
      throw new Error(`Failed to get bundle ID: ${error.message}`);
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/controllers/ShutdownSimulatorController.ts:
--------------------------------------------------------------------------------

```typescript
import { ShutdownSimulatorUseCase } from '../use-cases/ShutdownSimulatorUseCase.js';
import { DeviceId } from '../../../shared/domain/DeviceId.js';
import { ShutdownRequest } from '../domain/ShutdownRequest.js';
import { ShutdownResult, ShutdownOutcome, SimulatorNotFoundError, ShutdownCommandFailedError } from '../domain/ShutdownResult.js';
import { ErrorFormatter } from '../../../presentation/formatters/ErrorFormatter.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';

/**
 * Controller for the shutdown_simulator MCP tool
 * 
 * Handles input validation and orchestrates the shutdown simulator use case
 */
export class ShutdownSimulatorController implements MCPController {
  readonly name = 'shutdown_simulator';
  readonly description = 'Shutdown a simulator';
  
  constructor(
    private useCase: ShutdownSimulatorUseCase
  ) {}
  
  get inputSchema() {
    return {
      type: 'object' as const,
      properties: {
        deviceId: {
          type: 'string' as const,
          description: 'Device UDID or name of the simulator to shutdown'
        }
      },
      required: ['deviceId'] as const
    };
  }
  
  getToolDefinition() {
    return {
      name: this.name,
      description: this.description,
      inputSchema: this.inputSchema
    };
  }
  
  async execute(args: unknown): Promise<{ content: Array<{ type: string; text: string }> }> {
    try {
      // Cast to expected shape
      const input = args as { deviceId: unknown };

      // Create domain value object - will validate
      const deviceId = DeviceId.create(input.deviceId);

      // Create domain request
      const request = ShutdownRequest.create(deviceId);

      // Execute use case
      const result = await this.useCase.execute(request);
      
      // Format response
      return {
        content: [{
          type: 'text',
          text: this.formatResult(result)
        }]
      };
    } catch (error: any) {
      // Handle validation and other errors consistently
      const message = ErrorFormatter.format(error);
      return {
        content: [{
          type: 'text',
          text: `❌ ${message}`
        }]
      };
    }
  }
  
  private formatResult(result: ShutdownResult): string {
    const { outcome, diagnostics } = result;
    
    switch (outcome) {
      case ShutdownOutcome.Shutdown:
        return `✅ Successfully shutdown simulator: ${diagnostics.simulatorName} (${diagnostics.simulatorId})`;
      
      case ShutdownOutcome.AlreadyShutdown:
        return `✅ Simulator already shutdown: ${diagnostics.simulatorName} (${diagnostics.simulatorId})`;
      
      case ShutdownOutcome.Failed:
        const { error } = diagnostics;
        
        if (error instanceof SimulatorNotFoundError) {
          // Use consistent error formatting with ❌ emoji
          return `❌ Simulator not found: ${error.deviceId}`;
        }
        
        if (error instanceof ShutdownCommandFailedError) {
          const message = ErrorFormatter.format(error);
          // Include simulator context if available
          if (diagnostics.simulatorName && diagnostics.simulatorId) {
            return `❌ ${diagnostics.simulatorName} (${diagnostics.simulatorId}) - ${message}`;
          }
          return `❌ ${message}`;
        }
        
        // Shouldn't happen but handle gracefully
        const fallbackMessage = error ? ErrorFormatter.format(error) : 'Shutdown operation failed';
        return `❌ ${fallbackMessage}`;
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/tests/unit/SimulatorControlAdapter.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, jest, beforeEach } from '@jest/globals';
import { SimulatorControlAdapter } from '../../infrastructure/SimulatorControlAdapter.js';
import { ICommandExecutor } from '../../../../application/ports/CommandPorts.js';

describe('SimulatorControlAdapter', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  function createSUT() {
    const mockExecute = jest.fn<ICommandExecutor['execute']>();
    const mockExecutor: ICommandExecutor = {
      execute: mockExecute
    };
    const sut = new SimulatorControlAdapter(mockExecutor);
    return { sut, mockExecute };
  }

  describe('boot', () => {
    it('should boot simulator successfully', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: '',
        exitCode: 0
      });

      // Act
      await sut.boot('ABC-123');

      // Assert
      expect(mockExecute).toHaveBeenCalledWith('xcrun simctl boot "ABC-123"');
    });

    it('should handle already booted simulator gracefully', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: 'Unable to boot device in current state: Booted',
        exitCode: 149
      });

      // Act & Assert - should not throw
      await expect(sut.boot('ABC-123')).resolves.toBeUndefined();
    });

    it('should throw error for device not found', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: 'Invalid device: ABC-123',
        exitCode: 164
      });

      // Act & Assert
      await expect(sut.boot('ABC-123'))
        .rejects.toThrow('Invalid device: ABC-123');
    });

    it('should throw error when simulator runtime is not installed on system', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: 'The device runtime is not available',
        exitCode: 1
      });

      // Act & Assert
      await expect(sut.boot('ABC-123'))
        .rejects.toThrow('The device runtime is not available');
    });
  });

  describe('shutdown', () => {
    it('should shutdown simulator successfully', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: '',
        exitCode: 0
      });

      // Act
      await sut.shutdown('ABC-123');

      // Assert
      expect(mockExecute).toHaveBeenCalledWith('xcrun simctl shutdown "ABC-123"');
    });

    it('should handle already shutdown simulator gracefully', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: 'Unable to shutdown device in current state: Shutdown',
        exitCode: 149
      });

      // Act & Assert - should not throw
      await expect(sut.shutdown('ABC-123')).resolves.toBeUndefined();
    });

    it('should throw error for device not found', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: '',
        stderr: 'Invalid device: ABC-123',
        exitCode: 164
      });

      // Act & Assert
      await expect(sut.shutdown('ABC-123'))
        .rejects.toThrow('Invalid device: ABC-123');
    });
  });
});
```

--------------------------------------------------------------------------------
/src/utils/devices/SimulatorInfo.ts:
--------------------------------------------------------------------------------

```typescript
import { execAsync } from '../../utils.js';
import { createModuleLogger } from '../../logger.js';
import { SimulatorDevice, Platform } from '../../types.js';

const logger = createModuleLogger('SimulatorInfo');

/**
 * Provides information about simulators
 * Single responsibility: Query simulator state and logs
 */
export class SimulatorInfo {
  /**
   * List all available simulators, optionally filtered by platform
   */
  async list(platform?: Platform, showAll = false): Promise<SimulatorDevice[]> {
    try {
      const { stdout } = await execAsync('xcrun simctl list devices --json');
      const data = JSON.parse(stdout);
      
      const devices: SimulatorDevice[] = [];
      for (const [runtime, deviceList] of Object.entries(data.devices)) {
        // Filter by platform if specified
        if (platform) {
          const runtimeLower = runtime.toLowerCase();
          const platformLower = platform.toLowerCase();
          
          // Handle visionOS which is internally called xrOS
          const isVisionOS = platformLower === 'visionos' && runtimeLower.includes('xros');
          const isOtherPlatform = platformLower !== 'visionos' && runtimeLower.includes(platformLower);
          
          if (!isVisionOS && !isOtherPlatform) {
            continue;
          }
        }

        for (const device of deviceList as any[]) {
          if (!showAll && !device.isAvailable) {
            continue;
          }
          devices.push({
            udid: device.udid,
            name: device.name,
            state: device.state,
            deviceTypeIdentifier: device.deviceTypeIdentifier,
            runtime: runtime.replace('com.apple.CoreSimulator.SimRuntime.', ''),
            isAvailable: device.isAvailable
          });
        }
      }

      return devices;
    } catch (error: any) {
      logger.error({ error: error.message }, 'Failed to list simulators');
      throw new Error(`Failed to list simulators: ${error.message}`);
    }
  }

  /**
   * Get device logs from the simulator
   */
  async logs(deviceId?: string, predicate?: string, last: string = '5m'): Promise<string> {
    let command = `xcrun simctl spawn `;
    if (deviceId) {
      command += `"${deviceId}" `;
    } else {
      command += 'booted ';
    }
    command += `log show --style syslog --last ${last}`;
    
    if (predicate) {
      command += ` --predicate '${predicate}'`;
    }

    try {
      const { stdout } = await execAsync(command, { maxBuffer: 10 * 1024 * 1024 });
      // Return last 100 lines to keep it manageable
      const lines = stdout.split('\n').slice(-100);
      return lines.join('\n');
    } catch (error: any) {
      logger.error({ error: error.message, deviceId, predicate }, 'Failed to get device logs');
      throw new Error(`Failed to get device logs: ${error.message}`);
    }
  }

  /**
   * Get the state of a specific device
   */
  async getDeviceState(deviceId: string): Promise<string> {
    const devices = await this.list(undefined, true);
    const device = devices.find(d => d.udid === deviceId || d.name === deviceId);
    
    if (!device) {
      throw new Error(`Device '${deviceId}' not found`);
    }
    
    return device.state;
  }

  /**
   * Check if a device is available
   */
  async isAvailable(deviceId: string): Promise<boolean> {
    const devices = await this.list(undefined, true);
    const device = devices.find(d => d.udid === deviceId || d.name === deviceId);
    
    return device?.isAvailable || false;
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/controllers/BootSimulatorController.ts:
--------------------------------------------------------------------------------

```typescript
import { BootSimulatorUseCase } from '../use-cases/BootSimulatorUseCase.js';
import { BootRequest } from '../domain/BootRequest.js';
import { DeviceId } from '../../../shared/domain/DeviceId.js';
import { BootResult, BootOutcome, SimulatorNotFoundError, BootCommandFailedError, SimulatorBusyError } from '../domain/BootResult.js';
import { ErrorFormatter } from '../../../presentation/formatters/ErrorFormatter.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';

/**
 * Controller for the boot_simulator MCP tool
 *
 * Handles input validation and orchestrates the boot simulator use case
 */
export class BootSimulatorController implements MCPController {
  readonly name = 'boot_simulator';
  readonly description = 'Boot a simulator';
  
  constructor(
    private useCase: BootSimulatorUseCase
  ) {}
  
  get inputSchema() {
    return {
      type: 'object' as const,
      properties: {
        deviceId: {
          type: 'string' as const,
          description: 'Device UDID or name of the simulator to boot'
        }
      },
      required: ['deviceId'] as const
    };
  }
  
  getToolDefinition() {
    return {
      name: this.name,
      description: this.description,
      inputSchema: this.inputSchema
    };
  }
  
  async execute(args: unknown): Promise<{ content: Array<{ type: string; text: string }> }> {
    try {
      // Cast to expected shape
      const input = args as { deviceId: unknown };

      // Create domain value object - will validate
      const deviceId = DeviceId.create(input.deviceId);

      // Create domain request
      const request = BootRequest.create(deviceId);

      // Execute use case
      const result = await this.useCase.execute(request);
      
      // Format response
      return {
        content: [{
          type: 'text',
          text: this.formatResult(result)
        }]
      };
    } catch (error: any) {
      // Handle validation and other errors consistently
      const message = ErrorFormatter.format(error);
      return {
        content: [{
          type: 'text',
          text: `❌ ${message}`
        }]
      };
    }
  }
  
  private formatResult(result: BootResult): string {
    const { outcome, diagnostics } = result;
    
    switch (outcome) {
      case BootOutcome.Booted:
        return `✅ Successfully booted simulator: ${diagnostics.simulatorName} (${diagnostics.simulatorId})`;
      
      case BootOutcome.AlreadyBooted:
        return `✅ Simulator already booted: ${diagnostics.simulatorName} (${diagnostics.simulatorId})`;
      
      case BootOutcome.Failed:
        const { error } = diagnostics;
        
        if (error instanceof SimulatorNotFoundError) {
          // Use consistent error formatting with ❌ emoji
          return `❌ Simulator not found: ${error.deviceId}`;
        }
        
        if (error instanceof SimulatorBusyError) {
          // Handle simulator busy scenarios
          return `❌ Cannot boot simulator: currently ${error.currentState.toLowerCase()}`;
        }
        
        if (error instanceof BootCommandFailedError) {
          const message = ErrorFormatter.format(error);
          // Include simulator context if available
          if (diagnostics.simulatorName && diagnostics.simulatorId) {
            return `❌ ${diagnostics.simulatorName} (${diagnostics.simulatorId}) - ${message}`;
          }
          return `❌ ${message}`;
        }
        
        // Shouldn't happen but handle gracefully
        const fallbackMessage = error ? ErrorFormatter.format(error) : 'Boot operation failed';
        return `❌ ${fallbackMessage}`;
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/infrastructure/SimulatorLocatorAdapter.ts:
--------------------------------------------------------------------------------

```typescript
import { ISimulatorLocator, SimulatorInfo } from '../../../application/ports/SimulatorPorts.js';
import { ICommandExecutor } from '../../../application/ports/CommandPorts.js';
import { SimulatorState } from '../domain/SimulatorState.js';

/**
 * Locates simulators using xcrun simctl
 */
export class SimulatorLocatorAdapter implements ISimulatorLocator {
  constructor(private executor: ICommandExecutor) {}

  async findSimulator(idOrName: string): Promise<SimulatorInfo | null> {
    const result = await this.executor.execute('xcrun simctl list devices --json');
    const data = JSON.parse(result.stdout);
    
    const allMatches: Array<{
      device: any;
      runtime: string;
    }> = [];
    
    for (const [runtime, deviceList] of Object.entries(data.devices)) {
      for (const device of deviceList as any[]) {
        if ((device.udid === idOrName || device.name === idOrName) && device.isAvailable) {
          allMatches.push({ device, runtime });
        }
      }
    }
    
    if (allMatches.length === 0) {
      return null;
    }
    
    // Sort by: booted first, then newer runtime
    allMatches.sort((a, b) => {
      // Booted devices first
      if (a.device.state === SimulatorState.Booted && b.device.state !== SimulatorState.Booted) return -1;
      if (b.device.state === SimulatorState.Booted && a.device.state !== SimulatorState.Booted) return 1;
      
      // Then by runtime version (newer first)
      return this.compareRuntimeVersions(b.runtime, a.runtime);
    });
    
    const selected = allMatches[0];
    return {
      id: selected.device.udid,
      name: selected.device.name,
      state: SimulatorState.parse(selected.device.state),
      platform: this.extractPlatform(selected.runtime),
      runtime: selected.runtime
    };
  }

  async findBootedSimulator(): Promise<SimulatorInfo | null> {
    const result = await this.executor.execute('xcrun simctl list devices --json');
    const data = JSON.parse(result.stdout);
    
    const bootedDevices: SimulatorInfo[] = [];
    
    for (const [runtime, deviceList] of Object.entries(data.devices)) {
      for (const device of deviceList as any[]) {
        if (device.state === SimulatorState.Booted && device.isAvailable) {
          bootedDevices.push({
            id: device.udid,
            name: device.name,
            state: SimulatorState.Booted,
            platform: this.extractPlatform(runtime),
            runtime: runtime
          });
        }
      }
    }
    
    if (bootedDevices.length === 0) {
      return null;
    }
    
    if (bootedDevices.length > 1) {
      throw new Error(`Multiple booted simulators found (${bootedDevices.length}). Please specify a simulator ID.`);
    }
    
    return bootedDevices[0];
  }

  private extractPlatform(runtime: string): string {
    const runtimeLower = runtime.toLowerCase();
    
    if (runtimeLower.includes('ios')) return 'iOS';
    if (runtimeLower.includes('tvos')) return 'tvOS';
    if (runtimeLower.includes('watchos')) return 'watchOS';
    if (runtimeLower.includes('xros') || runtimeLower.includes('visionos')) return 'visionOS';
    
    return 'iOS';
  }

  private compareRuntimeVersions(runtimeA: string, runtimeB: string): number {
    const extractVersion = (runtime: string): number[] => {
      const match = runtime.match(/(\d+)-(\d+)/);
      if (!match) return [0, 0];
      return [parseInt(match[1]), parseInt(match[2])];
    };
    
    const [majorA, minorA] = extractVersion(runtimeA);
    const [majorB, minorB] = extractVersion(runtimeB);
    
    if (majorA !== majorB) return majorA - majorB;
    return minorA - minorB;
  }
}
```

--------------------------------------------------------------------------------
/src/features/app-management/controllers/InstallAppController.ts:
--------------------------------------------------------------------------------

```typescript
import { InstallAppUseCase } from '../use-cases/InstallAppUseCase.js';
import { InstallRequest } from '../domain/InstallRequest.js';
import {
  InstallResult,
  InstallOutcome,
  InstallCommandFailedError,
  SimulatorNotFoundError,
  NoBootedSimulatorError
} from '../domain/InstallResult.js';
import { ErrorFormatter } from '../../../presentation/formatters/ErrorFormatter.js';
import { MCPController } from '../../../presentation/interfaces/MCPController.js';

/**
 * MCP Controller for installing apps on simulators
 *
 * Handles input validation and orchestrates the install app use case
 */

interface InstallAppArgs {
  appPath: unknown;
  simulatorId?: unknown;
}

export class InstallAppController implements MCPController {
  // MCP Tool metadata
  readonly name = 'install_app';
  readonly description = 'Install an app on the simulator';
  
  constructor(
    private useCase: InstallAppUseCase
  ) {}
  
  get inputSchema() {
    return {
      type: 'object' as const,
      properties: {
        appPath: {
          type: 'string',
          description: 'Path to the .app bundle'
        },
        simulatorId: {
          type: 'string',
          description: 'Device UDID or name of the simulator (optional, uses booted device if not specified)'
        }
      },
      required: ['appPath']
    };
  }
  
  getToolDefinition() {
    return {
      name: this.name,
      description: this.description,
      inputSchema: this.inputSchema
    };
  }
  
  async execute(args: unknown): Promise<{ content: Array<{ type: string; text: string }> }> {
    try {
      // Type guard for input
      if (!args || typeof args !== 'object') {
        throw new Error('Invalid input: expected an object');
      }

      const input = args as InstallAppArgs;

      // Create domain request (validation happens here)
      const request = InstallRequest.create(input.appPath, input.simulatorId);

      // Execute use case
      const result = await this.useCase.execute(request);

      // Format response
      return {
        content: [{
          type: 'text',
          text: this.formatResult(result)
        }]
      };
    } catch (error: any) {
      // Handle validation and use case errors consistently
      const message = ErrorFormatter.format(error);
      return {
        content: [{
          type: 'text',
          text: `❌ ${message}`
        }]
      };
    }
  }
  
  private formatResult(result: InstallResult): string {
    const { outcome, diagnostics } = result;
    
    switch (outcome) {
      case InstallOutcome.Succeeded:
        return `✅ Successfully installed ${diagnostics.bundleId} on ${diagnostics.simulatorName} (${diagnostics.simulatorId?.toString()})`;
      
      case InstallOutcome.Failed:
        const { error } = diagnostics;
        
        if (error instanceof NoBootedSimulatorError) {
          return `❌ No booted simulator found. Please boot a simulator first or specify a simulator ID.`;
        }

        if (error instanceof SimulatorNotFoundError) {
          return `❌ Simulator not found: ${error.simulatorId}`;
        }
        
        if (error instanceof InstallCommandFailedError) {
          const message = ErrorFormatter.format(error);
          // Include simulator context if available
          if (diagnostics.simulatorName && diagnostics.simulatorId) {
            return `❌ ${diagnostics.simulatorName} (${diagnostics.simulatorId.toString()}) - ${message}`;
          }
          return `❌ ${message}`;
        }
        
        // Shouldn't happen but handle gracefully
        const fallbackMessage = error ? ErrorFormatter.format(error) : 'Install operation failed';
        return `❌ ${fallbackMessage}`;
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/app-management/use-cases/InstallAppUseCase.ts:
--------------------------------------------------------------------------------

```typescript
import { SimulatorState } from '../../simulator/domain/SimulatorState.js';
import { InstallRequest } from '../domain/InstallRequest.js';
import { DeviceId } from '../../../shared/domain/DeviceId.js';
import {
  InstallResult,
  InstallCommandFailedError,
  SimulatorNotFoundError,
  NoBootedSimulatorError
} from '../domain/InstallResult.js';
import { 
  ISimulatorLocator,
  ISimulatorControl,
  IAppInstaller 
} from '../../../application/ports/SimulatorPorts.js';
import { ILogManager } from '../../../application/ports/LoggingPorts.js';

/**
 * Use Case: Install an app on a simulator
 * Orchestrates finding the target simulator, booting if needed, and installing the app
 */
export class InstallAppUseCase {
  constructor(
    private simulatorLocator: ISimulatorLocator,
    private simulatorControl: ISimulatorControl,
    private appInstaller: IAppInstaller,
    private logManager: ILogManager
  ) {}

  async execute(request: InstallRequest): Promise<InstallResult> {
    // Get app name from the AppPath value object
    const appName = request.appPath.name;

    // Find target simulator
    const simulator = request.simulatorId
      ? await this.simulatorLocator.findSimulator(request.simulatorId.toString())
      : await this.simulatorLocator.findBootedSimulator();
    
    if (!simulator) {
      this.logManager.saveDebugData('install-app-failed', {
        reason: 'simulator_not_found',
        requestedId: request.simulatorId?.toString()
      }, appName);

      const error = request.simulatorId
        ? new SimulatorNotFoundError(request.simulatorId)
        : new NoBootedSimulatorError();
      return InstallResult.failed(error, request.appPath, request.simulatorId);
    }
    
    // Boot simulator if needed (only when specific ID provided)
    if (request.simulatorId) {
      if (simulator.state === SimulatorState.Shutdown) {
        try {
          await this.simulatorControl.boot(simulator.id);
          this.logManager.saveDebugData('simulator-auto-booted', {
            simulatorId: simulator.id,
            simulatorName: simulator.name
          }, appName);
        } catch (error: any) {
          this.logManager.saveDebugData('simulator-boot-failed', {
            simulatorId: simulator.id,
            error: error.message
          }, appName);
          const installError = new InstallCommandFailedError(error.message || error.toString());
          return InstallResult.failed(
            installError,
            request.appPath,
            DeviceId.create(simulator.id),
            simulator.name
          );
        }
      }
    }
    
    // Install the app
    try {
      await this.appInstaller.installApp(
        request.appPath.toString(),
        simulator.id
      );
      
      this.logManager.saveDebugData('install-app-success', {
        simulator: simulator.name,
        simulatorId: simulator.id,
        app: appName
      }, appName);
      
      // Try to get bundle ID from app (could be enhanced later)
      const bundleId = appName; // For now, use app name as bundle ID
      
      return InstallResult.succeeded(
        bundleId,
        DeviceId.create(simulator.id),
        simulator.name,
        request.appPath
      );
    } catch (error: any) {
      this.logManager.saveDebugData('install-app-error', {
        simulator: simulator.name,
        simulatorId: simulator.id,
        app: appName,
        error: error.message
      }, appName);
      
      const installError = new InstallCommandFailedError(error.message || error.toString());
      return InstallResult.failed(
        installError,
        request.appPath,
        DeviceId.create(simulator.id),
        simulator.name
      );
    }
  }
}
```

--------------------------------------------------------------------------------
/src/features/simulator/tests/unit/BootResult.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect } from '@jest/globals';
import { 
  BootResult, 
  BootOutcome, 
  SimulatorNotFoundError, 
  BootCommandFailedError 
} from '../../domain/BootResult.js';

describe('BootResult', () => {
  describe('booted', () => {
    it('should create a result for newly booted simulator', () => {
      // Arrange
      const simulatorId = 'ABC123';
      const simulatorName = 'iPhone 15';
      
      // Act
      const result = BootResult.booted(simulatorId, simulatorName);
      
      // Assert - Test behavior: result indicates success
      expect(result.outcome).toBe(BootOutcome.Booted);
      expect(result.diagnostics.simulatorId).toBe(simulatorId);
      expect(result.diagnostics.simulatorName).toBe(simulatorName);
    });

    it('should include optional diagnostics', () => {
      // Arrange
      const diagnostics = { platform: 'iOS', runtime: 'iOS-17.0' };
      
      // Act
      const result = BootResult.booted('ABC123', 'iPhone 15', diagnostics);
      
      // Assert - Test behavior: diagnostics are preserved
      expect(result.diagnostics.platform).toBe('iOS');
      expect(result.diagnostics.runtime).toBe('iOS-17.0');
    });
  });

  describe('alreadyBooted', () => {
    it('should create a result for already running simulator', () => {
      // Arrange & Act
      const result = BootResult.alreadyBooted('ABC123', 'iPhone 15');
      
      // Assert - Test behavior: result indicates already running
      expect(result.outcome).toBe(BootOutcome.AlreadyBooted);
      expect(result.diagnostics.simulatorId).toBe('ABC123');
      expect(result.diagnostics.simulatorName).toBe('iPhone 15');
    });
  });

  describe('failed', () => {
    it('should create a failure result with error', () => {
      // Arrange
      const error = new BootCommandFailedError('Device is locked');
      
      // Act
      const result = BootResult.failed('ABC123', 'iPhone 15', error);
      
      // Assert - Test behavior: result indicates failure with error
      expect(result.outcome).toBe(BootOutcome.Failed);
      expect(result.diagnostics.simulatorId).toBe('ABC123');
      expect(result.diagnostics.simulatorName).toBe('iPhone 15');
      expect(result.diagnostics.error).toBe(error);
    });

    it('should handle simulator not found error', () => {
      // Arrange
      const error = new SimulatorNotFoundError('iPhone-16');
      
      // Act
      const result = BootResult.failed('iPhone-16', '', error);
      
      // Assert - Test behavior: error type is preserved
      expect(result.outcome).toBe(BootOutcome.Failed);
      expect(result.diagnostics.error).toBeInstanceOf(SimulatorNotFoundError);
      expect((result.diagnostics.error as SimulatorNotFoundError).deviceId).toBe('iPhone-16');
    });

    it('should include optional diagnostics on failure', () => {
      // Arrange
      const error = new BootCommandFailedError('Boot failed');
      const diagnostics = { runtime: 'iOS-17.0' };
      
      // Act
      const result = BootResult.failed('ABC123', 'iPhone 15', error, diagnostics);
      
      // Assert - Test behavior: diagnostics preserved even on failure
      expect(result.diagnostics.runtime).toBe('iOS-17.0');
      expect(result.diagnostics.error).toBe(error);
    });
  });

  describe('immutability', () => {
    it('should create immutable results', () => {
      // Arrange
      const result = BootResult.booted('ABC123', 'iPhone 15');
      
      // Act & Assert - Test behavior: results cannot be modified
      expect(() => {
        (result as any).outcome = BootOutcome.Failed;
      }).toThrow();
      
      expect(() => {
        (result.diagnostics as any).simulatorId = 'XYZ789';
      }).toThrow();
    });
  });
});
```

--------------------------------------------------------------------------------
/src/infrastructure/tests/unit/DeviceRepository.unit.test.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, jest } from '@jest/globals';
import { DeviceRepository, DeviceList } from '../../repositories/DeviceRepository.js';
import { ICommandExecutor } from '../../../application/ports/CommandPorts.js';

describe('DeviceRepository', () => {
  function createSUT() {
    const mockExecute = jest.fn<ICommandExecutor['execute']>();
    const mockExecutor: ICommandExecutor = { execute: mockExecute };
    const sut = new DeviceRepository(mockExecutor);
    return { sut, mockExecute };
  }

  describe('getAllDevices', () => {
    it('should return parsed device list from xcrun simctl', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();

      const mockDevices: DeviceList = {
        'com.apple.CoreSimulator.SimRuntime.iOS-17-0': [
          {
            udid: 'test-uuid-1',
            name: 'iPhone 15',
            state: 'Booted',
            isAvailable: true,
            deviceTypeIdentifier: 'com.apple.iPhone15'
          }
        ],
        'com.apple.CoreSimulator.SimRuntime.iOS-16-4': [
          {
            udid: 'test-uuid-2',
            name: 'iPhone 14',
            state: 'Shutdown',
            isAvailable: true
          }
        ]
      };

      mockExecute.mockResolvedValue({
        stdout: JSON.stringify({ devices: mockDevices }),
        stderr: '',
        exitCode: 0
      });

      // Act
      const result = await sut.getAllDevices();

      // Assert
      expect(mockExecute).toHaveBeenCalledWith('xcrun simctl list devices --json');
      expect(result).toEqual(mockDevices);
    });

    it('should handle empty device list', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      const emptyDevices: DeviceList = {};

      mockExecute.mockResolvedValue({
        stdout: JSON.stringify({ devices: emptyDevices }),
        stderr: '',
        exitCode: 0
      });

      // Act
      const result = await sut.getAllDevices();

      // Assert
      expect(result).toEqual(emptyDevices);
    });

    it('should propagate executor errors', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      const error = new Error('Command failed');
      mockExecute.mockRejectedValue(error);

      // Act & Assert
      await expect(sut.getAllDevices()).rejects.toThrow('Command failed');
    });

    it('should throw on invalid JSON response', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();
      mockExecute.mockResolvedValue({
        stdout: 'not valid json',
        stderr: '',
        exitCode: 0
      });

      // Act & Assert
      await expect(sut.getAllDevices()).rejects.toThrow();
    });

    it('should handle devices with all optional fields', async () => {
      // Arrange
      const { sut, mockExecute } = createSUT();

      const deviceWithAllFields: DeviceList = {
        'com.apple.CoreSimulator.SimRuntime.iOS-17-0': [
          {
            udid: 'full-uuid',
            name: 'iPhone 15 Pro',
            state: 'Booted',
            isAvailable: true,
            deviceTypeIdentifier: 'com.apple.iPhone15Pro',
            dataPath: '/path/to/data',
            dataPathSize: 1024000,
            logPath: '/path/to/logs'
          }
        ]
      };

      mockExecute.mockResolvedValue({
        stdout: JSON.stringify({ devices: deviceWithAllFields }),
        stderr: '',
        exitCode: 0
      });

      // Act
      const result = await sut.getAllDevices();

      // Assert
      expect(result).toEqual(deviceWithAllFields);
      const device = result['com.apple.CoreSimulator.SimRuntime.iOS-17-0'][0];
      expect(device.dataPath).toBe('/path/to/data');
      expect(device.dataPathSize).toBe(1024000);
      expect(device.logPath).toBe('/path/to/logs');
    });
  });
});
```
Page 1/4FirstPrevNextLast