|
1 | 1 | /** |
2 | | - * Unified implementation of get_simulator_app_path_name tool |
3 | | - * Gets the app bundle path for a simulator by name using either a project or workspace file |
4 | | - * Supports both .xcodeproj and .xcworkspace files with XOR validation |
| 2 | + * Simulator Get App Path Plugin: Get Simulator App Path (Unified) |
| 3 | + * |
| 4 | + * Gets the app bundle path for a simulator by UUID or name using either a project or workspace file. |
| 5 | + * Accepts mutually exclusive `projectPath` or `workspacePath`. |
| 6 | + * Accepts mutually exclusive `simulatorId` or `simulatorName`. |
5 | 7 | */ |
6 | 8 |
|
7 | 9 | import { z } from 'zod'; |
@@ -88,56 +90,73 @@ function nullifyEmptyStrings(value: unknown): unknown { |
88 | 90 | } |
89 | 91 |
|
90 | 92 | // Define base schema |
91 | | -const baseGetSimulatorAppPathNameSchema = z.object({ |
| 93 | +const baseGetSimulatorAppPathSchema = z.object({ |
92 | 94 | projectPath: z.string().optional().describe('Path to the .xcodeproj file'), |
93 | 95 | workspacePath: z.string().optional().describe('Path to the .xcworkspace file'), |
94 | 96 | scheme: z.string().describe('The scheme to use (Required)'), |
95 | 97 | platform: z |
96 | 98 | .enum(['iOS Simulator', 'watchOS Simulator', 'tvOS Simulator', 'visionOS Simulator']) |
97 | 99 | .describe('Target simulator platform (Required)'), |
98 | | - simulatorName: z.string().describe("Name of the simulator to use (e.g., 'iPhone 16') (Required)"), |
| 100 | + simulatorId: z |
| 101 | + .string() |
| 102 | + .optional() |
| 103 | + .describe('UUID of the simulator to use (obtained from listSimulators)'), |
| 104 | + simulatorName: z.string().optional().describe("Name of the simulator to use (e.g., 'iPhone 16')"), |
99 | 105 | configuration: z.string().optional().describe('Build configuration (Debug, Release, etc.)'), |
100 | 106 | useLatestOS: z |
101 | 107 | .boolean() |
102 | 108 | .optional() |
103 | 109 | .describe('Whether to use the latest OS version for the named simulator'), |
104 | | - simulatorId: z.string().optional().describe('Optional simulator UUID'), |
105 | 110 | arch: z.string().optional().describe('Optional architecture'), |
106 | 111 | }); |
107 | 112 |
|
108 | 113 | // Add XOR validation with preprocessing |
109 | | -const getSimulatorAppPathNameSchema = z.preprocess( |
| 114 | +const getSimulatorAppPathSchema = z.preprocess( |
110 | 115 | nullifyEmptyStrings, |
111 | | - baseGetSimulatorAppPathNameSchema |
| 116 | + baseGetSimulatorAppPathSchema |
112 | 117 | .refine((val) => val.projectPath !== undefined || val.workspacePath !== undefined, { |
113 | 118 | message: 'Either projectPath or workspacePath is required.', |
114 | 119 | }) |
115 | 120 | .refine((val) => !(val.projectPath !== undefined && val.workspacePath !== undefined), { |
116 | 121 | message: 'projectPath and workspacePath are mutually exclusive. Provide only one.', |
| 122 | + }) |
| 123 | + .refine((val) => val.simulatorId !== undefined || val.simulatorName !== undefined, { |
| 124 | + message: 'Either simulatorId or simulatorName is required.', |
| 125 | + }) |
| 126 | + .refine((val) => !(val.simulatorId !== undefined && val.simulatorName !== undefined), { |
| 127 | + message: 'simulatorId and simulatorName are mutually exclusive. Provide only one.', |
117 | 128 | }), |
118 | 129 | ); |
119 | 130 |
|
120 | 131 | // Use z.infer for type safety |
121 | | -type GetSimulatorAppPathNameParams = z.infer<typeof getSimulatorAppPathNameSchema>; |
| 132 | +type GetSimulatorAppPathParams = z.infer<typeof getSimulatorAppPathSchema>; |
122 | 133 |
|
123 | 134 | /** |
124 | 135 | * Exported business logic function for getting app path |
125 | 136 | */ |
126 | | -export async function get_simulator_app_path_nameLogic( |
127 | | - params: GetSimulatorAppPathNameParams, |
| 137 | +export async function get_simulator_app_pathLogic( |
| 138 | + params: GetSimulatorAppPathParams, |
128 | 139 | executor: CommandExecutor, |
129 | 140 | ): Promise<ToolResponse> { |
130 | 141 | // Set defaults - Zod validation already ensures required params are present |
131 | 142 | const projectPath = params.projectPath; |
132 | 143 | const workspacePath = params.workspacePath; |
133 | 144 | const scheme = params.scheme; |
134 | 145 | const platform = params.platform; |
| 146 | + const simulatorId = params.simulatorId; |
135 | 147 | const simulatorName = params.simulatorName; |
136 | 148 | const configuration = params.configuration ?? 'Debug'; |
137 | 149 | const useLatestOS = params.useLatestOS ?? true; |
138 | | - const simulatorId = params.simulatorId; |
139 | 150 | const arch = params.arch; |
140 | 151 |
|
| 152 | + // Log warning if useLatestOS is provided with simulatorId |
| 153 | + if (simulatorId && params.useLatestOS !== undefined) { |
| 154 | + log( |
| 155 | + 'warning', |
| 156 | + `useLatestOS parameter is ignored when using simulatorId (UUID implies exact device/OS)`, |
| 157 | + ); |
| 158 | + } |
| 159 | + |
141 | 160 | log('info', `Getting app path for scheme ${scheme} on platform ${platform}`); |
142 | 161 |
|
143 | 162 | try { |
@@ -169,7 +188,7 @@ export async function get_simulator_app_path_nameLogic( |
169 | 188 | if (simulatorId) { |
170 | 189 | destinationString = `platform=${platform},id=${simulatorId}`; |
171 | 190 | } else if (simulatorName) { |
172 | | - destinationString = `platform=${platform},name=${simulatorName}${useLatestOS ? ',OS=latest' : ''}`; |
| 191 | + destinationString = `platform=${platform},name=${simulatorName}${(simulatorId ? false : useLatestOS) ? ',OS=latest' : ''}`; |
173 | 192 | } else { |
174 | 193 | return createTextResponse( |
175 | 194 | `For ${platform} platform, either simulatorId or simulatorName must be provided`, |
@@ -269,13 +288,13 @@ export async function get_simulator_app_path_nameLogic( |
269 | 288 | } |
270 | 289 |
|
271 | 290 | export default { |
272 | | - name: 'get_simulator_app_path_name', |
| 291 | + name: 'get_simulator_app_path', |
273 | 292 | description: |
274 | | - "Gets the app bundle path for a simulator by name using either a project or workspace file. IMPORTANT: Requires either projectPath OR workspacePath (not both), plus scheme, platform, and simulatorName. Example: get_simulator_app_path_name({ projectPath: '/path/to/project.xcodeproj', scheme: 'MyScheme', platform: 'iOS Simulator', simulatorName: 'iPhone 16' })", |
275 | | - schema: baseGetSimulatorAppPathNameSchema.shape, // MCP SDK compatibility |
276 | | - handler: createTypedTool<GetSimulatorAppPathNameParams>( |
277 | | - getSimulatorAppPathNameSchema as unknown as z.ZodType<GetSimulatorAppPathNameParams>, |
278 | | - get_simulator_app_path_nameLogic, |
| 293 | + "Gets the app bundle path for a simulator by UUID or name using either a project or workspace file. IMPORTANT: Requires either projectPath OR workspacePath (not both), plus scheme, platform, and either simulatorId OR simulatorName (not both). Example: get_simulator_app_path({ projectPath: '/path/to/project.xcodeproj', scheme: 'MyScheme', platform: 'iOS Simulator', simulatorName: 'iPhone 16' })", |
| 294 | + schema: baseGetSimulatorAppPathSchema.shape, // MCP SDK compatibility |
| 295 | + handler: createTypedTool<GetSimulatorAppPathParams>( |
| 296 | + getSimulatorAppPathSchema as unknown as z.ZodType<GetSimulatorAppPathParams>, |
| 297 | + get_simulator_app_pathLogic, |
279 | 298 | getDefaultCommandExecutor, |
280 | 299 | ), |
281 | 300 | }; |
0 commit comments