peachsim 0.1.2193 → 0.1.2195

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 (99) hide show
  1. package/README.md +4 -1
  2. package/cli/commands/control.ts +2 -0
  3. package/cli/commands/kotlin.ts +10 -3
  4. package/cli/commands/package.ts +2 -0
  5. package/cli/native-input.ts +2 -0
  6. package/cli/outbound-endpoints.ts +1 -1
  7. package/dist-lib/agent-daemon-client.cjs +1 -1
  8. package/dist-lib/agent-events.cjs +1 -1
  9. package/dist-lib/attached-projects.cjs +1 -1
  10. package/dist-lib/auth/shared-session.cjs +1 -1
  11. package/dist-lib/backend-origin.cjs +1 -1
  12. package/dist-lib/beta.cjs +1 -1
  13. package/dist-lib/beta.mjs +1 -1
  14. package/dist-lib/bridge-constants.cjs +1 -1
  15. package/dist-lib/bridge-contract-input.cjs +1 -1
  16. package/dist-lib/bridge-contract-input.mjs +1 -1
  17. package/dist-lib/bridge-contract.cjs +1 -1
  18. package/dist-lib/bridge-contract.mjs +1 -1
  19. package/dist-lib/bundle-channel.cjs +986 -785
  20. package/dist-lib/capture-contract.cjs +1 -1
  21. package/dist-lib/capture-contract.mjs +1 -1
  22. package/dist-lib/cloud-contract.cjs +1 -1
  23. package/dist-lib/cloud-contract.mjs +1 -1
  24. package/dist-lib/cloud-test-args.cjs +1 -1
  25. package/dist-lib/cloud-test-args.mjs +1 -1
  26. package/dist-lib/cloud.cjs +1 -1
  27. package/dist-lib/cloud.mjs +1 -1
  28. package/dist-lib/config.cjs +1 -1
  29. package/dist-lib/config.mjs +1 -1
  30. package/dist-lib/detox/index.cjs +1 -1
  31. package/dist-lib/dev-bundle-resolution.cjs +1 -1
  32. package/dist-lib/expo-swift-bundle.cjs +3 -3
  33. package/dist-lib/expo-swift-metadata.cjs +1 -1
  34. package/dist-lib/expo-swift-metadata.mjs +1 -1
  35. package/dist-lib/home-paths.cjs +1 -1
  36. package/dist-lib/host/bridge-host.cjs +991 -790
  37. package/dist-lib/host/fetch-proxy-handler.cjs +2 -2
  38. package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
  39. package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
  40. package/dist-lib/host/replacement-module-handler.cjs +1 -1
  41. package/dist-lib/host/websocket-proxy.cjs +1 -1
  42. package/dist-lib/index.cjs +2 -2
  43. package/dist-lib/jump-to-source-babel.cjs +1 -1
  44. package/dist-lib/jump-to-source-native.cjs +1 -1
  45. package/dist-lib/kotlin-host.cjs +82 -13
  46. package/dist-lib/menu.cjs +1 -1
  47. package/dist-lib/menu.mjs +1 -1
  48. package/dist-lib/metro-fingerprint-registry.cjs +1 -1
  49. package/dist-lib/metro-fingerprint-registry.mjs +1 -1
  50. package/dist-lib/metro-production-bundle.cjs +1 -1
  51. package/dist-lib/metro-production-bundle.mjs +1 -1
  52. package/dist-lib/metro.cjs +2 -2
  53. package/dist-lib/native-app-identity-project.cjs +1 -1
  54. package/dist-lib/native-app-identity-project.mjs +1 -1
  55. package/dist-lib/native-app-identity.cjs +1 -1
  56. package/dist-lib/native-app-identity.mjs +1 -1
  57. package/dist-lib/native-firebase-metadata.cjs +1 -1
  58. package/dist-lib/native-firebase-metadata.mjs +1 -1
  59. package/dist-lib/pdfium-raster.cjs +1 -1
  60. package/dist-lib/pdfium-raster.mjs +1 -1
  61. package/dist-lib/plist.cjs +1 -1
  62. package/dist-lib/plist.mjs +1 -1
  63. package/dist-lib/profiles.cjs +1 -1
  64. package/dist-lib/public-brand.cjs +1 -1
  65. package/dist-lib/public-origins-lib-esm.json +24 -24
  66. package/dist-lib/public-origins-lib.json +65 -62
  67. package/dist-lib/react-native-host-modules.cjs +1 -1
  68. package/dist-lib/react-native-host-modules.mjs +1 -1
  69. package/dist-lib/reap-browser.cjs +1 -1
  70. package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
  71. package/dist-lib/sdk.cjs +1 -1
  72. package/dist-lib/sdk.mjs +1 -1
  73. package/dist-lib/skills.cjs +1513 -1264
  74. package/dist-lib/swift-compile.cjs +1 -1
  75. package/dist-lib/swift-compile.mjs +1 -1
  76. package/dist-lib/swift-package.cjs +1 -1
  77. package/dist-lib/swift-package.mjs +1 -1
  78. package/dist-lib/swift-submit.cjs +1 -1
  79. package/dist-lib/swift-submit.mjs +1 -1
  80. package/dist-lib/swift-toolchain.cjs +1 -1
  81. package/dist-lib/swift.cjs +1 -1
  82. package/dist-lib/vite-swift.cjs +2 -2
  83. package/dist-lib/vite.cjs +2 -2
  84. package/dist-lib/worklet-executable.cjs +1 -1
  85. package/dist-lib/worklet-executable.mjs +1 -1
  86. package/dist-types/packages/peach-engine/src/components/native-ui/context-menu-types.d.ts +1 -0
  87. package/dist-types/packages/peach-engine/src/engine/types.d.ts +1 -0
  88. package/kotlin/sdk.tar.gz +0 -0
  89. package/package.json +1 -1
  90. package/src/android-bridge-dependencies.ts +93 -0
  91. package/src/android-bridge-packages.ts +1 -0
  92. package/src/android-gradle-sources.ts +76 -9
  93. package/src/androidGradleContract.ts +8 -0
  94. package/src/expo-kotlin-host.ts +20 -7
  95. package/src/expoKotlinContract.ts +1 -1
  96. package/src/java-module-abi.ts +7 -1
  97. package/src/kotlin-app.ts +120 -63
  98. package/src/kotlin-host.ts +1 -0
  99. package/src/kotlinSdkContract.ts +8 -1
