Skip to content

Commit 90dc951

Browse files
committed
refactor(simulator-management): adopt UDID terminology (simulatorUdid + z.string().uuid), add typed content, update tests; address PR review
1 parent dc695f5 commit 90dc951

File tree

2 files changed

+20
-16
lines changed

2 files changed

+20
-16
lines changed

src/mcp/tools/simulator-management/__tests__/erase_sims.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('erase_sims tool (UDID or ALL only)', () => {
1010
});
1111

1212
it('should have correct description', () => {
13-
expect(eraseSims.description).toContain('Provide exactly one of: simulatorUuid or all=true');
13+
expect(eraseSims.description).toContain('Provide exactly one of: simulatorUdid or all=true');
1414
expect(eraseSims.description).toContain('shutdownFirst');
1515
});
1616

@@ -21,7 +21,9 @@ describe('erase_sims tool (UDID or ALL only)', () => {
2121
it('should validate schema fields (shape only)', () => {
2222
const schema = z.object(eraseSims.schema);
2323
// Valid
24-
expect(schema.safeParse({ simulatorUuid: 'UDID-1' }).success).toBe(true);
24+
expect(
25+
schema.safeParse({ simulatorUdid: '123e4567-e89b-12d3-a456-426614174000' }).success,
26+
).toBe(true);
2527
expect(schema.safeParse({ all: true }).success).toBe(true);
2628
// Shape-level schema does not enforce selection rules; handler validation covers that.
2729
});
@@ -30,15 +32,15 @@ describe('erase_sims tool (UDID or ALL only)', () => {
3032
describe('Single mode', () => {
3133
it('erases a simulator successfully', async () => {
3234
const mock = createMockExecutor({ success: true, output: 'OK' });
33-
const res = await erase_simsLogic({ simulatorUuid: 'UD1' }, mock);
35+
const res = await erase_simsLogic({ simulatorUdid: 'UD1' }, mock);
3436
expect(res).toEqual({
3537
content: [{ type: 'text', text: 'Successfully erased simulator UD1' }],
3638
});
3739
});
3840

3941
it('returns failure when erase fails', async () => {
4042
const mock = createMockExecutor({ success: false, error: 'Booted device' });
41-
const res = await erase_simsLogic({ simulatorUuid: 'UD1' }, mock);
43+
const res = await erase_simsLogic({ simulatorUdid: 'UD1' }, mock);
4244
expect(res).toEqual({
4345
content: [{ type: 'text', text: 'Failed to erase simulator: Booted device' }],
4446
});
@@ -48,7 +50,7 @@ describe('erase_sims tool (UDID or ALL only)', () => {
4850
const bootedError =
4951
'An error was encountered processing the command (domain=com.apple.CoreSimulator.SimError, code=405):\nUnable to erase contents and settings in current state: Booted\n';
5052
const mock = createMockExecutor({ success: false, error: bootedError });
51-
const res = await erase_simsLogic({ simulatorUuid: 'UD1' }, mock);
53+
const res = await erase_simsLogic({ simulatorUdid: 'UD1' }, mock);
5254
expect((res.content?.[1] as any).text).toContain('Tool hint');
5355
expect((res.content?.[1] as any).text).toContain('shutdownFirst: true');
5456
});
@@ -59,7 +61,7 @@ describe('erase_sims tool (UDID or ALL only)', () => {
5961
calls.push(cmd);
6062
return { success: true, output: 'OK', error: '', process: { pid: 1 } as any };
6163
};
62-
const res = await erase_simsLogic({ simulatorUuid: 'UD1', shutdownFirst: true }, exec as any);
64+
const res = await erase_simsLogic({ simulatorUdid: 'UD1', shutdownFirst: true }, exec as any);
6365
expect(calls).toEqual([
6466
['xcrun', 'simctl', 'shutdown', 'UD1'],
6567
['xcrun', 'simctl', 'erase', 'UD1'],

src/mcp/tools/simulator-management/erase_sims.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { z } from 'zod';
2-
import { ToolResponse } from '../../../types/common.ts';
2+
import { ToolResponse, type ToolResponseContent } from '../../../types/common.ts';
33
import { log } from '../../../utils/logging/index.ts';
44
import { CommandExecutor, getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
55
import { createTypedTool } from '../../../utils/typed-tool-factory.ts';
66

77
const eraseSimsBaseSchema = z.object({
8-
simulatorUuid: z.string().optional().describe('UUID of the simulator to erase.'),
8+
simulatorUdid: z.string().uuid().optional().describe('UDID of the simulator to erase.'),
99
all: z.boolean().optional().describe('When true, erases all simulators.'),
1010
shutdownFirst: z
1111
.boolean()
@@ -15,10 +15,10 @@ const eraseSimsBaseSchema = z.object({
1515

1616
const eraseSimsSchema = eraseSimsBaseSchema.refine(
1717
(v) => {
18-
const selectors = (v.simulatorUuid ? 1 : 0) + (v.all === true ? 1 : 0);
18+
const selectors = (v.simulatorUdid ? 1 : 0) + (v.all === true ? 1 : 0);
1919
return selectors === 1;
2020
},
21-
{ message: 'Provide exactly one of: simulatorUuid OR all=true.' },
21+
{ message: 'Provide exactly one of: simulatorUdid or all=true.' },
2222
);
2323

2424
type EraseSimsParams = z.infer<typeof eraseSimsSchema>;
@@ -28,8 +28,8 @@ export async function erase_simsLogic(
2828
executor: CommandExecutor,
2929
): Promise<ToolResponse> {
3030
try {
31-
if (params.simulatorUuid) {
32-
const udid = params.simulatorUuid;
31+
if (params.simulatorUdid) {
32+
const udid = params.simulatorUdid;
3333
log(
3434
'info',
3535
`Erasing simulator ${udid}${params.shutdownFirst ? ' (shutdownFirst=true)' : ''}`,
@@ -66,7 +66,7 @@ export async function erase_simsLogic(
6666
{ type: 'text', text: `Failed to erase simulator: ${errText}` },
6767
{
6868
type: 'text',
69-
text: `Tool hint: The simulator appears to be Booted. Re-run erase_sims with { simulatorUuid: '${udid}', shutdownFirst: true } to shut it down before erasing.`,
69+
text: `Tool hint: The simulator appears to be Booted. Re-run erase_sims with { simulatorUdid: '${udid}', shutdownFirst: true } to shut it down before erasing.`,
7070
},
7171
],
7272
};
@@ -100,7 +100,9 @@ export async function erase_simsLogic(
100100
);
101101
if (!result.success) {
102102
const errText = result.error ?? 'Unknown error';
103-
const content = [{ type: 'text', text: `Failed to erase all simulators: ${errText}` }];
103+
const content: ToolResponseContent[] = [
104+
{ type: 'text', text: `Failed to erase all simulators: ${errText}` },
105+
];
104106
if (
105107
/Unable to erase contents and settings.*Booted/i.test(errText) &&
106108
!params.shutdownFirst
@@ -116,7 +118,7 @@ export async function erase_simsLogic(
116118
}
117119

118120
return {
119-
content: [{ type: 'text', text: 'Invalid parameters: provide simulatorUuid or all=true.' }],
121+
content: [{ type: 'text', text: 'Invalid parameters: provide simulatorUdid or all=true.' }],
120122
};
121123
} catch (error: unknown) {
122124
const message = error instanceof Error ? error.message : String(error);
@@ -128,7 +130,7 @@ export async function erase_simsLogic(
128130
export default {
129131
name: 'erase_sims',
130132
description:
131-
'Erases simulator content and settings. Provide exactly one of: simulatorUuid or all=true. Optional: shutdownFirst to shut down before erasing.',
133+
'Erases simulator content and settings. Provide exactly one of: simulatorUdid or all=true. Optional: shutdownFirst to shut down before erasing.',
132134
schema: eraseSimsBaseSchema.shape,
133135
handler: createTypedTool(eraseSimsSchema, erase_simsLogic, getDefaultCommandExecutor),
134136
};

0 commit comments

Comments
 (0)