-
-
Notifications
You must be signed in to change notification settings - Fork 260
Expand file tree
/
Copy pathboot_sim.ts
More file actions
124 lines (113 loc) · 3.91 KB
/
boot_sim.ts
File metadata and controls
124 lines (113 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import * as z from 'zod';
import type { ToolResponse } from '../../../types/common.ts';
import { log } from '../../../utils/logging/index.ts';
import { getDefaultCommandExecutor } from '../../../utils/execution/index.ts';
import type { CommandExecutor } from '../../../utils/execution/index.ts';
import {
createSessionAwareTool,
getSessionAwareToolSchemaShape,
} from '../../../utils/typed-tool-factory.ts';
import { ensureSimulatorAccessibility } from '../../../utils/simulator-accessibility.ts';
const baseSchemaObject = z.object({
simulatorId: z
.string()
.optional()
.describe(
'UUID of the simulator to use (obtained from list_sims). Provide EITHER this OR simulatorName, not both',
),
simulatorName: z
.string()
.optional()
.describe(
"Name of the simulator (e.g., 'iPhone 17'). Provide EITHER this OR simulatorId, not both",
),
});
// Internal schema requires simulatorId (factory resolves simulatorName → simulatorId)
const internalSchemaObject = z.object({
simulatorId: z.string(),
simulatorName: z.string().optional(),
});
type BootSimParams = z.infer<typeof internalSchemaObject>;
const publicSchemaObject = z.strictObject(
baseSchemaObject.omit({
simulatorId: true,
simulatorName: true,
} as const).shape,
);
export async function boot_simLogic(
params: BootSimParams,
executor: CommandExecutor,
): Promise<ToolResponse> {
log('info', `Starting xcrun simctl boot request for simulator ${params.simulatorId}`);
try {
const command = ['xcrun', 'simctl', 'boot', params.simulatorId];
const result = await executor(command, 'Boot Simulator', false);
if (!result.success) {
// If the simulator is already booted, still ensure accessibility defaults
const alreadyBooted =
result.error?.includes('Unable to boot device in current state: Booted') ?? false;
if (alreadyBooted) {
await ensureSimulatorAccessibility(params.simulatorId, executor);
}
return {
content: [
{
type: 'text',
text: alreadyBooted
? 'Simulator is already booted.'
: `Boot simulator operation failed: ${result.error}`,
},
],
...(alreadyBooted && {
nextStepParams: {
open_sim: {},
install_app_sim: { simulatorId: params.simulatorId, appPath: 'PATH_TO_YOUR_APP' },
launch_app_sim: {
simulatorId: params.simulatorId,
bundleId: 'YOUR_APP_BUNDLE_ID',
},
},
}),
};
}
// Ensure accessibility defaults are enabled (required for UI hierarchy on iOS 26+)
await ensureSimulatorAccessibility(params.simulatorId, executor);
return {
content: [
{
type: 'text',
text: `Simulator booted successfully.`,
},
],
nextStepParams: {
open_sim: {},
install_app_sim: { simulatorId: params.simulatorId, appPath: 'PATH_TO_YOUR_APP' },
launch_app_sim: { simulatorId: params.simulatorId, bundleId: 'YOUR_APP_BUNDLE_ID' },
},
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
log('error', `Error during boot simulator operation: ${errorMessage}`);
return {
content: [
{
type: 'text',
text: `Boot simulator operation failed: ${errorMessage}`,
},
],
};
}
}
export const schema = getSessionAwareToolSchemaShape({
sessionAware: publicSchemaObject,
legacy: baseSchemaObject,
});
export const handler = createSessionAwareTool<BootSimParams>({
internalSchema: internalSchemaObject as unknown as z.ZodType<BootSimParams, unknown>,
logicFunction: boot_simLogic,
getExecutor: getDefaultCommandExecutor,
requirements: [
{ oneOf: ['simulatorId', 'simulatorName'], message: 'Provide simulatorId or simulatorName' },
],
exclusivePairs: [['simulatorId', 'simulatorName']],
});