package/src/kotlin-app.ts CHANGED
@@ -19,6 +19,7 @@ import frameworkThemes from './generated/android-framework-themes.json' with { t
19
19
  import { isRecord } from './is-record'
20
20
  import { composeBomVersions } from './kotlin-compose-bom'
21
21
  import { KotlinVersionCatalog } from './kotlin-version-catalog'
22
+ import type { AndroidGradleDependency } from './androidGradleContract'
22
23
 
23
24
  // statusBarColor and navigationBarColor are ARGB
24
25
  export interface KotlinWindowTheme {
@@ -35,6 +36,7 @@ export interface KotlinAppProject {
35
36
  projectDir: string
36
37
  moduleDir: string
37
38
  sources: string[]
39
+ javaSources: string[]
38
40
  language: string
39
41
  usesSerialization: boolean
40
42
  packageName: string
@@ -93,6 +95,7 @@ const PLUGINS = new Set([
93
95
  // match their Android pins (Peach's activity actuals are that version's); the
94
96
  // lifecycle and savedstate artifacts are Peach's platform actuals.
95
97
  const PLATFORM_GROUPS = new Set(['androidx.lifecycle', 'androidx.savedstate'])
98
+ const PLATFORM_ARTIFACTS = new Set(['androidx.databinding:viewbinding'])
96
99
  // pinned by group, or by group and artifact where a group's artifacts version
97
100
  // apart (material-icons-core stopped at 1.7, beside material-ripple)
98
101
  const ANDROID_PIN: Record<string, keyof AndroidPins> = {
@@ -104,10 +107,12 @@ const ANDROID_PIN: Record<string, keyof AndroidPins> = {
104
107
  'androidx.navigation': 'navigation',
105
108
  'androidx.activity': 'activity',
106
109
  'org.jetbrains.kotlinx:kotlinx-serialization-core': 'serializationCore',
110
+ 'org.jetbrains.kotlinx:kotlinx-serialization-core-jvm': 'serializationCore',
107
111
  'org.jetbrains.kotlin:kotlin-stdlib': 'kotlin',
108
112
  'org.jetbrains.kotlin:kotlin-stdlib-jdk7': 'kotlin',
109
113
  'org.jetbrains.kotlin:kotlin-stdlib-jdk8': 'kotlin',
110
114
  'org.jetbrains.kotlinx:kotlinx-coroutines-core': 'coroutines',
115
+ 'org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm': 'coroutines',
111
116
  'org.jetbrains.kotlinx:kotlinx-coroutines-android': 'coroutines',
112
117
  }
113
118
 
@@ -242,6 +247,7 @@ async function checkModuleGradle(
242
247
  gradle: { file: string; text: string },
243
248
  pins: AndroidPins,
244
249
  catalog: KotlinVersionCatalog,
250
+ nativeDependencies: readonly AndroidGradleDependency[] | null,
245
251
  ) {
246
252
  const at = (index: number) => `${gradle.file}:${lineOf(gradle.text, index)}`
247
253
  const coordinates = (value: string, where: string): string[] => {
@@ -260,7 +266,13 @@ async function checkModuleGradle(
260
266
  const plugin = match[3]
261
267
  ? catalog.plugin(match[3], at(match.index)).id
262
268
  : (match[1] ?? `org.jetbrains.kotlin.${match[2]}`)
263
- if (!PLUGINS.has(plugin))
269
+ if (
270
+ !PLUGINS.has(plugin) &&
271
+ !(
272
+ nativeDependencies !== null &&
273
+ (plugin === 'com.google.devtools.ksp' || plugin === 'io.gitlab.arturbosch.detekt')
274
+ )
275
+ )
264
276
  throw new Error(`${at(match.index)}: plugin ${plugin} is not supported by Peach`)
265
277
  if (
266
278
  plugin === 'org.jetbrains.kotlin.plugin.serialization' &&
@@ -270,53 +282,66 @@ async function checkModuleGradle(
270
282
  )
271
283
  usesSerialization = true
272
284
  }
273
- for (const block of gradle.text.matchAll(/\bdependencies\s*\{/g)) {
274
- // the block runs to its matching brace, on one line or many; every
275
- // statement in it must be a literal dependency Peach can check
276
- const start = block.index + block[0].length
277
- let depth = 1
278
- let end = start
279
- for (; end < gradle.text.length && depth > 0; end++) {
280
- if (gradle.text[end] === '{') depth++
281
- else if (gradle.text[end] === '}') depth--
285
+ if (nativeDependencies !== null) {
286
+ for (const dependency of nativeDependencies) {
287
+ if (dependency.kind !== 'module')
288
+ throw new Error(
289
+ `${gradle.file}: ${dependency.kind} dependency ${dependency.name} is not in Peach's Kotlin closure`,
290
+ )
291
+ dependencies.push({
292
+ coordinate: `${dependency.group}:${dependency.name}:${dependency.version}`,
293
+ where: gradle.file,
294
+ })
282
295
  }
283
- if (depth > 0) throw new Error(`${at(block.index)}: dependencies block never closes`)
284
- const body = gradle.text.slice(start, end - 1)
285
- const platformVariables = new Map<string, string>()
286
- for (const statement of body.matchAll(/[^\n;]+/g)) {
287
- const text = statement[0].replace(/\/\/.*$/, '').trim()
288
- if (!text) continue
289
- const where = at(start + statement.index)
290
- const variable = /^val\s+(\w+)\s*=\s*(platform\(.*\))$/.exec(text)
291
- if (variable?.[1] && variable[2]) {
292
- platformVariables.set(variable[1], variable[2])
293
- continue
296
+ } else
297
+ for (const block of gradle.text.matchAll(/\bdependencies\s*\{/g)) {
298
+ // the block runs to its matching brace, on one line or many; every
299
+ // statement in it must be a literal dependency Peach can check
300
+ const start = block.index + block[0].length
301
+ let depth = 1
302
+ let end = start
303
+ for (; end < gradle.text.length && depth > 0; end++) {
304
+ if (gradle.text[end] === '{') depth++
305
+ else if (gradle.text[end] === '}') depth--
294
306
  }
295
- const call = /^(\w+)\s*\(\s*(.*?)\s*\)$/.exec(text)
296
- if (!call) throw new Error(`${where}: ${text} is not a literal dependency`)
297
- const [, configuration = '', value = ''] = call
298
- if (/^(test|androidTest|debug|release)/.test(configuration)) continue
299
- const platform = /^platform\(\s*(.*?)\s*\)$/.exec(
300
- platformVariables.get(value) ?? value,
301
- )
302
- if (platform?.[1]) {
303
- const declared = coordinates(platform[1], where)
304
- if (declared.length !== 1 || !declared[0])
305
- throw new Error(`${where}: platform expects one BOM coordinate`)
306
- for (const [name, version] of await composeBomVersions(declared[0])) {
307
- const previous = platforms.get(name)
308
- if (previous && previous !== version)
309
- throw new Error(
310
- `${where}: conflicting BOM versions ${previous} and ${version} for ${name}`,
311
- )
312
- platforms.set(name, version)
307
+ if (depth > 0)
308
+ throw new Error(`${at(block.index)}: dependencies block never closes`)
309
+ const body = gradle.text.slice(start, end - 1)
310
+ const platformVariables = new Map<string, string>()
311
+ for (const statement of body.matchAll(/[^\n;]+/g)) {
312
+ const text = statement[0].replace(/\/\/.*$/, '').trim()
313
+ if (!text) continue
314
+ const where = at(start + statement.index)
315
+ const variable = /^val\s+(\w+)\s*=\s*(platform\(.*\))$/.exec(text)
316
+ if (variable?.[1] && variable[2]) {
317
+ platformVariables.set(variable[1], variable[2])
318
+ continue
319
+ }
320
+ const call = /^(\w+)\s*\(\s*(.*?)\s*\)$/.exec(text)
321
+ if (!call) throw new Error(`${where}: ${text} is not a literal dependency`)
322
+ const [, configuration = '', value = ''] = call
323
+ if (/^(test|androidTest|debug|release)/.test(configuration)) continue
324
+ const platform = /^platform\(\s*(.*?)\s*\)$/.exec(
325
+ platformVariables.get(value) ?? value,
326
+ )
327
+ if (platform?.[1]) {
328
+ const declared = coordinates(platform[1], where)
329
+ if (declared.length !== 1 || !declared[0])
330
+ throw new Error(`${where}: platform expects one BOM coordinate`)
331
+ for (const [name, version] of await composeBomVersions(declared[0])) {
332
+ const previous = platforms.get(name)
333
+ if (previous && previous !== version)
334
+ throw new Error(
335
+ `${where}: conflicting BOM versions ${previous} and ${version} for ${name}`,
336
+ )
337
+ platforms.set(name, version)
338
+ }
339
+ } else {
340
+ for (const coordinate of coordinates(value, where))
341
+ dependencies.push({ coordinate, where })
313
342
  }
314
- } else {
315
- for (const coordinate of coordinates(value, where))
316
- dependencies.push({ coordinate, where })
317
343
  }
318
344
  }
319
- }
320
345
  for (const { coordinate, where } of dependencies) {
321
346
  const parts = /^([^:]+):([^:]+)(?::([^:]+))?$/.exec(coordinate)
322
347
  if (!parts)
@@ -336,7 +361,7 @@ async function checkModuleGradle(
336
361
  throw new Error(
337
362
  `${where}: ${name}:${version} differs from Peach's ${pin} pin ${pins[pin]}`,
338
363
  )
339
- } else if (!PLATFORM_GROUPS.has(group))
364
+ } else if (!PLATFORM_GROUPS.has(group) && !PLATFORM_ARTIFACTS.has(name))
340
365
  throw new Error(`${where}: ${name} is not in Peach's Kotlin closure`)
341
366
  }
342
367
  return { usesSerialization }
@@ -498,7 +523,7 @@ function isLauncher(element: XmlElement): boolean {
498
523
 
499
524
  export async function readKotlinApp(
500
525
  moduleArg: string,
501
- options: { activity?: string; pins: AndroidPins },
526
+ options: { activity?: string; variant?: string; pins: AndroidPins },
502
527
  ): Promise<KotlinAppProject> {
503
528
  const moduleDir = fs.realpathSync(path.resolve(moduleArg))
504
529
  const manifestFile = path.join(moduleDir, 'src/main/AndroidManifest.xml')
@@ -520,12 +545,42 @@ export async function readKotlinApp(
520
545
  const gradle = readGradle(moduleDir)
521
546
  if (!gradle) throw new Error(`${moduleDir} has no build.gradle`)
522
547
  const catalog = new KotlinVersionCatalog(projectDir)
523
- const { usesSerialization } = await checkModuleGradle(gradle, options.pins, catalog)
524
- const namespace = gradleLiteral(gradle, 'namespace', '"[\\w.]+"', catalog)
525
- const applicationId = gradleLiteral(gradle, 'applicationId', '"[\\w.]+"', catalog)
526
- const targetSdk = Number(
527
- gradleLiteral(gradle, 'targetSdk(?:Version)?', '\\d+', catalog),
548
+ const variant = options.variant
549
+ const selected =
550
+ variant === undefined
551
+ ? null
552
+ : await (async () => {
553
+ const { resolveAndroidGradleSources } = await import('./android-gradle-sources')
554
+ const [model] = await resolveAndroidGradleSources({
555
+ root: projectDir,
556
+ projects: [moduleDir],
557
+ variant,
558
+ })
559
+ if (!model || model.applicationId === null || model.targetSdk === null)
560
+ throw new Error(
561
+ `${moduleDir}: ${options.variant} is not an Android application variant`,
562
+ )
563
+ return {
564
+ ...model,
565
+ applicationId: model.applicationId,
566
+ targetSdk: model.targetSdk,
567
+ }
568
+ })()
569
+ const { usesSerialization } = await checkModuleGradle(
570
+ gradle,
571
+ options.pins,
572
+ catalog,
573
+ selected?.dependencies ?? null,
528
574
  )
575
+ const namespace = selected
576
+ ? selected.namespace
577
+ : gradleLiteral(gradle, 'namespace', '"[\\w.]+"', catalog)
578
+ const applicationId = selected
579
+ ? selected.applicationId
580
+ : gradleLiteral(gradle, 'applicationId', '"[\\w.]+"', catalog)
581
+ const targetSdk = selected
582
+ ? selected.targetSdk
583
+ : Number(gradleLiteral(gradle, 'targetSdk(?:Version)?', '\\d+', catalog))
529
584
  if (!Number.isInteger(targetSdk) || targetSdk <= 0)
530
585
  throw new Error(`${gradle.file}: declares no literal targetSdk`)
531
586
  const kotlin = kotlinPluginVersion(projectDir, gradle, catalog)
@@ -658,21 +713,22 @@ export async function readKotlinApp(
658
713
  if (!softInputAdjust)
659
714
  throw new Error(`${manifestFile}: unknown windowSoftInputMode ${adjust}`)
660
715
 
661
- const sources: string[] = []
662
- for (const set of ['java', 'kotlin']) {
663
- const dir = path.join(moduleDir, 'src/main', set)
664
- if (!fs.existsSync(dir)) continue
665
- const walk = (current: string) => {
666
- for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
667
- const full = path.join(current, entry.name)
668
- if (entry.isDirectory()) walk(full)
669
- else if (entry.name.endsWith('.java'))
670
- throw new Error(`${full}: Java sources are not supported by peach open`)
671
- else if (entry.name.endsWith('.kt')) sources.push(full)
716
+ const sources: string[] = selected ? selected.kotlin : []
717
+ if (!selected)
718
+ for (const set of ['java', 'kotlin']) {
719
+ const dir = path.join(moduleDir, 'src/main', set)
720
+ if (!fs.existsSync(dir)) continue
721
+ const walk = (current: string) => {
722
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
723
+ const full = path.join(current, entry.name)
724
+ if (entry.isDirectory()) walk(full)
725
+ else if (entry.name.endsWith('.java'))
726
+ throw new Error(`${full}: Java sources are not supported by peach open`)
727
+ else if (entry.name.endsWith('.kt')) sources.push(full)
728
+ }
672
729
  }
730
+ walk(dir)
673
731
  }
674
- walk(dir)
675
- }
676
732
  if (sources.length === 0)
677
733
  throw new Error(`${moduleDir}/src/main holds no Kotlin sources`)
678
734
  const resources = {
@@ -683,6 +739,7 @@ export async function readKotlinApp(
683
739
  projectDir,
684
740
  moduleDir,
685
741
  sources: sources.sort(),
742
+ javaSources: selected ? selected.java : [],
686
743
  language,
687
744
  usesSerialization,
688
745
  packageName: applicationId ?? base,
@@ -918,6 +918,7 @@ export async function kotlinAppArtifact(
918
918
  toolchain,
919
919
  language: app.language,
920
920
  sources: app.sources,
921
+ javaSpecs: app.javaSources,
921
922
  generated,
922
923
  sdkProfile: 'app',
923
924
  usesCompose: true,
@@ -37,12 +37,19 @@ export const KOTLIN_SDK_PROFILES = {
37
37
  'BridgeSources',
38
38
  'AndroidViewSources',
39
39
  'ComposeSources',
40
+ 'AndroidComposeSources',
40
41
  'ExpoComposeSources',
41
42
  ],
42
43
  },
43
44
  app: {
44
45
  compose: true,
45
- directories: [...platform, 'ComposeSources', 'AppSources', 'AndroidViewSources'],
46
+ directories: [
47
+ ...platform,
48
+ 'ComposeSources',
49
+ 'AppSources',
50
+ 'AndroidViewSources',
51
+ 'AndroidComposeSources',
52
+ ],
46
53
  },
47
54
  } satisfies Record<string, { compose: boolean; directories: string[] }>
48
55