#
tokens: 49525/50000 4/337 files (page 14/14)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 14 of 14. Use http://codebase.md/cameroncooke/xcodebuildmcp?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .axe-version
├── .claude
│   └── agents
│       └── xcodebuild-mcp-qa-tester.md
├── .cursor
│   ├── BUGBOT.md
│   └── environment.json
├── .cursorrules
├── .github
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   └── feature_request.yml
│   └── workflows
│       ├── ci.yml
│       ├── claude-code-review.yml
│       ├── claude-dispatch.yml
│       ├── claude.yml
│       ├── droid-code-review.yml
│       ├── README.md
│       ├── release.yml
│       └── sentry.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── .vscode
│   ├── extensions.json
│   ├── launch.json
│   ├── mcp.json
│   ├── settings.json
│   └── tasks.json
├── AGENTS.md
├── banner.png
├── build-plugins
│   ├── plugin-discovery.js
│   ├── plugin-discovery.ts
│   └── tsconfig.json
├── CHANGELOG.md
├── CLAUDE.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── docs
│   ├── ARCHITECTURE.md
│   ├── CODE_QUALITY.md
│   ├── CONTRIBUTING.md
│   ├── ESLINT_TYPE_SAFETY.md
│   ├── MANUAL_TESTING.md
│   ├── NODEJS_2025.md
│   ├── PLUGIN_DEVELOPMENT.md
│   ├── RELEASE_PROCESS.md
│   ├── RELOADEROO_FOR_XCODEBUILDMCP.md
│   ├── RELOADEROO_XCODEBUILDMCP_PRIMER.md
│   ├── RELOADEROO.md
│   ├── session_management_plan.md
│   ├── session-aware-migration-todo.md
│   ├── TEST_RUNNER_ENV_IMPLEMENTATION_PLAN.md
│   ├── TESTING.md
│   └── TOOLS.md
├── eslint.config.js
├── example_projects
│   ├── .vscode
│   │   └── launch.json
│   ├── iOS
│   │   ├── .cursor
│   │   │   └── rules
│   │   │       └── errors.mdc
│   │   ├── .vscode
│   │   │   └── settings.json
│   │   ├── Makefile
│   │   ├── MCPTest
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   ├── MCPTestApp.swift
│   │   │   └── Preview Content
│   │   │       └── Preview Assets.xcassets
│   │   │           └── Contents.json
│   │   ├── MCPTest.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata
│   │   │       └── xcschemes
│   │   │           └── MCPTest.xcscheme
│   │   └── MCPTestUITests
│   │       └── MCPTestUITests.swift
│   ├── iOS_Calculator
│   │   ├── CalculatorApp
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── CalculatorApp.swift
│   │   │   └── CalculatorApp.xctestplan
│   │   ├── CalculatorApp.xcodeproj
│   │   │   ├── project.pbxproj
│   │   │   └── xcshareddata
│   │   │       └── xcschemes
│   │   │           └── CalculatorApp.xcscheme
│   │   ├── CalculatorApp.xcworkspace
│   │   │   └── contents.xcworkspacedata
│   │   ├── CalculatorAppPackage
│   │   │   ├── .gitignore
│   │   │   ├── Package.swift
│   │   │   ├── Sources
│   │   │   │   └── CalculatorAppFeature
│   │   │   │       ├── BackgroundEffect.swift
│   │   │   │       ├── CalculatorButton.swift
│   │   │   │       ├── CalculatorDisplay.swift
│   │   │   │       ├── CalculatorInputHandler.swift
│   │   │   │       ├── CalculatorService.swift
│   │   │   │       └── ContentView.swift
│   │   │   └── Tests
│   │   │       └── CalculatorAppFeatureTests
│   │   │           └── CalculatorServiceTests.swift
│   │   ├── CalculatorAppTests
│   │   │   └── CalculatorAppTests.swift
│   │   └── Config
│   │       ├── Debug.xcconfig
│   │       ├── Release.xcconfig
│   │       ├── Shared.xcconfig
│   │       └── Tests.xcconfig
│   ├── macOS
│   │   ├── MCPTest
│   │   │   ├── Assets.xcassets
│   │   │   │   ├── AccentColor.colorset
│   │   │   │   │   └── Contents.json
│   │   │   │   ├── AppIcon.appiconset
│   │   │   │   │   └── Contents.json
│   │   │   │   └── Contents.json
│   │   │   ├── ContentView.swift
│   │   │   ├── MCPTest.entitlements
│   │   │   ├── MCPTestApp.swift
│   │   │   └── Preview Content
│   │   │       └── Preview Assets.xcassets
│   │   │           └── Contents.json
│   │   └── MCPTest.xcodeproj
│   │       ├── project.pbxproj
│   │       └── xcshareddata
│   │           └── xcschemes
│   │               └── MCPTest.xcscheme
│   └── spm
│       ├── .gitignore
│       ├── Package.resolved
│       ├── Package.swift
│       ├── Sources
│       │   ├── long-server
│       │   │   └── main.swift
│       │   ├── quick-task
│       │   │   └── main.swift
│       │   ├── spm
│       │   │   └── main.swift
│       │   └── TestLib
│       │       └── TaskManager.swift
│       └── Tests
│           └── TestLibTests
│               └── SimpleTests.swift
├── LICENSE
├── mcp-install-dark.png
├── package-lock.json
├── package.json
├── README.md
├── scripts
│   ├── analysis
│   │   └── tools-analysis.ts
│   ├── bundle-axe.sh
│   ├── check-code-patterns.js
│   ├── release.sh
│   ├── tools-cli.ts
│   └── update-tools-docs.ts
├── server.json
├── smithery.yaml
├── src
│   ├── core
│   │   ├── __tests__
│   │   │   └── resources.test.ts
│   │   ├── dynamic-tools.ts
│   │   ├── plugin-registry.ts
│   │   ├── plugin-types.ts
│   │   └── resources.ts
│   ├── doctor-cli.ts
│   ├── index.ts
│   ├── mcp
│   │   ├── resources
│   │   │   ├── __tests__
│   │   │   │   ├── devices.test.ts
│   │   │   │   ├── doctor.test.ts
│   │   │   │   └── simulators.test.ts
│   │   │   ├── devices.ts
│   │   │   ├── doctor.ts
│   │   │   └── simulators.ts
│   │   └── tools
│   │       ├── device
│   │       │   ├── __tests__
│   │       │   │   ├── build_device.test.ts
│   │       │   │   ├── get_device_app_path.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── install_app_device.test.ts
│   │       │   │   ├── launch_app_device.test.ts
│   │       │   │   ├── list_devices.test.ts
│   │       │   │   ├── re-exports.test.ts
│   │       │   │   ├── stop_app_device.test.ts
│   │       │   │   └── test_device.test.ts
│   │       │   ├── build_device.ts
│   │       │   ├── clean.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_app_bundle_id.ts
│   │       │   ├── get_device_app_path.ts
│   │       │   ├── index.ts
│   │       │   ├── install_app_device.ts
│   │       │   ├── launch_app_device.ts
│   │       │   ├── list_devices.ts
│   │       │   ├── list_schemes.ts
│   │       │   ├── show_build_settings.ts
│   │       │   ├── start_device_log_cap.ts
│   │       │   ├── stop_app_device.ts
│   │       │   ├── stop_device_log_cap.ts
│   │       │   └── test_device.ts
│   │       ├── discovery
│   │       │   ├── __tests__
│   │       │   │   └── discover_tools.test.ts
│   │       │   ├── discover_tools.ts
│   │       │   └── index.ts
│   │       ├── doctor
│   │       │   ├── __tests__
│   │       │   │   ├── doctor.test.ts
│   │       │   │   └── index.test.ts
│   │       │   ├── doctor.ts
│   │       │   ├── index.ts
│   │       │   └── lib
│   │       │       └── doctor.deps.ts
│   │       ├── logging
│   │       │   ├── __tests__
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── start_device_log_cap.test.ts
│   │       │   │   ├── start_sim_log_cap.test.ts
│   │       │   │   ├── stop_device_log_cap.test.ts
│   │       │   │   └── stop_sim_log_cap.test.ts
│   │       │   ├── index.ts
│   │       │   ├── start_device_log_cap.ts
│   │       │   ├── start_sim_log_cap.ts
│   │       │   ├── stop_device_log_cap.ts
│   │       │   └── stop_sim_log_cap.ts
│   │       ├── macos
│   │       │   ├── __tests__
│   │       │   │   ├── build_macos.test.ts
│   │       │   │   ├── build_run_macos.test.ts
│   │       │   │   ├── get_mac_app_path.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── launch_mac_app.test.ts
│   │       │   │   ├── re-exports.test.ts
│   │       │   │   ├── stop_mac_app.test.ts
│   │       │   │   └── test_macos.test.ts
│   │       │   ├── build_macos.ts
│   │       │   ├── build_run_macos.ts
│   │       │   ├── clean.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_mac_app_path.ts
│   │       │   ├── get_mac_bundle_id.ts
│   │       │   ├── index.ts
│   │       │   ├── launch_mac_app.ts
│   │       │   ├── list_schemes.ts
│   │       │   ├── show_build_settings.ts
│   │       │   ├── stop_mac_app.ts
│   │       │   └── test_macos.ts
│   │       ├── project-discovery
│   │       │   ├── __tests__
│   │       │   │   ├── discover_projs.test.ts
│   │       │   │   ├── get_app_bundle_id.test.ts
│   │       │   │   ├── get_mac_bundle_id.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── list_schemes.test.ts
│   │       │   │   └── show_build_settings.test.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_app_bundle_id.ts
│   │       │   ├── get_mac_bundle_id.ts
│   │       │   ├── index.ts
│   │       │   ├── list_schemes.ts
│   │       │   └── show_build_settings.ts
│   │       ├── project-scaffolding
│   │       │   ├── __tests__
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── scaffold_ios_project.test.ts
│   │       │   │   └── scaffold_macos_project.test.ts
│   │       │   ├── index.ts
│   │       │   ├── scaffold_ios_project.ts
│   │       │   └── scaffold_macos_project.ts
│   │       ├── session-management
│   │       │   ├── __tests__
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── session_clear_defaults.test.ts
│   │       │   │   ├── session_set_defaults.test.ts
│   │       │   │   └── session_show_defaults.test.ts
│   │       │   ├── index.ts
│   │       │   ├── session_clear_defaults.ts
│   │       │   ├── session_set_defaults.ts
│   │       │   └── session_show_defaults.ts
│   │       ├── simulator
│   │       │   ├── __tests__
│   │       │   │   ├── boot_sim.test.ts
│   │       │   │   ├── build_run_sim.test.ts
│   │       │   │   ├── build_sim.test.ts
│   │       │   │   ├── get_sim_app_path.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── install_app_sim.test.ts
│   │       │   │   ├── launch_app_logs_sim.test.ts
│   │       │   │   ├── launch_app_sim.test.ts
│   │       │   │   ├── list_sims.test.ts
│   │       │   │   ├── open_sim.test.ts
│   │       │   │   ├── record_sim_video.test.ts
│   │       │   │   ├── screenshot.test.ts
│   │       │   │   ├── stop_app_sim.test.ts
│   │       │   │   └── test_sim.test.ts
│   │       │   ├── boot_sim.ts
│   │       │   ├── build_run_sim.ts
│   │       │   ├── build_sim.ts
│   │       │   ├── clean.ts
│   │       │   ├── describe_ui.ts
│   │       │   ├── discover_projs.ts
│   │       │   ├── get_app_bundle_id.ts
│   │       │   ├── get_sim_app_path.ts
│   │       │   ├── index.ts
│   │       │   ├── install_app_sim.ts
│   │       │   ├── launch_app_logs_sim.ts
│   │       │   ├── launch_app_sim.ts
│   │       │   ├── list_schemes.ts
│   │       │   ├── list_sims.ts
│   │       │   ├── open_sim.ts
│   │       │   ├── record_sim_video.ts
│   │       │   ├── screenshot.ts
│   │       │   ├── show_build_settings.ts
│   │       │   ├── stop_app_sim.ts
│   │       │   └── test_sim.ts
│   │       ├── simulator-management
│   │       │   ├── __tests__
│   │       │   │   ├── erase_sims.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── reset_sim_location.test.ts
│   │       │   │   ├── set_sim_appearance.test.ts
│   │       │   │   ├── set_sim_location.test.ts
│   │       │   │   └── sim_statusbar.test.ts
│   │       │   ├── boot_sim.ts
│   │       │   ├── erase_sims.ts
│   │       │   ├── index.ts
│   │       │   ├── list_sims.ts
│   │       │   ├── open_sim.ts
│   │       │   ├── reset_sim_location.ts
│   │       │   ├── set_sim_appearance.ts
│   │       │   ├── set_sim_location.ts
│   │       │   └── sim_statusbar.ts
│   │       ├── swift-package
│   │       │   ├── __tests__
│   │       │   │   ├── active-processes.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── swift_package_build.test.ts
│   │       │   │   ├── swift_package_clean.test.ts
│   │       │   │   ├── swift_package_list.test.ts
│   │       │   │   ├── swift_package_run.test.ts
│   │       │   │   ├── swift_package_stop.test.ts
│   │       │   │   └── swift_package_test.test.ts
│   │       │   ├── active-processes.ts
│   │       │   ├── index.ts
│   │       │   ├── swift_package_build.ts
│   │       │   ├── swift_package_clean.ts
│   │       │   ├── swift_package_list.ts
│   │       │   ├── swift_package_run.ts
│   │       │   ├── swift_package_stop.ts
│   │       │   └── swift_package_test.ts
│   │       ├── ui-testing
│   │       │   ├── __tests__
│   │       │   │   ├── button.test.ts
│   │       │   │   ├── describe_ui.test.ts
│   │       │   │   ├── gesture.test.ts
│   │       │   │   ├── index.test.ts
│   │       │   │   ├── key_press.test.ts
│   │       │   │   ├── key_sequence.test.ts
│   │       │   │   ├── long_press.test.ts
│   │       │   │   ├── screenshot.test.ts
│   │       │   │   ├── swipe.test.ts
│   │       │   │   ├── tap.test.ts
│   │       │   │   ├── touch.test.ts
│   │       │   │   └── type_text.test.ts
│   │       │   ├── button.ts
│   │       │   ├── describe_ui.ts
│   │       │   ├── gesture.ts
│   │       │   ├── index.ts
│   │       │   ├── key_press.ts
│   │       │   ├── key_sequence.ts
│   │       │   ├── long_press.ts
│   │       │   ├── screenshot.ts
│   │       │   ├── swipe.ts
│   │       │   ├── tap.ts
│   │       │   ├── touch.ts
│   │       │   └── type_text.ts
│   │       └── utilities
│   │           ├── __tests__
│   │           │   ├── clean.test.ts
│   │           │   └── index.test.ts
│   │           ├── clean.ts
│   │           └── index.ts
│   ├── server
│   │   └── server.ts
│   ├── test-utils
│   │   └── mock-executors.ts
│   ├── types
│   │   └── common.ts
│   └── utils
│       ├── __tests__
│       │   ├── build-utils.test.ts
│       │   ├── environment.test.ts
│       │   ├── session-aware-tool-factory.test.ts
│       │   ├── session-store.test.ts
│       │   ├── simulator-utils.test.ts
│       │   ├── test-runner-env-integration.test.ts
│       │   └── typed-tool-factory.test.ts
│       ├── axe
│       │   └── index.ts
│       ├── axe-helpers.ts
│       ├── build
│       │   └── index.ts
│       ├── build-utils.ts
│       ├── capabilities.ts
│       ├── command.ts
│       ├── CommandExecutor.ts
│       ├── environment.ts
│       ├── errors.ts
│       ├── execution
│       │   └── index.ts
│       ├── FileSystemExecutor.ts
│       ├── log_capture.ts
│       ├── log-capture
│       │   └── index.ts
│       ├── logger.ts
│       ├── logging
│       │   └── index.ts
│       ├── plugin-registry
│       │   └── index.ts
│       ├── responses
│       │   └── index.ts
│       ├── schema-helpers.ts
│       ├── sentry.ts
│       ├── session-store.ts
│       ├── simulator-utils.ts
│       ├── template
│       │   └── index.ts
│       ├── template-manager.ts
│       ├── test
│       │   └── index.ts
│       ├── test-common.ts
│       ├── tool-registry.ts
│       ├── typed-tool-factory.ts
│       ├── validation
│       │   └── index.ts
│       ├── validation.ts
│       ├── version
│       │   └── index.ts
│       ├── video_capture.ts
│       ├── video-capture
│       │   └── index.ts
│       ├── xcode.ts
│       ├── xcodemake
│       │   └── index.ts
│       └── xcodemake.ts
├── tsconfig.json
├── tsconfig.test.json
├── tsup.config.ts
└── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/docs/PLUGIN_DEVELOPMENT.md:
--------------------------------------------------------------------------------

