Skip to content

Commit 4039044

Browse files
committed
feat: add additional simulators and accept license
1 parent a660ea2 commit 4039044

5 files changed

Lines changed: 239 additions & 63 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "default",
3-
"version": "1.15.0-beta.6",
3+
"version": "1.15.0",
44
"description": "Default plugin for Codify - provides 50+ declarative resources for managing development tools and system configuration across macOS and Linux",
55
"main": "dist/index.js",
66
"scripts": {
Lines changed: 124 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,142 @@
1-
// Known CoreSimulator device type identifiers shipped with Xcode.
2-
// These identifiers are stable across Xcode versions for each device family.
3-
export default async function loadIosSimulatorDeviceTypes(): Promise<string[]> {
1+
export default async function loadSimulatorDeviceTypes(): Promise<string[]> {
42
return [
5-
// iPhone SE
6-
'com.apple.CoreSimulator.SimDeviceType.iPhone-SE-3rd-generation',
7-
8-
// iPhone 14 family
9-
'com.apple.CoreSimulator.SimDeviceType.iPhone-14',
10-
'com.apple.CoreSimulator.SimDeviceType.iPhone-14-Plus',
11-
'com.apple.CoreSimulator.SimDeviceType.iPhone-14-Pro',
12-
'com.apple.CoreSimulator.SimDeviceType.iPhone-14-Pro-Max',
13-
14-
// iPhone 15 family
15-
'com.apple.CoreSimulator.SimDeviceType.iPhone-15',
16-
'com.apple.CoreSimulator.SimDeviceType.iPhone-15-Plus',
17-
'com.apple.CoreSimulator.SimDeviceType.iPhone-15-Pro',
18-
'com.apple.CoreSimulator.SimDeviceType.iPhone-15-Pro-Max',
19-
20-
// iPhone 16 family
21-
'com.apple.CoreSimulator.SimDeviceType.iPhone-16',
22-
'com.apple.CoreSimulator.SimDeviceType.iPhone-16-Plus',
3+
// iPhone
4+
'com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro',
5+
'com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro-Max',
6+
'com.apple.CoreSimulator.SimDeviceType.iPhone-Air',
7+
'com.apple.CoreSimulator.SimDeviceType.iPhone-17',
238
'com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro',
249
'com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro-Max',
10+
'com.apple.CoreSimulator.SimDeviceType.iPhone-16e',
11+
'com.apple.CoreSimulator.SimDeviceType.iPhone-16',
12+
'com.apple.CoreSimulator.SimDeviceType.iPhone-16-Plus',
13+
'com.apple.CoreSimulator.SimDeviceType.iPhone-15-Pro',
14+
'com.apple.CoreSimulator.SimDeviceType.iPhone-15-Pro-Max',
15+
'com.apple.CoreSimulator.SimDeviceType.iPhone-15',
16+
'com.apple.CoreSimulator.SimDeviceType.iPhone-15-Plus',
17+
'com.apple.CoreSimulator.SimDeviceType.iPhone-14-Pro',
18+
'com.apple.CoreSimulator.SimDeviceType.iPhone-14-Pro-Max',
19+
'com.apple.CoreSimulator.SimDeviceType.iPhone-14',
20+
'com.apple.CoreSimulator.SimDeviceType.iPhone-14-Plus',
21+
'com.apple.CoreSimulator.SimDeviceType.iPhone-SE-3rd-generation',
22+
'com.apple.CoreSimulator.SimDeviceType.iPhone-13-Pro',
23+
'com.apple.CoreSimulator.SimDeviceType.iPhone-13-Pro-Max',
24+
'com.apple.CoreSimulator.SimDeviceType.iPhone-13',
25+
'com.apple.CoreSimulator.SimDeviceType.iPhone-13-mini',
26+
'com.apple.CoreSimulator.SimDeviceType.iPhone-12-Pro',
27+
'com.apple.CoreSimulator.SimDeviceType.iPhone-12-Pro-Max',
28+
'com.apple.CoreSimulator.SimDeviceType.iPhone-12',
29+
'com.apple.CoreSimulator.SimDeviceType.iPhone-12-mini',
30+
'com.apple.CoreSimulator.SimDeviceType.iPhone-SE--2nd-generation-',
31+
'com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro',
32+
'com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro-Max',
33+
'com.apple.CoreSimulator.SimDeviceType.iPhone-11',
34+
'com.apple.CoreSimulator.SimDeviceType.iPhone-XR',
35+
'com.apple.CoreSimulator.SimDeviceType.iPhone-XS',
36+
'com.apple.CoreSimulator.SimDeviceType.iPhone-XS-Max',
37+
'com.apple.CoreSimulator.SimDeviceType.iPhone-X',
38+
'com.apple.CoreSimulator.SimDeviceType.iPhone-8',
39+
'com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus',
40+
'com.apple.CoreSimulator.SimDeviceType.iPhone-7',
41+
'com.apple.CoreSimulator.SimDeviceType.iPhone-7-Plus',
42+
'com.apple.CoreSimulator.SimDeviceType.iPhone-SE',
43+
'com.apple.CoreSimulator.SimDeviceType.iPhone-6s',
44+
'com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus',
2545

26-
// iPad mini
27-
'com.apple.CoreSimulator.SimDeviceType.iPad-mini-6th-generation',
28-
'com.apple.CoreSimulator.SimDeviceType.iPad-mini-A17-Pro',
46+
// iPad Pro
47+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M5-16GB',
48+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M5-12GB',
49+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-M5-16GB',
50+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-M5-12GB',
51+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M4-16GB',
52+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M4-8GB',
53+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-M4-16GB',
54+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-M4-8GB',
55+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-12-9-inch-6th-generation-16GB',
56+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-12-9-inch-6th-generation-8GB',
57+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-4th-generation-16GB',
58+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-4th-generation-8GB',
59+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-12-9-inch-5th-generation',
60+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-3rd-generation',
61+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---4th-generation-',
62+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--11-inch---2nd-generation-',
63+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---3rd-generation-',
64+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--11-inch-',
65+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--10-5-inch-',
66+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--12-9-inch---2nd-generation-',
67+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro--9-7-inch-',
68+
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro',
2969

3070
// iPad Air
31-
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-5th-generation',
32-
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-11-inch-M2',
71+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-13-inch-M3',
72+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-11-inch-M3',
3373
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-13-inch-M2',
74+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-11-inch-M2',
75+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-5th-generation',
76+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air--4th-generation-',
77+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air--3rd-generation-',
78+
'com.apple.CoreSimulator.SimDeviceType.iPad-Air-2',
3479

35-
// iPad Pro 11-inch
36-
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-4th-generation',
37-
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-M4',
38-
39-
// iPad Pro 12.9 / 13-inch
40-
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-12-9-inch-6th-generation',
41-
'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M4',
80+
// iPad
81+
'com.apple.CoreSimulator.SimDeviceType.iPad-A16',
82+
'com.apple.CoreSimulator.SimDeviceType.iPad-10th-generation',
83+
'com.apple.CoreSimulator.SimDeviceType.iPad-9th-generation',
84+
'com.apple.CoreSimulator.SimDeviceType.iPad--8th-generation-',
85+
'com.apple.CoreSimulator.SimDeviceType.iPad--7th-generation-',
86+
'com.apple.CoreSimulator.SimDeviceType.iPad--6th-generation-',
87+
'com.apple.CoreSimulator.SimDeviceType.iPad--5th-generation-',
4288

43-
// Apple Watch
44-
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-9-41mm',
45-
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-9-45mm',
46-
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Ultra-2-49mm',
89+
// iPad mini
90+
'com.apple.CoreSimulator.SimDeviceType.iPad-mini-A17-Pro',
91+
'com.apple.CoreSimulator.SimDeviceType.iPad-mini-6th-generation',
92+
'com.apple.CoreSimulator.SimDeviceType.iPad-mini--5th-generation-',
93+
'com.apple.CoreSimulator.SimDeviceType.iPad-mini-4',
4794

4895
// Apple TV
4996
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-3rd-generation-4K',
5097
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-3rd-generation-1080p',
98+
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-2nd-generation-4K',
99+
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-2nd-generation-1080p',
100+
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-4K',
101+
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-4K-1080p',
102+
'com.apple.CoreSimulator.SimDeviceType.Apple-TV-1080p',
103+
104+
// Apple Watch
105+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-11-46mm',
106+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-11-42mm',
107+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-10-46mm',
108+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-10-42mm',
109+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Ultra-3-49mm',
110+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Ultra-2-49mm',
111+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-9-45mm',
112+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-9-41mm',
113+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-3-44mm',
114+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-3-40mm',
115+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-8-45mm',
116+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-8-41mm',
117+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Ultra-49mm',
118+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-44mm-2nd-generation',
119+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-40mm-2nd-generation',
120+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-45mm',
121+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-7-41mm',
122+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-44mm',
123+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-6-40mm',
124+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-44mm',
125+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-SE-40mm',
126+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-44mm',
127+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-5-40mm',
128+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-4-44mm',
129+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-4-40mm',
130+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-42mm',
131+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-3-38mm',
132+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-42mm',
133+
'com.apple.CoreSimulator.SimDeviceType.Apple-Watch-Series-2-38mm',
51134

52135
// Apple Vision Pro
136+
'com.apple.CoreSimulator.SimDeviceType.Apple-Vision-Pro-4K',
53137
'com.apple.CoreSimulator.SimDeviceType.Apple-Vision-Pro',
138+
139+
// iPod touch
140+
'com.apple.CoreSimulator.SimDeviceType.iPod-touch--7th-generation-',
54141
];
55142
}
Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,43 @@
1-
// Known CoreSimulator runtime identifiers. Each entry corresponds to an iOS
2-
// (or watchOS/tvOS/visionOS) runtime that can be installed via Xcode.
31
export default async function loadIosSimulatorRuntimes(): Promise<string[]> {
42
return [
53
// iOS
6-
'com.apple.CoreSimulator.SimRuntime.iOS-16-0',
7-
'com.apple.CoreSimulator.SimRuntime.iOS-16-1',
8-
'com.apple.CoreSimulator.SimRuntime.iOS-16-2',
9-
'com.apple.CoreSimulator.SimRuntime.iOS-16-4',
10-
'com.apple.CoreSimulator.SimRuntime.iOS-17-0',
11-
'com.apple.CoreSimulator.SimRuntime.iOS-17-2',
12-
'com.apple.CoreSimulator.SimRuntime.iOS-17-4',
13-
'com.apple.CoreSimulator.SimRuntime.iOS-17-5',
14-
'com.apple.CoreSimulator.SimRuntime.iOS-18-0',
15-
'com.apple.CoreSimulator.SimRuntime.iOS-18-1',
16-
'com.apple.CoreSimulator.SimRuntime.iOS-18-2',
17-
'com.apple.CoreSimulator.SimRuntime.iOS-18-3',
4+
'com.apple.CoreSimulator.SimRuntime.iOS-26-0',
185
'com.apple.CoreSimulator.SimRuntime.iOS-18-4',
6+
'com.apple.CoreSimulator.SimRuntime.iOS-18-3',
7+
'com.apple.CoreSimulator.SimRuntime.iOS-18-2',
8+
'com.apple.CoreSimulator.SimRuntime.iOS-18-1',
9+
'com.apple.CoreSimulator.SimRuntime.iOS-18-0',
10+
'com.apple.CoreSimulator.SimRuntime.iOS-17-5',
11+
'com.apple.CoreSimulator.SimRuntime.iOS-17-4',
12+
'com.apple.CoreSimulator.SimRuntime.iOS-17-2',
13+
'com.apple.CoreSimulator.SimRuntime.iOS-17-0',
14+
'com.apple.CoreSimulator.SimRuntime.iOS-16-4',
15+
'com.apple.CoreSimulator.SimRuntime.iOS-16-2',
16+
'com.apple.CoreSimulator.SimRuntime.iOS-16-1',
17+
'com.apple.CoreSimulator.SimRuntime.iOS-16-0',
1918

2019
// watchOS
21-
'com.apple.CoreSimulator.SimRuntime.watchOS-10-0',
22-
'com.apple.CoreSimulator.SimRuntime.watchOS-10-4',
23-
'com.apple.CoreSimulator.SimRuntime.watchOS-11-0',
20+
'com.apple.CoreSimulator.SimRuntime.watchOS-26-0',
21+
'com.apple.CoreSimulator.SimRuntime.watchOS-11-4',
2422
'com.apple.CoreSimulator.SimRuntime.watchOS-11-2',
23+
'com.apple.CoreSimulator.SimRuntime.watchOS-11-0',
24+
'com.apple.CoreSimulator.SimRuntime.watchOS-10-4',
25+
'com.apple.CoreSimulator.SimRuntime.watchOS-10-0',
2526

2627
// tvOS
27-
'com.apple.CoreSimulator.SimRuntime.tvOS-17-0',
28-
'com.apple.CoreSimulator.SimRuntime.tvOS-17-4',
29-
'com.apple.CoreSimulator.SimRuntime.tvOS-18-0',
28+
'com.apple.CoreSimulator.SimRuntime.tvOS-26-0',
29+
'com.apple.CoreSimulator.SimRuntime.tvOS-18-4',
3030
'com.apple.CoreSimulator.SimRuntime.tvOS-18-2',
31+
'com.apple.CoreSimulator.SimRuntime.tvOS-18-0',
32+
'com.apple.CoreSimulator.SimRuntime.tvOS-17-4',
33+
'com.apple.CoreSimulator.SimRuntime.tvOS-17-0',
3134

3235
// visionOS
33-
'com.apple.CoreSimulator.SimRuntime.xrOS-1-0',
34-
'com.apple.CoreSimulator.SimRuntime.xrOS-1-2',
35-
'com.apple.CoreSimulator.SimRuntime.xrOS-2-0',
36+
'com.apple.CoreSimulator.SimRuntime.xrOS-26-0',
37+
'com.apple.CoreSimulator.SimRuntime.xrOS-2-4',
3638
'com.apple.CoreSimulator.SimRuntime.xrOS-2-2',
39+
'com.apple.CoreSimulator.SimRuntime.xrOS-2-0',
40+
'com.apple.CoreSimulator.SimRuntime.xrOS-1-2',
41+
'com.apple.CoreSimulator.SimRuntime.xrOS-1-0',
3742
];
3843
}

src/resources/ios/ios-simulator/ios-simulator.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ const schema = z.object({
2525
.array(simulatorSchema)
2626
.optional()
2727
.describe('List of iOS simulators to create and manage.'),
28+
acceptLicense: z
29+
.boolean()
30+
.optional()
31+
.describe(
32+
'Automatically accept the Xcode license agreement if it has not been accepted yet. ' +
33+
'Runs `sudo xcodebuild -license accept`. Defaults to true.'
34+
),
2835
});
2936

3037
export type IosSimulatorConfig = z.infer<typeof schema>;
@@ -40,6 +47,16 @@ interface SimctlDevicesOutput {
4047
devices: Record<string, SimDevice[]>;
4148
}
4249

50+
interface SimctlRuntime {
51+
identifier: string;
52+
isAvailable: boolean;
53+
name: string;
54+
}
55+
56+
interface SimctlRuntimesOutput {
57+
runtimes: SimctlRuntime[];
58+
}
59+
4360
const defaultConfig: Partial<IosSimulatorConfig> & { os: any } = {
4461
simulators: [],
4562
os: ['macOS'],
@@ -85,6 +102,12 @@ const exampleMultiDevice: ExampleConfig = {
85102
],
86103
};
87104

105+
// com.apple.CoreSimulator.SimRuntime.iOS-18-0 → "iOS"
106+
function runtimeToXcodebuildPlatform(runtimeId: string): string {
107+
const match = runtimeId.match(/SimRuntime\.([a-zA-Z]+)/);
108+
return match ? match[1] : runtimeId;
109+
}
110+
88111
export class IosSimulatorResource extends Resource<IosSimulatorConfig> {
89112
getSettings(): ResourceSettings<IosSimulatorConfig> {
90113
return {
@@ -109,6 +132,7 @@ export class IosSimulatorResource extends Resource<IosSimulatorConfig> {
109132
current.filter((c) => desired.some((d) => d.name === c.name)),
110133
canModify: true,
111134
},
135+
acceptLicense: { type: 'boolean', setting: true, default: true },
112136
},
113137
};
114138
}
@@ -132,7 +156,11 @@ export class IosSimulatorResource extends Resource<IosSimulatorConfig> {
132156
}
133157

134158
async create(plan: CreatePlan<IosSimulatorConfig>): Promise<void> {
159+
if (plan.desiredConfig.acceptLicense !== false) {
160+
await this.acceptLicenseIfNeeded();
161+
}
135162
await this.assertSimctlAvailable();
163+
await this.assertRuntimesAvailable(plan.desiredConfig.simulators ?? []);
136164
const $ = getPty();
137165
for (const sim of plan.desiredConfig.simulators ?? []) {
138166
await $.spawn(
@@ -192,7 +220,8 @@ export class IosSimulatorResource extends Resource<IosSimulatorConfig> {
192220

193221
private async assertSimctlAvailable(): Promise<void> {
194222
const $ = getPty();
195-
const { status } = await $.spawnSafe('xcrun simctl help');
223+
// Use `xcrun -f simctl` to locate the binary without invoking it — avoids triggering the license prompt
224+
const { status } = await $.spawnSafe('xcrun -f simctl');
196225
if (status !== SpawnStatus.SUCCESS) {
197226
throw new Error(
198227
'xcrun simctl is not available. Xcode must be installed to manage iOS simulators. ' +
@@ -201,6 +230,42 @@ export class IosSimulatorResource extends Resource<IosSimulatorConfig> {
201230
}
202231
}
203232

233+
private async assertRuntimesAvailable(simulators: SimulatorDeclaration[]): Promise<void> {
234+
const $ = getPty();
235+
const { status, data } = await $.spawnSafe('xcrun simctl list runtimes --json');
236+
if (status !== SpawnStatus.SUCCESS) return; // can't verify, let simctl fail with its own message
237+
238+
let availableRuntimes: Set<string>;
239+
try {
240+
const parsed: SimctlRuntimesOutput = JSON.parse(data);
241+
availableRuntimes = new Set(
242+
parsed.runtimes.filter((r) => r.isAvailable).map((r) => r.identifier),
243+
);
244+
} catch {
245+
return;
246+
}
247+
248+
const missing = [...new Set(simulators.map((s) => s.runtime))].filter(
249+
(r) => !availableRuntimes.has(r),
250+
);
251+
252+
if (missing.length > 0) {
253+
throw new Error(
254+
`The following simulator runtime${missing.length > 1 ? 's are' : ' is'} not installed:\n` +
255+
missing.map((r) => ` ${r}`).join('\n') + '\n' +
256+
'Download runtimes in Xcode → Settings → Platforms, or via:\n' +
257+
missing.map((r) => ` xcodebuild -downloadPlatform ${runtimeToXcodebuildPlatform(r)}`).join('\n'),
258+
);
259+
}
260+
}
261+
262+
private async acceptLicenseIfNeeded(): Promise<void> {
263+
const $ = getPty();
264+
const { status } = await $.spawnSafe('xcodebuild -license status');
265+
if (status === SpawnStatus.SUCCESS) return;
266+
await $.spawn('xcodebuild -license accept', { requiresRoot: true });
267+
}
268+
204269
private async listAllDevices(): Promise<Record<string, SimDevice[]> | null> {
205270
const $ = getPty();
206271
const { status, data } = await $.spawnSafe('xcrun simctl list devices --json');

0 commit comments

Comments
 (0)