peachsim 0.1.648 → 0.1.650
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.
- package/README.md +10 -9
- package/cli/command-registry.ts +2 -1
- package/cli/commands/guest-host.ts +67 -0
- package/cli/commands/kotlin.ts +231 -0
- package/cli/commands/project-report.ts +1 -1
- package/cli/commands/report-issue.ts +55 -32
- package/cli/commands/setup.ts +10 -14
- package/cli/commands/support.ts +399 -0
- package/cli/commands/swift.ts +6 -52
- package/cli/commands/telemetry.ts +10 -13
- package/cli/main.ts +22 -10
- package/cli/outbound-endpoints.ts +23 -2
- package/cli/privacy.ts +23 -25
- package/cli/runtime-notes.ts +3 -2
- package/cli/telemetry.ts +109 -14
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract-input.cjs +1 -1
- package/dist-lib/bridge-contract-input.mjs +1 -1
- package/dist-lib/bridge-contract.cjs +1 -1
- package/dist-lib/bridge-contract.mjs +1 -1
- package/dist-lib/capture-contract.cjs +1 -1
- package/dist-lib/capture-contract.mjs +1 -1
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/cloud-contract.cjs +1 -1
- package/dist-lib/cloud-contract.mjs +1 -1
- package/dist-lib/cloud-test-args.cjs +1 -1
- package/dist-lib/cloud-test-args.mjs +1 -1
- package/dist-lib/cloud.cjs +1 -1
- package/dist-lib/cloud.mjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +3 -3
- package/dist-lib/host/bridge-host.cjs +1 -1
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/replacement-module-handler.cjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +1 -1
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/jump-to-source-native.cjs +1 -1
- package/dist-lib/kotlin-host.cjs +102 -21
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro-fingerprint-registry.cjs +1 -1
- package/dist-lib/metro-fingerprint-registry.mjs +1 -1
- package/dist-lib/metro-production-bundle.cjs +1 -1
- package/dist-lib/metro-production-bundle.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/native-app-identity.cjs +1 -1
- package/dist-lib/native-app-identity.mjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/react-native-host-modules.cjs +1 -1
- package/dist-lib/react-native-host-modules.mjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +1 -1
- package/dist-lib/sdk.mjs +1 -1
- package/dist-lib/skills.cjs +28 -39
- package/dist-lib/swift-compile.cjs +6 -3
- package/dist-lib/swift-compile.mjs +6 -3
- package/dist-lib/swift-package.cjs +1 -1
- package/dist-lib/swift-package.mjs +1 -1
- package/dist-lib/swift-submit.cjs +1 -1
- package/dist-lib/swift-submit.mjs +1 -1
- package/dist-lib/swift.cjs +1 -1
- package/dist-lib/vite-swift.cjs +6 -3
- package/dist-lib/vite.cjs +1 -1
- package/kotlin/AppSources/android/app/Activity.kt +85 -0
- package/kotlin/AppSources/android/app/Application.kt +7 -0
- package/kotlin/AppSources/android/content/Context.kt +5 -0
- package/kotlin/AppSources/android/content/Intent.kt +16 -0
- package/kotlin/AppSources/android/os/Bundle.kt +5 -0
- package/kotlin/AppSources/android/util/SuperNotCalledException.kt +3 -0
- package/kotlin/AppSources/android/view/View.kt +72 -0
- package/kotlin/AppSources/android/view/Window.kt +44 -0
- package/kotlin/AppSources/android/widget/FrameLayout.kt +6 -0
- package/kotlin/AppSources/androidx/activity/ComponentActivity.kt +57 -0
- package/kotlin/AppSources/androidx/activity/compose/ComponentActivity.kt +29 -0
- package/kotlin/AppSources/androidx/compose/ui/platform/ComposeView.kt +67 -0
- package/kotlin/AppSources/dev/peach/app/PeachApp.kt +136 -0
- package/kotlin/AppSources/dev/peach/app/PeachWindowHost.kt +13 -0
- package/kotlin/ComposeSources/PeachComposeHost.kt +316 -0
- package/kotlin/Sources/dev/onejs/one/OneNativeSourceViewDispatch.kt +13 -0
- package/kotlin/Sources/org/json/JSON.kt +6 -0
- package/kotlin/fixtures/counter/Counter.d.kt.ts +16 -0
- package/kotlin/fixtures/counter/Counter.kt +18 -0
- package/kotlin/fixtures/counter/CounterApp.native.tsx +34 -0
- package/kotlin/fixtures/counter/CounterApp.tsx +3 -0
- package/kotlin/fixtures/counter/CounterScreen.d.kt.ts +7 -0
- package/kotlin/fixtures/counter/CounterScreen.kt +18 -3
- package/kotlin/fixtures/counter/app/_layout.tsx +4 -0
- package/kotlin/fixtures/counter/app/index+spa.tsx +1 -0
- package/kotlin/fixtures/counter/app/routes.d.ts +18 -0
- package/kotlin/fixtures/counter/package.json +7 -0
- package/kotlin/fixtures/counter/tsconfig.json +19 -0
- package/kotlin/fixtures/counter/vite.config.ts +10 -0
- package/kotlin/fixtures/headless-counter/Headless.kt +5 -0
- package/kotlin/fixtures/kotlin-app/app/build.gradle.kts +30 -0
- package/kotlin/fixtures/kotlin-app/app/src/main/AndroidManifest.xml +13 -0
- package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/MainActivity.kt +60 -0
- package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/ProbeApplication.kt +18 -0
- package/kotlin/fixtures/kotlin-app/build.gradle.kts +5 -0
- package/kotlin/fixtures/kotlin-app/gradle.properties +4 -0
- package/kotlin/fixtures/kotlin-app/settings.gradle.kts +4 -0
- package/kotlin/fork/NOTICE +7 -5
- package/kotlin/fork/README.md +41 -49
- package/kotlin/fork/build.sh +3 -2
- package/kotlin/fork/compose-worker-globals.patch +22 -11
- package/kotlin/fork/fork.json +2 -2
- package/kotlin/fork/publish.ts +30 -15
- package/kotlin/fork/skiko-worker-clock.patch +38 -0
- package/kotlin/toolchain.json +9 -9
- package/package.json +1 -1
- package/skills/contrast/SKILL.md +2 -1
- package/skills/peach-setup/SKILL.md +2 -2
- package/src/{swift-guest.ts → guest-bundle.ts} +22 -7
- package/src/home-paths.ts +5 -3
- package/src/kotlin-app.ts +411 -0
- package/src/kotlin-host.ts +148 -25
- package/src/swift-compile.ts +7 -2
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
package dev.contrast.kotlinapp
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import androidx.activity.ComponentActivity
|
|
5
|
+
import androidx.activity.compose.setContent
|
|
6
|
+
import androidx.compose.foundation.background
|
|
7
|
+
import androidx.compose.foundation.layout.Arrangement
|
|
8
|
+
import androidx.compose.foundation.layout.Column
|
|
9
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
10
|
+
import androidx.compose.foundation.layout.padding
|
|
11
|
+
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
12
|
+
import androidx.compose.material3.Button
|
|
13
|
+
import androidx.compose.material3.Text
|
|
14
|
+
import androidx.compose.runtime.Composable
|
|
15
|
+
import androidx.compose.runtime.LaunchedEffect
|
|
16
|
+
import androidx.compose.runtime.SideEffect
|
|
17
|
+
import androidx.compose.runtime.getValue
|
|
18
|
+
import androidx.compose.runtime.mutableIntStateOf
|
|
19
|
+
import androidx.compose.runtime.remember
|
|
20
|
+
import androidx.compose.runtime.setValue
|
|
21
|
+
import androidx.compose.ui.Modifier
|
|
22
|
+
import androidx.compose.ui.graphics.Color
|
|
23
|
+
import androidx.compose.ui.platform.testTag
|
|
24
|
+
import androidx.compose.ui.unit.dp
|
|
25
|
+
|
|
26
|
+
class MainActivity : ComponentActivity() {
|
|
27
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
28
|
+
super.onCreate(savedInstanceState)
|
|
29
|
+
Probe.log += "activity.onCreate ${intent.action}"
|
|
30
|
+
setContent { ProbeScreen(content = "first", replace = { replaceContent() }) }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// a second setContent on the same activity: android reuses its ComposeView
|
|
34
|
+
private fun replaceContent() {
|
|
35
|
+
Probe.log += "activity.setContent"
|
|
36
|
+
setContent { ProbeScreen(content = "second", replace = { replaceContent() }) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override fun onStart() { super.onStart(); Probe.log += "activity.onStart" }
|
|
40
|
+
override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState); Probe.log += "activity.onPostCreate" }
|
|
41
|
+
override fun onResume() { super.onResume(); Probe.log += "activity.onResume" }
|
|
42
|
+
override fun onPostResume() { super.onPostResume(); Probe.log += "activity.onPostResume" }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Composable
|
|
46
|
+
fun ProbeScreen(content: String, replace: () -> Unit) {
|
|
47
|
+
var count by remember { mutableIntStateOf(0) }
|
|
48
|
+
SideEffect { if ("compose" !in Probe.log) Probe.log += "compose" }
|
|
49
|
+
LaunchedEffect(Unit) { Probe.log += "effect" }
|
|
50
|
+
Column(
|
|
51
|
+
Modifier.fillMaxSize().background(Color(0xFFE8EEF8)).safeDrawingPadding().padding(16.dp),
|
|
52
|
+
verticalArrangement = Arrangement.spacedBy(12.dp),
|
|
53
|
+
) {
|
|
54
|
+
Text("Content: $content", Modifier.testTag("content"))
|
|
55
|
+
Text("Greeting: ${Probe.greeting}", Modifier.testTag("greeting"))
|
|
56
|
+
Button(onClick = { count += 1 }, Modifier.testTag("count")) { Text("Count: $count") }
|
|
57
|
+
Button(onClick = replace, Modifier.testTag("replace")) { Text("Replace content") }
|
|
58
|
+
Text(Probe.log.joinToString("\n"), Modifier.testTag("log"))
|
|
59
|
+
}
|
|
60
|
+
}
|
package/kotlin/fixtures/kotlin-app/app/src/main/java/dev/contrast/kotlinapp/ProbeApplication.kt
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package dev.contrast.kotlinapp
|
|
2
|
+
|
|
3
|
+
import android.app.Application
|
|
4
|
+
|
|
5
|
+
// process globals the probe reads back: the cold-start order and a value only
|
|
6
|
+
// the application sets before any activity exists.
|
|
7
|
+
object Probe {
|
|
8
|
+
val log = mutableListOf<String>()
|
|
9
|
+
var greeting = "unset"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class ProbeApplication : Application() {
|
|
13
|
+
override fun onCreate() {
|
|
14
|
+
super.onCreate()
|
|
15
|
+
Probe.log += "app.onCreate"
|
|
16
|
+
Probe.greeting = "set by application"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/kotlin/fork/NOTICE
CHANGED
|
@@ -17,9 +17,11 @@ The license text is in LICENSE beside this file.
|
|
|
17
17
|
https://android.googlesource.com/platform/frameworks/base
|
|
18
18
|
|
|
19
19
|
Modifications: compose-worker-globals.patch and skiko-worker-clock.patch
|
|
20
|
-
change
|
|
21
|
-
|
|
22
|
-
navigator.
|
|
23
|
-
|
|
20
|
+
change clock and clipboard reads to globalThis rather than window, and add an
|
|
21
|
+
explicit ui-text locale provider and Skiko host OS provider whose defaults
|
|
22
|
+
retain upstream navigator behavior. Each modified file carries a notice saying so. The Skiko
|
|
23
|
+
loader build also reads import.meta.url instead of self.location.href, which
|
|
24
|
+
React Native tenants do not expose. The built klibs are ui-wasm-js and ui-text-wasm-js
|
|
24
25
|
1.13.0-alpha01 and skiko-wasm-js 0.152.0-alpha02 compiled from the patched
|
|
25
|
-
sources.
|
|
26
|
+
sources; skiko-wasm-0.152.0-alpha02.jar contains that worker-safe loader and
|
|
27
|
+
Skiko's own wasm runtime.
|
package/kotlin/fork/README.md
CHANGED
|
@@ -1,59 +1,51 @@
|
|
|
1
1
|
# Peach's JetBrains web fork
|
|
2
2
|
|
|
3
|
-
Peach runs Compose in a tenant worker,
|
|
4
|
-
|
|
5
|
-
0.152.0-alpha02
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Peach runs Compose in a React Native tenant worker, with no `window`,
|
|
4
|
+
`document`, `location`, or browser navigator language/platform fields. The official
|
|
5
|
+
Compose UI 1.13.0-alpha01 and Skiko 0.152.0-alpha02 platform actuals assume
|
|
6
|
+
browser globals that this native host does not publish. Peach carries patched
|
|
7
|
+
builds until upstream supplies equivalent worker and native host hooks.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
| module | file | read |
|
|
9
|
+
| module | file | native host binding |
|
|
12
10
|
| --- | --- | --- |
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
the upstream Gradle build for the changed modules only.
|
|
31
|
-
|
|
32
|
-
`packages/peachsim/kotlin/toolchain.json` names each built klib by its sha256
|
|
33
|
-
at `https://r2.rnxsim.com/peach-kotlin-fork/<sha256>/<file>`, beside a copy of
|
|
34
|
-
the patches, `fork.json`, `LICENSE` and `NOTICE`. Every other Compose library
|
|
35
|
-
is the official Maven artifact. The klibs load only for an app whose Kotlin
|
|
36
|
-
imports Compose, like the rest of the Compose closure.
|
|
37
|
-
|
|
38
|
-
## rebuilding
|
|
11
|
+
| Compose `ui` | `Actuals.wasm.kt` | clock reads `globalThis.performance.now()` |
|
|
12
|
+
| Compose `ui` | `PlatformClipboard.web.kt` | worker-safe secure-context and clipboard reads |
|
|
13
|
+
| Compose `ui-text` | `PlatformLocale.web.kt` | explicit `setPlatformLocaleProvider`; its default keeps upstream navigator behavior |
|
|
14
|
+
| Skiko | `OsArch.web.kt` | explicit `setHostOsProvider`; its default lazily retains upstream OS detection |
|
|
15
|
+
| Skiko | `Actuals.web.kt` | nanosecond clock reads `globalThis.performance.now()` |
|
|
16
|
+
| Skiko loader build | `OptimizeSkikoWasmTask.kt` | script directory reads `import.meta.url`, without `self.location` |
|
|
17
|
+
|
|
18
|
+
The Compose host installs the locale provider once before any scene, from the
|
|
19
|
+
same device locale it passes to `PlatformContext`, and installs `OS.Android`
|
|
20
|
+
through Skiko’s host OS provider before any scene. Browser navigator fields
|
|
21
|
+
stay absent in guest JS. Changes to device language after launch are outside
|
|
22
|
+
this contract.
|
|
23
|
+
|
|
24
|
+
`fork.json` pins repositories, commits, patch hashes, JDK and Android tools.
|
|
25
|
+
Every changed upstream file carries a modification notice. `LICENSE` and
|
|
26
|
+
`NOTICE` travel with the patches. `build.sh` builds the changed KLIBs and Skiko
|
|
27
|
+
runtime jar with the upstream Gradle builds on the Linux builder.
|
|
39
28
|
|
|
40
29
|
```sh
|
|
41
30
|
bun remote bash packages/peachsim/kotlin/fork/build.sh
|
|
42
31
|
bun packages/peachsim/kotlin/fork/publish.ts .remote-out/kotlin-fork
|
|
43
32
|
```
|
|
44
33
|
|
|
45
|
-
The
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
34
|
+
The delivery includes `artifacts.sha256` and its exact fork record. Publication
|
|
35
|
+
stores each binary at `peach-kotlin-fork/<binary-sha256>/<file>` and its record
|
|
36
|
+
at `peach-kotlin-fork/<binary-sha256>/records/<record-sha256>/`. It refuses to
|
|
37
|
+
replace existing bytes. A metadata change cannot overwrite a previous record
|
|
38
|
+
when a binary is unchanged. `toolchain.json` pins these immutable binary URLs;
|
|
39
|
+
all other Compose libraries remain official Maven artifacts. Everything stays
|
|
40
|
+
lazy for Kotlin/Compose apps.
|
|
41
|
+
|
|
42
|
+
The isolated worker probe cannot certify the native tenant's absent globals.
|
|
43
|
+
`scripts/debug/peach-compose-mount/tenant-run.ts` boots the actual capture tenant
|
|
44
|
+
with the imported `.kt` component, asserts those globals stay absent, and
|
|
45
|
+
checks `Locale.current` and `LocalLocaleList` against an ar-EG device setting
|
|
46
|
+
with an en-US browser.
|
|
47
|
+
|
|
48
|
+
Delete the fork when official releases provide worker-safe clocks/clipboard,
|
|
49
|
+
a location-independent loader and equivalent native locale/host OS provider hooks,
|
|
50
|
+
then rematch the Android pins in `plans/peach/kotlin-everywhere.md`. The prepared
|
|
51
|
+
upstream issue names these hooks and the full guest regression vehicle.
|
package/kotlin/fork/build.sh
CHANGED
|
@@ -115,7 +115,8 @@ checkout 1
|
|
|
115
115
|
cd "${SOURCE}/skiko"
|
|
116
116
|
gradle -Pdeploy.version=0.152.0-alpha02 -Pdeploy.release=true \
|
|
117
117
|
-Pskiko.wasm.enabled=true -Pskiko.awt.enabled=false \
|
|
118
|
-
:publishWasmJsPublicationToMavenLocal
|
|
118
|
+
:publishWasmJsPublicationToMavenLocal :skikoWasmJar
|
|
119
|
+
cp build/libs/skiko-wasm-0.152.0-alpha02.jar "${DELIVER}/"
|
|
119
120
|
)
|
|
120
121
|
|
|
121
122
|
cp "${M2}/org/jetbrains/compose/ui/ui-wasm-js/1.13.0-alpha01/ui-wasm-js-1.13.0-alpha01.klib" \
|
|
@@ -125,4 +126,4 @@ cp "${M2}/org/jetbrains/compose/ui/ui-wasm-js/1.13.0-alpha01/ui-wasm-js-1.13.0-a
|
|
|
125
126
|
# the record travels with the klibs it describes, so publishing attaches what
|
|
126
127
|
# this build used, not whatever the checkout holds later
|
|
127
128
|
cp "${FORK}/fork.json" "${FORK}/LICENSE" "${FORK}/NOTICE" "${FORK}"/*.patch "${DELIVER}/"
|
|
128
|
-
(cd "${DELIVER}" && sha256sum -- *.klib >
|
|
129
|
+
(cd "${DELIVER}" && sha256sum -- *.klib *.jar > artifacts.sha256 && cat artifacts.sha256)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
diff --git a/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt b/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt
|
|
2
|
-
index 6e80e51..28f1de1 100644
|
|
3
2
|
--- a/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt
|
|
4
3
|
+++ b/compose/ui/ui-text/src/webMain/kotlin/androidx/compose/ui/text/intl/PlatformLocale.web.kt
|
|
5
4
|
@@ -12,6 +12,10 @@
|
|
@@ -7,20 +6,32 @@ index 6e80e51..28f1de1 100644
|
|
|
7
6
|
* See the License for the specific language governing permissions and
|
|
8
7
|
* limitations under the License.
|
|
9
8
|
+ *
|
|
10
|
-
+ *
|
|
11
|
-
+ *
|
|
12
|
-
+ *
|
|
9
|
+
+ * modified for Peach: an explicit locale provider lets a native host supply
|
|
10
|
+
+ * device languages without exposing browser navigator fields to guest code.
|
|
11
|
+
+ * see the fork record for the patch and upstream revision.
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
14
|
package androidx.compose.ui.text.intl
|
|
16
|
-
@@ -
|
|
15
|
+
@@ -64,8 +68,18 @@
|
|
16
|
+
// The locale code en-001 denotes the English language spoken in the World.
|
|
17
|
+
private const val FALLBACK_LANGUAGE_TAG = "en-001"
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
+private var currentLocaleProvider: () -> LocaleList = {
|
|
20
|
+
+ localeListFromLanguageTags(userPreferredLanguages())
|
|
21
|
+
+}
|
|
22
|
+
+
|
|
23
|
+
+// the host installs the device provider before constructing its first scene.
|
|
24
|
+
+@InternalComposeUiApi
|
|
25
|
+
+fun setPlatformLocaleProvider(provider: () -> LocaleList) {
|
|
26
|
+
+ currentLocaleProvider = provider
|
|
27
|
+
+}
|
|
28
|
+
+
|
|
29
|
+
internal actual fun createPlatformLocaleDelegate(): PlatformLocaleDelegate =
|
|
30
|
+
object : PlatformLocaleDelegate {
|
|
31
|
+
override val current: LocaleList
|
|
32
|
+
- get() = localeListFromLanguageTags(userPreferredLanguages())
|
|
33
|
+
+ get() = currentLocaleProvider()
|
|
34
|
+
}
|
|
24
35
|
diff --git a/compose/ui/ui/src/wasmJsMain/kotlin/androidx/compose/ui/Actuals.wasm.kt b/compose/ui/ui/src/wasmJsMain/kotlin/androidx/compose/ui/Actuals.wasm.kt
|
|
25
36
|
index 26aa8ea..aa4f6d4 100644
|
|
26
37
|
--- a/compose/ui/ui/src/wasmJsMain/kotlin/androidx/compose/ui/Actuals.wasm.kt
|
package/kotlin/fork/fork.json
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"tag": "v1.13.0-alpha01",
|
|
19
19
|
"commit": "a9e47e8aa04c95cfe572ab4297c770f3cbfb234e",
|
|
20
20
|
"patch": "compose-worker-globals.patch",
|
|
21
|
-
"patchSha256": "
|
|
21
|
+
"patchSha256": "51fa45bda1e0aae7db2eab1b056def406352958257e1d3b899c5c3d8aa5edddb"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"name": "skiko",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"tag": "v0.152.0-alpha02",
|
|
28
28
|
"commit": "96378296bb23c23c5f30cd2b0d42d6f8fdeff730",
|
|
29
29
|
"patch": "skiko-worker-clock.patch",
|
|
30
|
-
"patchSha256": "
|
|
30
|
+
"patchSha256": "735a42f7a9d3be1ab288f4d67bef44924ec2b6bbcd59f5a5f76edf22f912c347"
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
package/kotlin/fork/publish.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// uploads the
|
|
1
|
+
// uploads the artifacts one build.sh run delivered to R2, each under its sha256
|
|
2
2
|
// beside the record that run copied (patches, fork.json, LICENSE, NOTICE,
|
|
3
|
-
//
|
|
3
|
+
// artifacts.sha256), and prints the toolchain.json entries that name them. keys
|
|
4
4
|
// are immutable: an existing object with other bytes stops the publish. needs
|
|
5
5
|
// R2 credentials; reads are public.
|
|
6
6
|
//
|
|
@@ -22,27 +22,32 @@ const files = readdirSync(delivered)
|
|
|
22
22
|
const record = files.filter(
|
|
23
23
|
(name) =>
|
|
24
24
|
name.endsWith('.patch') ||
|
|
25
|
-
['fork.json', 'LICENSE', 'NOTICE', '
|
|
25
|
+
['fork.json', 'LICENSE', 'NOTICE', 'artifacts.sha256'].includes(name),
|
|
26
|
+
)
|
|
27
|
+
if (
|
|
28
|
+
record.length !==
|
|
29
|
+
files.filter((name) => !name.endsWith('.klib') && !name.endsWith('.jar')).length
|
|
26
30
|
)
|
|
27
|
-
if (record.length !== files.filter((name) => !name.endsWith('.klib')).length)
|
|
28
31
|
throw new Error(`${delivered} holds files build.sh does not deliver`)
|
|
29
|
-
if (!record.includes('
|
|
32
|
+
if (!record.includes('artifacts.sha256') || !record.includes('fork.json'))
|
|
30
33
|
throw new Error(`${delivered} is not a build.sh delivery`)
|
|
31
34
|
|
|
32
|
-
// the
|
|
35
|
+
// the artifacts are exactly the ones the build hashed
|
|
33
36
|
const built = new Map(
|
|
34
|
-
readFileSync(path.join(delivered, '
|
|
37
|
+
readFileSync(path.join(delivered, 'artifacts.sha256'), 'utf8')
|
|
35
38
|
.trim()
|
|
36
39
|
.split('\n')
|
|
37
40
|
.map((line) => {
|
|
38
41
|
const [hash, name] = line.split(/\s+/)
|
|
39
|
-
if (!hash || !name) throw new Error(`malformed
|
|
42
|
+
if (!hash || !name) throw new Error(`malformed artifacts.sha256 line: ${line}`)
|
|
40
43
|
return [name, hash]
|
|
41
44
|
}),
|
|
42
45
|
)
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
const artifacts = files
|
|
47
|
+
.filter((name) => name.endsWith('.klib') || name.endsWith('.jar'))
|
|
48
|
+
.sort()
|
|
49
|
+
if (artifacts.length === 0 || artifacts.length !== built.size)
|
|
50
|
+
throw new Error(`${delivered} artifacts do not match artifacts.sha256`)
|
|
46
51
|
|
|
47
52
|
async function put(key: string, bytes: Buffer, contentType: string) {
|
|
48
53
|
const existing = await readR2Object(key, 120000)
|
|
@@ -53,23 +58,33 @@ async function put(key: string, bytes: Buffer, contentType: string) {
|
|
|
53
58
|
await uploadToR2(key, bytes, contentType, IMMUTABLE)
|
|
54
59
|
}
|
|
55
60
|
|
|
61
|
+
const recordHash = sha256(
|
|
62
|
+
Buffer.concat(
|
|
63
|
+
record
|
|
64
|
+
.sort()
|
|
65
|
+
.flatMap((file) => [
|
|
66
|
+
Buffer.from(file + '\0'),
|
|
67
|
+
readFileSync(path.join(delivered, file)),
|
|
68
|
+
]),
|
|
69
|
+
),
|
|
70
|
+
)
|
|
56
71
|
const entries = []
|
|
57
|
-
for (const name of
|
|
72
|
+
for (const name of artifacts) {
|
|
58
73
|
const bytes = readFileSync(path.join(delivered, name))
|
|
59
74
|
const hash = sha256(bytes)
|
|
60
75
|
if (built.get(name) !== hash)
|
|
61
|
-
throw new Error(`${name} is not the
|
|
76
|
+
throw new Error(`${name} is not the artifact the build hashed`)
|
|
62
77
|
const prefix = `peach-kotlin-fork/${hash}`
|
|
63
78
|
await put(`${prefix}/${name}`, bytes, 'application/octet-stream')
|
|
64
79
|
for (const file of record)
|
|
65
80
|
await put(
|
|
66
|
-
`${prefix}/${file}`,
|
|
81
|
+
`${prefix}/records/${recordHash}/${file}`,
|
|
67
82
|
readFileSync(path.join(delivered, file)),
|
|
68
83
|
'text/plain; charset=utf-8',
|
|
69
84
|
)
|
|
70
85
|
// the loader caches a library by its name, so the name carries the hash
|
|
71
86
|
entries.push({
|
|
72
|
-
name: name.replace(/\.klib$/, `-peach-${hash.slice(0, 12)}
|
|
87
|
+
name: name.replace(/\.(klib|jar)$/, `-peach-${hash.slice(0, 12)}.$1`),
|
|
73
88
|
url: `${RNX_PUBLIC.publicR2Origin}/${prefix}/${name}`,
|
|
74
89
|
sha256: hash,
|
|
75
90
|
})
|
|
@@ -31,3 +31,41 @@ index 366ed37..d56c267 100644
|
|
|
31
31
|
+ js("globalThis.performance.now() * 1000000")
|
|
32
32
|
|
|
33
33
|
annotation class WebImport(val name : String)
|
|
34
|
+
diff --git a/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt b/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt
|
|
35
|
+
--- a/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt
|
|
36
|
+
+++ b/skiko/buildSrc/src/main/kotlin/OptimizeSkikoWasmTask.kt
|
|
37
|
+
@@ -65,6 +65,12 @@ abstract class OptimizeSkikoWasmTask : AbstractSkikoNativeToolTask() {
|
|
38
|
+
"${inputFile.nameWithoutExtension}.wasm",
|
|
39
|
+
"${libOutputFileName.get()}.wasm"
|
|
40
|
+
)
|
|
41
|
+
+ // peach tenants hide location from react native;
|
|
42
|
+
+ // emscripten already uses this module url below.
|
|
43
|
+
+ .replace(
|
|
44
|
+
+ "scriptDirectory=self.location.href",
|
|
45
|
+
+ "scriptDirectory=import.meta.url"
|
|
46
|
+
+ )
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
diff --git a/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt b/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt
|
|
51
|
+
--- a/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt
|
|
52
|
+
+++ b/skiko/src/webMain/kotlin/org/jetbrains/skiko/OsArch.web.kt
|
|
53
|
+
@@ -3,6 +3,15 @@
|
|
54
|
+
import kotlinx.browser.window
|
|
55
|
+
import kotlin.js.js
|
|
56
|
+
-
|
|
57
|
+
+
|
|
58
|
+
-actual val hostOs: OS = detectHostOs()
|
|
59
|
+
+private val defaultHostOs: OS by lazy { detectHostOs() }
|
|
60
|
+
+private var hostOsProvider: () -> OS = { defaultHostOs }
|
|
61
|
+
+
|
|
62
|
+
+// modified for Peach: native hosts install their device's platform before
|
|
63
|
+
+// any compose scene. see the fork record for the patch and upstream revision.
|
|
64
|
+
+fun setHostOsProvider(provider: () -> OS) {
|
|
65
|
+
+ hostOsProvider = provider
|
|
66
|
+
+}
|
|
67
|
+
+
|
|
68
|
+
+actual val hostOs: OS get() = hostOsProvider()
|
|
69
|
+
-
|
|
70
|
+
+
|
|
71
|
+
actual val hostArch: Arch = Arch.Unknown
|
package/kotlin/toolchain.json
CHANGED
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"sha256": "6187e199922b061cffa16fd9ae2ed920d6a59f0b0f7c3207e829b983ff132d38"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
|
-
"name": "skiko-wasm-js-0.152.0-alpha02-peach-
|
|
37
|
-
"url": "https://r2.rnxsim.com/peach-kotlin-fork/
|
|
38
|
-
"sha256": "
|
|
36
|
+
"name": "skiko-wasm-js-0.152.0-alpha02-peach-3834433e1790.klib",
|
|
37
|
+
"url": "https://r2.rnxsim.com/peach-kotlin-fork/3834433e17902a3d86dc973abb245b7af5aae0012ca29e1ac9668d74335f3115/skiko-wasm-js-0.152.0-alpha02.klib",
|
|
38
|
+
"sha256": "3834433e17902a3d86dc973abb245b7af5aae0012ca29e1ac9668d74335f3115"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"name": "annotation-wasm-js-1.9.1.klib",
|
|
@@ -73,9 +73,9 @@
|
|
|
73
73
|
"sha256": "dab0b337dd99ec99e8a3cc4efd365d8101db050971490eff6839fc566aeadc6c"
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
|
-
"name": "ui-text-wasm-js-1.13.0-alpha01-peach-
|
|
77
|
-
"url": "https://r2.rnxsim.com/peach-kotlin-fork/
|
|
78
|
-
"sha256": "
|
|
76
|
+
"name": "ui-text-wasm-js-1.13.0-alpha01-peach-10c54ff0fa5f.klib",
|
|
77
|
+
"url": "https://r2.rnxsim.com/peach-kotlin-fork/10c54ff0fa5fc0ff066fb4561e2d5ca9d5c41fedcb32a61414016ef215b035ba/ui-text-wasm-js-1.13.0-alpha01.klib",
|
|
78
|
+
"sha256": "10c54ff0fa5fc0ff066fb4561e2d5ca9d5c41fedcb32a61414016ef215b035ba"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "ui-unit-wasm-js-1.13.0-alpha01.klib",
|
|
@@ -290,9 +290,9 @@
|
|
|
290
290
|
"skiko": "0.152.0-alpha02"
|
|
291
291
|
},
|
|
292
292
|
"composeRuntime": {
|
|
293
|
-
"name": "skiko-wasm-0.152.0-alpha02.jar",
|
|
294
|
-
"url": "https://
|
|
295
|
-
"sha256": "
|
|
293
|
+
"name": "skiko-wasm-0.152.0-alpha02-peach-4814686165d0.jar",
|
|
294
|
+
"url": "https://r2.rnxsim.com/peach-kotlin-fork/4814686165d0ba869e605e661d0fb261ecc79f5e984ed6ae78dfe20300923c98/skiko-wasm-0.152.0-alpha02.jar",
|
|
295
|
+
"sha256": "4814686165d0ba869e605e661d0fb261ecc79f5e984ed6ae78dfe20300923c98"
|
|
296
296
|
},
|
|
297
297
|
"composeJsLibraries": [
|
|
298
298
|
{
|
package/package.json
CHANGED
package/skills/contrast/SKILL.md
CHANGED
|
@@ -20,6 +20,7 @@ automation, inspecting the render tree, and managing sims.
|
|
|
20
20
|
| command | description |
|
|
21
21
|
| --- | --- |
|
|
22
22
|
| `peach swift` | preview a SwiftPM app with hosted compilation and live Swift edits |
|
|
23
|
+
| `peach kotlin` | run an Android Compose app module from its launcher activity |
|
|
23
24
|
| `peach maestro` | author, generate, and run Maestro YAML flows against peach |
|
|
24
25
|
| `peach detox` | run existing Detox suites against peach on headless Chromium |
|
|
25
26
|
| `peach cleanup` | inspect and reclaim local peach disk usage |
|
|
@@ -56,7 +57,7 @@ automation, inspecting the render tree, and managing sims.
|
|
|
56
57
|
| `peach setup` | configure optional local conveniences |
|
|
57
58
|
| `peach compat` | check package compatibility |
|
|
58
59
|
| `peach project-report` | print local project and toolchain metadata |
|
|
59
|
-
| `peach
|
|
60
|
+
| `peach support` | ask for help, report a problem, and read our replies |
|
|
60
61
|
| `peach desktop` | launch or install the desktop companion |
|
|
61
62
|
| `peach daemon` | manage the recommended background bridge service |
|
|
62
63
|
| `peach version` | show the CLI + engine runtime versions you are running |
|
|
@@ -119,13 +119,13 @@ run `peach compat --json` from the app project root during setup. if the scan
|
|
|
119
119
|
identifies a plausible missing Peach seam, or the running app gives concrete
|
|
120
120
|
evidence that behavior is missing or broken specifically in Peach, summarize
|
|
121
121
|
the package, expected behavior, actual behavior, and runtime evidence for the
|
|
122
|
-
user. then offer to send that finding with `peach report
|
|
122
|
+
user. then offer to send that finding with `peach support report`.
|
|
123
123
|
|
|
124
124
|
**never submit a report automatically or behind the user's back.** wait for an
|
|
125
125
|
explicit yes. only then run this from the app project root:
|
|
126
126
|
|
|
127
127
|
```sh
|
|
128
|
-
peach report
|
|
128
|
+
peach support report --yes "<package; expected behavior; actual behavior; runtime evidence>"
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
the command automatically attaches the local compatibility scan plus bounded
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// the built-in
|
|
2
|
-
// the author supplies Swift;
|
|
1
|
+
// the built-in guests use the existing Metro runtime and host module seam.
|
|
2
|
+
// the author supplies Swift or Kotlin; an entry carries no engine or compiler
|
|
3
|
+
// code, only the registration of the host module's root.
|
|
3
4
|
import {
|
|
4
5
|
appendRNXMetroModuleIdentityFooter,
|
|
5
6
|
RNX_METRO_MODULE_IDENTITY_VERSION,
|
|
@@ -7,12 +8,26 @@ import {
|
|
|
7
8
|
import { METRO_REQUIRE_POLYFILL } from './metro-runtime-source'
|
|
8
9
|
|
|
9
10
|
export function swiftGuestBundle(packageName: string): string {
|
|
11
|
+
return guestBundle(
|
|
12
|
+
'peachsim/swift',
|
|
13
|
+
`AppRegistry.registerComponent('PeachSwift', () => host.createSwiftPreviewEntry(${JSON.stringify(packageName)}))`,
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function kotlinGuestBundle(): string {
|
|
18
|
+
return guestBundle(
|
|
19
|
+
'peachsim/kotlin',
|
|
20
|
+
`AppRegistry.registerComponent('PeachKotlin', () => host.KotlinAppRoot)`,
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function guestBundle(hostModule: string, registration: string): string {
|
|
10
25
|
const modules = [
|
|
11
26
|
{
|
|
12
|
-
name: 'peach-
|
|
27
|
+
name: 'peach-guest-entry.js',
|
|
13
28
|
code: `const { AppRegistry } = require(1)
|
|
14
|
-
const
|
|
15
|
-
|
|
29
|
+
const host = require(2)
|
|
30
|
+
${registration}`,
|
|
16
31
|
deps: [1, 2],
|
|
17
32
|
},
|
|
18
33
|
{
|
|
@@ -21,8 +36,8 @@ AppRegistry.registerComponent('PeachSwift', () => createSwiftPreviewEntry(${JSON
|
|
|
21
36
|
deps: [],
|
|
22
37
|
},
|
|
23
38
|
{
|
|
24
|
-
name:
|
|
25
|
-
code: `module.exports = global.__contrastHostModules[
|
|
39
|
+
name: hostModule,
|
|
40
|
+
code: `module.exports = global.__contrastHostModules[${JSON.stringify(hostModule)}]`,
|
|
26
41
|
deps: [],
|
|
27
42
|
},
|
|
28
43
|
{
|
package/src/home-paths.ts
CHANGED
|
@@ -264,13 +264,15 @@ export interface PrivacyPreferences {
|
|
|
264
264
|
configured: boolean
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
// bounded diagnostics and automatic crash reports are on until the person turns
|
|
268
|
+
// them off (`peach config telemetry off`, or DO_NOT_TRACK for one run).
|
|
267
269
|
export function readPrivacyPreferences(): PrivacyPreferences {
|
|
268
270
|
const settings = readSharedConfig().settings
|
|
269
271
|
const productAnalytics = settings?.productAnalytics
|
|
270
272
|
const crashReports = settings?.crashReports
|
|
271
273
|
return {
|
|
272
|
-
productAnalytics: typeof productAnalytics === 'boolean' ? productAnalytics :
|
|
273
|
-
crashReports: typeof crashReports === 'boolean' ? crashReports :
|
|
274
|
+
productAnalytics: typeof productAnalytics === 'boolean' ? productAnalytics : true,
|
|
275
|
+
crashReports: typeof crashReports === 'boolean' ? crashReports : true,
|
|
274
276
|
configured: typeof productAnalytics === 'boolean',
|
|
275
277
|
}
|
|
276
278
|
}
|
|
@@ -286,7 +288,7 @@ export function writePrivacyPreferences(
|
|
|
286
288
|
})
|
|
287
289
|
}
|
|
288
290
|
|
|
289
|
-
// created
|
|
291
|
+
// created on the first diagnostic sent, alongside the privacy preferences.
|
|
290
292
|
export function readOrCreateAnonymousId(): string {
|
|
291
293
|
const existing = readSharedConfig().settings?.anonymousId
|
|
292
294
|
if (
|