```markdown
  1 | # XcodeBuildMCP Plugin Development Guide
  2 | 
  3 | This guide provides comprehensive instructions for creating new tools and workflow groups in XcodeBuildMCP using the filesystem-based auto-discovery system.
  4 | 
  5 | ## Table of Contents
  6 | 
  7 | 1. [Overview](#overview)
  8 | 2. [Plugin Architecture](#plugin-architecture)
  9 | 3. [Creating New Tools](#creating-new-tools)
 10 | 4. [Creating New Workflow Groups](#creating-new-workflow-groups)
 11 | 5. [Creating MCP Resources](#creating-mcp-resources)
 12 | 6. [Auto-Discovery System](#auto-discovery-system)
 13 | 7. [Testing Guidelines](#testing-guidelines)
 14 | 8. [Development Workflow](#development-workflow)
 15 | 9. [Best Practices](#best-practices)
 16 | 
 17 | ## Overview
 18 | 
 19 | XcodeBuildMCP uses a **plugin-based architecture** with **filesystem-based auto-discovery**. Tools are automatically discovered and loaded without manual registration, and can be dynamically enabled using AI-powered workflow selection.
 20 | 
 21 | ### Key Features
 22 | 
 23 | - **Auto-Discovery**: Tools are automatically found by scanning `src/mcp/tools/` directory
 24 | - **Dynamic Loading**: AI can select relevant workflow groups based on user tasks
 25 | - **Dependency Injection**: All tools use testable patterns with mock-friendly executors
 26 | - **Workflow Organization**: Tools are grouped into end-to-end development workflows
 27 | 
 28 | ## Plugin Architecture
 29 | 
 30 | ### Directory Structure
 31 | 
 32 | ```
 33 | src/mcp/tools/
 34 | ├── simulator-workspace/        # iOS Simulator + Workspace tools
 35 | ├── simulator-project/          # iOS Simulator + Project tools (re-exports)
 36 | ├── simulator-shared/           # Shared simulator tools (canonical)
 37 | ├── device-workspace/           # iOS Device + Workspace tools
 38 | ├── device-project/             # iOS Device + Project tools (re-exports)
 39 | ├── device-shared/              # Shared device tools (canonical)
 40 | ├── macos-workspace/            # macOS + Workspace tools
 41 | ├── macos-project/              # macOS + Project tools (re-exports)
 42 | ├── macos-shared/               # Shared macOS tools (canonical)
 43 | ├── swift-package/              # Swift Package Manager tools
 44 | ├── ui-testing/                 # UI automation tools
 45 | ├── project-discovery/          # Project analysis tools
 46 | ├── utilities/                  # General utilities
 47 | ├── doctor/                     # System health check tools
 48 | ├── logging/                    # Log capture tools
 49 | └── discovery/                  # Dynamic tool discovery
 50 | ```
 51 | 
 52 | ### Plugin Tool Types
 53 | 
 54 | 1. **Canonical Workflows**: Standalone workflow groups (e.g., `swift-package`, `ui-testing`) defined as folders in the `src/mcp/tools/` directory
 55 | 2. **Shared Tools**: Common tools in `*-shared` directories (not exposed to clients)
 56 | 3. **Re-exported Tools**: Share tools to other workflow groups by re-exporting them
 57 | 
 58 | ## Creating New Tools
 59 | 
 60 | ### 1. Tool File Structure
 61 | 
 62 | Every tool follows this standardized pattern:
 63 | 
 64 | ```typescript
 65 | // src/mcp/tools/my-workflow/my_tool.ts
 66 | import { z } from 'zod';
 67 | import { ToolResponse } from '../../../types/common.js';
 68 | import { CommandExecutor, getDefaultCommandExecutor } from '../../../utils/command.js';
 69 | import { log, validateRequiredParam, createTextResponse, createErrorResponse } from '../../../utils/index.js';
 70 | 
 71 | // 1. Define parameters type for clarity
 72 | type MyToolParams = {
 73 |   requiredParam: string;
 74 |   optionalParam?: string;
 75 | };
 76 | 
 77 | // 2. Implement the core logic in a separate, testable function
 78 | export async function my_toolLogic(
 79 |   params: MyToolParams,
 80 |   executor: CommandExecutor,
 81 | ): Promise<ToolResponse> {
 82 |   // 3. Validate required parameters
 83 |   const requiredValidation = validateRequiredParam('requiredParam', params.requiredParam);
 84 |   if (!requiredValidation.isValid) {
 85 |     return requiredValidation.errorResponse;
 86 |   }
 87 | 
 88 |   log('info', `Executing my_tool with param: ${params.requiredParam}`);
 89 | 
 90 |   try {
 91 |     // 4. Build and execute the command using the injected executor
 92 |     const command = ['my-command', '--param', params.requiredParam];
 93 |     if (params.optionalParam) {
 94 |       command.push('--optional', params.optionalParam);
 95 |     }
 96 | 
 97 |     const result = await executor(command, 'My Tool Operation');
 98 | 
 99 |     if (!result.success) {
100 |       return createErrorResponse('My Tool operation failed', result.error);
101 |     }
102 | 
103 |     return createTextResponse(`✅ Success: ${result.output}`);
104 |   } catch (error) {
105 |     const errorMessage = error instanceof Error ? error.message : String(error);
106 |     log('error', `My Tool execution error: ${errorMessage}`);
107 |     return createErrorResponse('Tool execution failed', errorMessage);
108 |   }
109 | }
110 | 
111 | // 5. Export the tool definition as the default export
112 | export default {
113 |   name: 'my_tool',
114 |   description: 'A brief description of what my_tool does, with a usage example. e.g. my_tool({ requiredParam: "value" })',
115 |   schema: {
116 |     requiredParam: z.string().describe('Description of the required parameter.'),
117 |     optionalParam: z.string().optional().describe('Description of the optional parameter.'),
118 |   },
119 |   // The handler wraps the logic function with the default executor for production use
120 |   handler: async (args: Record<string, unknown>): Promise<ToolResponse> => {
121 |     return my_toolLogic(args as MyToolParams, getDefaultCommandExecutor());
122 |   },
123 | };
124 | ```
125 | 
126 | ### 2. Required Tool Plugin Properties
127 | 
128 | Every tool plugin **must** export a default object with these properties:
129 | 
130 | | Property | Type | Description |
131 | |----------|------|-------------|
132 | | `name` | `string` | Tool name (must match filename without extension) |
133 | | `description` | `string` | Clear description with usage examples |
134 | | `schema` | `Record<string, z.ZodTypeAny>` | Zod validation schema for parameters |
135 | | `handler` | `function` | Async function: `(args) => Promise<ToolResponse>` |
136 | 
137 | ### 3. Naming Conventions
138 | 
139 | Tools follow the pattern: `{action}_{target}_{specifier}_{projectType}`
140 | 
141 | **Examples:**
142 | - `build_sim_id_ws` → Build + Simulator + ID + Workspace
143 | - `build_sim_name_proj` → Build + Simulator + Name + Project  
144 | - `test_device_ws` → Test + Device + Workspace
145 | - `swift_package_build` → Swift Package + Build
146 | 
147 | **Project Type Suffixes:**
148 | - `_ws` → Works with `.xcworkspace` files
149 | - `_proj` → Works with `.xcodeproj` files
150 | - No suffix → Generic or canonical tools
151 | 
152 | ### 4. Parameter Validation Patterns
153 | 
154 | Use utility functions for consistent validation:
155 | 
156 | ```typescript
157 | // Required parameter validation
158 | const pathValidation = validateRequiredParam('workspacePath', params.workspacePath);
159 | if (!pathValidation.isValid) return pathValidation.errorResponse;
160 | 
161 | // At-least-one parameter validation
162 | const identifierValidation = validateAtLeastOneParam(
163 |   'simulatorId', params.simulatorId,
164 |   'simulatorName', params.simulatorName
165 | );
166 | if (!identifierValidation.isValid) return identifierValidation.errorResponse;
167 | 
168 | // File existence validation
169 | const fileValidation = validateFileExists(params.workspacePath as string);
170 | if (!fileValidation.isValid) return fileValidation.errorResponse;
171 | ```
172 | 
173 | ### 5. Response Patterns
174 | 
175 | Use utility functions for consistent responses:
176 | 
177 | ```typescript
178 | // Success responses
179 | return createTextResponse('✅ Operation succeeded');
180 | return createTextResponse('Operation completed', false); // Not an error
181 | 
182 | // Error responses  
183 | return createErrorResponse('Operation failed', errorDetails);
184 | return createErrorResponse('Validation failed', errorMessage, 'ValidationError');
185 | 
186 | // Complex responses
187 | return {
188 |   content: [
189 |     { type: 'text', text: '✅ Build succeeded' },
190 |     { type: 'text', text: 'Next steps: Run install_app_sim...' }
191 |   ],
192 |   isError: false
193 | };
194 | ```
195 | 
196 | ## Creating New Workflow Groups
197 | 
198 | ### 1. Workflow Group Structure
199 | 
200 | Each workflow group requires:
201 | 
202 | 1. **Directory**: Following naming convention
203 | 2. **Workflow Metadata**: `index.ts` file with workflow export
204 | 3. **Tool Files**: Individual tool implementations
205 | 4. **Tests**: Comprehensive test coverage
206 | 
207 | ### 2. Directory Naming Convention
208 | 
209 | ```
210 | [platform]-[projectType]/     # e.g., simulator-workspace, device-project
211 | [platform]-shared/            # e.g., simulator-shared, macos-shared
212 | [workflow-name]/               # e.g., swift-package, ui-testing
213 | ```
214 | 
215 | ### 3. Workflow Metadata (index.ts)
216 | 
217 | **Required for all workflow groups:**
218 | 
219 | ```typescript
220 | // Example: src/mcp/tools/simulator-workspace/index.ts
221 | export const workflow = {
222 |   name: 'iOS Simulator Workspace Development',
223 |   description: 'Complete iOS development workflow for .xcworkspace files including build, test, deploy, and debug capabilities',
224 |   platforms: ['iOS'],
225 |   targets: ['simulator'], 
226 |   projectTypes: ['workspace'],
227 |   capabilities: ['build', 'test', 'deploy', 'debug', 'ui-automation', 'log-capture'],
228 | };
229 | ```
230 | 
231 | **Required Properties:**
232 | - `name`: Human-readable workflow name
233 | - `description`: Clear description of workflow purpose
234 | - `platforms`: Array of supported platforms
235 | - `targets`: Array of deployment targets  
236 | - `projectTypes`: Array of supported project types
237 | - `capabilities`: Array of workflow capabilities
238 | 
239 | ### 4. Tool Organization Patterns
240 | 
241 | #### Canonical Workflow Groups
242 | Self-contained workflows that don't re-export from other groups:
243 | 
244 | ```
245 | swift-package/
246 | ├── index.ts                    # Workflow metadata
247 | ├── swift_package_build.ts      # Build tool
248 | ├── swift_package_test.ts       # Test tool
249 | ├── swift_package_run.ts        # Run tool
250 | └── __tests__/                  # Test directory
251 |     ├── index.test.ts           # Workflow tests
252 |     ├── swift_package_build.test.ts
253 |     └── ...
254 | ```
255 | 
256 | #### Shared Workflow Groups  
257 | Provide canonical tools for re-export by project/workspace variants:
258 | 
259 | ```
260 | simulator-shared/
261 | ├── boot_sim.ts                 # Canonical simulator boot tool
262 | ├── install_app_sim.ts          # Canonical app install tool
263 | └── __tests__/                  # Test directory
264 |     ├── boot_sim.test.ts
265 |     └── ...
266 | ```
267 | 
268 | #### Project/Workspace Workflow Groups
269 | Re-export shared tools and add variant-specific tools:
270 | 
271 | ```
272 | simulator-project/
273 | ├── index.ts                    # Workflow metadata
274 | ├── boot_sim.ts                 # Re-export: export { default } from '../simulator-shared/boot_sim.js';
275 | ├── build_sim_id_proj.ts        # Project-specific build tool
276 | └── __tests__/                  # Test directory
277 |     ├── index.test.ts           # Workflow tests  
278 |     ├── re-exports.test.ts      # Re-export validation
279 |     └── ...
280 | ```
281 | 
282 | ### 5. Re-export Implementation
283 | 
284 | For project/workspace groups that share tools:
285 | 
286 | ```typescript
287 | // simulator-project/boot_sim.ts
288 | export { default } from '../simulator-shared/boot_sim.js';
289 | ```
290 | 
291 | **Re-export Rules:**
292 | 1. Re-exports come from canonical `-shared` groups
293 | 2. No chained re-exports (re-exports from re-exports)
294 | 3. Each tool maintains project or workspace specificity
295 | 4. Implementation shared, interfaces remain unique
296 | 
297 | ## Creating MCP Resources
298 | 
299 | MCP Resources provide efficient URI-based data access for clients that support the MCP resource specification
300 | 
301 | ### 1. Resource Structure
302 | 
303 | Resources are located in `src/resources/` and follow this pattern:
304 | 
305 | ```typescript
306 | // src/resources/example.ts
307 | import { log, getDefaultCommandExecutor, CommandExecutor } from '../../utils/index.js';
308 | 
309 | // Testable resource logic separated from MCP handler
310 | export async function exampleResourceLogic(
311 |   executor: CommandExecutor,
312 | ): Promise<{ contents: Array<{ text: string }> }> {
313 |   try {
314 |     log('info', 'Processing example resource request');
315 |     
316 |     // Use the executor to get data
317 |     const result = await executor(['some', 'command'], 'Example Resource Operation');
318 |     
319 |     if (!result.success) {
320 |       throw new Error(result.error || 'Failed to get resource data');
321 |     }
322 | 
323 |     return {
324 |       contents: [{ text: result.output || 'resource data' }]
325 |     };
326 |   } catch (error) {
327 |     const errorMessage = error instanceof Error ? error.message : String(error);
328 |     log('error', `Error in example resource handler: ${errorMessage}`);
329 | 
330 |     return {
331 |       contents: [
332 |         {
333 |           text: `Error retrieving resource data: ${errorMessage}`,
334 |         },
335 |       ],
336 |     };
337 |   }
338 | }
339 | 
340 | export default {
341 |   uri: 'xcodebuildmcp://example',
342 |   name: 'example',
343 |   description: 'Description of the resource data',
344 |   mimeType: 'text/plain',
345 |   async handler(_uri: URL): Promise<{ contents: Array<{ text: string }> }> {
346 |     return exampleResourceLogic(getDefaultCommandExecutor());
347 |   },
348 | };
349 | ```
350 | 
351 | ### 2. Resource Implementation Guidelines
352 | 
353 | **Reuse Existing Logic**: Resources that mirror tools should reuse existing tool logic for consistency:
354 | 
355 | ```typescript
356 | // src/mcp/resources/simulators.ts (simplified example)
357 | import { list_simsLogic } from '../tools/simulator-shared/list_sims.js';
358 | 
359 | export default {
360 |   uri: 'xcodebuildmcp://simulators',
361 |   name: 'simulators'
362 |   description: 'Available iOS simulators with UUIDs and states',
363 |   mimeType: 'text/plain',
364 |   async handler(uri: URL): Promise<{ contents: Array<{ text: string }> }> {
365 |     const executor = getDefaultCommandExecutor();
366 |     const result = await list_simsLogic({}, executor);
367 |     return {
368 |       contents: [{ text: result.content[0].text }]
369 |     };
370 |   }
371 | };
372 | ```
373 | 
374 | As not all clients support resources it important that resource content that would be ideally be served by resources be mirroed as a tool as well. This ensurew clients that don't support this capability continue to will still have access to that resource data via a simple tool call.
375 | 
376 | ### 3. Resource Testing
377 | 
378 | Create tests in `src/mcp/resources/__tests__/`:
379 | 
380 | ```typescript
381 | // src/mcp/resources/__tests__/example.test.ts
382 | import exampleResource, { exampleResourceLogic } from '../example.js';
383 | import { createMockExecutor } from '../../utils/test-common.js';
384 | 
385 | describe('example resource', () => {
386 |   describe('Export Field Validation', () => {
387 |     it('should export correct uri', () => {
388 |       expect(exampleResource.uri).toBe('xcodebuildmcp://example');
389 |     });
390 | 
391 |     it('should export correct description', () => {
392 |       expect(exampleResource.description).toBe('Description of the resource data');
393 |     });
394 | 
395 |     it('should export correct mimeType', () => {
396 |       expect(exampleResource.mimeType).toBe('text/plain');
397 |     });
398 | 
399 |     it('should export handler function', () => {
400 |       expect(typeof exampleResource.handler).toBe('function');
401 |     });
402 |   });
403 | 
404 |   describe('Resource Logic Functionality', () => {
405 |     it('should return resource data successfully', async () => {
406 |       const mockExecutor = createMockExecutor({
407 |         success: true,
408 |         output: 'test data'
409 |       });
410 |       
411 |       // Test the logic function directly, not the handler
412 |       const result = await exampleResourceLogic(mockExecutor);
413 |       
414 |       expect(result.contents).toHaveLength(1);
415 |       expect(result.contents[0].text).toContain('expected data');
416 |     });
417 | 
418 |     it('should handle command execution errors', async () => {
419 |       const mockExecutor = createMockExecutor({
420 |         success: false,
421 |         error: 'Command failed'
422 |       });
423 |       
424 |       const result = await exampleResourceLogic(mockExecutor);
425 |       
426 |       expect(result.contents[0].text).toContain('Error retrieving');
427 |     });
428 |   });
429 | });
430 | ```
431 | 
432 | ### 4. Auto-Discovery
433 | 
434 | Resources are automatically discovered and loaded by the build system. After creating a resource:
435 | 
436 | 1. Run `npm run build` to regenerate resource loaders
437 | 2. The resource will be available at its URI for supported clients
438 | 
439 | ## Auto-Discovery System
440 | 
441 | ### How Auto-Discovery Works
442 | 
443 | 1. **Filesystem Scan**: `loadPlugins()` scans `src/mcp/tools/` directory
444 | 2. **Workflow Loading**: Each subdirectory is treated as a potential workflow group
445 | 3. **Metadata Validation**: `index.ts` files provide workflow metadata
446 | 4. **Tool Discovery**: All `.ts` files (except tests and index) are loaded as tools
447 | 5. **Registration**: Tools are automatically registered with the MCP server
448 | 
449 | ### Discovery Process
450 | 
451 | ```typescript
452 | // Simplified discovery flow
453 | const plugins = await loadPlugins();
454 | for (const plugin of plugins.values()) {
455 |   server.tool(plugin.name, plugin.description, plugin.schema, plugin.handler);
456 | }
457 | ```
458 | 
459 | ### Dynamic Mode Integration
460 | 
461 | When `XCODEBUILDMCP_DYNAMIC_TOOLS=true`:
462 | 
463 | 1. Only `discover_tools` is loaded initially
464 | 2. User provides task description to `discover_tools`
465 | 3. AI analyzes task and selects relevant workflow groups
466 | 4. Selected workflows are dynamically enabled via `enableWorkflows()`
467 | 5. Client is notified of new available tools
468 | 
469 | #### Environment Configuration
470 | 
471 | - **Static Mode** (default): `XCODEBUILDMCP_DYNAMIC_TOOLS=false` or unset
472 | - **Dynamic Mode**: `XCODEBUILDMCP_DYNAMIC_TOOLS=true`
473 | - **Debug Mode**: `XCODEBUILDMCP_DEBUG=true`
474 | 
475 | **Note**: The previous system of enabling individual tools and groups via `XCODEBUILDMCP_TOOL_*` and `XCODEBUILDMCP_GROUP_*` environment variables is no longer supported. The server now operates in either static or dynamic mode.
476 | 
477 | ## Testing Guidelines
478 | 
479 | ### Test Organization
480 | 
481 | ```
482 | __tests__/
483 | ├── index.test.ts              # Workflow metadata tests (canonical groups only)
484 | ├── re-exports.test.ts         # Re-export validation (project/workspace groups)
485 | └── tool_name.test.ts          # Individual tool tests
486 | ```
487 | 
488 | ### Dependency Injection Testing
489 | 
490 | **✅ CORRECT Pattern:**
491 | ```typescript
492 | import { createMockExecutor } from '../../../utils/test-common.js';
493 | 
494 | describe('build_sim_name_ws', () => {
495 |   it('should build successfully', async () => {
496 |     const mockExecutor = createMockExecutor({
497 |       success: true,
498 |       output: 'BUILD SUCCEEDED'
499 |     });
500 | 
501 |     const result = await build_sim_name_wsLogic(params, mockExecutor);
502 |     expect(result.isError).toBe(false);
503 |   });
504 | });
505 | ```
506 | 
507 | **❌ FORBIDDEN Pattern (Vitest Mocking Banned):**
508 | ```typescript
509 | // ❌ ALL VITEST MOCKING IS COMPLETELY BANNED
510 | vi.mock('child_process');
511 | const mockSpawn = vi.fn();
512 | ```
513 | 
514 | ### Three-Dimensional Testing
515 | 
516 | Every tool test must cover:
517 | 
518 | 1. **Input Validation**: Parameter schema validation and error cases
519 | 2. **Command Generation**: Verify correct CLI commands are built
520 | 3. **Output Processing**: Test response formatting and error handling
521 | 
522 | ### Test Template
523 | 
524 | ```typescript
525 | import { describe, it, expect } from 'vitest';
526 | import { createMockExecutor } from '../../../utils/test-common.js';
527 | import tool, { toolNameLogic } from '../tool_name.js';
528 | 
529 | describe('tool_name', () => {
530 |   describe('Export Validation', () => {
531 |     it('should export correct name', () => {
532 |       expect(tool.name).toBe('tool_name');
533 |     });
534 | 
535 |     it('should export correct description', () => {
536 |       expect(tool.description).toContain('Expected description');
537 |     });
538 | 
539 |     it('should export handler function', () => {
540 |       expect(typeof tool.handler).toBe('function');
541 |     });
542 |   });
543 | 
544 |   describe('Parameter Validation', () => {
545 |     it('should validate required parameters', async () => {
546 |       const mockExecutor = createMockExecutor({ success: true, output: '' });
547 |       
548 |       const result = await toolNameLogic({}, mockExecutor);
549 |       
550 |       expect(result.isError).toBe(true);
551 |       expect(result.content[0].text).toContain("Required parameter");
552 |     });
553 |   });
554 | 
555 |   describe('Command Generation', () => {
556 |     it('should generate correct command', async () => {
557 |       const mockExecutor = createMockExecutor({ success: true, output: 'SUCCESS' });
558 |       
559 |       await toolNameLogic({ param: 'value' }, mockExecutor);
560 |       
561 |       expect(mockExecutor).toHaveBeenCalledWith(
562 |         expect.arrayContaining(['expected', 'command']),
563 |         expect.any(String),
564 |         expect.any(Boolean)
565 |       );
566 |     });
567 |   });
568 | 
569 |   describe('Response Processing', () => {
570 |     it('should handle successful execution', async () => {
571 |       const mockExecutor = createMockExecutor({ success: true, output: 'SUCCESS' });
572 |       
573 |       const result = await toolNameLogic({ param: 'value' }, mockExecutor);
574 |       
575 |       expect(result.isError).toBe(false);
576 |       expect(result.content[0].text).toContain('✅');
577 |     });
578 | 
579 |     it('should handle execution errors', async () => {
580 |       const mockExecutor = createMockExecutor({ success: false, error: 'Command failed' });
581 |       
582 |       const result = await toolNameLogic({ param: 'value' }, mockExecutor);
583 |       
584 |       expect(result.isError).toBe(true);
585 |       expect(result.content[0].text).toContain('Command failed');
586 |     });
587 |   });
588 | });
589 | ```
590 | 
591 | ## Development Workflow
592 | 
593 | ### Adding a New Tool
594 | 
595 | 1. **Choose Directory**: Select appropriate workflow group or create new one
596 | 2. **Create Tool File**: Follow naming convention and structure
597 | 3. **Implement Logic**: Use dependency injection pattern
598 | 4. **Define Schema**: Add comprehensive Zod validation
599 | 5. **Write Tests**: Cover all three dimensions
600 | 6. **Test Integration**: Build and verify auto-discovery
601 | 
602 | ### Step-by-Step Tool Creation
603 | 
604 | ```bash
605 | # 1. Create tool file
606 | touch src/mcp/tools/simulator-workspace/my_new_tool_ws.ts
607 | 
608 | # 2. Implement tool following patterns above
609 | 
610 | # 3. Create test file
611 | touch src/mcp/tools/simulator-workspace/__tests__/my_new_tool_ws.test.ts
612 | 
613 | # 4. Build project
614 | npm run build
615 | 
616 | # 5. Verify tool is discovered (should appear in tools list)
617 | npm run inspect  # Use MCP Inspector to verify
618 | ```
619 | 
620 | ### Adding a New Workflow Group
621 | 
622 | 1. **Create Directory**: Follow naming convention
623 | 2. **Add Workflow Metadata**: Create `index.ts` with workflow export
624 | 3. **Implement Tools**: Add tool files following patterns
625 | 4. **Create Tests**: Add comprehensive test coverage
626 | 5. **Verify Discovery**: Test auto-discovery and dynamic mode
627 | 
628 | ### Step-by-Step Workflow Creation
629 | 
630 | ```bash
631 | # 1. Create workflow directory
632 | mkdir src/mcp/tools/my-new-workflow
633 | 
634 | # 2. Create workflow metadata
635 | cat > src/mcp/tools/my-new-workflow/index.ts << 'EOF'
636 | export const workflow = {
637 |   name: 'My New Workflow',
638 |   description: 'Description of workflow capabilities',
639 |   platforms: ['iOS'],
640 |   targets: ['simulator'],
641 |   projectTypes: ['workspace'],
642 |   capabilities: ['build', 'test'],
643 | };
644 | EOF
645 | 
646 | # 3. Create tools directory and test directory
647 | mkdir src/mcp/tools/my-new-workflow/__tests__
648 | 
649 | # 4. Implement tools following patterns
650 | 
651 | # 5. Build and verify
652 | npm run build
653 | npm run inspect
654 | ```
655 | 
656 | ## Best Practices
657 | 
658 | ### Tool Design
659 | 
660 | 1. **Single Responsibility**: Each tool should have one clear purpose
661 | 2. **Descriptive Names**: Follow naming conventions for discoverability
662 | 3. **Clear Descriptions**: Include usage examples in tool descriptions
663 | 4. **Comprehensive Validation**: Validate all parameters with helpful error messages
664 | 5. **Consistent Responses**: Use utility functions for response formatting
665 | 
666 | ### Error Handling
667 | 
668 | 1. **Graceful Failures**: Always return ToolResponse, never throw from handlers
669 | 2. **Descriptive Errors**: Provide actionable error messages
670 | 3. **Error Types**: Use appropriate error types for different scenarios
671 | 4. **Logging**: Log important events and errors for debugging
672 | 
673 | ### Testing
674 | 
675 | 1. **Dependency Injection**: Always test with mock executors
676 | 2. **Complete Coverage**: Test all input, command, and output scenarios
677 | 3. **Literal Assertions**: Use exact string expectations to catch changes
678 | 4. **Fast Execution**: Tests should complete quickly without real system calls
679 | 
680 | ### Workflow Organization  
681 | 
682 | 1. **End-to-End Workflows**: Groups should provide complete functionality
683 | 2. **Logical Grouping**: Group related tools together
684 | 3. **Clear Capabilities**: Document what each workflow can accomplish
685 | 4. **Consistent Patterns**: Follow established patterns for maintainability
686 | 
687 | ### Dynamic Mode Considerations
688 | 
689 | 1. **Workflow Completeness**: Each group should be self-sufficient
690 | 2. **Clear Descriptions**: AI uses descriptions to select workflows
691 | 3. **Platform Clarity**: Make supported platforms and targets obvious
692 | 4. **Capability Documentation**: List all workflow capabilities clearly
693 | 
694 | ## Integration with Dynamic Discovery
695 | 
696 | When creating new tools and workflows, consider:
697 | 
698 | 1. **AI Selection**: How will the AI understand when to select your workflow?
699 | 2. **Description Quality**: Is your workflow description clear for AI analysis?
700 | 3. **Platform Targeting**: Are platform and target requirements obvious?
701 | 4. **Workflow Completeness**: Does the workflow provide end-to-end functionality?
702 | 
703 | The auto-discovery system makes your tools immediately available, while the dynamic mode allows AI to intelligently select relevant workflows based on user tasks. Following these patterns ensures seamless integration with both systems.
704 | 
705 | ## Updating TOOLS.md Documentation
706 | 
707 | ### Critical Documentation Maintenance
708 | 
709 | **Every time you add, change, move, edit, or delete a tool, you MUST review and update the `docs/TOOLS.md` file to reflect the current state of the codebase.**
710 | 
711 | ### Documentation Update Process
712 | 
713 | #### 1. Use Tree CLI for Accurate Discovery
714 | 
715 | **Always use the `tree` command to get the actual filesystem representation of tools:**
716 | 
717 | ```bash
718 | # Get the definitive source of truth for all workflow groups and tools
719 | tree src/mcp/tools/ -I "__tests__" -I "*.test.ts"
720 | ```
721 | 
722 | This command:
723 | - Shows ALL workflow directories and their tools
724 | - Excludes test files (`__tests__` directories and `*.test.ts` files)
725 | - Provides the actual proof of what exists in the codebase
726 | - Gives an accurate count of tools per workflow group
727 | 
728 | #### 2. Ignore Shared Groups in Documentation
729 | 
730 | When updating `docs/TOOLS.md`:
731 | 
732 | - **Ignore `*-shared` directories** (e.g., `simulator-shared`, `device-shared`, `macos-shared`)
733 | - These are implementation details, not user-facing workflow groups
734 | - Only document the main workflow groups that users interact with
735 | - The group count should exclude shared groups
736 | 
737 | #### 3. List Actual Tool Names
738 | 
739 | Instead of using generic descriptions like "Additional Tools: Simulator management, logging, UI testing tools":
740 | 
741 | **❌ Wrong:**
742 | ```markdown
743 | - **Additional Tools**: Simulator management, logging, UI testing tools
744 | ```
745 | 
746 | **✅ Correct:**
747 | ```markdown
748 | - `boot_sim`, `install_app_sim`, `launch_app_sim`, `list_sims`, `open_sim`
749 | - `describe_ui`, `screenshot`, `start_sim_log_cap`, `stop_sim_log_cap`
750 | ```
751 | 
752 | #### 4. Systematic Documentation Update Steps
753 | 
754 | 1. **Run the tree command** to get current filesystem state
755 | 2. **Identify all non-shared workflow directories** 
756 | 3. **Count actual tool files** in each directory (exclude `index.ts` and test files)
757 | 4. **List all tool names** explicitly in the documentation
758 | 5. **Update tool counts** to reflect actual numbers
759 | 6. **Verify consistency** between filesystem and documentation
760 | 
761 | #### 5. Documentation Formatting Requirements
762 | 
763 | **Format: One Tool Per Bullet Point with Description**
764 | 
765 | Each tool must be listed individually with its actual description from the tool file:
766 | 
767 | ```markdown
768 | ### 1. My Awesome Workflow (`my-awesome-workflow`)
769 | **Purpose**: A short description of what this workflow is for. (2 tools)
770 | - `my_tool_one` - Description for my_tool_one from its definition file.
771 | - `my_tool_two` - Description for my_tool_two from its definition file.
772 | ```
773 | 
774 | **Description Sources:**
775 | - Use the actual `description` field from each tool's TypeScript file
776 | - Descriptions should be concise but informative for end users
777 | - Include platform/context information (iOS, macOS, simulator, device, etc.)
778 | - Mention required parameters when critical for usage
779 | 
780 | #### 6. Validation Checklist
781 | 
782 | After updating `docs/TOOLS.md`:
783 | 
784 | - [ ] Tool counts match actual filesystem counts (from tree command)
785 | - [ ] Each tool has its own bullet point (one tool per line)
786 | - [ ] Each tool includes its actual description from the tool file
787 | - [ ] No generic descriptions like "Additional Tools: X, Y, Z"
788 | - [ ] Descriptions are user-friendly and informative
789 | - [ ] Shared groups (`*-shared`) are not included in main workflow list
790 | - [ ] Workflow group count reflects only user-facing groups (15 groups)
791 | - [ ] Tree command output was used as source of truth
792 | - [ ] Documentation is user-focused, not implementation-focused
793 | - [ ] Tool names are in alphabetical order within each workflow group
794 | 
795 | ### Why This Process Matters
796 | 
797 | 1. **Accuracy**: Tree command provides definitive proof of current state
798 | 2. **Maintainability**: Systematic process prevents documentation drift
799 | 3. **User Experience**: Accurate documentation helps users understand available tools
800 | 4. **Development Confidence**: Developers can trust the documentation reflects reality
801 | 
802 | **Remember**: The filesystem is the source of truth. Documentation must always reflect the actual codebase structure, and the tree command is the most reliable way to ensure accuracy.
```

--------------------------------------------------------------------------------
/docs/MANUAL_TESTING.md:
--------------------------------------------------------------------------------

