peachsim 0.1.1625 → 0.1.1640

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +15 -2
  3. package/cli/app-config.ts +18 -6
  4. package/cli/app-fonts.ts +37 -17
  5. package/cli/app-stubs.ts +284 -20
  6. package/cli/bridge-flow-runner.ts +66 -45
  7. package/cli/cloud-client.ts +60 -40
  8. package/cli/command-registry.ts +1 -0
  9. package/cli/commands/control.ts +283 -49
  10. package/cli/commands/doctor.ts +30 -189
  11. package/cli/commands/flow.ts +79 -11
  12. package/cli/commands/inspect/core.ts +10 -5
  13. package/cli/commands/inspect/settling.ts +14 -2
  14. package/cli/commands/inspect/shared.ts +9 -4
  15. package/cli/commands/inspect/wait-ready.ts +12 -0
  16. package/cli/commands/inspect.ts +91 -50
  17. package/cli/commands/install-desktop.ts +1 -0
  18. package/cli/commands/maestro-compare.ts +97 -38
  19. package/cli/commands/maestro.ts +9 -1
  20. package/cli/commands/preview.ts +1 -1
  21. package/cli/commands/record.ts +118 -48
  22. package/cli/commands/screenshot.ts +23 -1
  23. package/cli/commands/serve.ts +7 -2
  24. package/cli/commands/setup.ts +19 -42
  25. package/cli/commands/swift.ts +14 -3
  26. package/cli/commands/upload.ts +93 -48
  27. package/cli/desktop-companion.ts +102 -17
  28. package/cli/drivers/desktop.ts +14 -1
  29. package/cli/drivers/playwright-sim-host.ts +103 -45
  30. package/cli/drivers/playwright.ts +9 -8
  31. package/cli/drivers/types.ts +5 -0
  32. package/cli/maestro-accessibility.ts +1 -1
  33. package/cli/maestro-compare.ts +84 -12
  34. package/cli/main.ts +3 -2
  35. package/cli/outbound-endpoints.ts +20 -6
  36. package/cli/pause-aware-timeout.ts +106 -0
  37. package/cli/scene-video.ts +89 -0
  38. package/cli/ws-bridge.ts +37 -19
  39. package/detox/attempt-events.cjs +66 -5
  40. package/detox/attempt-events.d.cts +7 -0
  41. package/detox/expectations.ts +7 -3
  42. package/detox/index.ts +269 -170
  43. package/detox/motion-change.cjs +206 -21
  44. package/detox/motion-change.d.cts +39 -2
  45. package/detox/navigation-lifecycle.ts +35 -3
  46. package/dist-lib/agent-daemon-client.cjs +1 -1
  47. package/dist-lib/agent-events.cjs +1 -1
  48. package/dist-lib/attached-projects.cjs +1 -1
  49. package/dist-lib/auth/shared-session.cjs +1 -1
  50. package/dist-lib/backend-origin.cjs +8 -7
  51. package/dist-lib/beta.cjs +1 -1
  52. package/dist-lib/beta.mjs +1 -1
  53. package/dist-lib/bridge-constants.cjs +13 -1
  54. package/dist-lib/bridge-contract-input.cjs +1 -1
  55. package/dist-lib/bridge-contract-input.mjs +1 -1
  56. package/dist-lib/bridge-contract.cjs +14 -8
  57. package/dist-lib/bridge-contract.mjs +13 -7
  58. package/dist-lib/bundle-channel.cjs +11887 -7900
  59. package/dist-lib/capture-contract.cjs +1 -1
  60. package/dist-lib/capture-contract.mjs +1 -1
  61. package/dist-lib/cloud-contract.cjs +1 -1
  62. package/dist-lib/cloud-contract.mjs +1 -1
  63. package/dist-lib/cloud-test-args.cjs +1 -1
  64. package/dist-lib/cloud-test-args.mjs +1 -1
  65. package/dist-lib/cloud.cjs +1 -1
  66. package/dist-lib/cloud.mjs +1 -1
  67. package/dist-lib/config.cjs +6 -3
  68. package/dist-lib/config.mjs +6 -3
  69. package/dist-lib/detox/index.cjs +1379 -725
  70. package/dist-lib/dev-bundle-resolution.cjs +14 -2
  71. package/dist-lib/expo-swift-bundle.cjs +9341 -5462
  72. package/dist-lib/expo-swift-metadata.cjs +11 -7
  73. package/dist-lib/expo-swift-metadata.mjs +11 -7
  74. package/dist-lib/home-paths.cjs +32 -3
  75. package/dist-lib/host/bridge-host.cjs +50204 -7258
  76. package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
  77. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  78. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  79. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  80. package/dist-lib/host/websocket-proxy.cjs +1 -1
  81. package/dist-lib/index.cjs +3541 -448
  82. package/dist-lib/jump-to-source-babel.cjs +1 -1
  83. package/dist-lib/jump-to-source-native.cjs +1 -1
  84. package/dist-lib/kotlin-host.cjs +1 -1
  85. package/dist-lib/menu.cjs +1 -1
  86. package/dist-lib/menu.mjs +1 -1
  87. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  88. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  89. package/dist-lib/metro-production-bundle.cjs +1 -1
  90. package/dist-lib/metro-production-bundle.mjs +1 -1
  91. package/dist-lib/metro.cjs +2931 -104
  92. package/dist-lib/native-app-identity-project.cjs +289 -49
  93. package/dist-lib/native-app-identity-project.mjs +289 -49
  94. package/dist-lib/native-app-identity.cjs +77 -26
  95. package/dist-lib/native-app-identity.mjs +76 -26
  96. package/dist-lib/native-firebase-metadata.cjs +1 -1
  97. package/dist-lib/native-firebase-metadata.mjs +1 -1
  98. package/dist-lib/plist.cjs +1 -1
  99. package/dist-lib/plist.mjs +1 -1
  100. package/dist-lib/profiles.cjs +1 -1
  101. package/dist-lib/public-brand.cjs +1 -1
  102. package/dist-lib/react-native-host-modules.cjs +6 -2
  103. package/dist-lib/react-native-host-modules.mjs +6 -2
  104. package/dist-lib/scripts/dev-server-scanner.cjs +22 -8
  105. package/dist-lib/sdk.cjs +27 -11
  106. package/dist-lib/sdk.mjs +27 -10
  107. package/dist-lib/skills.cjs +72201 -26208
  108. package/dist-lib/swift-compile.cjs +1007 -140
  109. package/dist-lib/swift-compile.mjs +1049 -174
  110. package/dist-lib/swift-package.cjs +12 -3
  111. package/dist-lib/swift-package.mjs +12 -3
  112. package/dist-lib/swift-submit.cjs +13 -5
  113. package/dist-lib/swift-submit.mjs +11 -5
  114. package/dist-lib/swift-toolchain.cjs +423 -33
  115. package/dist-lib/swift.cjs +1 -1
  116. package/dist-lib/vite-swift.cjs +8628 -5268
  117. package/dist-lib/vite.cjs +2859 -12
  118. package/dist-lib/worklet-executable.cjs +14 -2
  119. package/dist-lib/worklet-executable.mjs +14 -2
  120. package/kotlin/AppSources/dev/peach/app/PeachDrawable.kt +21 -14
  121. package/kotlin/Sources/androidx/annotation/DrawableRes.kt +14 -0
  122. package/package.json +1 -1
  123. package/scripts/dev-server-scanner.ts +2 -1
  124. package/skills/peach-perf/SKILL.md +11 -5
  125. package/skills/peach-setup/SKILL.md +16 -19
  126. package/src/backend-origin.ts +13 -6
  127. package/src/bridge-constants.ts +11 -0
  128. package/src/bridge-contract.ts +22 -34
  129. package/src/config.ts +15 -0
  130. package/src/desktop-host-delivery.ts +5 -1
  131. package/src/dev-bundle-resolution.ts +2 -1
  132. package/src/expo-manifest-body.ts +13 -0
  133. package/src/expo-swift-host.ts +196 -49
  134. package/src/expo-swift-ready.ts +78 -0
  135. package/src/expoKotlinContract.ts +4 -7
  136. package/src/expoSwiftContract.ts +17 -6
  137. package/src/home-paths.ts +48 -2
  138. package/src/host/bridge-host.ts +5 -2
  139. package/src/host/staged-host-files.ts +9 -0
  140. package/src/native-app-identity-project.ts +27 -6
  141. package/src/native-app-identity.ts +91 -4
  142. package/src/native-firebase-config.ts +209 -13
  143. package/src/nativeAppIconContract.ts +1 -4
  144. package/src/output-lock-stdio.ts +36 -0
  145. package/src/process-group.ts +25 -2
  146. package/src/react-native-bridge-modules.ts +431 -0
  147. package/src/react-native-host-modules.ts +8 -1
  148. package/src/settings-bundle.ts +1 -4
  149. package/src/swift-binary-modules.ts +2 -2
  150. package/src/swift-compile.ts +918 -109
  151. package/src/swift-compiler-digest.ts +14 -0
  152. package/src/swift-distribution.lock.json +24 -12
  153. package/src/swift-distribution.ts +103 -4
  154. package/src/swift-host.ts +180 -55
  155. package/src/swift-icu.ts +27 -13
  156. package/src/swift-objc-compile.ts +355 -0
  157. package/src/swift-objc-sdk.ts +821 -27
  158. package/src/swift-objc-standin.ts +148 -14
  159. package/src/swift-package-manifest.ts +60 -7
  160. package/src/swift-package.ts +15 -1
  161. package/src/swift-packages.ts +154 -81
  162. package/src/swift-standin-emit.ts +96 -15
  163. package/src/swift-standins.ts +530 -116
  164. package/src/swift-submit.ts +13 -5
  165. package/src/swift-toolchain.ts +500 -42
  166. package/src/vite-plugin.ts +12 -1
  167. package/src/worker-system-chunks.ts +11 -12
  168. package/src/worklet-executable.ts +19 -1
  169. package/src/xcode-project.ts +270 -30