```markdown
  1 | # XcodeBuildMCP Manual Testing Guidelines
  2 | 
  3 | This document provides comprehensive guidelines for manual black-box testing of XcodeBuildMCP using Reloaderoo inspect commands. This is the authoritative guide for validating all tools through the Model Context Protocol interface.
  4 | 
  5 | ## Table of Contents
  6 | 
  7 | 1. [Testing Philosophy](#testing-philosophy)
  8 | 2. [Black Box Testing via Reloaderoo](#black-box-testing-via-reloaderoo)
  9 | 3. [Testing Psychology & Bias Prevention](#testing-psychology--bias-prevention)
 10 | 4. [Tool Dependency Graph Testing Strategy](#tool-dependency-graph-testing-strategy)
 11 | 5. [Prerequisites](#prerequisites)
 12 | 6. [Step-by-Step Testing Process](#step-by-step-testing-process)
 13 | 7. [Error Testing](#error-testing)
 14 | 8. [Testing Report Generation](#testing-report-generation)
 15 | 9. [Troubleshooting](#troubleshooting)
 16 | 
 17 | ## Testing Philosophy
 18 | 
 19 | ### 🚨 CRITICAL: THOROUGHNESS OVER EFFICIENCY - NO SHORTCUTS ALLOWED
 20 | 
 21 | **ABSOLUTE PRINCIPLE: EVERY TOOL MUST BE TESTED INDIVIDUALLY**
 22 | 
 23 | **🚨 MANDATORY TESTING SCOPE - NO EXCEPTIONS:**
 24 | - **EVERY SINGLE TOOL** - All tools must be tested individually, one by one
 25 | - **NO REPRESENTATIVE SAMPLING** - Testing similar tools does NOT validate other tools
 26 | - **NO PATTERN RECOGNITION SHORTCUTS** - Similar-looking tools may have different behaviors
 27 | - **NO EFFICIENCY OPTIMIZATIONS** - Thoroughness is more important than speed
 28 | - **NO TIME CONSTRAINTS** - This is a long-running task with no deadline pressure
 29 | 
 30 | **❌ FORBIDDEN EFFICIENCY SHORTCUTS:**
 31 | - **NEVER** assume testing `build_sim_id_proj` validates `build_sim_name_proj`
 32 | - **NEVER** skip tools because they "look similar" to tested ones
 33 | - **NEVER** use representative sampling instead of complete coverage
 34 | - **NEVER** stop testing due to time concerns or perceived redundancy
 35 | - **NEVER** group tools together for batch testing
 36 | - **NEVER** make assumptions about untested tools based on tested patterns
 37 | 
 38 | **✅ REQUIRED COMPREHENSIVE APPROACH:**
 39 | 1. **Individual Tool Testing**: Each tool gets its own dedicated test execution
 40 | 2. **Complete Documentation**: Every tool result must be recorded, regardless of outcome
 41 | 3. **Systematic Progress**: Use TodoWrite to track every single tool as tested/untested
 42 | 4. **Failure Documentation**: Test tools that cannot work and mark them as failed/blocked
 43 | 5. **No Assumptions**: Treat each tool as potentially unique requiring individual validation
 44 | 
 45 | **TESTING COMPLETENESS VALIDATION:**
 46 | - **Start Count**: Record exact number of tools discovered using `npm run tools`
 47 | - **End Count**: Verify same number of tools have been individually tested
 48 | - **Missing Tools = Testing Failure**: If any tools remain untested, the testing is incomplete
 49 | - **TodoWrite Tracking**: Every tool must appear in todo list and be marked completed
 50 | 
 51 | ## Black Box Testing via Reloaderoo
 52 | 
 53 | ### 🚨 CRITICAL: Black Box Testing via Reloaderoo Inspect
 54 | 
 55 | **DEFINITION: Black Box Testing**
 56 | Black Box Testing means testing ONLY through external interfaces without any knowledge of internal implementation. For XcodeBuildMCP, this means testing exclusively through the Model Context Protocol (MCP) interface using Reloaderoo as the MCP client.
 57 | 
 58 | **🚨 MANDATORY: RELOADEROO INSPECT IS THE ONLY ALLOWED TESTING METHOD**
 59 | 
 60 | **ABSOLUTE TESTING RULES - NO EXCEPTIONS:**
 61 | 
 62 | 1. **✅ ONLY ALLOWED: Reloaderoo Inspect Commands**
 63 |    - `npx reloaderoo@latest inspect call-tool "TOOL_NAME" --params 'JSON' -- node build/index.js`
 64 |    - `npx reloaderoo@latest inspect list-tools -- node build/index.js`
 65 |    - `npx reloaderoo@latest inspect read-resource "URI" -- node build/index.js`
 66 |    - `npx reloaderoo@latest inspect server-info -- node build/index.js`
 67 |    - `npx reloaderoo@latest inspect ping -- node build/index.js`
 68 | 
 69 | 2. **❌ COMPLETELY FORBIDDEN ACTIONS:**
 70 |    - **NEVER** call `mcp__XcodeBuildMCP__tool_name()` functions directly
 71 |    - **NEVER** use MCP server tools as if they were native functions
 72 |    - **NEVER** access internal server functionality
 73 |    - **NEVER** read source code to understand how tools work
 74 |    - **NEVER** examine implementation files during testing
 75 |    - **NEVER** diagnose internal server issues or registration problems
 76 |    - **NEVER** suggest code fixes or implementation changes
 77 | 
 78 | 3. **🚨 CRITICAL VIOLATION EXAMPLES:**
 79 |    ```typescript
 80 |    // ❌ FORBIDDEN - Direct MCP tool calls
 81 |    await mcp__XcodeBuildMCP__list_devices();
 82 |    await mcp__XcodeBuildMCP__build_sim_id_proj({ ... });
 83 |    
 84 |    // ❌ FORBIDDEN - Using tools as native functions
 85 |    const devices = await list_devices();
 86 |    const result = await doctor();
 87 |    
 88 |    // ✅ CORRECT - Only through Reloaderoo inspect
 89 |    npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js
 90 |    npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js
 91 |    ```
 92 | 
 93 | **WHY RELOADEROO INSPECT IS MANDATORY:**
 94 | - **Higher Fidelity**: Provides clear input/output visibility for each tool call
 95 | - **Real-world Simulation**: Tests exactly how MCP clients interact with the server
 96 | - **Interface Validation**: Ensures MCP protocol compliance and proper JSON formatting
 97 | - **Black Box Enforcement**: Prevents accidental access to internal implementation details
 98 | - **Clean State**: Each tool call runs with a fresh MCP server instance, preventing cross-contamination
 99 | 
100 | **IMPORTANT: STATEFUL TOOL LIMITATIONS**
101 | 
102 | **Reloaderoo Inspect Behavior:**
103 | Reloaderoo starts a fresh MCP server instance for each individual tool call and terminates it immediately after the response. This ensures:
104 | - ✅ **Clean Testing Environment**: No state contamination between tool calls
105 | - ✅ **Isolated Testing**: Each tool test is independent and repeatable
106 | - ✅ **Real-world Accuracy**: Simulates how most MCP clients interact with servers
107 | 
108 | **Expected False Negatives:**
109 | Some tools rely on in-memory state within the MCP server and will fail when tested via Reloaderoo inspect. These failures are **expected and acceptable** as false negatives:
110 | 
111 | - **`swift_package_stop`** - Requires in-memory process tracking from `swift_package_run`
112 | - **`stop_app_device`** - Requires in-memory process tracking from `launch_app_device`  
113 | - **`stop_app_sim`** - Requires in-memory process tracking from `launch_app_sim`
114 | - **`stop_device_log_cap`** - Requires in-memory session tracking from `start_device_log_cap`
115 | - **`stop_sim_log_cap`** - Requires in-memory session tracking from `start_sim_log_cap`
116 | - **`stop_mac_app`** - Requires in-memory process tracking from `launch_mac_app`
117 | 
118 | **Testing Protocol for Stateful Tools:**
119 | 1. **Test the tool anyway** - Execute the Reloaderoo inspect command
120 | 2. **Expect failure** - Tool will likely fail due to missing state
121 | 3. **Mark as false negative** - Document the failure as expected due to stateful limitations
122 | 4. **Continue testing** - Do not attempt to fix or investigate the failure
123 | 5. **Report as finding** - Note in testing report that stateful tools failed as expected
124 | 
125 | **COMPLETE COVERAGE REQUIREMENTS:**
126 | - ✅ **Test ALL tools individually** - No exceptions, every tool gets manual verification
127 | - ✅ **Follow dependency graphs** - Test tools in correct order based on data dependencies
128 | - ✅ **Capture key outputs** - Record UUIDs, paths, schemes needed by dependent tools
129 | - ✅ **Test real workflows** - Complete end-to-end workflows from discovery to execution
130 | - ✅ **Use tool-summary.js script** - Accurate tool/resource counting and discovery
131 | - ✅ **Document all observations** - Record exactly what you see via testing
132 | - ✅ **Report discrepancies as findings** - Note unexpected results without investigation
133 | 
134 | **MANDATORY INDIVIDUAL TOOL TESTING PROTOCOL:**
135 | 
136 | **Step 1: Create Complete Tool Inventory**
137 | ```bash
138 | # Use the official tool summary script to get accurate tool count and list
139 | npm run tools > /tmp/summary_output.txt
140 | TOTAL_TOOLS=$(grep "Tools:" /tmp/summary_output.txt | awk '{print $2}')
141 | echo "TOTAL TOOLS TO TEST: $TOTAL_TOOLS"
142 | 
143 | # Generate detailed tool list and extract tool names
144 | npm run tools:list > /tmp/tools_detailed.txt
145 | grep "^   • " /tmp/tools_detailed.txt | sed 's/^   • //' > /tmp/tool_names.txt
146 | ```
147 | 
148 | **Step 2: Create TodoWrite Task List for Every Tool**
149 | ```bash
150 | # Create individual todo items for each tool discovered
151 | # Use the actual tool count from step 1
152 | # Example for first few tools:
153 | # 1. [ ] Test tool: doctor  
154 | # 2. [ ] Test tool: list_devices
155 | # 3. [ ] Test tool: list_sims
156 | # ... (continue for ALL $TOTAL_TOOLS tools)
157 | ```
158 | 
159 | **Step 3: Test Each Tool Individually**
160 | For EVERY tool in the list:
161 | ```bash
162 | # Test each tool individually - NO BATCHING
163 | npx reloaderoo@latest inspect call-tool "TOOL_NAME" --params 'APPROPRIATE_PARAMS' -- node build/index.js
164 | 
165 | # Mark tool as completed in TodoWrite IMMEDIATELY after testing
166 | # Record result (success/failure/blocked) for each tool
167 | ```
168 | 
169 | **Step 4: Validate Complete Coverage**
170 | ```bash
171 | # Verify all tools tested
172 | COMPLETED_TOOLS=$(count completed todo items)
173 | if [ $COMPLETED_TOOLS -ne $TOTAL_TOOLS ]; then
174 |     echo "ERROR: Testing incomplete. $COMPLETED_TOOLS/$TOTAL_TOOLS tested"
175 |     exit 1
176 | fi
177 | ```
178 | 
179 | **CRITICAL: NO TOOL LEFT UNTESTED**
180 | - **Every tool name from the JSON list must be individually tested**
181 | - **Every tool must have a TodoWrite entry that gets marked completed**
182 | - **Tools that fail due to missing parameters should be tested anyway and marked as blocked**
183 | - **Tools that require setup (like running processes) should be tested and documented as requiring dependencies**
184 | - **NO ASSUMPTIONS**: Test tools even if they seem redundant or similar to others
185 | 
186 | **BLACK BOX TESTING ENFORCEMENT:**
187 | - ✅ **Test only through Reloaderoo MCP interface** - Simulates real-world MCP client usage
188 | - ✅ **Use task lists** - Track progress with TodoWrite tool for every single tool
189 | - ✅ **Tick off each tool** - Mark completed in task list after manual verification
190 | - ✅ **Manual oversight** - Human verification of each tool's input and output
191 | - ❌ **Never examine source code** - No reading implementation files during testing
192 | - ❌ **Never diagnose internal issues** - No investigation of build processes or tool registration
193 | - ❌ **Never suggest implementation fixes** - Report issues as findings, don't solve them
194 | - ❌ **Never use scripts for tool testing** - Each tool must be manually executed and verified
195 | 
196 | ## Testing Psychology & Bias Prevention
197 | 
198 | **COMMON ANTI-PATTERNS TO AVOID:**
199 | 
200 | **1. Efficiency Bias (FORBIDDEN)**
201 | - **Symptom**: "These tools look similar, I'll test one to validate the others"
202 | - **Correction**: Every tool is unique and must be tested individually
203 | - **Enforcement**: Count tools at start, verify same count tested at end
204 | 
205 | **2. Pattern Recognition Override (FORBIDDEN)**  
206 | - **Symptom**: "I see the pattern, the rest will work the same way"
207 | - **Correction**: Patterns may hide edge cases, bugs, or different implementations
208 | - **Enforcement**: No assumptions allowed, test every tool regardless of apparent similarity
209 | 
210 | **3. Time Pressure Shortcuts (FORBIDDEN)**
211 | - **Symptom**: "This is taking too long, let me speed up by sampling"
212 | - **Correction**: This is explicitly a long-running task with no time constraints
213 | - **Enforcement**: Thoroughness is the ONLY priority, efficiency is irrelevant
214 | 
215 | **4. False Confidence (FORBIDDEN)**
216 | - **Symptom**: "The architecture is solid, so all tools must work"
217 | - **Correction**: Architecture validation does not guarantee individual tool functionality
218 | - **Enforcement**: Test tools to discover actual issues, not to confirm assumptions
219 | 
220 | **MANDATORY MINDSET:**
221 | - **Every tool is potentially broken** until individually tested
222 | - **Every tool may have unique edge cases** not covered by similar tools
223 | - **Every tool deserves individual attention** regardless of apparent redundancy
224 | - **Testing completion means EVERY tool tested**, not "enough tools to validate patterns"
225 | - **The goal is discovering problems**, not confirming everything works
226 | 
227 | **TESTING COMPLETENESS CHECKLIST:**
228 | - [ ] Generated complete tool list using `npm run tools:list`
229 | - [ ] Created TodoWrite entry for every single tool
230 | - [ ] Tested every tool individually via Reloaderoo inspect
231 | - [ ] Marked every tool as completed in TodoWrite
232 | - [ ] Verified tool count: tested_count == total_count
233 | - [ ] Documented all results, including failures and blocked tools
234 | - [ ] Created final report covering ALL tools, not just successful ones
235 | 
236 | ## Tool Dependency Graph Testing Strategy
237 | 
238 | **CRITICAL: Tools must be tested in dependency order:**
239 | 
240 | 1. **Foundation Tools** (provide data for other tools):
241 |    - `doctor` - System info
242 |    - `list_devices` - Device UUIDs
243 |    - `list_sims` - Simulator UUIDs  
244 |    - `discover_projs` - Project/workspace paths
245 | 
246 | 2. **Discovery Tools** (provide metadata for build tools):
247 |    - `list_schemes` - Scheme names
248 |    - `show_build_settings` - Build settings
249 | 
250 | 3. **Build Tools** (create artifacts for install tools):
251 |    - `build_*` tools - Create app bundles
252 |    - `get_*_app_path_*` tools - Locate built app bundles
253 |    - `get_*_bundle_id` tools - Extract bundle IDs
254 | 
255 | 4. **Installation Tools** (depend on built artifacts):
256 |    - `install_app_*` tools - Install built apps
257 |    - `launch_app_*` tools - Launch installed apps
258 | 
259 | 5. **Testing Tools** (depend on projects/schemes):
260 |    - `test_*` tools - Run test suites
261 | 
262 | 6. **UI Automation Tools** (depend on running apps):
263 |    - `describe_ui`, `screenshot`, `tap`, etc.
264 | 
265 | **MANDATORY: Record Key Outputs**
266 | 
267 | Must capture and document these values for dependent tools:
268 | - **Device UUIDs** from `list_devices`
269 | - **Simulator UUIDs** from `list_sims`
270 | - **Project/workspace paths** from `discover_projs`
271 | - **Scheme names** from `list_schems_*`
272 | - **App bundle paths** from `get_*_app_path_*`
273 | - **Bundle IDs** from `get_*_bundle_id`
274 | 
275 | ## Prerequisites
276 | 
277 | 1. **Build the server**: `npm run build`
278 | 2. **Install jq**: `brew install jq` (required for JSON parsing)
279 | 3. **System Requirements**: macOS with Xcode installed, connected devices/simulators optional
280 | 
281 | ## Step-by-Step Testing Process
282 | 
283 | **Note**: All tool and resource discovery now uses the official `tool-summary.js` script (available as `npm run tools`, `npm run tools:list`, and `npm run tools:all`) instead of direct reloaderoo calls. This ensures accurate counts and lists without hardcoded values.
284 | 
285 | ### Step 1: Programmatic Discovery and Official Testing Lists
286 | 
287 | #### Generate Official Tool and Resource Lists using tool-summary.js
288 | 
289 | ```bash
290 | # Use the official tool summary script to get accurate counts and lists
291 | npm run tools > /tmp/summary_output.txt
292 | 
293 | # Extract tool and resource counts from summary
294 | TOOL_COUNT=$(grep "Tools:" /tmp/summary_output.txt | awk '{print $2}')
295 | RESOURCE_COUNT=$(grep "Resources:" /tmp/summary_output.txt | awk '{print $2}')
296 | echo "Official tool count: $TOOL_COUNT"
297 | echo "Official resource count: $RESOURCE_COUNT"
298 | 
299 | # Generate detailed tool list for testing checklist
300 | npm run tools:list > /tmp/tools_detailed.txt
301 | 
302 | # Extract tool names from the detailed output
303 | grep "^   • " /tmp/tools_detailed.txt | sed 's/^   • //' > /tmp/tool_names.txt
304 | echo "Tool names saved to /tmp/tool_names.txt"
305 | 
306 | # Generate detailed resource list for testing checklist  
307 | npm run tools:all > /tmp/tools_and_resources.txt
308 | 
309 | # Extract resource URIs from the detailed output
310 | sed -n '/📚 Available Resources:/,/✅ Tool summary complete!/p' /tmp/tools_and_resources.txt | grep "^   • " | sed 's/^   • //' | cut -d' ' -f1 > /tmp/resource_uris.txt
311 | echo "Resource URIs saved to /tmp/resource_uris.txt"
312 | ```
313 | 
314 | #### Create Tool Testing Checklist
315 | 
316 | ```bash
317 | # Generate markdown checklist from actual tool list
318 | echo "# Official Tool Testing Checklist" > /tmp/tool_testing_checklist.md
319 | echo "" >> /tmp/tool_testing_checklist.md
320 | echo "Total Tools: $TOOL_COUNT" >> /tmp/tool_testing_checklist.md
321 | echo "" >> /tmp/tool_testing_checklist.md
322 | 
323 | # Add each tool as unchecked item
324 | while IFS= read -r tool_name; do
325 |     echo "- [ ] $tool_name" >> /tmp/tool_testing_checklist.md
326 | done < /tmp/tool_names.txt
327 | 
328 | echo "Tool testing checklist created at /tmp/tool_testing_checklist.md"
329 | ```
330 | 
331 | #### Create Resource Testing Checklist
332 | 
333 | ```bash
334 | # Generate markdown checklist from actual resource list
335 | echo "# Official Resource Testing Checklist" > /tmp/resource_testing_checklist.md
336 | echo "" >> /tmp/resource_testing_checklist.md
337 | echo "Total Resources: $RESOURCE_COUNT" >> /tmp/resource_testing_checklist.md
338 | echo "" >> /tmp/resource_testing_checklist.md
339 | 
340 | # Add each resource as unchecked item
341 | while IFS= read -r resource_uri; do
342 |     echo "- [ ] $resource_uri" >> /tmp/resource_testing_checklist.md
343 | done < /tmp/resource_uris.txt
344 | 
345 | echo "Resource testing checklist created at /tmp/resource_testing_checklist.md"
346 | ```
347 | 
348 | ### Step 2: Tool Schema Discovery for Parameter Testing
349 | 
350 | #### Extract Tool Schema Information
351 | 
352 | ```bash
353 | # Get schema for specific tool to understand required parameters
354 | TOOL_NAME="list_devices"
355 | jq --arg tool "$TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema' /tmp/tools.json
356 | 
357 | # Get tool description for usage guidance
358 | jq --arg tool "$TOOL_NAME" '.tools[] | select(.name == $tool) | .description' /tmp/tools.json
359 | 
360 | # Generate parameter template for tool testing
361 | jq --arg tool "$TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema.properties // {}' /tmp/tools.json
362 | ```
363 | 
364 | #### Batch Schema Extraction
365 | 
366 | ```bash
367 | # Create schema reference file for all tools
368 | echo "# Tool Schema Reference" > /tmp/tool_schemas.md
369 | echo "" >> /tmp/tool_schemas.md
370 | 
371 | while IFS= read -r tool_name; do
372 |     echo "## $tool_name" >> /tmp/tool_schemas.md
373 |     echo "" >> /tmp/tool_schemas.md
374 |     
375 |     # Get description
376 |     description=$(jq -r --arg tool "$tool_name" '.tools[] | select(.name == $tool) | .description' /tmp/tools.json)
377 |     echo "**Description:** $description" >> /tmp/tool_schemas.md
378 |     echo "" >> /tmp/tool_schemas.md
379 |     
380 |     # Get required parameters
381 |     required=$(jq -r --arg tool "$tool_name" '.tools[] | select(.name == $tool) | .inputSchema.required // [] | join(", ")' /tmp/tools.json)
382 |     if [ "$required" != "" ]; then
383 |         echo "**Required Parameters:** $required" >> /tmp/tool_schemas.md
384 |     else
385 |         echo "**Required Parameters:** None" >> /tmp/tool_schemas.md
386 |     fi
387 |     echo "" >> /tmp/tool_schemas.md
388 |     
389 |     # Get all parameters
390 |     echo "**All Parameters:**" >> /tmp/tool_schemas.md
391 |     jq --arg tool "$tool_name" '.tools[] | select(.name == $tool) | .inputSchema.properties // {} | keys[]' /tmp/tools.json | while read param; do
392 |         echo "- $param" >> /tmp/tool_schemas.md
393 |     done
394 |     echo "" >> /tmp/tool_schemas.md
395 |     
396 | done < /tmp/tool_names.txt
397 | 
398 | echo "Tool schema reference created at /tmp/tool_schemas.md"
399 | ```
400 | 
401 | ### Step 3: Manual Tool-by-Tool Testing
402 | 
403 | #### 🚨 CRITICAL: STEP-BY-STEP BLACK BOX TESTING PROCESS
404 | 
405 | **ABSOLUTE RULE: ALL TESTING MUST BE DONE MANUALLY, ONE TOOL AT A TIME USING RELOADEROO INSPECT**
406 | 
407 | **SYSTEMATIC TESTING PROCESS:**
408 | 
409 | 1. **Create TodoWrite Task List**
410 |    - Add all tools (from `npm run tools` count) to task list before starting
411 |    - Mark each tool as "pending" initially
412 |    - Update status to "in_progress" when testing begins
413 |    - Mark "completed" only after manual verification
414 | 
415 | 2. **Test Each Tool Individually**
416 |    - Execute ONLY via `npx reloaderoo@latest inspect call-tool "TOOL_NAME" --params 'JSON' -- node build/index.js`
417 |    - Wait for complete response before proceeding to next tool
418 |    - Read and verify each tool's output manually
419 |    - Record key outputs (UUIDs, paths, schemes) for dependent tools
420 | 
421 | 3. **Manual Verification Requirements**
422 |    - ✅ **Read each response** - Manually verify tool output makes sense
423 |    - ✅ **Check for errors** - Identify any tool failures or unexpected responses  
424 |    - ✅ **Record UUIDs/paths** - Save outputs needed for dependent tools
425 |    - ✅ **Update task list** - Mark each tool complete after verification
426 |    - ✅ **Document issues** - Record any problems found during testing
427 | 
428 | 4. **FORBIDDEN SHORTCUTS:**
429 |    - ❌ **NO SCRIPTS** - Scripts hide what's happening and prevent proper verification
430 |    - ❌ **NO AUTOMATION** - Every tool call must be manually executed and verified
431 |    - ❌ **NO BATCHING** - Cannot test multiple tools simultaneously
432 |    - ❌ **NO MCP DIRECT CALLS** - Only Reloaderoo inspect commands allowed
433 | 
434 | #### Phase 1: Infrastructure Validation
435 | 
436 | **Manual Commands (execute individually):**
437 | 
438 | ```bash
439 | # Test server connectivity
440 | npx reloaderoo@latest inspect ping -- node build/index.js
441 | 
442 | # Get server information  
443 | npx reloaderoo@latest inspect server-info -- node build/index.js
444 | 
445 | # Verify tool count manually
446 | npx reloaderoo@latest inspect list-tools -- node build/index.js 2>/dev/null | jq '.tools | length'
447 | 
448 | # Verify resource count manually
449 | npx reloaderoo@latest inspect list-resources -- node build/index.js 2>/dev/null | jq '.resources | length'
450 | ```
451 | 
452 | #### Phase 2: Resource Testing
453 | 
454 | ```bash
455 | # Test each resource systematically
456 | while IFS= read -r resource_uri; do
457 |     echo "Testing resource: $resource_uri"
458 |     npx reloaderoo@latest inspect read-resource "$resource_uri" -- node build/index.js 2>/dev/null
459 |     echo "---"
460 | done < /tmp/resource_uris.txt
461 | ```
462 | 
463 | #### Phase 3: Foundation Tools (Data Collection)
464 | 
465 | **CRITICAL: Capture ALL key outputs for dependent tools**
466 | 
467 | ```bash
468 | echo "=== FOUNDATION TOOL TESTING & DATA COLLECTION ==="
469 | 
470 | # 1. Test doctor (no dependencies)
471 | echo "Testing doctor..."
472 | npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js 2>/dev/null
473 | 
474 | # 2. Collect device data
475 | echo "Collecting device UUIDs..."
476 | npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js 2>/dev/null > /tmp/devices_output.json
477 | DEVICE_UUIDS=$(jq -r '.content[0].text' /tmp/devices_output.json | grep -E "UDID: [A-F0-9-]+" | sed 's/.*UDID: //' | head -2)
478 | echo "Device UUIDs captured: $DEVICE_UUIDS"
479 | 
480 | # 3. Collect simulator data  
481 | echo "Collecting simulator UUIDs..."
482 | npx reloaderoo@latest inspect call-tool "list_sims" --params '{}' -- node build/index.js 2>/dev/null > /tmp/sims_output.json
483 | SIMULATOR_UUIDS=$(jq -r '.content[0].text' /tmp/sims_output.json | grep -E "\([A-F0-9-]+\)" | sed 's/.*(\([A-F0-9-]*\)).*/\1/' | head -3)
484 | echo "Simulator UUIDs captured: $SIMULATOR_UUIDS"
485 | 
486 | # 4. Collect project data
487 | echo "Collecting project paths..."
488 | npx reloaderoo@latest inspect call-tool "discover_projs" --params '{"workspaceRoot": "/Volumes/Developer/XcodeBuildMCP"}' -- node build/index.js 2>/dev/null > /tmp/projects_output.json
489 | PROJECT_PATHS=$(jq -r '.content[1].text' /tmp/projects_output.json | grep -E "\.xcodeproj$" | sed 's/.*- //' | head -3)
490 | WORKSPACE_PATHS=$(jq -r '.content[2].text' /tmp/projects_output.json | grep -E "\.xcworkspace$" | sed 's/.*- //' | head -2)
491 | echo "Project paths captured: $PROJECT_PATHS"
492 | echo "Workspace paths captured: $WORKSPACE_PATHS"
493 | 
494 | # Save key data for dependent tools
495 | echo "$DEVICE_UUIDS" > /tmp/device_uuids.txt
496 | echo "$SIMULATOR_UUIDS" > /tmp/simulator_uuids.txt  
497 | echo "$PROJECT_PATHS" > /tmp/project_paths.txt
498 | echo "$WORKSPACE_PATHS" > /tmp/workspace_paths.txt
499 | ```
500 | 
501 | #### Phase 4: Discovery Tools (Metadata Collection)
502 | 
503 | ```bash
504 | echo "=== DISCOVERY TOOL TESTING & METADATA COLLECTION ==="
505 | 
506 | # Collect schemes for each project
507 | while IFS= read -r project_path; do
508 |     if [ -n "$project_path" ]; then
509 |         echo "Getting schemes for: $project_path"
510 |         npx reloaderoo@latest inspect call-tool "list_schems_proj" --params "{\"projectPath\": \"$project_path\"}" -- node build/index.js 2>/dev/null > /tmp/schemes_$$.json
511 |         SCHEMES=$(jq -r '.content[1].text' /tmp/schemes_$$.json 2>/dev/null || echo "NoScheme")
512 |         echo "$project_path|$SCHEMES" >> /tmp/project_schemes.txt
513 |         echo "Schemes captured for $project_path: $SCHEMES"
514 |     fi
515 | done < /tmp/project_paths.txt
516 | 
517 | # Collect schemes for each workspace
518 | while IFS= read -r workspace_path; do
519 |     if [ -n "$workspace_path" ]; then
520 |         echo "Getting schemes for: $workspace_path"
521 |         npx reloaderoo@latest inspect call-tool "list_schemes" --params "{\"workspacePath\": \"$workspace_path\"}" -- node build/index.js 2>/dev/null > /tmp/ws_schemes_$$.json
522 |         SCHEMES=$(jq -r '.content[1].text' /tmp/ws_schemes_$$.json 2>/dev/null || echo "NoScheme")
523 |         echo "$workspace_path|$SCHEMES" >> /tmp/workspace_schemes.txt
524 |         echo "Schemes captured for $workspace_path: $SCHEMES"
525 |     fi
526 | done < /tmp/workspace_paths.txt
527 | ```
528 | 
529 | #### Phase 5: Manual Individual Tool Testing (All Tools)
530 | 
531 | **CRITICAL: Test every single tool manually, one at a time**
532 | 
533 | **Manual Testing Process:**
534 | 
535 | 1. **Create task list** with TodoWrite tool for all tools (using count from `npm run tools`)
536 | 2. **Test each tool individually** with proper parameters
537 | 3. **Mark each tool complete** in task list after manual verification
538 | 4. **Record results** and observations for each tool
539 | 5. **NO SCRIPTS** - Each command executed manually
540 | 
541 | **STEP-BY-STEP MANUAL TESTING COMMANDS:**
542 | 
543 | ```bash
544 | # STEP 1: Test foundation tools (no parameters required)
545 | # Execute each command individually, wait for response, verify manually
546 | npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js
547 | # [Wait for response, read output, mark tool complete in task list]
548 | 
549 | npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js
550 | # [Record device UUIDs from response for dependent tools]
551 | 
552 | npx reloaderoo@latest inspect call-tool "list_sims" --params '{}' -- node build/index.js
553 | # [Record simulator UUIDs from response for dependent tools]
554 | 
555 | # STEP 2: Test project discovery (use discovered project paths)
556 | npx reloaderoo@latest inspect call-tool "list_schems_proj" --params '{"projectPath": "/actual/path/from/discover_projs.xcodeproj"}' -- node build/index.js
557 | # [Record scheme names from response for build tools]
558 | 
559 | # STEP 3: Test workspace tools (use discovered workspace paths)  
560 | npx reloaderoo@latest inspect call-tool "list_schemes" --params '{"workspacePath": "/actual/path/from/discover_projs.xcworkspace"}' -- node build/index.js
561 | # [Record scheme names from response for build tools]
562 | 
563 | # STEP 4: Test simulator tools (use captured simulator UUIDs from step 1)
564 | npx reloaderoo@latest inspect call-tool "boot_sim" --params '{"simulatorUuid": "ACTUAL_UUID_FROM_LIST_SIMS"}' -- node build/index.js
565 | # [Verify simulator boots successfully]
566 | 
567 | # STEP 5: Test build tools (requires project + scheme + simulator from previous steps)
568 | npx reloaderoo@latest inspect call-tool "build_sim_id_proj" --params '{"projectPath": "/actual/project.xcodeproj", "scheme": "ActualSchemeName", "simulatorId": "ACTUAL_SIMULATOR_UUID"}' -- node build/index.js
569 | # [Verify build succeeds and record app bundle path]
570 | ```
571 | 
572 | **CRITICAL: EACH COMMAND MUST BE:**
573 | 1. **Executed individually** - One command at a time, manually typed or pasted
574 | 2. **Verified manually** - Read the complete response before continuing
575 | 3. **Tracked in task list** - Mark tool complete only after verification
576 | 4. **Use real data** - Replace placeholder values with actual captured data
577 | 5. **Wait for completion** - Allow each command to finish before proceeding
578 | 
579 | ### TESTING VIOLATIONS AND ENFORCEMENT
580 | 
581 | **🚨 CRITICAL VIOLATIONS THAT WILL TERMINATE TESTING:**
582 | 
583 | 1. **Direct MCP Tool Usage Violation:**
584 |    ```typescript
585 |    // ❌ IMMEDIATE TERMINATION - Using MCP tools directly
586 |    await mcp__XcodeBuildMCP__list_devices();
587 |    const result = await list_sims();
588 |    ```
589 | 
590 | 2. **Script-Based Testing Violation:**
591 |    ```bash
592 |    # ❌ IMMEDIATE TERMINATION - Using scripts to test tools
593 |    for tool in $(cat tool_list.txt); do
594 |      npx reloaderoo inspect call-tool "$tool" --params '{}' -- node build/index.js
595 |    done
596 |    ```
597 | 
598 | 3. **Batching/Automation Violation:**
599 |    ```bash
600 |    # ❌ IMMEDIATE TERMINATION - Testing multiple tools simultaneously
601 |    npx reloaderoo inspect call-tool "list_devices" & npx reloaderoo inspect call-tool "list_sims" &
602 |    ```
603 | 
604 | 4. **Source Code Examination Violation:**
605 |    ```typescript
606 |    // ❌ IMMEDIATE TERMINATION - Reading implementation during testing
607 |    const toolImplementation = await Read('/src/mcp/tools/device-shared/list_devices.ts');
608 |    ```
609 | 
610 | **ENFORCEMENT PROCEDURE:**
611 | 1. **First Violation**: Immediate correction and restart of testing process
612 | 2. **Documentation Update**: Add explicit prohibition to prevent future violations  
613 | 3. **Method Validation**: Ensure all future testing uses only Reloaderoo inspect commands
614 | 4. **Progress Reset**: Restart testing from foundation tools if direct MCP usage detected
615 | 
616 | **VALID TESTING SEQUENCE EXAMPLE:**
617 | ```bash
618 | # ✅ CORRECT - Step-by-step manual execution via Reloaderoo
619 | # Tool 1: Test doctor
620 | npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js
621 | # [Read response, verify, mark complete in TodoWrite]
622 | 
623 | # Tool 2: Test list_devices  
624 | npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js
625 | # [Read response, capture UUIDs, mark complete in TodoWrite]
626 | 
627 | # Tool 3: Test list_sims
628 | npx reloaderoo@latest inspect call-tool "list_sims" --params '{}' -- node build/index.js
629 | # [Read response, capture UUIDs, mark complete in TodoWrite]
630 | 
631 | # Tool X: Test stateful tool (expected to fail)
632 | npx reloaderoo@latest inspect call-tool "swift_package_stop" --params '{"pid": 12345}' -- node build/index.js
633 | # [Tool fails as expected - no in-memory state available]
634 | # [Mark as "false negative - stateful tool limitation" in TodoWrite]
635 | # [Continue to next tool without investigation]
636 | 
637 | # Continue individually for all tools (use count from npm run tools)...
638 | ```
639 | 
640 | **HANDLING STATEFUL TOOL FAILURES:**
641 | ```bash
642 | # ✅ CORRECT Response to Expected Stateful Tool Failure
643 | # Tool fails with "No process found" or similar state-related error
644 | # Response: Mark tool as "tested - false negative (stateful)" in task list
645 | # Do NOT attempt to diagnose, fix, or investigate the failure
646 | # Continue immediately to next tool in sequence
647 | ```
648 | 
649 | ## Error Testing
650 | 
651 | ```bash
652 | # Test error handling systematically
653 | echo "=== Error Testing ==="
654 | 
655 | # Test with invalid JSON parameters
656 | echo "Testing invalid parameter types..."
657 | npx reloaderoo@latest inspect call-tool list_schems_proj --params '{"projectPath": 123}' -- node build/index.js 2>/dev/null
658 | 
659 | # Test with non-existent paths
660 | echo "Testing non-existent paths..."
661 | npx reloaderoo@latest inspect call-tool list_schems_proj --params '{"projectPath": "/nonexistent/path.xcodeproj"}' -- node build/index.js 2>/dev/null
662 | 
663 | # Test with invalid UUIDs
664 | echo "Testing invalid UUIDs..."
665 | npx reloaderoo@latest inspect call-tool boot_sim --params '{"simulatorUuid": "invalid-uuid"}' -- node build/index.js 2>/dev/null
666 | ```
667 | 
668 | ## Testing Report Generation
669 | 
670 | ```bash
671 | # Create comprehensive testing session report
672 | cat > TESTING_SESSION_$(date +%Y-%m-%d).md << EOF
673 | # Manual Testing Session - $(date +%Y-%m-%d)
674 | 
675 | ## Environment
676 | - macOS Version: $(sw_vers -productVersion)
677 | - XcodeBuildMCP Version: $(jq -r '.version' package.json 2>/dev/null || echo "unknown")
678 | - Testing Method: Reloaderoo @latest via npx
679 | 
680 | ## Official Counts (Programmatically Verified)
681 | - Total Tools: $TOOL_COUNT
682 | - Total Resources: $RESOURCE_COUNT
683 | 
684 | ## Test Results
685 | [Document test results here]
686 | 
687 | ## Issues Found
688 | [Document any discrepancies or failures]
689 | 
690 | ## Performance Notes
691 | [Document response times and performance observations]
692 | EOF
693 | 
694 | echo "Testing session template created: TESTING_SESSION_$(date +%Y-%m-%d).md"
695 | ```
696 | 
697 | ### Key Commands Reference
698 | 
699 | ```bash
700 | # Essential testing commands
701 | npx reloaderoo@latest inspect ping -- node build/index.js
702 | npx reloaderoo@latest inspect server-info -- node build/index.js
703 | npx reloaderoo@latest inspect list-tools -- node build/index.js | jq '.tools | length'
704 | npx reloaderoo@latest inspect list-resources -- node build/index.js | jq '.resources | length'
705 | npx reloaderoo@latest inspect call-tool TOOL_NAME --params '{}' -- node build/index.js
706 | npx reloaderoo@latest inspect read-resource "xcodebuildmcp://RESOURCE" -- node build/index.js
707 | 
708 | # Schema extraction
709 | jq --arg tool "TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema' /tmp/tools.json
710 | jq --arg tool "TOOL_NAME" '.tools[] | select(.name == $tool) | .description' /tmp/tools.json
711 | ```
712 | 
713 | ## Troubleshooting
714 | 
715 | ### Common Issues
716 | 
717 | #### 1. Reloaderoo Command Timeouts
718 | **Symptoms**: Commands hang or timeout after extended periods
719 | **Cause**: Server startup issues or MCP protocol communication problems
720 | **Resolution**: 
721 | - Verify server builds successfully: `npm run build`
722 | - Test direct server startup: `node build/index.js`
723 | - Check for TypeScript compilation errors
724 | 
725 | #### 2. Tool Parameter Validation Errors
726 | **Symptoms**: Tools return parameter validation errors
727 | **Cause**: Missing or incorrect required parameters
728 | **Resolution**:
729 | - Check tool schema: `jq --arg tool "TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema' /tmp/tools.json`
730 | - Verify parameter types and required fields
731 | - Use captured dependency data (UUIDs, paths, schemes)
732 | 
733 | #### 3. "No Such Tool" Errors
734 | **Symptoms**: Reloaderoo reports tool not found
735 | **Cause**: Tool name mismatch or server registration issues
736 | **Resolution**:
737 | - Verify tool exists in list: `npx reloaderoo@latest inspect list-tools -- node build/index.js | jq '.tools[].name'`
738 | - Check exact tool name spelling and case sensitivity
739 | - Ensure server built successfully
740 | 
741 | #### 4. Empty or Malformed Responses
742 | **Symptoms**: Tools return empty responses or JSON parsing errors
743 | **Cause**: Tool implementation issues or server errors
744 | **Resolution**:
745 | - Document as testing finding - do not investigate implementation
746 | - Mark tool as "failed - empty response" in task list
747 | - Continue with next tool in sequence
748 | 
749 | This systematic approach ensures comprehensive, accurate testing using programmatic discovery and validation of all XcodeBuildMCP functionality through the MCP interface exclusively.
```

--------------------------------------------------------------------------------
/scripts/check-code-patterns.js:
--------------------------------------------------------------------------------

```javascript
  1 | #!/usr/bin/env node
  2 | 
  3 | /**
  4 |  * XcodeBuildMCP Code Pattern Violations Checker
  5 |  * 
  6 |  * Validates that all code files follow XcodeBuildMCP-specific architectural patterns.
  7 |  * This script focuses on domain-specific rules that ESLint cannot express.
  8 |  * 
  9 |  * USAGE:
 10 |  *   node scripts/check-code-patterns.js [--pattern=vitest|execsync|handler|handler-testing|all]
 11 |  *   node scripts/check-code-patterns.js --help
 12 |  * 
 13 |  * ARCHITECTURAL RULES ENFORCED:
 14 |  * 1. NO vitest mocking patterns (vi.mock, vi.fn, .mockResolvedValue, etc.)
 15 |  * 2. NO execSync usage in production code (use CommandExecutor instead)
 16 |  * 3. ONLY dependency injection with createMockExecutor() and createMockFileSystemExecutor()
 17 |  * 4. NO handler signature violations (handlers must have exact MCP SDK signatures)
 18 |  * 5. NO handler testing violations (test logic functions, not handlers directly)
 19 |  * 
 20 |  * For comprehensive code quality documentation, see docs/CODE_QUALITY.md
 21 |  * 
 22 |  * Note: General code quality rules (TypeScript, ESLint) are handled by other tools.
 23 |  * This script only enforces XcodeBuildMCP-specific architectural patterns.
 24 |  */
 25 | 
 26 | import { readFileSync, readdirSync, statSync } from 'fs';
 27 | import { join, relative } from 'path';
 28 | import { fileURLToPath } from 'url';
 29 | import { dirname } from 'path';
 30 | 
 31 | const __filename = fileURLToPath(import.meta.url);
 32 | const __dirname = dirname(__filename);
 33 | const projectRoot = join(__dirname, '..');
 34 | 
 35 | // Parse command line arguments
 36 | const args = process.argv.slice(2);
 37 | const patternFilter = args.find(arg => arg.startsWith('--pattern='))?.split('=')[1] || 'all';
 38 | const showHelp = args.includes('--help') || args.includes('-h');
 39 | 
 40 | if (showHelp) {
 41 |   console.log(`
 42 | XcodeBuildMCP Code Pattern Violations Checker
 43 | 
 44 | USAGE:
 45 |   node scripts/check-code-patterns.js [options]
 46 | 
 47 | OPTIONS:
 48 |   --pattern=TYPE    Check specific pattern type (vitest|execsync|handler|handler-testing|server-typing|all) [default: all]
 49 |   --help, -h        Show this help message
 50 | 
 51 | PATTERN TYPES:
 52 |   vitest           Check only vitest mocking violations (vi.mock, vi.fn, etc.)
 53 |   execsync         Check only execSync usage in production code
 54 |   handler          Check only handler signature violations
 55 |   handler-testing  Check only handler testing violations (testing handlers instead of logic functions)
 56 |   server-typing    Check only improper server typing violations (Record<string, unknown> casts)
 57 |   all              Check all pattern violations (default)
 58 | 
 59 |   Note: General code quality (TypeScript, etc.) is handled by ESLint
 60 | 
 61 | EXAMPLES:
 62 |   node scripts/check-code-patterns.js
 63 |   node scripts/check-code-patterns.js --pattern=vitest
 64 |   node scripts/check-code-patterns.js --pattern=handler
 65 |   node scripts/check-code-patterns.js --pattern=handler-testing
 66 |   node scripts/check-code-patterns.js --pattern=server-typing
 67 | `);
 68 |   process.exit(0);
 69 | }
 70 | 
 71 | // Patterns for execSync usage in production code (FORBIDDEN)
 72 | // Note: execSync is allowed in test files for mocking, but not in production code
 73 | const EXECSYNC_PATTERNS = [
 74 |   /\bexecSync\s*\(/,                 // Direct execSync usage
 75 |   /\bexecSyncFn\s*[=:]/,             // execSyncFn parameter or assignment
 76 |   /^import\s+(?!type\s)[^}]*from\s+['"]child_process['"]/m,    // Importing from child_process (except type-only imports)
 77 |   /^import\s+{[^}]*(?:exec|spawn|execSync)[^}]*}\s+from\s+['"](?:node:)?child_process['"]/m, // Named imports of functions
 78 | ];
 79 | 
 80 | // CRITICAL: ALL VITEST MOCKING PATTERNS ARE COMPLETELY FORBIDDEN
 81 | // ONLY dependency injection with approved mock utilities is allowed
 82 | const VITEST_GENERIC_PATTERNS = [
 83 |   /vi\.mock\s*\(/,                   // vi.mock() - BANNED
 84 |   /vi\.fn\s*\(/,                     // vi.fn() - BANNED
 85 |   /vi\.mocked\s*\(/,                 // vi.mocked() - BANNED
 86 |   /vi\.spyOn\s*\(/,                  // vi.spyOn() - BANNED
 87 |   /vi\.clearAllMocks\s*\(/,          // vi.clearAllMocks() - BANNED
 88 |   /\.mockResolvedValue/,             // .mockResolvedValue - BANNED
 89 |   /\.mockRejectedValue/,             // .mockRejectedValue - BANNED
 90 |   /\.mockReturnValue/,               // .mockReturnValue - BANNED
 91 |   /\.mockImplementation/,            // .mockImplementation - BANNED
 92 |   /\.mockClear/,                     // .mockClear - BANNED
 93 |   /\.mockReset/,                     // .mockReset - BANNED
 94 |   /\.mockRestore/,                   // .mockRestore - BANNED
 95 |   /\.toHaveBeenCalled/,              // .toHaveBeenCalled - BANNED
 96 |   /\.toHaveBeenCalledWith/,          // .toHaveBeenCalledWith - BANNED
 97 |   /MockedFunction/,                  // MockedFunction type - BANNED
 98 |   /as MockedFunction/,               // Type casting to MockedFunction - BANNED
 99 |   /\bexecSync\b/,                    // execSync usage - BANNED (use executeCommand instead)
100 |   /\bexecSyncFn\b/,                  // execSyncFn usage - BANNED (use executeCommand instead)
101 | ];
102 | 
103 | // APPROVED mock utilities - ONLY these are allowed
104 | const APPROVED_MOCK_PATTERNS = [
105 |   /\bcreateMockExecutor\b/,
106 |   /\bcreateMockFileSystemExecutor\b/,
107 |   /\bcreateNoopExecutor\b/,
108 |   /\bcreateNoopFileSystemExecutor\b/,
109 |   /\bcreateCommandMatchingMockExecutor\b/,
110 |   /\bcreateMockEnvironmentDetector\b/,
111 | ];
112 | 
113 | // REFINED PATTERNS - Only flag ACTUAL vitest violations, not approved dependency injection patterns
114 | // Manual executors and mock objects are APPROVED when used for dependency injection
115 | const UNAPPROVED_MOCK_PATTERNS = [
116 |   // ONLY ACTUAL VITEST PATTERNS (vi.* usage) - Everything else is approved
117 |   /\bmock[A-Z][a-zA-Z0-9]*\s*=\s*vi\./,              // mockSomething = vi.fn() - vitest assignments only
118 | 
119 |   // No other patterns - manual executors and mock objects are approved for dependency injection
120 | ];
121 | 
122 | // Function to check if a line contains unapproved mock patterns
123 | function hasUnapprovedMockPattern(line) {
124 |   // Skip lines that contain approved patterns
125 |   const hasApprovedPattern = APPROVED_MOCK_PATTERNS.some(pattern => pattern.test(line));
126 |   if (hasApprovedPattern) {
127 |     return false;
128 |   }
129 | 
130 |   // Check for unapproved patterns
131 |   return UNAPPROVED_MOCK_PATTERNS.some(pattern => pattern.test(line));
132 | }
133 | 
134 | // Combined pattern checker for backward compatibility
135 | const VITEST_MOCKING_PATTERNS = VITEST_GENERIC_PATTERNS;
136 | 
137 | // CRITICAL: ARCHITECTURAL VIOLATIONS - Utilities bypassing CommandExecutor (BANNED)
138 | const UTILITY_BYPASS_PATTERNS = [
139 |   /spawn\s*\(/,                      // Direct Node.js spawn usage in utilities - BANNED
140 |   /exec\s*\(/,                       // Direct Node.js exec usage in utilities - BANNED  
141 |   /execSync\s*\(/,                   // Direct Node.js execSync usage in utilities - BANNED
142 |   /child_process\./,                 // Direct child_process module usage in utilities - BANNED
143 | ];
144 | 
145 | // TypeScript patterns are now handled by ESLint - removed from domain-specific checks
146 | // ESLint has comprehensive TypeScript rules with proper test file exceptions
147 | 
148 | // CRITICAL: HANDLER SIGNATURE VIOLATIONS ARE FORBIDDEN
149 | // MCP SDK requires handlers to have exact signatures: 
150 | // Tools: (args: Record<string, unknown>) => Promise<ToolResponse>
151 | // Resources: (uri: URL) => Promise<{ contents: Array<{ text: string }> }>
152 | const HANDLER_SIGNATURE_VIOLATIONS = [
153 |   /async\s+handler\s*\([^)]*:\s*[^,)]+,\s*[^)]+\s*:/ms,  // Handler with multiple parameters separated by comma - BANNED
154 |   /async\s+handler\s*\(\s*args\?\s*:/ms,                   // Handler with optional args parameter - BANNED (should be required)
155 |   /async\s+handler\s*\([^)]*,\s*[^)]*CommandExecutor/ms,  // Handler with CommandExecutor parameter - BANNED
156 |   /async\s+handler\s*\([^)]*,\s*[^)]*FileSystemExecutor/ms, // Handler with FileSystemExecutor parameter - BANNED
157 |   /async\s+handler\s*\([^)]*,\s*[^)]*Dependencies/ms,      // Handler with Dependencies parameter - BANNED
158 |   /async\s+handler\s*\([^)]*,\s*[^)]*executor\s*:/ms,      // Handler with executor parameter - BANNED
159 |   /async\s+handler\s*\([^)]*,\s*[^)]*dependencies\s*:/ms,  // Handler with dependencies parameter - BANNED
160 | ];
161 | 
162 | // CRITICAL: HANDLER TESTING IN TESTS IS FORBIDDEN
163 | // Tests must ONLY call logic functions with dependency injection, NEVER handlers directly
164 | // Handlers are thin wrappers for MCP SDK - testing them violates dependency injection architecture
165 | const HANDLER_TESTING_VIOLATIONS = [
166 |   /\.handler\s*\(/,                     // Direct handler calls in tests - BANNED
167 |   /await\s+\w+\.handler\s*\(/,          // Awaited handler calls - BANNED
168 |   /const\s+result\s*=\s*await\s+\w+\.handler/, // Handler result assignment - BANNED
169 |   /expect\s*\(\s*await\s+\w+\.handler/, // Handler expectation calls - BANNED
170 | ];
171 | 
172 | // CRITICAL: IMPROPER SERVER TYPING PATTERNS ARE FORBIDDEN  
173 | // Server instances must use proper MCP SDK types, not generic Record<string, unknown> casts
174 | const IMPROPER_SERVER_TYPING_VIOLATIONS = [
175 |   /as Record<string, unknown>.*server/,           // Casting server to Record - BANNED
176 |   /server.*as Record<string, unknown>/,           // Casting server to Record - BANNED
177 |   /mcpServer\?\s*:\s*Record<string, unknown>/,    // Typing server as Record - BANNED
178 |   /server\.server\?\?\s*server.*as Record/,       // Complex server casting - BANNED
179 |   /interface\s+MCPServerInterface\s*{/,           // Custom MCP interfaces when SDK types exist - BANNED
180 | ];
181 | 
182 | // ALLOWED PATTERNS for cleanup (not mocking)
183 | const ALLOWED_CLEANUP_PATTERNS = [
184 |   // All cleanup patterns removed - no exceptions allowed
185 | ];
186 | 
187 | // Patterns that indicate TRUE dependency injection approach
188 | const DEPENDENCY_INJECTION_PATTERNS = [
189 |   /createMockExecutor/,              // createMockExecutor usage
190 |   /createMockFileSystemExecutor/,    // createMockFileSystemExecutor usage
191 |   /executor\?\s*:\s*CommandExecutor/, // executor?: CommandExecutor parameter
192 | ];
193 | 
194 | function findTestFiles(dir) {
195 |   const testFiles = [];
196 | 
197 |   function traverse(currentDir) {
198 |     const items = readdirSync(currentDir);
199 | 
200 |     for (const item of items) {
201 |       const fullPath = join(currentDir, item);
202 |       const stat = statSync(fullPath);
203 | 
204 |       if (stat.isDirectory()) {
205 |         // Skip node_modules and other non-relevant directories
206 |         if (!item.startsWith('.') && item !== 'node_modules' && item !== 'dist' && item !== 'build') {
207 |           traverse(fullPath);
208 |         }
209 |       } else if (item.endsWith('.test.ts') || item.endsWith('.test.js')) {
210 |         testFiles.push(fullPath);
211 |       }
212 |     }
213 |   }
214 | 
215 |   traverse(dir);
216 |   return testFiles;
217 | }
218 | 
219 | function findToolAndResourceFiles(dir) {
220 |   const toolFiles = [];
221 | 
222 |   function traverse(currentDir) {
223 |     const items = readdirSync(currentDir);
224 | 
225 |     for (const item of items) {
226 |       const fullPath = join(currentDir, item);
227 |       const stat = statSync(fullPath);
228 | 
229 |       if (stat.isDirectory()) {
230 |         // Skip test directories and other non-relevant directories
231 |         if (!item.startsWith('.') && item !== '__tests__' && item !== 'node_modules' && item !== 'dist' && item !== 'build') {
232 |           traverse(fullPath);
233 |         }
234 |       } else if ((item.endsWith('.ts') || item.endsWith('.js')) && !item.includes('.test.') && item !== 'index.ts' && item !== 'index.js') {
235 |         toolFiles.push(fullPath);
236 |       }
237 |     }
238 |   }
239 | 
240 |   traverse(dir);
241 |   return toolFiles;
242 | }
243 | 
244 | function findUtilityFiles(dir) {
245 |   const utilityFiles = [];
246 | 
247 |   function traverse(currentDir) {
248 |     const items = readdirSync(currentDir);
249 | 
250 |     for (const item of items) {
251 |       const fullPath = join(currentDir, item);
252 |       const stat = statSync(fullPath);
253 | 
254 |       if (stat.isDirectory()) {
255 |         // Skip test directories and other non-relevant directories
256 |         if (!item.startsWith('.') && item !== '__tests__' && item !== 'node_modules' && item !== 'dist' && item !== 'build') {
257 |           traverse(fullPath);
258 |         }
259 |       } else if ((item.endsWith('.ts') || item.endsWith('.js')) && !item.includes('.test.') && item !== 'index.ts' && item !== 'index.js') {
260 |         // Only include key utility files that should use CommandExecutor
261 |         // Exclude command.ts itself as it's the core implementation that is allowed to use spawn()
262 |         if (fullPath.includes('/utils/') && (
263 |           fullPath.includes('log_capture.ts') ||
264 |           fullPath.includes('build.ts') ||
265 |           fullPath.includes('simctl.ts')
266 |         ) && !fullPath.includes('command.ts')) {
267 |           utilityFiles.push(fullPath);
268 |         }
269 |       }
270 |     }
271 |   }
272 | 
273 |   traverse(dir);
274 |   return utilityFiles;
275 | }
276 | 
277 | // Helper function to determine if a file is a test file
278 | function isTestFile(filePath) {
279 |   return filePath.includes('__tests__') || filePath.endsWith('.test.ts') || filePath.endsWith('.test.js');
280 | }
281 | 
282 | // Helper function to determine if a file is a production file
283 | function isProductionFile(filePath) {
284 |   return !isTestFile(filePath) && (filePath.endsWith('.ts') || filePath.endsWith('.js'));
285 | }
286 | 
287 | // Helper function to determine if a file is allowed to use child_process
288 | function isAllowedChildProcessFile(filePath) {
289 |   // These files need direct child_process access for their core functionality
290 |   return filePath.includes('command.ts') || // Core CommandExecutor implementation
291 |     filePath.includes('swift_package_run.ts'); // Needs spawn for background process management
292 | }
293 | 
294 | function analyzeTestFile(filePath) {
295 |   try {
296 |     const content = readFileSync(filePath, 'utf8');
297 |     const relativePath = relative(projectRoot, filePath);
298 | 
299 |     // Check for vitest mocking patterns using new robust approach
300 |     const vitestMockingDetails = [];
301 |     const lines = content.split('\n');
302 | 
303 |     // 1. Check generic vi.* patterns (always violations)
304 |     lines.forEach((line, index) => {
305 |       VITEST_GENERIC_PATTERNS.forEach(pattern => {
306 |         if (pattern.test(line)) {
307 |           vitestMockingDetails.push({
308 |             line: index + 1,
309 |             content: line.trim(),
310 |             pattern: pattern.source,
311 |             type: 'vitest-generic'
312 |           });
313 |         }
314 |       });
315 | 
316 |       // 2. Check for unapproved mock patterns
317 |       if (hasUnapprovedMockPattern(line)) {
318 |         // Find which specific pattern matched for better reporting
319 |         const matchedPattern = UNAPPROVED_MOCK_PATTERNS.find(pattern => pattern.test(line));
320 |         vitestMockingDetails.push({
321 |           line: index + 1,
322 |           content: line.trim(),
323 |           pattern: matchedPattern ? matchedPattern.source : 'unapproved mock pattern',
324 |           type: 'unapproved-mock'
325 |         });
326 |       }
327 |     });
328 | 
329 |     const hasVitestMockingPatterns = vitestMockingDetails.length > 0;
330 | 
331 |     // TypeScript patterns now handled by ESLint
332 |     const hasTypescriptAntipatterns = false;
333 | 
334 |     // Check for handler testing violations (FORBIDDEN - ARCHITECTURAL VIOLATION)
335 |     const hasHandlerTestingViolations = HANDLER_TESTING_VIOLATIONS.some(pattern => pattern.test(content));
336 | 
337 |     // Check for improper server typing violations (FORBIDDEN - ARCHITECTURAL VIOLATION)
338 |     const hasImproperServerTypingViolations = IMPROPER_SERVER_TYPING_VIOLATIONS.some(pattern => pattern.test(content));
339 | 
340 |     // Check for dependency injection patterns (TRUE DI)
341 |     const hasDIPatterns = DEPENDENCY_INJECTION_PATTERNS.some(pattern => pattern.test(content));
342 | 
343 |     // Extract specific pattern occurrences for details
344 |     const execSyncDetails = []; // Not applicable to test files
345 |     const typescriptAntipatternDetails = []; // Unused - TypeScript handled by ESLint
346 |     const handlerTestingDetails = [];
347 |     const improperServerTypingDetails = [];
348 | 
349 |     lines.forEach((line, index) => {
350 | 
351 |       // TypeScript anti-patterns now handled by ESLint - removed from domain checks
352 | 
353 |       HANDLER_TESTING_VIOLATIONS.forEach(pattern => {
354 |         if (pattern.test(line)) {
355 |           handlerTestingDetails.push({
356 |             line: index + 1,
357 |             content: line.trim(),
358 |             pattern: pattern.source
359 |           });
360 |         }
361 |       });
362 | 
363 |       IMPROPER_SERVER_TYPING_VIOLATIONS.forEach(pattern => {
364 |         if (pattern.test(line)) {
365 |           improperServerTypingDetails.push({
366 |             line: index + 1,
367 |             content: line.trim(),
368 |             pattern: pattern.source
369 |           });
370 |         }
371 |       });
372 |     });
373 | 
374 |     return {
375 |       filePath: relativePath,
376 |       hasExecSyncPatterns: false, // Not applicable to test files
377 |       hasVitestMockingPatterns,
378 |       hasTypescriptAntipatterns,
379 |       hasHandlerTestingViolations,
380 |       hasImproperServerTypingViolations,
381 |       hasDIPatterns,
382 |       execSyncDetails,
383 |       vitestMockingDetails,
384 |       typescriptAntipatternDetails,
385 |       handlerTestingDetails,
386 |       improperServerTypingDetails,
387 |       needsConversion: hasVitestMockingPatterns || hasHandlerTestingViolations || hasImproperServerTypingViolations,
388 |       isConverted: hasDIPatterns && !hasVitestMockingPatterns && !hasHandlerTestingViolations && !hasImproperServerTypingViolations,
389 |       isMixed: (hasVitestMockingPatterns || hasHandlerTestingViolations || hasImproperServerTypingViolations) && hasDIPatterns
390 |     };
391 |   } catch (error) {
392 |     console.error(`Error reading file ${filePath}: ${error.message}`);
393 |     return null;
394 |   }
395 | }
396 | 
397 | function analyzeToolOrResourceFile(filePath) {
398 |   try {
399 |     const content = readFileSync(filePath, 'utf8');
400 |     const relativePath = relative(projectRoot, filePath);
401 | 
402 |     // Check for execSync patterns in production code (excluding allowed files)
403 |     const hasExecSyncPatterns = isProductionFile(filePath) &&
404 |       !isAllowedChildProcessFile(filePath) &&
405 |       EXECSYNC_PATTERNS.some(pattern => pattern.test(content));
406 | 
407 |     // Check for vitest mocking patterns using new robust approach
408 |     const vitestMockingDetails = [];
409 |     const lines = content.split('\n');
410 | 
411 |     // 1. Check generic vi.* patterns (always violations)
412 |     lines.forEach((line, index) => {
413 |       VITEST_GENERIC_PATTERNS.forEach(pattern => {
414 |         if (pattern.test(line)) {
415 |           vitestMockingDetails.push({
416 |             line: index + 1,
417 |             content: line.trim(),
418 |             pattern: pattern.source,
419 |             type: 'vitest-generic'
420 |           });
421 |         }
422 |       });
423 | 
424 |       // 2. Check for unapproved mock patterns
425 |       if (hasUnapprovedMockPattern(line)) {
426 |         // Find which specific pattern matched for better reporting
427 |         const matchedPattern = UNAPPROVED_MOCK_PATTERNS.find(pattern => pattern.test(line));
428 |         vitestMockingDetails.push({
429 |           line: index + 1,
430 |           content: line.trim(),
431 |           pattern: matchedPattern ? matchedPattern.source : 'unapproved mock pattern',
432 |           type: 'unapproved-mock'
433 |         });
434 |       }
435 |     });
436 | 
437 |     const hasVitestMockingPatterns = vitestMockingDetails.length > 0;
438 | 
439 |     // TypeScript patterns now handled by ESLint
440 |     const hasTypescriptAntipatterns = false;
441 | 
442 |     // Check for dependency injection patterns (TRUE DI)
443 |     const hasDIPatterns = DEPENDENCY_INJECTION_PATTERNS.some(pattern => pattern.test(content));
444 | 
445 |     // Check for handler signature violations (FORBIDDEN)
446 |     const hasHandlerSignatureViolations = HANDLER_SIGNATURE_VIOLATIONS.some(pattern => pattern.test(content));
447 | 
448 |     // Check for improper server typing violations (FORBIDDEN - ARCHITECTURAL VIOLATION)
449 |     const hasImproperServerTypingViolations = IMPROPER_SERVER_TYPING_VIOLATIONS.some(pattern => pattern.test(content));
450 | 
451 |     // Check for utility bypass patterns (ARCHITECTURAL VIOLATION)
452 |     const hasUtilityBypassPatterns = UTILITY_BYPASS_PATTERNS.some(pattern => pattern.test(content));
453 | 
454 |     // Extract specific pattern occurrences for details
455 |     const execSyncDetails = [];
456 |     const typescriptAntipatternDetails = []; // Unused - TypeScript handled by ESLint
457 |     const handlerSignatureDetails = [];
458 |     const improperServerTypingDetails = [];
459 |     const utilityBypassDetails = [];
460 | 
461 |     lines.forEach((line, index) => {
462 |       if (isProductionFile(filePath) && !isAllowedChildProcessFile(filePath)) {
463 |         EXECSYNC_PATTERNS.forEach(pattern => {
464 |           if (pattern.test(line)) {
465 |             execSyncDetails.push({
466 |               line: index + 1,
467 |               content: line.trim(),
468 |               pattern: pattern.source
469 |             });
470 |           }
471 |         });
472 |       }
473 | 
474 |       // TypeScript anti-patterns now handled by ESLint - removed from domain checks
475 | 
476 |       IMPROPER_SERVER_TYPING_VIOLATIONS.forEach(pattern => {
477 |         if (pattern.test(line)) {
478 |           improperServerTypingDetails.push({
479 |             line: index + 1,
480 |             content: line.trim(),
481 |             pattern: pattern.source
482 |           });
483 |         }
484 |       });
485 | 
486 |       UTILITY_BYPASS_PATTERNS.forEach(pattern => {
487 |         if (pattern.test(line)) {
488 |           utilityBypassDetails.push({
489 |             line: index + 1,
490 |             content: line.trim(),
491 |             pattern: pattern.source
492 |           });
493 |         }
494 |       });
495 |     });
496 |     if (hasHandlerSignatureViolations) {
497 |       // Use regex to find the violation and its line number
498 |       const lines = content.split('\n');
499 |       const fullContent = content;
500 | 
501 |       HANDLER_SIGNATURE_VIOLATIONS.forEach(pattern => {
502 |         let match;
503 |         const globalPattern = new RegExp(pattern.source, pattern.flags + 'g');
504 |         while ((match = globalPattern.exec(fullContent)) !== null) {
505 |           // Find which line this match is on
506 |           const beforeMatch = fullContent.substring(0, match.index);
507 |           const lineNumber = beforeMatch.split('\n').length;
508 | 
509 |           handlerSignatureDetails.push({
510 |             line: lineNumber,
511 |             content: match[0].replace(/\s+/g, ' ').trim(),
512 |             pattern: pattern.source
513 |           });
514 |         }
515 |       });
516 |     }
517 | 
518 |     return {
519 |       filePath: relativePath,
520 |       hasExecSyncPatterns,
521 |       hasVitestMockingPatterns,
522 |       hasTypescriptAntipatterns,
523 |       hasDIPatterns,
524 |       hasHandlerSignatureViolations,
525 |       hasImproperServerTypingViolations,
526 |       hasUtilityBypassPatterns,
527 |       execSyncDetails,
528 |       vitestMockingDetails,
529 |       typescriptAntipatternDetails,
530 |       handlerSignatureDetails,
531 |       improperServerTypingDetails,
532 |       utilityBypassDetails,
533 |       needsConversion: hasExecSyncPatterns || hasVitestMockingPatterns || hasHandlerSignatureViolations || hasImproperServerTypingViolations || hasUtilityBypassPatterns,
534 |       isConverted: hasDIPatterns && !hasExecSyncPatterns && !hasVitestMockingPatterns && !hasHandlerSignatureViolations && !hasImproperServerTypingViolations && !hasUtilityBypassPatterns,
535 |       isMixed: (hasExecSyncPatterns || hasVitestMockingPatterns || hasHandlerSignatureViolations || hasImproperServerTypingViolations || hasUtilityBypassPatterns) && hasDIPatterns
536 |     };
537 |   } catch (error) {
538 |     console.error(`Error reading file ${filePath}: ${error.message}`);
539 |     return null;
540 |   }
541 | }
542 | 
543 | function main() {
544 |   console.log('🔍 XcodeBuildMCP Code Pattern Violations Checker\n');
545 |   console.log(`🎯 Checking pattern type: ${patternFilter.toUpperCase()}\n`);
546 |   console.log('CODE GUIDELINES ENFORCED:');
547 |   console.log('✅ ONLY ALLOWED: createMockExecutor() and createMockFileSystemExecutor()');
548 |   console.log('❌ BANNED: vitest mocking patterns (vi.mock, vi.fn, .mockResolvedValue, etc.)');
549 |   console.log('❌ BANNED: execSync usage in production code (use CommandExecutor instead)');
550 |   console.log('ℹ️  TypeScript patterns: Handled by ESLint with proper test exceptions');
551 |   console.log('❌ BANNED: handler signature violations (handlers must have exact MCP SDK signatures)');
552 |   console.log('❌ BANNED: handler testing violations (test logic functions, not handlers directly)');
553 |   console.log('❌ BANNED: improper server typing (use McpServer type, not Record<string, unknown>)\n');
554 | 
555 |   const testFiles = findTestFiles(join(projectRoot, 'src'));
556 |   const testResults = testFiles.map(analyzeTestFile).filter(Boolean);
557 | 
558 |   // Also check tool and resource files for TypeScript anti-patterns AND handler signature violations
559 |   const toolFiles = findToolAndResourceFiles(join(projectRoot, 'src', 'mcp', 'tools'));
560 |   const resourceFiles = findToolAndResourceFiles(join(projectRoot, 'src', 'mcp', 'resources'));
561 |   const allToolAndResourceFiles = [...toolFiles, ...resourceFiles];
562 |   const toolResults = allToolAndResourceFiles.map(analyzeToolOrResourceFile).filter(Boolean);
563 | 
564 |   // Check utility files for architectural violations (bypassing CommandExecutor)
565 |   const utilityFiles = findUtilityFiles(join(projectRoot, 'src'));
566 |   const utilityResults = utilityFiles.map(analyzeToolOrResourceFile).filter(Boolean);
567 | 
568 |   // Combine test, tool, and utility file results for analysis
569 |   const results = [...testResults, ...toolResults, ...utilityResults];
570 |   const handlerResults = toolResults;
571 |   const utilityBypassResults = utilityResults.filter(r => r.hasUtilityBypassPatterns);
572 | 
573 |   // Filter results based on pattern type
574 |   let filteredResults;
575 |   let filteredHandlerResults = [];
576 | 
577 |   switch (patternFilter) {
578 |     case 'vitest':
579 |       filteredResults = results.filter(r => r.hasVitestMockingPatterns);
580 |       console.log(`Filtering to show only vitest mocking violations (${filteredResults.length} files)`);
581 |       break;
582 |     case 'execsync':
583 |       filteredResults = results.filter(r => r.hasExecSyncPatterns);
584 |       console.log(`Filtering to show only execSync violations (${filteredResults.length} files)`);
585 |       break;
586 |     // TypeScript case removed - now handled by ESLint
587 |     case 'handler':
588 |       filteredResults = [];
589 |       filteredHandlerResults = handlerResults.filter(r => r.hasHandlerSignatureViolations);
590 |       console.log(`Filtering to show only handler signature violations (${filteredHandlerResults.length} files)`);
591 |       break;
592 |     case 'handler-testing':
593 |       filteredResults = results.filter(r => r.hasHandlerTestingViolations);
594 |       console.log(`Filtering to show only handler testing violations (${filteredResults.length} files)`);
595 |       break;
596 |     case 'server-typing':
597 |       filteredResults = results.filter(r => r.hasImproperServerTypingViolations);
598 |       console.log(`Filtering to show only improper server typing violations (${filteredResults.length} files)`);
599 |       break;
600 |     case 'all':
601 |     default:
602 |       filteredResults = results.filter(r => r.needsConversion);
603 |       filteredHandlerResults = handlerResults.filter(r => r.hasHandlerSignatureViolations);
604 |       console.log(`Showing all pattern violations (${filteredResults.length} test files + ${filteredHandlerResults.length} handler files)`);
605 |       break;
606 |   }
607 | 
608 |   const needsConversion = filteredResults;
609 |   const converted = results.filter(r => r.isConverted);
610 |   const mixed = results.filter(r => r.isMixed);
611 |   const execSyncOnly = results.filter(r => r.hasExecSyncPatterns && !r.hasVitestMockingPatterns && true && !r.hasHandlerTestingViolations && !r.hasImproperServerTypingViolations && !r.hasDIPatterns);
612 |   const vitestMockingOnly = results.filter(r => r.hasVitestMockingPatterns && !r.hasExecSyncPatterns && true && !r.hasHandlerTestingViolations && !r.hasImproperServerTypingViolations && !r.hasDIPatterns);
613 |   const typescriptOnly = results.filter(r => r.false && !r.hasExecSyncPatterns && !r.hasVitestMockingPatterns && !r.hasHandlerTestingViolations && !r.hasImproperServerTypingViolations && !r.hasDIPatterns);
614 |   const handlerTestingOnly = results.filter(r => r.hasHandlerTestingViolations && !r.hasExecSyncPatterns && !r.hasVitestMockingPatterns && true && !r.hasImproperServerTypingViolations && !r.hasDIPatterns);
615 |   const improperServerTypingOnly = results.filter(r => r.hasImproperServerTypingViolations && !r.hasExecSyncPatterns && !r.hasVitestMockingPatterns && !r.hasHandlerTestingViolations && !r.hasDIPatterns);
616 |   const noPatterns = results.filter(r => !r.hasExecSyncPatterns && !r.hasVitestMockingPatterns && true && !r.hasHandlerTestingViolations && !r.hasImproperServerTypingViolations && !r.hasDIPatterns);
617 | 
618 |   console.log(`📊 CODE PATTERN VIOLATION ANALYSIS`);
619 |   console.log(`=================================`);
620 |   console.log(`Total files analyzed: ${results.length}`);
621 |   console.log(`🚨 FILES WITH VIOLATIONS: ${needsConversion.length}`);
622 |   console.log(`  └─ execSync production violations: ${execSyncOnly.length}`);
623 |   console.log(`  └─ vitest mocking violations: ${vitestMockingOnly.length}`);
624 |   // TypeScript anti-patterns now handled by ESLint
625 |   console.log(`  └─ handler testing violations: ${handlerTestingOnly.length}`);
626 |   console.log(`  └─ improper server typing violations: ${improperServerTypingOnly.length}`);
627 |   console.log(`🚨 ARCHITECTURAL VIOLATIONS: ${utilityBypassResults.length}`);
628 |   console.log(`✅ COMPLIANT (best practices): ${converted.length}`);
629 |   console.log(`⚠️  MIXED VIOLATIONS: ${mixed.length}`);
630 |   console.log(`📝 No patterns detected: ${noPatterns.length}`);
631 |   console.log('');
632 | 
633 |   if (needsConversion.length > 0) {
634 |     console.log(`❌ FILES THAT NEED CONVERSION (${needsConversion.length}):`);
635 |     console.log(`=====================================`);
636 |     needsConversion.forEach((result, index) => {
637 |       console.log(`${index + 1}. ${result.filePath}`);
638 | 
639 |       if (result.execSyncDetails && result.execSyncDetails.length > 0) {
640 |         console.log(`   🚨 EXECSYNC PATTERNS (${result.execSyncDetails.length}):`);
641 |         result.execSyncDetails.slice(0, 2).forEach(detail => {
642 |           console.log(`   Line ${detail.line}: ${detail.content}`);
643 |         });
644 |         if (result.execSyncDetails.length > 2) {
645 |           console.log(`   ... and ${result.execSyncDetails.length - 2} more execSync patterns`);
646 |         }
647 |         console.log(`   🔧 FIX: Replace execSync with CommandExecutor dependency injection`);
648 |       }
649 | 
650 |       if (result.vitestMockingDetails.length > 0) {
651 |         console.log(`   🧪 VITEST MOCKING PATTERNS (${result.vitestMockingDetails.length}):`);
652 |         result.vitestMockingDetails.slice(0, 2).forEach(detail => {
653 |           console.log(`   Line ${detail.line}: ${detail.content}`);
654 |         });
655 |         if (result.vitestMockingDetails.length > 2) {
656 |           console.log(`   ... and ${result.vitestMockingDetails.length - 2} more vitest patterns`);
657 |         }
658 |       }
659 | 
660 |       // TypeScript violations now handled by ESLint - removed from domain checks
661 | 
662 |       if (result.handlerTestingDetails && result.handlerTestingDetails.length > 0) {
663 |         console.log(`   🚨 HANDLER TESTING VIOLATIONS (${result.handlerTestingDetails.length}):`);
664 |         result.handlerTestingDetails.slice(0, 2).forEach(detail => {
665 |           console.log(`   Line ${detail.line}: ${detail.content}`);
666 |         });
667 |         if (result.handlerTestingDetails.length > 2) {
668 |           console.log(`   ... and ${result.handlerTestingDetails.length - 2} more handler testing violations`);
669 |         }
670 |         console.log(`   🔧 FIX: Replace handler calls with logic function calls using dependency injection`);
671 |       }
672 | 
673 |       if (result.improperServerTypingDetails && result.improperServerTypingDetails.length > 0) {
674 |         console.log(`   🔧 IMPROPER SERVER TYPING VIOLATIONS (${result.improperServerTypingDetails.length}):`);
675 |         result.improperServerTypingDetails.slice(0, 2).forEach(detail => {
676 |           console.log(`   Line ${detail.line}: ${detail.content}`);
677 |         });
678 |         if (result.improperServerTypingDetails.length > 2) {
679 |           console.log(`   ... and ${result.improperServerTypingDetails.length - 2} more server typing violations`);
680 |         }
681 |         console.log(`   🔧 FIX: Import McpServer from SDK and use proper typing instead of Record<string, unknown>`);
682 |       }
683 | 
684 |       console.log('');
685 |     });
686 |   }
687 | 
688 |   // Utility bypass violations reporting  
689 |   if (utilityBypassResults.length > 0) {
690 |     console.log(`🚨 CRITICAL: UTILITY ARCHITECTURAL VIOLATIONS (${utilityBypassResults.length}):`);
691 |     console.log(`=======================================================`);
692 |     console.log('⚠️  These utilities bypass CommandExecutor and break our testing architecture!');
693 |     console.log('');
694 |     utilityBypassResults.forEach((result, index) => {
695 |       console.log(`${index + 1}. ${result.filePath}`);
696 | 
697 |       if (result.utilityBypassDetails.length > 0) {
698 |         console.log(`   🚨 BYPASS PATTERNS (${result.utilityBypassDetails.length}):`);
699 |         result.utilityBypassDetails.forEach(detail => {
700 |           console.log(`   Line ${detail.line}: ${detail.content}`);
701 |         });
702 |       }
703 | 
704 |       console.log('   🔧 FIX: Refactor to accept CommandExecutor and use it instead of direct spawn/exec calls');
705 |       console.log('');
706 |     });
707 |   }
708 | 
709 |   // Handler signature violations reporting
710 |   if (filteredHandlerResults.length > 0) {
711 |     console.log(`🚨 HANDLER SIGNATURE VIOLATIONS (${filteredHandlerResults.length}):`);
712 |     console.log(`===========================================`);
713 |     filteredHandlerResults.forEach((result, index) => {
714 |       console.log(`${index + 1}. ${result.filePath}`);
715 | 
716 |       if (result.handlerSignatureDetails.length > 0) {
717 |         console.log(`   🛠️  HANDLER VIOLATIONS (${result.handlerSignatureDetails.length}):`);
718 |         result.handlerSignatureDetails.forEach(detail => {
719 |           console.log(`   Line ${detail.line}: ${detail.content}`);
720 |         });
721 |       }
722 | 
723 |       console.log('');
724 |     });
725 |   }
726 | 
727 |   if (mixed.length > 0) {
728 |     console.log(`⚠️  FILES WITH MIXED PATTERNS (${mixed.length}):`);
729 |     console.log(`===================================`);
730 |     mixed.forEach((result, index) => {
731 |       console.log(`${index + 1}. ${result.filePath}`);
732 |       console.log(`   ⚠️  Contains both setTimeout and dependency injection patterns`);
733 |       console.log('');
734 |     });
735 |   }
736 | 
737 |   if (converted.length > 0) {
738 |     console.log(`✅ SUCCESSFULLY CONVERTED FILES (${converted.length}):`);
739 |     console.log(`====================================`);
740 |     converted.forEach((result, index) => {
741 |       console.log(`${index + 1}. ${result.filePath}`);
742 |     });
743 |     console.log('');
744 |   }
745 | 
746 |   // Summary for next steps
747 |   const hasViolations = needsConversion.length > 0 || filteredHandlerResults.length > 0 || utilityBypassResults.length > 0;
748 | 
749 |   if (needsConversion.length > 0) {
750 |     console.log(`🚨 CRITICAL ACTION REQUIRED (TEST FILES):`);
751 |     console.log(`=======================================`);
752 |     console.log(`1. IMMEDIATELY remove ALL vitest mocking from ${needsConversion.length} files`);
753 |     console.log(`2. BANNED: vi.mock(), vi.fn(), .mockResolvedValue(), .toHaveBeenCalled(), etc.`);
754 |     console.log(`3. BANNED: Testing handlers directly (.handler()) - test logic functions with dependency injection`);
755 |     console.log(`4. ONLY ALLOWED: createMockExecutor() and createMockFileSystemExecutor()`);
756 |     console.log(`4. Update plugin implementations to accept executor?: CommandExecutor parameter`);
757 |     console.log(`5. Run this script again after each fix to track progress`);
758 |     console.log('');
759 | 
760 |     // Show top files by total violation count
761 |     const sortedByPatterns = needsConversion
762 |       .sort((a, b) => {
763 |         const totalA = (a.execSyncDetails?.length || 0) + a.vitestMockingDetails.length + (a.handlerTestingDetails?.length || 0) + (a.improperServerTypingDetails?.length || 0);
764 |         const totalB = (b.execSyncDetails?.length || 0) + b.vitestMockingDetails.length + (b.handlerTestingDetails?.length || 0) + (b.improperServerTypingDetails?.length || 0);
765 |         return totalB - totalA;
766 |       })
767 |       .slice(0, 5);
768 | 
769 |     console.log(`🚨 TOP 5 FILES WITH MOST VIOLATIONS:`);
770 |     sortedByPatterns.forEach((result, index) => {
771 |       const totalPatterns = (result.execSyncDetails?.length || 0) + result.vitestMockingDetails.length + (result.handlerTestingDetails?.length || 0) + (result.improperServerTypingDetails?.length || 0);
772 |       console.log(`${index + 1}. ${result.filePath} (${totalPatterns} violations: ${result.execSyncDetails?.length || 0} execSync + ${result.vitestMockingDetails.length} vitest + ${result.handlerTestingDetails?.length || 0} handler + ${result.improperServerTypingDetails?.length || 0} server)`);
773 |     });
774 |     console.log('');
775 |   }
776 | 
777 |   if (utilityBypassResults.length > 0) {
778 |     console.log(`🚨 CRITICAL ACTION REQUIRED (UTILITY FILES):`);
779 |     console.log(`==========================================`);
780 |     console.log(`1. IMMEDIATELY fix ALL architectural violations in ${utilityBypassResults.length} files`);
781 |     console.log(`2. Refactor utilities to accept CommandExecutor parameter`);
782 |     console.log(`3. Replace direct spawn/exec calls with executor calls`);
783 |     console.log(`4. These violations break our entire testing strategy`);
784 |     console.log(`5. Run this script again after each fix to track progress`);
785 |     console.log('');
786 |   }
787 | 
788 |   if (filteredHandlerResults.length > 0) {
789 |     console.log(`🚨 CRITICAL ACTION REQUIRED (HANDLER FILES):`);
790 |     console.log(`==========================================`);
791 |     console.log(`1. IMMEDIATELY fix ALL handler signature violations in ${filteredHandlerResults.length} files`);
792 |     console.log(`2. Tools: Handler must be: async handler(args: Record<string, unknown>): Promise<ToolResponse>`);
793 |     console.log(`3. Resources: Handler must be: async handler(uri: URL): Promise<{ contents: Array<{ text: string }> }>`);
794 |     console.log(`4. Inject dependencies INSIDE handler body: const executor = getDefaultCommandExecutor()`);
795 |     console.log(`5. Run this script again after each fix to track progress`);
796 |     console.log('');
797 |   }
798 | 
799 |   if (!hasViolations && mixed.length === 0) {
800 |     console.log(`🎉 ALL FILES COMPLY WITH PROJECT STANDARDS!`);
801 |     console.log(`==========================================`);
802 |     console.log(`✅ All files use ONLY createMockExecutor() and createMockFileSystemExecutor()`);
803 |     console.log(`✅ All files follow TypeScript best practices (no unsafe casts)`);
804 |     console.log(`✅ All handler signatures comply with MCP SDK requirements`);
805 |     console.log(`✅ All utilities properly use CommandExecutor dependency injection`);
806 |     console.log(`✅ No violations detected!`);
807 |   }
808 | 
809 |   // Exit with appropriate code
810 |   process.exit(hasViolations || mixed.length > 0 ? 1 : 0);
811 | }
812 | 
813 | main();
```

--------------------------------------------------------------------------------
/docs/TESTING.md:
--------------------------------------------------------------------------------

```markdown
   1 | # XcodeBuildMCP Plugin Testing Guidelines
   2 | 
   3 | This document provides comprehensive testing guidelines for XcodeBuildMCP plugins, ensuring consistent, robust, and maintainable test coverage across the entire codebase.
   4 | 
   5 | ## Table of Contents
   6 | 
   7 | 1. [Testing Philosophy](#testing-philosophy)
   8 | 2. [Test Architecture](#test-architecture)  
   9 | 3. [Dependency Injection Strategy](#dependency-injection-strategy)
  10 | 4. [Three-Dimensional Testing](#three-dimensional-testing)
  11 | 5. [Test Organization](#test-organization)
  12 | 6. [Test Patterns](#test-patterns)
  13 | 7. [Performance Requirements](#performance-requirements)
  14 | 8. [Coverage Standards](#coverage-standards)
  15 | 9. [Common Patterns](#common-patterns)
  16 | 10. [Manual Testing with Reloaderoo](#manual-testing-with-reloaderoo)
  17 | 11. [Troubleshooting](#troubleshooting)
  18 | 
  19 | ## Testing Philosophy
  20 | 
  21 | ### 🚨 CRITICAL: No Vitest Mocking Allowed
  22 | 
  23 | ### ABSOLUTE RULE: ALL VITEST MOCKING IS COMPLETELY BANNED
  24 | 
  25 | ### FORBIDDEN PATTERNS (will cause immediate test failure):
  26 | 
  27 | #### Vitest Mocking (COMPLETELY BANNED):
  28 | - `vi.mock()` - BANNED
  29 | - `vi.fn()` - BANNED  
  30 | - `vi.mocked()` - BANNED
  31 | - `vi.spyOn()` - BANNED
  32 | - `.mockResolvedValue()` - BANNED
  33 | - `.mockRejectedValue()` - BANNED
  34 | - `.mockReturnValue()` - BANNED
  35 | - `.mockImplementation()` - BANNED
  36 | - `.toHaveBeenCalled()` - BANNED
  37 | - `.toHaveBeenCalledWith()` - BANNED
  38 | - `MockedFunction` type - BANNED
  39 | 
  40 | #### Manual Mock Implementations (BANNED - use our utilities instead):
  41 | - `const mockExecutor = async (...) => { ... }` - Use `createMockExecutor()` instead
  42 | - `const mockFsDeps = { readFile: async () => ... }` - Use `createMockFileSystemExecutor()` instead
  43 | - `const mockServer = { ... }` - Refactor to use dependency injection pattern
  44 | - Any manual async function implementations for mocking behavior
  45 | 
  46 | ### ONLY ALLOWED MOCKING:
  47 | - `createMockExecutor({ success: true, output: 'result' })` - command execution
  48 | - `createMockFileSystemExecutor({ readFile: async () => 'content' })` - file system operations
  49 | 
  50 | ### OUR CORE PRINCIPLE
  51 | 
  52 | **Simple Rule**: No mocking other than `createMockExecutor()` and `createMockFileSystemExecutor()` (and their noop variants).
  53 | 
  54 | **Why This Rule Exists**:
  55 | 1. **Consistency**: All tests use the same mocking utilities, making them predictable and maintainable
  56 | 2. **Reliability**: Our utilities are thoroughly tested and handle edge cases properly
  57 | 3. **Architectural Enforcement**: Prevents bypassing our dependency injection patterns
  58 | 4. **Simplicity**: One clear rule instead of complex guidelines about what mocking is acceptable
  59 | 
  60 | ### Integration Testing with Dependency Injection
  61 | 
  62 | XcodeBuildMCP follows a **pure dependency injection** testing philosophy that eliminates vitest mocking:
  63 | 
  64 | - ✅ **Test plugin interfaces** (public API contracts)
  65 | - ✅ **Test integration flows** (plugin → utilities → external tools)
  66 | - ✅ **Use dependency injection** with createMockExecutor()
  67 | - ❌ **Never mock vitest functions** (vi.mock, vi.fn, etc.)
  68 | 
  69 | ### Benefits
  70 | 
  71 | 1. **Implementation Independence**: Internal refactoring doesn't break tests
  72 | 2. **Real Coverage**: Tests verify actual user data flows
  73 | 3. **Maintainability**: No brittle vitest mocks that break on implementation changes
  74 | 4. **True Integration**: Catches integration bugs between layers
  75 | 5. **Test Safety**: Default executors throw errors in test environment
  76 | 
  77 | ### Automated Violation Checking
  78 | 
  79 | To enforce the no-mocking policy, the project includes a script that automatically checks for banned testing patterns.
  80 | 
  81 | ```bash
  82 | # Run the script to check for violations
  83 | node scripts/check-code-patterns.js
  84 | ```
  85 | 
  86 | This script is part of the standard development workflow and should be run before committing changes to ensure compliance with the testing standards.
  87 | 
  88 | ### What the Script Flags vs. What It Should NOT Flag
  89 | 
  90 | #### ✅ LEGITIMATE VIOLATIONS (correctly flagged):
  91 | - Manual mock executors: `const mockExecutor = async (...) => { ... }`
  92 | - Manual filesystem mocks: `const mockFsDeps = { readFile: async () => ... }`
  93 | - Manual server mocks: `const mockServer = { ... }`
  94 | - Vitest mocking patterns: `vi.mock()`, `vi.fn()`, etc.
  95 | 
  96 | #### ❌ FALSE POSITIVES (should NOT be flagged):
  97 | - Test data tracking: `commandCalls.push({ ... })` - This is just collecting test data, not mocking behavior
  98 | - Regular variables: `const testData = { ... }` - Non-mocking object assignments
  99 | - Test setup: Regular const assignments that don't implement mock behavior
 100 | 
 101 | The script has been refined to minimize false positives while catching all legitimate violations of our core rule.
 102 | 
 103 | ## Test Architecture
 104 | 
 105 | ### Correct Test Flow
 106 | ```
 107 | Test → Plugin Handler → utilities → [DEPENDENCY INJECTION] createMockExecutor()
 108 | ```
 109 | 
 110 | ### What Gets Tested
 111 | - Plugin parameter validation
 112 | - Business logic execution  
 113 | - Command generation
 114 | - Response formatting
 115 | - Error handling
 116 | - Integration between layers
 117 | 
 118 | ### What Gets Mocked
 119 | - Command execution via `createMockExecutor()`
 120 | - File system operations via `createMockFileSystemExecutor()`
 121 | - Nothing else - all vitest mocking is banned
 122 | 
 123 | ## Dependency Injection Strategy
 124 | 
 125 | ### Handler Requirements
 126 | 
 127 | All plugin handlers must support dependency injection:
 128 | 
 129 | ```typescript
 130 | export function tool_nameLogic(
 131 |   args: Record<string, unknown>, 
 132 |   commandExecutor: CommandExecutor,
 133 |   fileSystemExecutor?: FileSystemExecutor
 134 | ): Promise<ToolResponse> {
 135 |   // Use injected executors
 136 |   const result = await executeCommand(['xcrun', 'simctl', 'list'], commandExecutor);
 137 |   return createTextResponse(result.output);
 138 | }
 139 | 
 140 | export default {
 141 |   name: 'tool_name',
 142 |   description: 'Tool description',
 143 |   schema: { /* zod schema */ },
 144 |   async handler(args: Record<string, unknown>): Promise<ToolResponse> {
 145 |     return tool_nameLogic(args, getDefaultCommandExecutor(), getDefaultFileSystemExecutor());
 146 |   },
 147 | };
 148 | ```
 149 | 
 150 | **Important**: The dependency injection pattern applies to ALL handlers, including:
 151 | - Tool handlers
 152 | - Resource handlers
 153 | - Any future handler types (prompts, etc.)
 154 | 
 155 | Always use default parameter values (e.g., `= getDefaultCommandExecutor()`) to ensure production code works without explicit executor injection, while tests can override with mock executors.
 156 | 
 157 | ### Test Requirements
 158 | 
 159 | All tests must explicitly provide mock executors:
 160 | 
 161 | ```typescript
 162 | it('should handle successful command execution', async () => {
 163 |   const mockExecutor = createMockExecutor({
 164 |     success: true,
 165 |     output: 'BUILD SUCCEEDED'
 166 |   });
 167 |   
 168 |   const result = await tool_nameLogic(
 169 |     { projectPath: '/test.xcodeproj', scheme: 'MyApp' },
 170 |     mockExecutor
 171 |   );
 172 |   
 173 |   expect(result.content[0].text).toContain('Build succeeded');
 174 | });
 175 | ```
 176 | 
 177 | ## Three-Dimensional Testing
 178 | 
 179 | Every plugin test suite must validate three critical dimensions:
 180 | 
 181 | ### 1. Input Validation (Schema Testing)
 182 | 
 183 | Test parameter validation and schema compliance:
 184 | 
 185 | ```typescript
 186 | describe('Parameter Validation', () => {
 187 |   it('should accept valid parameters', () => {
 188 |     const schema = z.object(tool.schema);
 189 |     expect(schema.safeParse({
 190 |       projectPath: '/valid/path.xcodeproj',
 191 |       scheme: 'ValidScheme'
 192 |     }).success).toBe(true);
 193 |   });
 194 |   
 195 |   it('should reject invalid parameters', () => {
 196 |     const schema = z.object(tool.schema);
 197 |     expect(schema.safeParse({
 198 |       projectPath: 123, // Wrong type
 199 |       scheme: 'ValidScheme'
 200 |     }).success).toBe(false);
 201 |   });
 202 |   
 203 |   it('should handle missing required parameters', async () => {
 204 |     const mockExecutor = createMockExecutor({ success: true });
 205 |     
 206 |     const result = await tool.handler({ scheme: 'MyApp' }, mockExecutor); // Missing projectPath
 207 |     
 208 |     expect(result).toEqual({
 209 |       content: [{
 210 |         type: 'text',
 211 |         text: "Required parameter 'projectPath' is missing. Please provide a value for this parameter."
 212 |       }],
 213 |       isError: true
 214 |     });
 215 |   });
 216 | });
 217 | ```
 218 | 
 219 | ### 2. Command Generation (CLI Testing)
 220 | 
 221 | ### CRITICAL: No command spying allowed. Test command generation through response validation.
 222 | 
 223 | ```typescript
 224 | describe('Command Generation', () => {
 225 |   it('should execute correct command with minimal parameters', async () => {
 226 |     const mockExecutor = createMockExecutor({
 227 |       success: true,
 228 |       output: 'BUILD SUCCEEDED'
 229 |     });
 230 |     
 231 |     const result = await tool.handler({
 232 |       projectPath: '/test.xcodeproj',
 233 |       scheme: 'MyApp'
 234 |     }, mockExecutor);
 235 |     
 236 |     // Verify through successful response - command was executed correctly
 237 |     expect(result.content[0].text).toContain('Build succeeded');
 238 |   });
 239 |   
 240 |   it('should handle paths with spaces correctly', async () => {
 241 |     const mockExecutor = createMockExecutor({
 242 |       success: true,
 243 |       output: 'BUILD SUCCEEDED'
 244 |     });
 245 |     
 246 |     const result = await tool.handler({
 247 |       projectPath: '/Users/dev/My Project/app.xcodeproj',
 248 |       scheme: 'MyApp'
 249 |     }, mockExecutor);
 250 |     
 251 |     // Verify successful execution (proper path handling)
 252 |     expect(result.content[0].text).toContain('Build succeeded');
 253 |   });
 254 | });
 255 | ```
 256 | 
 257 | ### 3. Output Processing (Response Testing)
 258 | 
 259 | Test response formatting and error handling:
 260 | 
 261 | ```typescript
 262 | describe('Response Processing', () => {
 263 |   it('should format successful response', async () => {
 264 |     const mockExecutor = createMockExecutor({
 265 |       success: true,
 266 |       output: 'BUILD SUCCEEDED'
 267 |     });
 268 |     
 269 |     const result = await tool.handler({ projectPath: '/test', scheme: 'MyApp' }, mockExecutor);
 270 |     
 271 |     expect(result).toEqual({
 272 |       content: [{ type: 'text', text: '✅ Build succeeded for scheme MyApp' }]
 273 |     });
 274 |   });
 275 |   
 276 |   it('should handle command failures', async () => {
 277 |     const mockExecutor = createMockExecutor({
 278 |       success: false,
 279 |       output: 'Build failed with errors',
 280 |       error: 'Compilation error'
 281 |     });
 282 |     
 283 |     const result = await tool.handler({ projectPath: '/test', scheme: 'MyApp' }, mockExecutor);
 284 |     
 285 |     expect(result.isError).toBe(true);
 286 |     expect(result.content[0].text).toContain('Build failed');
 287 |   });
 288 |   
 289 |   it('should handle executor errors', async () => {
 290 |     const mockExecutor = createMockExecutor(new Error('spawn xcodebuild ENOENT'));
 291 |     
 292 |     const result = await tool.handler({ projectPath: '/test', scheme: 'MyApp' }, mockExecutor);
 293 |     
 294 |     expect(result).toEqual({
 295 |       content: [{ type: 'text', text: 'Error during build: spawn xcodebuild ENOENT' }],
 296 |       isError: true
 297 |     });
 298 |   });
 299 | });
 300 | ```
 301 | 
 302 | ## Test Organization
 303 | 
 304 | ### Directory Structure
 305 | 
 306 | ```
 307 | src/plugins/[workflow-group]/
 308 | ├── __tests__/
 309 | │   ├── index.test.ts          # Workflow metadata tests (canonical groups only)
 310 | │   ├── re-exports.test.ts     # Re-export validation (project/workspace groups only)
 311 | │   ├── tool1.test.ts          # Individual tool tests
 312 | │   ├── tool2.test.ts
 313 | │   └── ...
 314 | ├── tool1.ts
 315 | ├── tool2.ts
 316 | ├── index.ts                   # Workflow metadata
 317 | └── ...
 318 | ```
 319 | 
 320 | ### Test File Types
 321 | 
 322 | #### 1. Tool Tests (`tool_name.test.ts`)
 323 | Test individual plugin tools with full three-dimensional coverage.
 324 | 
 325 | #### 2. Workflow Tests (`index.test.ts`)
 326 | Test workflow metadata for canonical groups:
 327 | 
 328 | ```typescript
 329 | describe('simulator-workspace workflow metadata', () => {
 330 |   it('should have correct workflow name', () => {
 331 |     expect(workflow.name).toBe('iOS Simulator Workspace Development');
 332 |   });
 333 |   
 334 |   it('should have correct capabilities', () => {
 335 |     expect(workflow.capabilities).toEqual([
 336 |       'build', 'test', 'deploy', 'debug', 'ui-automation', 'log-capture'
 337 |     ]);
 338 |   });
 339 | });
 340 | ```
 341 | 
 342 | #### 3. Re-export Tests (`re-exports.test.ts`) 
 343 | Test re-export integrity for project/workspace groups:
 344 | 
 345 | ```typescript
 346 | describe('simulator-project re-exports', () => {
 347 |   it('should re-export boot_sim from simulator-shared', () => {
 348 |     expect(bootSim.name).toBe('boot_sim');
 349 |     expect(typeof bootSim.handler).toBe('function');
 350 |   });
 351 | });
 352 | ```
 353 | 
 354 | ## Test Patterns
 355 | 
 356 | ### Standard Test Template
 357 | 
 358 | ```typescript
 359 | import { vi, describe, it, expect, beforeEach } from 'vitest';
 360 | import { z } from 'zod';
 361 | 
 362 | // CRITICAL: NO VITEST MOCKING ALLOWED
 363 | // Import ONLY what you need - no mock setup
 364 | 
 365 | import tool from '../tool_name.ts';
 366 | import { createMockExecutor } from '../../utils/command.js';
 367 | 
 368 | describe('tool_name', () => {
 369 | 
 370 |   describe('Export Field Validation (Literal)', () => {
 371 |     it('should export correct name', () => {
 372 |       expect(tool.name).toBe('tool_name');
 373 |     });
 374 | 
 375 |     it('should export correct description', () => {
 376 |       expect(tool.description).toBe('Expected literal description');
 377 |     });
 378 | 
 379 |     it('should export handler function', () => {
 380 |       expect(typeof tool.handler).toBe('function');
 381 |     });
 382 | 
 383 |     // Schema validation tests...
 384 |   });
 385 | 
 386 |   describe('Command Generation', () => {
 387 |     it('should execute commands successfully', async () => {
 388 |       const mockExecutor = createMockExecutor({
 389 |         success: true,
 390 |         output: 'Expected output'
 391 |       });
 392 |       
 393 |       const result = await tool.handler(validParams, mockExecutor);
 394 |       
 395 |       expect(result.content[0].text).toContain('Expected result');
 396 |     });
 397 |   });
 398 | 
 399 |   describe('Response Processing', () => {
 400 |     // Output handling tests...
 401 |   });
 402 | });
 403 | ```
 404 | 
 405 | ## Performance Requirements
 406 | 
 407 | ### Test Execution Speed
 408 | 
 409 | - **Individual test**: < 100ms
 410 | - **Test file**: < 5 seconds  
 411 | - **Full test suite**: < 20 seconds
 412 | - **No real system calls**: Tests must use mocks
 413 | 
 414 | ### Performance Anti-Patterns
 415 | 
 416 | ❌ **Real command execution**:
 417 | ```
 418 | [INFO] Executing command: xcodebuild -showBuildSettings...
 419 | ```
 420 | 
 421 | ❌ **Long timeouts** (indicates real calls)
 422 | ❌ **File system operations** (unless testing file utilities)
 423 | ❌ **Network requests** (unless testing network utilities)
 424 | 
 425 | ## Coverage Standards
 426 | 
 427 | ### Target Coverage
 428 | - **Overall**: 95%+
 429 | - **Plugin handlers**: 100%
 430 | - **Command generation**: 100%
 431 | - **Error paths**: 100%
 432 | 
 433 | ### Coverage Validation
 434 | ```bash
 435 | # Check coverage for specific plugin group
 436 | npm run test:coverage -- plugins/simulator-workspace/
 437 | 
 438 | # Ensure all code paths are tested
 439 | npm run test:coverage -- --reporter=lcov
 440 | ```
 441 | 
 442 | ### Required Test Paths
 443 | 
 444 | Every plugin test must cover:
 445 | 
 446 | - ✅ **Valid parameter combinations**
 447 | - ✅ **Invalid parameter rejection**  
 448 | - ✅ **Missing required parameters**
 449 | - ✅ **Successful command execution**
 450 | - ✅ **Command failure scenarios**
 451 | - ✅ **Executor error handling**
 452 | - ✅ **Output parsing edge cases**
 453 | 
 454 | ## Common Patterns
 455 | 
 456 | ### Testing Parameter Defaults
 457 | 
 458 | ```typescript
 459 | it('should use default configuration when not provided', async () => {
 460 |   const mockExecutor = createMockExecutor({
 461 |     success: true,
 462 |     output: 'BUILD SUCCEEDED'
 463 |   });
 464 |   
 465 |   const result = await tool.handler({
 466 |     projectPath: '/test.xcodeproj',
 467 |     scheme: 'MyApp'
 468 |     // configuration intentionally omitted
 469 |   }, mockExecutor);
 470 |   
 471 |   // Verify default behavior through successful response
 472 |   expect(result.content[0].text).toContain('Build succeeded');
 473 | });
 474 | ```
 475 | 
 476 | ### Testing Complex Output Parsing
 477 | 
 478 | ```typescript
 479 | it('should extract app path from build settings', async () => {
 480 |   const mockExecutor = createMockExecutor({
 481 |     success: true,
 482 |     output: `
 483 |       CONFIGURATION_BUILD_DIR = /path/to/build
 484 |       BUILT_PRODUCTS_DIR = /path/to/products  
 485 |       FULL_PRODUCT_NAME = MyApp.app
 486 |       OTHER_SETTING = ignored_value
 487 |     `
 488 |   });
 489 |   
 490 |   const result = await tool.handler({ projectPath: '/test', scheme: 'MyApp' }, mockExecutor);
 491 |   
 492 |   expect(result.content[0].text).toContain('/path/to/products/MyApp.app');
 493 | });
 494 | ```
 495 | 
 496 | ### Testing Error Message Formatting
 497 | 
 498 | ```typescript
 499 | it('should format validation errors correctly', async () => {
 500 |   const mockExecutor = createMockExecutor({ success: true });
 501 |   
 502 |   const result = await tool.handler({}, mockExecutor); // Missing required params
 503 |   
 504 |   expect(result).toEqual({
 505 |     content: [{
 506 |       type: 'text',
 507 |       text: "Required parameter 'projectPath' is missing. Please provide a value for this parameter."
 508 |     }],
 509 |     isError: true
 510 |   });
 511 | });
 512 | ```
 513 | 
 514 | ## Manual Testing with Reloaderoo
 515 | 
 516 | ### 🚨 CRITICAL: THOROUGHNESS OVER EFFICIENCY - NO SHORTCUTS ALLOWED
 517 | 
 518 | ### ABSOLUTE PRINCIPLE: EVERY TOOL MUST BE TESTED INDIVIDUALLY
 519 | 
 520 | ### 🚨 MANDATORY TESTING SCOPE - NO EXCEPTIONS
 521 | - **EVERY SINGLE TOOL** - All 83+ tools must be tested individually, one by one
 522 | - **NO REPRESENTATIVE SAMPLING** - Testing similar tools does NOT validate other tools
 523 | - **NO PATTERN RECOGNITION SHORTCUTS** - Similar-looking tools may have different behaviors
 524 | - **NO EFFICIENCY OPTIMIZATIONS** - Thoroughness is more important than speed
 525 | - **NO TIME CONSTRAINTS** - This is a long-running task with no deadline pressure
 526 | 
 527 | ### ❌ FORBIDDEN EFFICIENCY SHORTCUTS
 528 | - **NEVER** assume testing `build_sim_id_proj` validates `build_sim_name_proj`
 529 | - **NEVER** skip tools because they "look similar" to tested ones
 530 | - **NEVER** use representative sampling instead of complete coverage
 531 | - **NEVER** stop testing due to time concerns or perceived redundancy
 532 | - **NEVER** group tools together for batch testing
 533 | - **NEVER** make assumptions about untested tools based on tested patterns
 534 | 
 535 | ### ✅ REQUIRED COMPREHENSIVE APPROACH
 536 | 1. **Individual Tool Testing**: Each tool gets its own dedicated test execution
 537 | 2. **Complete Documentation**: Every tool result must be recorded, regardless of outcome
 538 | 3. **Systematic Progress**: Use TodoWrite to track every single tool as tested/untested
 539 | 4. **Failure Documentation**: Test tools that cannot work and mark them as failed/blocked
 540 | 5. **No Assumptions**: Treat each tool as potentially unique requiring individual validation
 541 | 
 542 | ### TESTING COMPLETENESS VALIDATION
 543 | - **Start Count**: Record exact number of tools discovered (e.g., 83 tools)
 544 | - **End Count**: Verify same number of tools have been individually tested
 545 | - **Missing Tools = Testing Failure**: If any tools remain untested, the testing is incomplete
 546 | - **TodoWrite Tracking**: Every tool must appear in todo list and be marked completed
 547 | 
 548 | ### 🚨 CRITICAL: Black Box Testing via Reloaderoo Inspect
 549 | 
 550 | ### DEFINITION: Black Box Testing
 551 | Black Box Testing means testing ONLY through external interfaces without any knowledge of internal implementation. For XcodeBuildMCP, this means testing exclusively through the Model Context Protocol (MCP) interface using Reloaderoo as the MCP client.
 552 | 
 553 | ### 🚨 MANDATORY: RELOADEROO INSPECT IS THE ONLY ALLOWED TESTING METHOD
 554 | 
 555 | ### ABSOLUTE TESTING RULES - NO EXCEPTIONS
 556 | 
 557 | 1. **✅ ONLY ALLOWED: Reloaderoo Inspect Commands**
 558 |    - `npx reloaderoo@latest inspect call-tool "TOOL_NAME" --params 'JSON' -- node build/index.js`
 559 |    - `npx reloaderoo@latest inspect list-tools -- node build/index.js`
 560 |    - `npx reloaderoo@latest inspect read-resource "URI" -- node build/index.js`
 561 |    - `npx reloaderoo@latest inspect server-info -- node build/index.js`
 562 |    - `npx reloaderoo@latest inspect ping -- node build/index.js`
 563 | 
 564 | 2. **❌ COMPLETELY FORBIDDEN ACTIONS:**
 565 |    - **NEVER** call `mcp__XcodeBuildMCP__tool_name()` functions directly
 566 |    - **NEVER** use MCP server tools as if they were native functions
 567 |    - **NEVER** access internal server functionality
 568 |    - **NEVER** read source code to understand how tools work
 569 |    - **NEVER** examine implementation files during testing
 570 |    - **NEVER** diagnose internal server issues or registration problems
 571 |    - **NEVER** suggest code fixes or implementation changes
 572 | 
 573 | 3. **🚨 CRITICAL VIOLATION EXAMPLES:**
 574 |    ```typescript
 575 |    // ❌ FORBIDDEN - Direct MCP tool calls
 576 |    await mcp__XcodeBuildMCP__list_devices();
 577 |    await mcp__XcodeBuildMCP__build_sim_id_proj({ ... });
 578 |    
 579 |    // ❌ FORBIDDEN - Using tools as native functions
 580 |    const devices = await list_devices();
 581 |    const result = await doctor();
 582 |    
 583 |    // ✅ CORRECT - Only through Reloaderoo inspect
 584 |    npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js
 585 |    npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js
 586 |    ```
 587 | 
 588 | ### WHY RELOADEROO INSPECT IS MANDATORY
 589 | - **Higher Fidelity**: Provides clear input/output visibility for each tool call
 590 | - **Real-world Simulation**: Tests exactly how MCP clients interact with the server
 591 | - **Interface Validation**: Ensures MCP protocol compliance and proper JSON formatting
 592 | - **Black Box Enforcement**: Prevents accidental access to internal implementation details
 593 | - **Clean State**: Each tool call runs with a fresh MCP server instance, preventing cross-contamination
 594 | 
 595 | ### IMPORTANT: STATEFUL TOOL LIMITATIONS
 596 | 
 597 | #### Reloaderoo Inspect Behavior:
 598 | Reloaderoo starts a fresh MCP server instance for each individual tool call and terminates it immediately after the response. This ensures:
 599 | - ✅ **Clean Testing Environment**: No state contamination between tool calls
 600 | - ✅ **Isolated Testing**: Each tool test is independent and repeatable
 601 | - ✅ **Real-world Accuracy**: Simulates how most MCP clients interact with servers
 602 | 
 603 | #### Expected False Negatives:
 604 | Some tools rely on in-memory state within the MCP server and will fail when tested via Reloaderoo inspect. These failures are **expected and acceptable** as false negatives:
 605 | 
 606 | - **`swift_package_stop`** - Requires in-memory process tracking from `swift_package_run`
 607 | - **`stop_app_device`** - Requires in-memory process tracking from `launch_app_device`  
 608 | - **`stop_app_sim`** - Requires in-memory process tracking from `launch_app_sim`
 609 | - **`stop_device_log_cap`** - Requires in-memory session tracking from `start_device_log_cap`
 610 | - **`stop_sim_log_cap`** - Requires in-memory session tracking from `start_sim_log_cap`
 611 | - **`stop_mac_app`** - Requires in-memory process tracking from `launch_mac_app`
 612 | 
 613 | #### Testing Protocol for Stateful Tools:
 614 | 1. **Test the tool anyway** - Execute the Reloaderoo inspect command
 615 | 2. **Expect failure** - Tool will likely fail due to missing state
 616 | 3. **Mark as false negative** - Document the failure as expected due to stateful limitations
 617 | 4. **Continue testing** - Do not attempt to fix or investigate the failure
 618 | 5. **Report as finding** - Note in testing report that stateful tools failed as expected
 619 | 
 620 | ### COMPLETE COVERAGE REQUIREMENTS
 621 | - ✅ **Test ALL 83+ tools individually** - No exceptions, every tool gets manual verification
 622 | - ✅ **Follow dependency graphs** - Test tools in correct order based on data dependencies
 623 | - ✅ **Capture key outputs** - Record UUIDs, paths, schemes needed by dependent tools
 624 | - ✅ **Test real workflows** - Complete end-to-end workflows from discovery to execution
 625 | - ✅ **Use programmatic JSON parsing** - Accurate tool/resource counting and discovery
 626 | - ✅ **Document all observations** - Record exactly what you see via testing
 627 | - ✅ **Report discrepancies as findings** - Note unexpected results without investigation
 628 | 
 629 | ### MANDATORY INDIVIDUAL TOOL TESTING PROTOCOL
 630 | 
 631 | #### Step 1: Create Complete Tool Inventory
 632 | ```bash
 633 | # Generate complete list of all tools
 634 | npx reloaderoo@latest inspect list-tools -- node build/index.js > /tmp/all_tools.json
 635 | TOTAL_TOOLS=$(jq '.tools | length' /tmp/all_tools.json)
 636 | echo "TOTAL TOOLS TO TEST: $TOTAL_TOOLS"
 637 | 
 638 | # Extract all tool names for systematic testing
 639 | jq -r '.tools[].name' /tmp/all_tools.json > /tmp/tool_names.txt
 640 | ```
 641 | 
 642 | #### Step 2: Create TodoWrite Task List for Every Tool
 643 | ```bash
 644 | # Create individual todo items for each of the 83+ tools
 645 | # Example for first few tools:
 646 | # 1. [ ] Test tool: doctor  
 647 | # 2. [ ] Test tool: list_devices
 648 | # 3. [ ] Test tool: list_sims
 649 | # ... (continue for ALL 83+ tools)
 650 | ```
 651 | 
 652 | #### Step 3: Test Each Tool Individually
 653 | For EVERY tool in the list:
 654 | ```bash
 655 | # Test each tool individually - NO BATCHING
 656 | npx reloaderoo@latest inspect call-tool "TOOL_NAME" --params 'APPROPRIATE_PARAMS' -- node build/index.js
 657 | 
 658 | # Mark tool as completed in TodoWrite IMMEDIATELY after testing
 659 | # Record result (success/failure/blocked) for each tool
 660 | ```
 661 | 
 662 | #### Step 4: Validate Complete Coverage
 663 | ```bash
 664 | # Verify all tools tested
 665 | COMPLETED_TOOLS=$(count completed todo items)
 666 | if [ $COMPLETED_TOOLS -ne $TOTAL_TOOLS ]; then
 667 |     echo "ERROR: Testing incomplete. $COMPLETED_TOOLS/$TOTAL_TOOLS tested"
 668 |     exit 1
 669 | fi
 670 | ```
 671 | 
 672 | ### CRITICAL: NO TOOL LEFT UNTESTED
 673 | - **Every tool name from the JSON list must be individually tested**
 674 | - **Every tool must have a TodoWrite entry that gets marked completed**
 675 | - **Tools that fail due to missing parameters should be tested anyway and marked as blocked**
 676 | - **Tools that require setup (like running processes) should be tested and documented as requiring dependencies**
 677 | - **NO ASSUMPTIONS**: Test tools even if they seem redundant or similar to others
 678 | 
 679 | ### BLACK BOX TESTING ENFORCEMENT
 680 | - ✅ **Test only through Reloaderoo MCP interface** - Simulates real-world MCP client usage
 681 | - ✅ **Use task lists** - Track progress with TodoWrite tool for every single tool
 682 | - ✅ **Tick off each tool** - Mark completed in task list after manual verification
 683 | - ✅ **Manual oversight** - Human verification of each tool's input and output
 684 | - ❌ **Never examine source code** - No reading implementation files during testing
 685 | - ❌ **Never diagnose internal issues** - No investigation of build processes or tool registration
 686 | - ❌ **Never suggest implementation fixes** - Report issues as findings, don't solve them
 687 | - ❌ **Never use scripts for tool testing** - Each tool must be manually executed and verified
 688 | 
 689 | ### 🚨 TESTING PSYCHOLOGY & BIAS PREVENTION
 690 | 
 691 | ### COMMON ANTI-PATTERNS TO AVOID
 692 | 
 693 | #### 1. Efficiency Bias (FORBIDDEN)
 694 | - **Symptom**: "These tools look similar, I'll test one to validate the others"
 695 | - **Correction**: Every tool is unique and must be tested individually
 696 | - **Enforcement**: Count tools at start, verify same count tested at end
 697 | 
 698 | #### 2. Pattern Recognition Override (FORBIDDEN)  
 699 | - **Symptom**: "I see the pattern, the rest will work the same way"
 700 | - **Correction**: Patterns may hide edge cases, bugs, or different implementations
 701 | - **Enforcement**: No assumptions allowed, test every tool regardless of apparent similarity
 702 | 
 703 | #### 3. Time Pressure Shortcuts (FORBIDDEN)
 704 | - **Symptom**: "This is taking too long, let me speed up by sampling"
 705 | - **Correction**: This is explicitly a long-running task with no time constraints
 706 | - **Enforcement**: Thoroughness is the ONLY priority, efficiency is irrelevant
 707 | 
 708 | #### 4. False Confidence (FORBIDDEN)
 709 | - **Symptom**: "The architecture is solid, so all tools must work"
 710 | - **Correction**: Architecture validation does not guarantee individual tool functionality
 711 | - **Enforcement**: Test tools to discover actual issues, not to confirm assumptions
 712 | 
 713 | ### MANDATORY MINDSET
 714 | - **Every tool is potentially broken** until individually tested
 715 | - **Every tool may have unique edge cases** not covered by similar tools
 716 | - **Every tool deserves individual attention** regardless of apparent redundancy
 717 | - **Testing completion means EVERY tool tested**, not "enough tools to validate patterns"
 718 | - **The goal is discovering problems**, not confirming everything works
 719 | 
 720 | ### TESTING COMPLETENESS CHECKLIST
 721 | - [ ] Generated complete tool list (83+ tools)
 722 | - [ ] Created TodoWrite entry for every single tool
 723 | - [ ] Tested every tool individually via Reloaderoo inspect
 724 | - [ ] Marked every tool as completed in TodoWrite
 725 | - [ ] Verified tool count: tested_count == total_count
 726 | - [ ] Documented all results, including failures and blocked tools
 727 | - [ ] Created final report covering ALL tools, not just successful ones
 728 | 
 729 | ### Tool Dependency Graph Testing Strategy
 730 | 
 731 | **CRITICAL: Tools must be tested in dependency order:**
 732 | 
 733 | 1. **Foundation Tools** (provide data for other tools):
 734 |    - `doctor` - System info
 735 |    - `list_devices` - Device UUIDs
 736 |    - `list_sims` - Simulator UUIDs  
 737 |    - `discover_projs` - Project/workspace paths
 738 | 
 739 | 2. **Discovery Tools** (provide metadata for build tools):
 740 |    - `list_schemes` - Scheme names
 741 |    - `show_build_settings` - Build settings
 742 | 
 743 | 3. **Build Tools** (create artifacts for install tools):
 744 |    - `build_*` tools - Create app bundles
 745 |    - `get_*_app_path_*` tools - Locate built app bundles
 746 |    - `get_*_bundle_id` tools - Extract bundle IDs
 747 | 
 748 | 4. **Installation Tools** (depend on built artifacts):
 749 |    - `install_app_*` tools - Install built apps
 750 |    - `launch_app_*` tools - Launch installed apps
 751 | 
 752 | 5. **Testing Tools** (depend on projects/schemes):
 753 |    - `test_*` tools - Run test suites
 754 | 
 755 | 6. **UI Automation Tools** (depend on running apps):
 756 |    - `describe_ui`, `screenshot`, `tap`, etc.
 757 | 
 758 | ### MANDATORY: Record Key Outputs
 759 | 
 760 | Must capture and document these values for dependent tools:
 761 | - **Device UUIDs** from `list_devices`
 762 | - **Simulator UUIDs** from `list_sims`
 763 | - **Project/workspace paths** from `discover_projs`
 764 | - **Scheme names** from `list_schems_*`
 765 | - **App bundle paths** from `get_*_app_path_*`
 766 | - **Bundle IDs** from `get_*_bundle_id`
 767 | 
 768 | ### Prerequisites
 769 | 
 770 | 1. **Build the server**: `npm run build`
 771 | 2. **Install jq**: `brew install jq` (required for JSON parsing)
 772 | 3. **System Requirements**: macOS with Xcode installed, connected devices/simulators optional
 773 | 
 774 | ### Step 1: Programmatic Discovery and Official Testing Lists
 775 | 
 776 | #### Generate Official Tool List
 777 | 
 778 | ```bash
 779 | # Generate complete tool list with accurate count
 780 | npx reloaderoo@latest inspect list-tools -- node build/index.js 2>/dev/null > /tmp/tools.json
 781 | 
 782 | # Get accurate tool count
 783 | TOOL_COUNT=$(jq '.tools | length' /tmp/tools.json)
 784 | echo "Official tool count: $TOOL_COUNT"
 785 | 
 786 | # Generate tool names list for testing checklist
 787 | jq -r '.tools[] | .name' /tmp/tools.json > /tmp/tool_names.txt
 788 | echo "Tool names saved to /tmp/tool_names.txt"
 789 | ```
 790 | 
 791 | #### Generate Official Resource List
 792 | 
 793 | ```bash
 794 | # Generate complete resource list
 795 | npx reloaderoo@latest inspect list-resources -- node build/index.js 2>/dev/null > /tmp/resources.json
 796 | 
 797 | # Get accurate resource count  
 798 | RESOURCE_COUNT=$(jq '.resources | length' /tmp/resources.json)
 799 | echo "Official resource count: $RESOURCE_COUNT"
 800 | 
 801 | # Generate resource URIs for testing checklist
 802 | jq -r '.resources[] | .uri' /tmp/resources.json > /tmp/resource_uris.txt
 803 | echo "Resource URIs saved to /tmp/resource_uris.txt"
 804 | ```
 805 | 
 806 | #### Create Tool Testing Checklist
 807 | 
 808 | ```bash
 809 | # Generate markdown checklist from actual tool list
 810 | echo "# Official Tool Testing Checklist" > /tmp/tool_testing_checklist.md
 811 | echo "" >> /tmp/tool_testing_checklist.md
 812 | echo "Total Tools: $TOOL_COUNT" >> /tmp/tool_testing_checklist.md
 813 | echo "" >> /tmp/tool_testing_checklist.md
 814 | 
 815 | # Add each tool as unchecked item
 816 | while IFS= read -r tool_name; do
 817 |     echo "- [ ] $tool_name" >> /tmp/tool_testing_checklist.md
 818 | done < /tmp/tool_names.txt
 819 | 
 820 | echo "Tool testing checklist created at /tmp/tool_testing_checklist.md"
 821 | ```
 822 | 
 823 | #### Create Resource Testing Checklist
 824 | 
 825 | ```bash
 826 | # Generate markdown checklist from actual resource list
 827 | echo "# Official Resource Testing Checklist" > /tmp/resource_testing_checklist.md
 828 | echo "" >> /tmp/resource_testing_checklist.md
 829 | echo "Total Resources: $RESOURCE_COUNT" >> /tmp/resource_testing_checklist.md
 830 | echo "" >> /tmp/resource_testing_checklist.md
 831 | 
 832 | # Add each resource as unchecked item
 833 | while IFS= read -r resource_uri; do
 834 |     echo "- [ ] $resource_uri" >> /tmp/resource_testing_checklist.md
 835 | done < /tmp/resource_uris.txt
 836 | 
 837 | echo "Resource testing checklist created at /tmp/resource_testing_checklist.md"
 838 | ```
 839 | 
 840 | ### Step 2: Tool Schema Discovery for Parameter Testing
 841 | 
 842 | #### Extract Tool Schema Information
 843 | 
 844 | ```bash
 845 | # Get schema for specific tool to understand required parameters
 846 | TOOL_NAME="list_devices"
 847 | jq --arg tool "$TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema' /tmp/tools.json
 848 | 
 849 | # Get tool description for usage guidance
 850 | jq --arg tool "$TOOL_NAME" '.tools[] | select(.name == $tool) | .description' /tmp/tools.json
 851 | 
 852 | # Generate parameter template for tool testing
 853 | jq --arg tool "$TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema.properties // {}' /tmp/tools.json
 854 | ```
 855 | 
 856 | #### Batch Schema Extraction
 857 | 
 858 | ```bash
 859 | # Create schema reference file for all tools
 860 | echo "# Tool Schema Reference" > /tmp/tool_schemas.md
 861 | echo "" >> /tmp/tool_schemas.md
 862 | 
 863 | while IFS= read -r tool_name; do
 864 |     echo "## $tool_name" >> /tmp/tool_schemas.md
 865 |     echo "" >> /tmp/tool_schemas.md
 866 |     
 867 |     # Get description
 868 |     description=$(jq -r --arg tool "$tool_name" '.tools[] | select(.name == $tool) | .description' /tmp/tools.json)
 869 |     echo "**Description:** $description" >> /tmp/tool_schemas.md
 870 |     echo "" >> /tmp/tool_schemas.md
 871 |     
 872 |     # Get required parameters
 873 |     required=$(jq -r --arg tool "$tool_name" '.tools[] | select(.name == $tool) | .inputSchema.required // [] | join(", ")' /tmp/tools.json)
 874 |     if [ "$required" != "" ]; then
 875 |         echo "**Required Parameters:** $required" >> /tmp/tool_schemas.md
 876 |     else
 877 |         echo "**Required Parameters:** None" >> /tmp/tool_schemas.md
 878 |     fi
 879 |     echo "" >> /tmp/tool_schemas.md
 880 |     
 881 |     # Get all parameters
 882 |     echo "**All Parameters:**" >> /tmp/tool_schemas.md
 883 |     jq --arg tool "$tool_name" '.tools[] | select(.name == $tool) | .inputSchema.properties // {} | keys[]' /tmp/tools.json | while read param; do
 884 |         echo "- $param" >> /tmp/tool_schemas.md
 885 |     done
 886 |     echo "" >> /tmp/tool_schemas.md
 887 |     
 888 | done < /tmp/tool_names.txt
 889 | 
 890 | echo "Tool schema reference created at /tmp/tool_schemas.md"
 891 | ```
 892 | 
 893 | ### Step 3: Manual Tool-by-Tool Testing
 894 | 
 895 | #### 🚨 CRITICAL: STEP-BY-STEP BLACK BOX TESTING PROCESS
 896 | 
 897 | ### ABSOLUTE RULE: ALL TESTING MUST BE DONE MANUALLY, ONE TOOL AT A TIME USING RELOADEROO INSPECT
 898 | 
 899 | ### SYSTEMATIC TESTING PROCESS
 900 | 
 901 | 1. **Create TodoWrite Task List**
 902 |    - Add all 83 tools to task list before starting
 903 |    - Mark each tool as "pending" initially
 904 |    - Update status to "in_progress" when testing begins
 905 |    - Mark "completed" only after manual verification
 906 | 
 907 | 2. **Test Each Tool Individually**
 908 |    - Execute ONLY via `npx reloaderoo@latest inspect call-tool "TOOL_NAME" --params 'JSON' -- node build/index.js`
 909 |    - Wait for complete response before proceeding to next tool
 910 |    - Read and verify each tool's output manually
 911 |    - Record key outputs (UUIDs, paths, schemes) for dependent tools
 912 | 
 913 | 3. **Manual Verification Requirements**
 914 |    - ✅ **Read each response** - Manually verify tool output makes sense
 915 |    - ✅ **Check for errors** - Identify any tool failures or unexpected responses  
 916 |    - ✅ **Record UUIDs/paths** - Save outputs needed for dependent tools
 917 |    - ✅ **Update task list** - Mark each tool complete after verification
 918 |    - ✅ **Document issues** - Record any problems found during testing
 919 | 
 920 | 4. **FORBIDDEN SHORTCUTS:**
 921 |    - ❌ **NO SCRIPTS** - Scripts hide what's happening and prevent proper verification
 922 |    - ❌ **NO AUTOMATION** - Every tool call must be manually executed and verified
 923 |    - ❌ **NO BATCHING** - Cannot test multiple tools simultaneously
 924 |    - ❌ **NO MCP DIRECT CALLS** - Only Reloaderoo inspect commands allowed
 925 | 
 926 | #### Phase 1: Infrastructure Validation
 927 | 
 928 | #### Manual Commands (execute individually):
 929 | 
 930 | ```bash
 931 | # Test server connectivity
 932 | npx reloaderoo@latest inspect ping -- node build/index.js
 933 | 
 934 | # Get server information  
 935 | npx reloaderoo@latest inspect server-info -- node build/index.js
 936 | 
 937 | # Verify tool count manually
 938 | npx reloaderoo@latest inspect list-tools -- node build/index.js 2>/dev/null | jq '.tools | length'
 939 | 
 940 | # Verify resource count manually
 941 | npx reloaderoo@latest inspect list-resources -- node build/index.js 2>/dev/null | jq '.resources | length'
 942 | ```
 943 | 
 944 | #### Phase 2: Resource Testing
 945 | 
 946 | ```bash
 947 | # Test each resource systematically
 948 | while IFS= read -r resource_uri; do
 949 |     echo "Testing resource: $resource_uri"
 950 |     npx reloaderoo@latest inspect read-resource "$resource_uri" -- node build/index.js 2>/dev/null
 951 |     echo "---"
 952 | done < /tmp/resource_uris.txt
 953 | ```
 954 | 
 955 | #### Phase 3: Foundation Tools (Data Collection)
 956 | 
 957 | ### CRITICAL: Capture ALL key outputs for dependent tools
 958 | 
 959 | ```bash
 960 | echo "=== FOUNDATION TOOL TESTING & DATA COLLECTION ==="
 961 | 
 962 | # 1. Test doctor (no dependencies)
 963 | echo "Testing doctor..."
 964 | npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js 2>/dev/null
 965 | 
 966 | # 2. Collect device data
 967 | echo "Collecting device UUIDs..."
 968 | npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js 2>/dev/null > /tmp/devices_output.json
 969 | DEVICE_UUIDS=$(jq -r '.content[0].text' /tmp/devices_output.json | grep -E "UDID: [A-F0-9-]+" | sed 's/.*UDID: //' | head -2)
 970 | echo "Device UUIDs captured: $DEVICE_UUIDS"
 971 | 
 972 | # 3. Collect simulator data  
 973 | echo "Collecting simulator UUIDs..."
 974 | npx reloaderoo@latest inspect call-tool "list_sims" --params '{}' -- node build/index.js 2>/dev/null > /tmp/sims_output.json
 975 | SIMULATOR_UUIDS=$(jq -r '.content[0].text' /tmp/sims_output.json | grep -E "\([A-F0-9-]+\)" | sed 's/.*(\([A-F0-9-]*\)).*/\1/' | head -3)
 976 | echo "Simulator UUIDs captured: $SIMULATOR_UUIDS"
 977 | 
 978 | # 4. Collect project data
 979 | echo "Collecting project paths..."
 980 | npx reloaderoo@latest inspect call-tool "discover_projs" --params '{"workspaceRoot": "/Volumes/Developer/XcodeBuildMCP"}' -- node build/index.js 2>/dev/null > /tmp/projects_output.json
 981 | PROJECT_PATHS=$(jq -r '.content[1].text' /tmp/projects_output.json | grep -E "\.xcodeproj$" | sed 's/.*- //' | head -3)
 982 | WORKSPACE_PATHS=$(jq -r '.content[2].text' /tmp/projects_output.json | grep -E "\.xcworkspace$" | sed 's/.*- //' | head -2)
 983 | echo "Project paths captured: $PROJECT_PATHS"
 984 | echo "Workspace paths captured: $WORKSPACE_PATHS"
 985 | 
 986 | # Save key data for dependent tools
 987 | echo "$DEVICE_UUIDS" > /tmp/device_uuids.txt
 988 | echo "$SIMULATOR_UUIDS" > /tmp/simulator_uuids.txt  
 989 | echo "$PROJECT_PATHS" > /tmp/project_paths.txt
 990 | echo "$WORKSPACE_PATHS" > /tmp/workspace_paths.txt
 991 | ```
 992 | 
 993 | #### Phase 4: Discovery Tools (Metadata Collection)
 994 | 
 995 | ```bash
 996 | echo "=== DISCOVERY TOOL TESTING & METADATA COLLECTION ==="
 997 | 
 998 | # Collect schemes for each project
 999 | while IFS= read -r project_path; do
1000 |     if [ -n "$project_path" ]; then
1001 |         echo "Getting schemes for: $project_path"
1002 |         npx reloaderoo@latest inspect call-tool "list_schems_proj" --params "{\"projectPath\": \"$project_path\"}" -- node build/index.js 2>/dev/null > /tmp/schemes_$$.json
1003 |         SCHEMES=$(jq -r '.content[1].text' /tmp/schemes_$$.json 2>/dev/null || echo "NoScheme")
1004 |         echo "$project_path|$SCHEMES" >> /tmp/project_schemes.txt
1005 |         echo "Schemes captured for $project_path: $SCHEMES"
1006 |     fi
1007 | done < /tmp/project_paths.txt
1008 | 
1009 | # Collect schemes for each workspace
1010 | while IFS= read -r workspace_path; do
1011 |     if [ -n "$workspace_path" ]; then
1012 |         echo "Getting schemes for: $workspace_path"
1013 |         npx reloaderoo@latest inspect call-tool "list_schemes" --params "{\"workspacePath\": \"$workspace_path\"}" -- node build/index.js 2>/dev/null > /tmp/ws_schemes_$$.json
1014 |         SCHEMES=$(jq -r '.content[1].text' /tmp/ws_schemes_$$.json 2>/dev/null || echo "NoScheme")
1015 |         echo "$workspace_path|$SCHEMES" >> /tmp/workspace_schemes.txt
1016 |         echo "Schemes captured for $workspace_path: $SCHEMES"
1017 |     fi
1018 | done < /tmp/workspace_paths.txt
1019 | ```
1020 | 
1021 | #### Phase 5: Manual Individual Tool Testing (All 83 Tools)
1022 | 
1023 | ### CRITICAL: Test every single tool manually, one at a time
1024 | 
1025 | #### Manual Testing Process:
1026 | 
1027 | 1. **Create task list** with TodoWrite tool for all 83 tools
1028 | 2. **Test each tool individually** with proper parameters
1029 | 3. **Mark each tool complete** in task list after manual verification
1030 | 4. **Record results** and observations for each tool
1031 | 5. **NO SCRIPTS** - Each command executed manually
1032 | 
1033 | ### STEP-BY-STEP MANUAL TESTING COMMANDS
1034 | 
1035 | ```bash
1036 | # STEP 1: Test foundation tools (no parameters required)
1037 | # Execute each command individually, wait for response, verify manually
1038 | npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js
1039 | # [Wait for response, read output, mark tool complete in task list]
1040 | 
1041 | npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js
1042 | # [Record device UUIDs from response for dependent tools]
1043 | 
1044 | npx reloaderoo@latest inspect call-tool "list_sims" --params '{}' -- node build/index.js
1045 | # [Record simulator UUIDs from response for dependent tools]
1046 | 
1047 | # STEP 2: Test project discovery (use discovered project paths)
1048 | npx reloaderoo@latest inspect call-tool "list_schems_proj" --params '{"projectPath": "/actual/path/from/discover_projs.xcodeproj"}' -- node build/index.js
1049 | # [Record scheme names from response for build tools]
1050 | 
1051 | # STEP 3: Test workspace tools (use discovered workspace paths)  
1052 | npx reloaderoo@latest inspect call-tool "list_schemes" --params '{"workspacePath": "/actual/path/from/discover_projs.xcworkspace"}' -- node build/index.js
1053 | # [Record scheme names from response for build tools]
1054 | 
1055 | # STEP 4: Test simulator tools (use captured simulator UUIDs from step 1)
1056 | npx reloaderoo@latest inspect call-tool "boot_sim" --params '{"simulatorUuid": "ACTUAL_UUID_FROM_LIST_SIMS"}' -- node build/index.js
1057 | # [Verify simulator boots successfully]
1058 | 
1059 | # STEP 5: Test build tools (requires project + scheme + simulator from previous steps)
1060 | npx reloaderoo@latest inspect call-tool "build_sim_id_proj" --params '{"projectPath": "/actual/project.xcodeproj", "scheme": "ActualSchemeName", "simulatorId": "ACTUAL_SIMULATOR_UUID"}' -- node build/index.js
1061 | # [Verify build succeeds and record app bundle path]
1062 | ```
1063 | 
1064 | ### CRITICAL: EACH COMMAND MUST BE
1065 | 1. **Executed individually** - One command at a time, manually typed or pasted
1066 | 2. **Verified manually** - Read the complete response before continuing
1067 | 3. **Tracked in task list** - Mark tool complete only after verification
1068 | 4. **Use real data** - Replace placeholder values with actual captured data
1069 | 5. **Wait for completion** - Allow each command to finish before proceeding
1070 | 
1071 | ### TESTING VIOLATIONS AND ENFORCEMENT
1072 | 
1073 | ### 🚨 CRITICAL VIOLATIONS THAT WILL TERMINATE TESTING
1074 | 
1075 | 1. **Direct MCP Tool Usage Violation:**
1076 |    ```typescript
1077 |    // ❌ IMMEDIATE TERMINATION - Using MCP tools directly
1078 |    await mcp__XcodeBuildMCP__list_devices();
1079 |    const result = await list_sims();
1080 |    ```
1081 | 
1082 | 2. **Script-Based Testing Violation:**
1083 |    ```bash
1084 |    # ❌ IMMEDIATE TERMINATION - Using scripts to test tools
1085 |    for tool in $(cat tool_list.txt); do
1086 |      npx reloaderoo inspect call-tool "$tool" --params '{}' -- node build/index.js
1087 |    done
1088 |    ```
1089 | 
1090 | 3. **Batching/Automation Violation:**
1091 |    ```bash
1092 |    # ❌ IMMEDIATE TERMINATION - Testing multiple tools simultaneously
1093 |    npx reloaderoo inspect call-tool "list_devices" & npx reloaderoo inspect call-tool "list_sims" &
1094 |    ```
1095 | 
1096 | 4. **Source Code Examination Violation:**
1097 |    ```typescript
1098 |    // ❌ IMMEDIATE TERMINATION - Reading implementation during testing
1099 |    const toolImplementation = await Read('/src/mcp/tools/device-shared/list_devices.ts');
1100 |    ```
1101 | 
1102 | ### ENFORCEMENT PROCEDURE
1103 | 1. **First Violation**: Immediate correction and restart of testing process
1104 | 2. **Documentation Update**: Add explicit prohibition to prevent future violations  
1105 | 3. **Method Validation**: Ensure all future testing uses only Reloaderoo inspect commands
1106 | 4. **Progress Reset**: Restart testing from foundation tools if direct MCP usage detected
1107 | 
1108 | ### VALID TESTING SEQUENCE EXAMPLE
1109 | ```bash
1110 | # ✅ CORRECT - Step-by-step manual execution via Reloaderoo
1111 | # Tool 1: Test doctor
1112 | npx reloaderoo@latest inspect call-tool "doctor" --params '{}' -- node build/index.js
1113 | # [Read response, verify, mark complete in TodoWrite]
1114 | 
1115 | # Tool 2: Test list_devices  
1116 | npx reloaderoo@latest inspect call-tool "list_devices" --params '{}' -- node build/index.js
1117 | # [Read response, capture UUIDs, mark complete in TodoWrite]
1118 | 
1119 | # Tool 3: Test list_sims
1120 | npx reloaderoo@latest inspect call-tool "list_sims" --params '{}' -- node build/index.js
1121 | # [Read response, capture UUIDs, mark complete in TodoWrite]
1122 | 
1123 | # Tool X: Test stateful tool (expected to fail)
1124 | npx reloaderoo@latest inspect call-tool "swift_package_stop" --params '{"pid": 12345}' -- node build/index.js
1125 | # [Tool fails as expected - no in-memory state available]
1126 | # [Mark as "false negative - stateful tool limitation" in TodoWrite]
1127 | # [Continue to next tool without investigation]
1128 | 
1129 | # Continue individually for all 83 tools...
1130 | ```
1131 | 
1132 | ### HANDLING STATEFUL TOOL FAILURES
1133 | ```bash
1134 | # ✅ CORRECT Response to Expected Stateful Tool Failure
1135 | # Tool fails with "No process found" or similar state-related error
1136 | # Response: Mark tool as "tested - false negative (stateful)" in task list
1137 | # Do NOT attempt to diagnose, fix, or investigate the failure
1138 | # Continue immediately to next tool in sequence
1139 | ```
1140 | 
1141 | ### Step 4: Error Testing
1142 | 
1143 | ```bash
1144 | # Test error handling systematically
1145 | echo "=== Error Testing ==="
1146 | 
1147 | # Test with invalid JSON parameters
1148 | echo "Testing invalid parameter types..."
1149 | npx reloaderoo@latest inspect call-tool list_schems_proj --params '{"projectPath": 123}' -- node build/index.js 2>/dev/null
1150 | 
1151 | # Test with non-existent paths
1152 | echo "Testing non-existent paths..."
1153 | npx reloaderoo@latest inspect call-tool list_schems_proj --params '{"projectPath": "/nonexistent/path.xcodeproj"}' -- node build/index.js 2>/dev/null
1154 | 
1155 | # Test with invalid UUIDs
1156 | echo "Testing invalid UUIDs..."
1157 | npx reloaderoo@latest inspect call-tool boot_sim --params '{"simulatorUuid": "invalid-uuid"}' -- node build/index.js 2>/dev/null
1158 | ```
1159 | 
1160 | ### Step 5: Generate Testing Report
1161 | 
1162 | ```bash
1163 | # Create comprehensive testing session report
1164 | cat > TESTING_SESSION_$(date +%Y-%m-%d).md << EOF
1165 | # Manual Testing Session - $(date +%Y-%m-%d)
1166 | 
1167 | ## Environment
1168 | - macOS Version: $(sw_vers -productVersion)
1169 | - XcodeBuildMCP Version: $(jq -r '.version' package.json 2>/dev/null || echo "unknown")
1170 | - Testing Method: Reloaderoo @latest via npx
1171 | 
1172 | ## Official Counts (Programmatically Verified)
1173 | - Total Tools: $TOOL_COUNT
1174 | - Total Resources: $RESOURCE_COUNT
1175 | 
1176 | ## Test Results
1177 | [Document test results here]
1178 | 
1179 | ## Issues Found
1180 | [Document any discrepancies or failures]
1181 | 
1182 | ## Performance Notes
1183 | [Document response times and performance observations]
1184 | EOF
1185 | 
1186 | echo "Testing session template created: TESTING_SESSION_$(date +%Y-%m-%d).md"
1187 | ```
1188 | 
1189 | ### Key Commands Reference
1190 | 
1191 | ```bash
1192 | # Essential testing commands
1193 | npx reloaderoo@latest inspect ping -- node build/index.js
1194 | npx reloaderoo@latest inspect server-info -- node build/index.js
1195 | npx reloaderoo@latest inspect list-tools -- node build/index.js | jq '.tools | length'
1196 | npx reloaderoo@latest inspect list-resources -- node build/index.js | jq '.resources | length'
1197 | npx reloaderoo@latest inspect call-tool TOOL_NAME --params '{}' -- node build/index.js
1198 | npx reloaderoo@latest inspect read-resource "xcodebuildmcp://RESOURCE" -- node build/index.js
1199 | 
1200 | # Schema extraction
1201 | jq --arg tool "TOOL_NAME" '.tools[] | select(.name == $tool) | .inputSchema' /tmp/tools.json
1202 | jq --arg tool "TOOL_NAME" '.tools[] | select(.name == $tool) | .description' /tmp/tools.json
1203 | ```
1204 | 
1205 | This systematic approach ensures comprehensive, accurate testing using programmatic discovery and validation of all XcodeBuildMCP functionality.
1206 | 
1207 | ## Troubleshooting
1208 | 
1209 | ### Common Issues
1210 | 
1211 | #### 1. "Real System Executor Detected" Error
1212 | **Symptoms**: Test fails with error about real system executor being used
1213 | **Cause**: Handler not receiving mock executor parameter
1214 | **Fix**: Ensure test passes createMockExecutor() to handler:
1215 | 
1216 | ```typescript
1217 | // ❌ WRONG
1218 | const result = await tool.handler(params);
1219 | 
1220 | // ✅ CORRECT
1221 | const mockExecutor = createMockExecutor({ success: true });
1222 | const result = await tool.handler(params, mockExecutor);
1223 | ```
1224 | 
1225 | #### 2. "Real Filesystem Executor Detected" Error
1226 | **Symptoms**: Test fails when trying to access file system
1227 | **Cause**: Handler not receiving mock file system executor
1228 | **Fix**: Pass createMockFileSystemExecutor():
1229 | 
1230 | ```typescript
1231 | const mockCmd = createMockExecutor({ success: true });
1232 | const mockFS = createMockFileSystemExecutor({ readFile: async () => 'content' });
1233 | const result = await tool.handler(params, mockCmd, mockFS);
1234 | ```
1235 | 
1236 | #### 3. Handler Signature Errors
1237 | **Symptoms**: TypeScript errors about handler parameters
1238 | **Cause**: Handler doesn't support dependency injection
1239 | **Fix**: Update handler signature:
1240 | 
1241 | ```typescript
1242 | async handler(args: Record<string, unknown>): Promise<ToolResponse> {
1243 |   return tool_nameLogic(args, getDefaultCommandExecutor(), getDefaultFileSystemExecutor());
1244 | }
1245 | ```
1246 | 
1247 | ### Debug Commands
1248 | 
1249 | ```bash
1250 | # Run specific test file
1251 | npm test -- src/plugins/simulator-workspace/__tests__/tool_name.test.ts
1252 | 
1253 | # Run with verbose output
1254 | npm test -- --reporter=verbose
1255 | 
1256 | # Check for banned patterns
1257 | node scripts/check-code-patterns.js
1258 | 
1259 | # Verify dependency injection compliance
1260 | node scripts/audit-dependency-container.js
1261 | 
1262 | # Coverage for specific directory
1263 | npm run test:coverage -- src/plugins/simulator-workspace/
1264 | ```
1265 | 
1266 | ### Validation Scripts
1267 | 
1268 | ```bash
1269 | # Check for vitest mocking violations
1270 | node scripts/check-code-patterns.js --pattern=vitest
1271 | 
1272 | # Check dependency injection compliance
1273 | node scripts/audit-dependency-container.js
1274 | 
1275 | # Both scripts must pass before committing
1276 | ```
1277 | 
1278 | ## Best Practices Summary
1279 | 
1280 | 1. **Dependency injection**: Always use createMockExecutor() and createMockFileSystemExecutor()
1281 | 2. **No vitest mocking**: All vi.mock, vi.fn, etc. patterns are banned
1282 | 3. **Three dimensions**: Test input validation, command execution, and output processing
1283 | 4. **Literal expectations**: Use exact strings in assertions to catch regressions
1284 | 5. **Performance**: Ensure fast execution through proper mocking
1285 | 6. **Coverage**: Aim for 95%+ with focus on error paths
1286 | 7. **Consistency**: Follow standard patterns across all plugin tests
1287 | 8. **Test safety**: Default executors prevent accidental real system calls
1288 | 
1289 | This testing strategy ensures robust, maintainable tests that provide confidence in plugin functionality while remaining resilient to implementation changes and completely eliminating vitest mocking dependencies.
```
Page 14/14FirstPrevNextLast