@@ -0,0 +1,355 @@
1
+ import { spawnSync } from 'node:child_process'
2
+ import { createHash } from 'node:crypto'
3
+ import fs from 'node:fs'
4
+ import path from 'node:path'
5
+ import { cacheDir } from './home-paths'
6
+ import { swiftSdkPaths, swiftModuleSdk } from './swift-compile'
7
+ import { swiftModuleToolchain } from './swift-distribution'
8
+ import { IOS_SDK_ID, materializeObjcSdk } from './swift-objc-standin'
9
+ import { swiftTargetModuleName } from './swift-package'
10
+ import { swiftPackageManifest, swiftTargetFiles } from './swift-package-manifest'
11
+ import { remoteSwiftCheckouts, type SwiftPackageBinary } from './swift-packages'
12
+ import { readPackageFile } from './swift-source-file'
13
+ import { swiftEnvironment } from './swift-toolchain'
14
+ import type { XcodeAppTarget } from './xcode-project'
15
+
16
+ /** compile original implementations before any header-derived replacement can hide them.
17
+ * successful objects still require the canonical framework bridge before linking. */
18
+ export function compileXcodeObjCImplementations(
19
+ app: XcodeAppTarget,
20
+ binaries: readonly SwiftPackageBinary[],
21
+ moduleRoot: string,
22
+ ): never {
23
+ const toolchain = swiftModuleToolchain(moduleRoot)
24
+ const sdk = swiftSdkPaths(moduleRoot, toolchain.toolchainBin)
25
+ const sources = new Map<string, Buffer>()
26
+ const links: Record<string, string> = {}
27
+ const checkouts = remoteSwiftCheckouts(app.rootDir)
28
+ const add = (file: string, header = false) => {
29
+ const resolved = header ? fs.realpathSync(file) : file
30
+ if (resolved !== file) links[file] = resolved
31
+ if (!sources.has(file))
32
+ sources.set(
33
+ file,
34
+ readPackageFile(
35
+ file.startsWith(`${checkouts}${path.sep}`) ? checkouts : app.rootDir,
36
+ resolved,
37
+ Infinity,
38
+ ),
39
+ )
40
+ }
41
+ const addHeaders = (directory: string): void => {
42
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
43
+ const file = path.join(directory, entry.name)
44
+ if (entry.isDirectory()) addHeaders(file)
45
+ else if (/\.(h|hh|hpp|hxx|inc|inl|modulemap)$/.test(entry.name)) add(file, true)
46
+ }
47
+ }
48
+ const targets: {
49
+ name: string
50
+ deploymentTarget: string | null
51
+ files: string[]
52
+ includes: string[]
53
+ frameworks: string[]
54
+ flags: string[]
55
+ cxxFlags: string[]
56
+ prefix: string | null
57
+ fileFlags: Record<string, string[]>
58
+ publicHeaders?: string
59
+ }[] = []
60
+ const configuration = app.configuration === 'Debug' ? 'debug' : 'release'
61
+ for (const binary of binaries) {
62
+ if (!binary.reached || binary.publicHeaders === undefined) continue
63
+ const manifest = swiftPackageManifest(binary.dir)
64
+ const target = manifest.targets.get(binary.target)
65
+ if (!target)
66
+ throw new Error(`missing original implementation target ${binary.target}`)
67
+ const files = swiftTargetFiles(manifest, target)
68
+ for (const file of files) add(file)
69
+ addHeaders(path.join(target.dir, target.publicHeadersPath))
70
+ for (const dependency of binary.headerDependencies ?? [])
71
+ addHeaders(path.resolve(binary.dir, dependency.path))
72
+ const settings = target.nativeSettings.filter(
73
+ (setting) =>
74
+ setting.configuration === null || setting.configuration === configuration,
75
+ )
76
+ targets.push({
77
+ name: target.name,
78
+ deploymentTarget: app.iosDeploymentTarget,
79
+ files: files.filter((file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file)),
80
+ includes: [
81
+ path.join(target.dir, target.publicHeadersPath),
82
+ ...(binary.headerDependencies ?? []).map((dependency) =>
83
+ path.resolve(binary.dir, dependency.path),
84
+ ),
85
+ ],
86
+ frameworks: [],
87
+ // retain the source iOS package's ARC and module semantics on the wasm ABI.
88
+ flags: [
89
+ '-fobjc-arc',
90
+ '-fmodules',
91
+ '-DSWIFT_PACKAGE',
92
+ ...(configuration === 'debug' ? ['-DDEBUG'] : []),
93
+ ...settings
94
+ .filter((setting) => setting.tool === 'c')
95
+ .flatMap((setting) => setting.flags),
96
+ ],
97
+ cxxFlags: settings
98
+ .filter((setting) => setting.tool === 'cxx')
99
+ .flatMap((setting) => setting.flags),
100
+ prefix: null,
101
+ fileFlags: {},
102
+ publicHeaders: path.join(target.dir, target.publicHeadersPath),
103
+ })
104
+ }
105
+ for (const target of [...app.frameworks, app]) {
106
+ if (!target.objc) continue
107
+ const files = target.allSources.filter((file) => /\.(c|cc|cpp|cxx|m|mm)$/.test(file))
108
+ for (const file of files) add(file)
109
+ for (const file of [
110
+ ...target.objc.headers,
111
+ ...[target.objc.prefixHeader, target.objc.bridgingHeader].filter(
112
+ (file): file is string => file !== null,
113
+ ),
114
+ ])
115
+ add(file, true)
116
+ targets.push({
117
+ name: target.moduleName,
118
+ deploymentTarget: target.iosDeploymentTarget,
119
+ files,
120
+ includes: target.objc.headerSearchPaths,
121
+ frameworks: target.objc.frameworkSearchPaths,
122
+ flags: target.objc.flags,
123
+ cxxFlags: target.objc.cxxFlags,
124
+ prefix: target.objc.prefixHeader,
125
+ fileFlags: target.objc.fileFlags,
126
+ })
127
+ }
128
+ const digest = (bytes: Buffer | string) =>
129
+ createHash('sha256').update(bytes).digest('hex')
130
+ const inputs = Object.fromEntries(
131
+ [...sources].map(([file, bytes]) => [file, digest(bytes)]),
132
+ )
133
+ const identity = {
134
+ version: 1,
135
+ release: toolchain.release,
136
+ compiler: digest(fs.readFileSync(path.join(toolchain.toolchainBin, 'clang'))),
137
+ sdk: swiftModuleSdk(moduleRoot),
138
+ declarations: IOS_SDK_ID,
139
+ targets,
140
+ inputs,
141
+ links,
142
+ }
143
+ const parent = path.join(cacheDir(), 'swift-objc-implementations')
144
+ fs.mkdirSync(parent, { recursive: true })
145
+ const key = digest(JSON.stringify(identity))
146
+ const work = path.join(parent, key)
147
+ const resultFile = path.join(work, 'result.json')
148
+ const record = (value: unknown): value is Record<string, unknown> =>
149
+ value !== null && typeof value === 'object' && !Array.isArray(value)
150
+ if (fs.existsSync(work)) {
151
+ let message: string
152
+ try {
153
+ const result: unknown = JSON.parse(
154
+ readPackageFile(work, resultFile, Infinity).toString(),
155
+ )
156
+ if (
157
+ !record(result) ||
158
+ result.key !== key ||
159
+ typeof result.message !== 'string' ||
160
+ !result.message ||
161
+ !record(result.files) ||
162
+ Object.keys(result.files).length < sources.size + 1 ||
163
+ !('receipt.json' in result.files)
164
+ )
165
+ throw new Error('invalid completed receipt')
166
+ for (const [file, hash] of Object.entries(result.files)) {
167
+ if (
168
+ typeof hash !== 'string' ||
169
+ digest(readPackageFile(work, path.resolve(work, file), Infinity)) !== hash
170
+ )
171
+ throw new Error(`retained file changed: ${file}`)
172
+ }
173
+ message = result.message
174
+ } catch (cause) {
175
+ throw new Error(
176
+ `Objective-C implementation preparation has an incomplete or damaged receipt at ${work}`,
177
+ { cause },
178
+ )
179
+ }
180
+ throw new Error(message)
181
+ }
182
+ // exclusive creation prevents another caller from writing the same objects.
183
+ fs.mkdirSync(work)
184
+ const staged = (file: string): string => {
185
+ for (const { root, name } of [
186
+ { root: checkouts, name: 'packages' },
187
+ { root: app.rootDir, name: 'project' },
188
+ ]) {
189
+ const relative = path.relative(root, file)
190
+ if (
191
+ relative !== '..' &&
192
+ !relative.startsWith(`..${path.sep}`) &&
193
+ !path.isAbsolute(relative)
194
+ )
195
+ return path.join(work, name, relative)
196
+ }
197
+ // native SDK include paths select the wasm SDK, never host system headers.
198
+ if (file.startsWith('/usr/include/'))
199
+ return path.join(sdk.sysroot, 'include', file.slice('/usr/include/'.length))
200
+ throw new Error(
201
+ `Objective-C compiler input is outside the project and its pinned packages: ${file}`,
202
+ )
203
+ }
204
+ for (const [file, bytes] of sources) {
205
+ const output = staged(file)
206
+ fs.mkdirSync(path.dirname(output), { recursive: true })
207
+ fs.writeFileSync(output, bytes)
208
+ }
209
+ const headers = materializeObjcSdk(path.join(cacheDir(), 'swift-standins'))
210
+ const modulemaps = targets.flatMap((target, index) => {
211
+ if (!target.publicHeaders) return []
212
+ const custom = path.join(target.publicHeaders, 'module.modulemap')
213
+ if (sources.has(custom)) return [`-fmodule-map-file=${staged(custom)}`]
214
+ const output = path.join(work, `module-${index}.modulemap`)
215
+ fs.writeFileSync(
216
+ output,
217
+ `module ${swiftTargetModuleName(target.name)} {\n umbrella ${JSON.stringify(staged(target.publicHeaders))}\n export *\n}\n`,
218
+ )
219
+ return [`-fmodule-map-file=${output}`]
220
+ })
221
+ const commands: {
222
+ target: string
223
+ source: string
224
+ args: string[]
225
+ status: number | null
226
+ signal: string | null
227
+ object?: string
228
+ }[] = []
229
+ const receipt = path.join(work, 'receipt.json')
230
+ const save = (status: string) =>
231
+ fs.writeFileSync(
232
+ receipt,
233
+ JSON.stringify({ ...identity, work, status, commands }, null, 2),
234
+ )
235
+ const finish = (status: string, message: string): never => {
236
+ save(status)
237
+ const files = [
238
+ ...[...sources.keys()].map(staged),
239
+ ...modulemaps.map((flag) => flag.slice('-fmodule-map-file='.length)),
240
+ receipt,
241
+ ...commands.flatMap((command) => {
242
+ const output = command.args[command.args.lastIndexOf('-o') + 1]!
243
+ return [output.replace(/\.o$/, '.log'), ...(command.object ? [output] : [])]
244
+ }),
245
+ ]
246
+ const result = {
247
+ key,
248
+ message,
249
+ files: Object.fromEntries(
250
+ files.map((file) => [path.relative(work, file), digest(fs.readFileSync(file))]),
251
+ ),
252
+ }
253
+ fs.writeFileSync(`${resultFile}.pending`, JSON.stringify(result, null, 2))
254
+ fs.renameSync(`${resultFile}.pending`, resultFile)
255
+ throw new Error(message)
256
+ }
257
+ save('compiling')
258
+ for (const [index, target] of targets.entries()) {
259
+ const version = /^(\d{1,2})(?:\.(\d{1,2}))?(?:\.(\d{1,2}))?$/.exec(
260
+ target.deploymentTarget ?? '',
261
+ )
262
+ if (!version) {
263
+ return finish(
264
+ 'unsupported-deployment-target',
265
+ `${target.name}: Objective-C compilation requires an explicit numeric IPHONEOS_DEPLOYMENT_TARGET; received ${JSON.stringify(target.deploymentTarget)}. Inputs: ${receipt}`,
266
+ )
267
+ }
268
+ const minimum =
269
+ Number(version[1]) * 10_000 +
270
+ Number(version[2] ?? 0) * 100 +
271
+ Number(version[3] ?? 0)
272
+ for (const [unit, file] of target.files.entries()) {
273
+ const output = path.join(work, `${index}-${unit}.o`)
274
+ const cxx = /\.(mm|cc|cpp|cxx)$/.test(file)
275
+ const objc = /\.mm?$/.test(file)
276
+ const flags = [
277
+ ...target.flags.filter(
278
+ (flag) =>
279
+ (!cxx || !flag.startsWith('-std=')) && (objc || flag !== '-fobjc-arc'),
280
+ ),
281
+ ...(cxx ? target.cxxFlags : []),
282
+ ...(target.fileFlags[file] ?? []),
283
+ ].map((flag, index, flags) => {
284
+ if (
285
+ ['-I', '-F', '-iquote', '-isystem', '-include'].includes(flags[index - 1] ?? '')
286
+ )
287
+ return staged(flag)
288
+ const include = /^(-I|-F)(\/.*)$/.exec(flag)
289
+ return include ? `${include[1]}${staged(include[2]!)}` : flag
290
+ })
291
+ const args = [
292
+ '--target=wasm32-unknown-wasip1',
293
+ `--sysroot=${sdk.sysroot}`,
294
+ '-fwasm-exceptions',
295
+ '-fexceptions',
296
+ '-D_WASI_EMULATED_SIGNAL',
297
+ '-D_WASI_EMULATED_MMAN',
298
+ `-D__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__=${minimum}`,
299
+ `-D__IPHONE_OS_VERSION_MIN_REQUIRED=${minimum}`,
300
+ ...(objc ? ['-fobjc-runtime=gnustep-2.2', '-fobjc-exceptions', '-fblocks'] : []),
301
+ '-F',
302
+ path.join(headers, 'System/Library/Frameworks'),
303
+ // installed libc and objc runtime headers own the target ABI.
304
+ '-idirafter',
305
+ path.join(headers, 'usr/include'),
306
+ ...target.includes.flatMap((include) => ['-I', staged(include)]),
307
+ ...target.frameworks.flatMap((framework) => ['-F', staged(framework)]),
308
+ ...modulemaps,
309
+ `-fmodule-name=${swiftTargetModuleName(target.name)}`,
310
+ `-fmodules-cache-path=${path.join(work, 'module-cache')}`,
311
+ ...flags,
312
+ ...(target.prefix ? ['-include', staged(target.prefix)] : []),
313
+ '-Os',
314
+ '-c',
315
+ staged(file),
316
+ '-o',
317
+ output,
318
+ ]
319
+ const result = spawnSync(
320
+ path.join(toolchain.toolchainBin, cxx ? 'clang++' : 'clang'),
321
+ args,
322
+ {
323
+ cwd: work,
324
+ encoding: 'utf8',
325
+ env: swiftEnvironment(),
326
+ timeout: 120_000,
327
+ maxBuffer: 16 * 1024 * 1024,
328
+ },
329
+ )
330
+ fs.writeFileSync(
331
+ path.join(work, `${index}-${unit}.log`),
332
+ `${result.stdout ?? ''}${result.stderr ?? ''}${result.error?.message ?? ''}`,
333
+ )
334
+ commands.push({
335
+ target: target.name,
336
+ source: file,
337
+ args,
338
+ status: result.status,
339
+ signal: result.signal,
340
+ ...(result.status === 0 ? { object: digest(fs.readFileSync(output)) } : {}),
341
+ })
342
+ if (result.error || result.status !== 0) {
343
+ return finish(
344
+ 'compile-failed',
345
+ `Objective-C implementation compile failed in ${target.name}: ${file}\n${result.stderr || result.stdout || result.error?.message}\nOriginal inputs, compiler command and diagnostics: ${receipt}`,
346
+ )
347
+ }
348
+ save('compiling')
349
+ }
350
+ }
351
+ return finish(
352
+ 'requires-framework-bridge',
353
+ `Objective-C implementations compiled, but linking their original method bodies requires the canonical Swift framework object bridge. No implementation was replaced. Inputs and objects: ${receipt}`,
354
+ )
355
+ }