stim 1.13.0 → 1.15.0

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 (133) hide show
  1. package/README.md +2 -0
  2. package/dist/{activity-DfVKZTEB.mjs → activity-B2-kb7k0.mjs} +281 -41
  3. package/dist/{android-BHfAu2mf.mjs → android-CYmq0jNi.mjs} +2 -2
  4. package/dist/{android-CD8pr8Q2.mjs → android-Cu_L4RpL.mjs} +524 -412
  5. package/dist/{android-qx_31wJo.mjs → android-Db2eEMaf.mjs} +152 -65
  6. package/dist/android-cas-PnKfAdB2.mjs +167 -0
  7. package/dist/android-cas-compiler.mjs +2 -2
  8. package/dist/{app-install-CDFY2nUL.mjs → app-install-CAAplXAt.mjs} +162 -173
  9. package/dist/{budget-E5o91NR1.mjs → budget-CMiqghig.mjs} +1048 -77
  10. package/dist/{build-plan-BTa93o_r.mjs → build-plan-aeGMFX7e.mjs} +193 -650
  11. package/dist/build-progress-C2Jv1AtA.mjs +872 -0
  12. package/dist/build-slots-Df1ApSuH.mjs +127 -0
  13. package/dist/{cache-manifest-DWPF4RKJ.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
  14. package/dist/cache-manifest.mjs +1 -1
  15. package/dist/{chrome-B5hWgQJS.mjs → chrome-BrcVWQyD.mjs} +4 -4
  16. package/dist/cli-0cX5s4NM.mjs +45 -0
  17. package/dist/cli.mjs +6 -42
  18. package/dist/client-C2IS36Qf.mjs +1333 -0
  19. package/dist/collector-run.mjs +8 -7
  20. package/dist/{command-output-BIL7rlX7.mjs → command-output-CliHHn7a.mjs} +1 -1
  21. package/dist/{config-0jCcMM0E.mjs → config-D0DbpZtM.mjs} +29 -29
  22. package/dist/{created-devices-Cd558h31.mjs → created-devices-BwVb3liH.mjs} +2 -2
  23. package/dist/{dependency-state-DNN0yfx6.mjs → dependency-state-BmsjKZ2H.mjs} +2 -2
  24. package/dist/{deps-2Wo81np9.mjs → deps-BFlKbOIp.mjs} +3 -3
  25. package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
  26. package/dist/dev-client-CjzLoNs0.mjs +80 -0
  27. package/dist/{device-Cf7vl-so.mjs → device-BZ1IyS5A.mjs} +7 -7
  28. package/dist/device-capacity-DMuKC7nx.mjs +136 -0
  29. package/dist/device-host-worker.d.mts +1 -0
  30. package/dist/device-host-worker.mjs +769 -0
  31. package/dist/device-ios-DMQBUPus.mjs +381 -0
  32. package/dist/{device-lease-CL9dZf73.mjs → device-lease-W5Pi1q38.mjs} +43 -36
  33. package/dist/{device-pool-MuoiyRcu.mjs → device-pool-B2r38YjS.mjs} +4 -4
  34. package/dist/{device-remote-DT9ngZiD.mjs → device-remote-9ulPsdhY.mjs} +68 -162
  35. package/dist/{doctor-D2iysNNH.mjs → doctor-BcE5xsBn.mjs} +191 -99
  36. package/dist/{error-diagnostics-BoiOhck8.mjs → error-diagnostics-Cb0P1WLS.mjs} +12 -11
  37. package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
  38. package/dist/{gc-eA-PRBX8.mjs → gc-BuL1Genr.mjs} +430 -102
  39. package/dist/{android-cas-B9Kv9aIy.mjs → gradle-CmdOBq1d.mjs} +8 -294
  40. package/dist/{guide-BfZ0OmiP.mjs → guide-cCSGRFd3.mjs} +2052 -240
  41. package/dist/{guide-status-BaMYu55M.mjs → guide-status-CIoWK6mG.mjs} +3 -3
  42. package/dist/hosted-macos-DwowNU7W.mjs +447 -0
  43. package/dist/idle-shutdown-B5LPaNyY.mjs +122 -0
  44. package/dist/in-use-CndPMilN.mjs +110 -0
  45. package/dist/{ios-CmEzZiOj.mjs → ios-3CtCRhwr.mjs} +201 -10
  46. package/dist/{ios-CcfCeZ19.mjs → ios-Chob8ny7.mjs} +560 -259
  47. package/dist/{ios-device-BW-t_Lkv.mjs → ios-device-DERmMmk-.mjs} +12 -7
  48. package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
  49. package/dist/{launch-verify-CuJaBpEa.mjs → launch-verify-CLlofxRt.mjs} +42 -11
  50. package/dist/{logs-DcSRbC2t.mjs → logs-h9h6MUvE.mjs} +95 -13
  51. package/dist/machine-usage-D_YYMzfR.mjs +283 -0
  52. package/dist/machines-CYtOCqcj.mjs +259 -0
  53. package/dist/macos-BwtbUtTN.mjs +468 -0
  54. package/dist/macos-run.d.mts +5 -0
  55. package/dist/macos-run.mjs +2 -0
  56. package/dist/{merge-state-ytFQCeh4.mjs → merge-state-BnxLNQiM.mjs} +22 -12
  57. package/dist/{metro-BPeY1YMh.mjs → metro-Di8EN2Tb.mjs} +20 -120
  58. package/dist/{named-ports-n7tnJsI8.mjs → named-ports-Dj_XBNaL.mjs} +8 -64
  59. package/dist/native-run-DFDoIRbY.mjs +147 -0
  60. package/dist/{native-runtime-CiiFHt0e.mjs → native-runtime-i6OkVg-w.mjs} +11 -6
  61. package/dist/offload-worker.d.mts +121 -0
  62. package/dist/offload-worker.mjs +601 -0
  63. package/dist/{ownership-Bz2kETAS.mjs → ownership-BkYxUtuj.mjs} +3 -2
  64. package/dist/{page-BTu7I60K.mjs → page-QF_Ke10s.mjs} +7 -2
  65. package/dist/{ports-C5UutqpJ.mjs → ports-DddwttKM.mjs} +3 -3
  66. package/dist/prebuild-BvxDlD6C.mjs +213 -0
  67. package/dist/process-identity-BmRm1qV0.mjs +12 -0
  68. package/dist/{project-DGeclhvO.mjs → project-CV3tDFHl.mjs} +9 -18
  69. package/dist/pull-request-pxnDCQzn.mjs +322 -0
  70. package/dist/pull-requests.d.mts +120 -0
  71. package/dist/pull-requests.mjs +2 -0
  72. package/dist/recordings-GEXp4iBT.mjs +37 -0
  73. package/dist/{reload-C-cV5yy_.mjs → reload-ChPiwvot.mjs} +70 -22
  74. package/dist/{remote-cache--aehr4Pr.mjs → remote-cache-CO2elm_b.mjs} +4 -4
  75. package/dist/run-B-xqRrsg.mjs +119 -0
  76. package/dist/{server-bare-Bq8BpSIo.mjs → server-bare-X7PUgizL.mjs} +60 -13
  77. package/dist/{server-expo-DUCg52-K.mjs → server-expo-DhtX6bom.mjs} +6 -10
  78. package/dist/server-expo-KJeD109I.mjs +2 -0
  79. package/dist/{settings-xB0Frkg6.mjs → settings-CduVcoxj.mjs} +77 -26
  80. package/dist/{settings-ssVBToDR.mjs → settings-DbL6uhH8.mjs} +16 -10
  81. package/dist/settings.schema.json +357 -2
  82. package/dist/{simslim-Bbg9UWrt.mjs → simslim-Ciluxlq4.mjs} +8 -132
  83. package/dist/slot-launch-BY0BrOLh.mjs +65 -0
  84. package/dist/{spawn-claims-PT8aQpCa.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
  85. package/dist/spawn-entry-DncpJvWL.mjs +16 -0
  86. package/dist/stage-CzaiwFsI.mjs +143 -0
  87. package/dist/start-CPO4wRg7.mjs +2 -0
  88. package/dist/{start-BZhItkiL.mjs → start-CUD9nasA.mjs} +108 -61
  89. package/dist/state-B4PQFXMW.d.mts +12 -0
  90. package/dist/state-BxCgeTQu.mjs +41 -0
  91. package/dist/{state-DwAU2_-D.mjs → state-CaeaHbDA.mjs} +7 -4
  92. package/dist/{state-l1pYwOre.mjs → state-DFm77wRn.mjs} +67 -5
  93. package/dist/stats-DBLLFmKd.mjs +66 -0
  94. package/dist/{status-TJlL0HWo.mjs → status-DYXxNOT0.mjs} +425 -260
  95. package/dist/{status-sszP4XKU.mjs → status-l84Gbvp2.mjs} +122 -20
  96. package/dist/stdout-reader-C8yjre1x.mjs +23 -0
  97. package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
  98. package/dist/stim-footprint.swift +32 -0
  99. package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
  100. package/dist/{stop-BZ2qMiBP.mjs → stop-Bad61z_2.mjs} +128 -19
  101. package/dist/stop-Bvf1MflS.mjs +48 -0
  102. package/dist/{stop-DskDKNTU.mjs → stop-CceYh1yG.mjs} +2 -2
  103. package/dist/stop-cause-CZ_Mr-v9.mjs +665 -0
  104. package/dist/supervisor-run.d.mts +44 -12
  105. package/dist/supervisor-run.mjs +276 -33
  106. package/dist/support-CDQbDkL5.mjs +315 -0
  107. package/dist/support-WLOzVKUv.mjs +176 -0
  108. package/dist/teardown-BYuQafiA.mjs +718 -0
  109. package/dist/{xcode-LM6A8cNZ.mjs → toolchain-DmeYjXD9.mjs} +363 -13
  110. package/dist/warm-progress-DVHLN4uC.mjs +463 -0
  111. package/dist/{idle-DxLi5OkN.mjs → watchman-Bx0wceoF.mjs} +55 -8
  112. package/dist/{web-sWXd5iek.mjs → web-k6w8-HnE.mjs} +39 -22
  113. package/dist/web-run.mjs +326 -13
  114. package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
  115. package/dist/workspace-state-CL2V2Ons.mjs +371 -0
  116. package/dist/worktree-BT_uULFx.mjs +2 -0
  117. package/dist/{worktree-DeBQSVtR.mjs → worktree-C0c5Udwa.mjs} +55 -54
  118. package/dist/{worktree-D4Do_XiQ.mjs → worktree-qXKzADSC.mjs} +161 -255
  119. package/package.json +10 -5
  120. package/shim/bundle-response.cjs +55 -10
  121. package/shim/bundle-response.d.cts +1 -0
  122. package/shim/expo-metro-config.cjs +10 -2
  123. package/dist/build-progress-l7d-X-ZP.mjs +0 -247
  124. package/dist/in-use-wYEaKQM9.mjs +0 -249
  125. package/dist/ownership-PUP4Dwai.mjs +0 -1138
  126. package/dist/server-expo-BeYwP_Xy.mjs +0 -2
  127. package/dist/slot-launch-BIWEW-wI.mjs +0 -19
  128. package/dist/start-Rw2GD3nV.mjs +0 -2
  129. package/dist/stats-CaSwmsSZ.mjs +0 -62
  130. package/dist/stats-D8rUTPHd.mjs +0 -368
  131. package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
  132. package/dist/worktree-3cBa-bQt.mjs +0 -2
  133. package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
@@ -0,0 +1,167 @@
1
+ import { d as getConfigDir } from "./config-D0DbpZtM.mjs";
2
+ import { r as register } from "./cache-manifest-DnUHBJaU.mjs";
3
+ import { E as withDirLock, p as ensureWorkspaceStorage } from "./workspace-state-CL2V2Ons.mjs";
4
+ import { createHash, randomUUID } from "node:crypto";
5
+ import { accessSync, constants, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, symlinkSync, writeFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { isJsonObject, readJsonFile } from "@stim-cli/core/state";
8
+ import { fileURLToPath } from "node:url";
9
+ //#region src/engine/android-cas.ts
10
+ const CAS_TOOLCHAIN_FIELDS = [
11
+ "clang",
12
+ "clangxx",
13
+ "lld",
14
+ "ar",
15
+ "ranlib",
16
+ "ndk",
17
+ "resourceDir"
18
+ ];
19
+ const CAS_TOOLCHAIN_BINARIES = [
20
+ "clang",
21
+ "clangxx",
22
+ "lld",
23
+ "ar",
24
+ "ranlib"
25
+ ];
26
+ function executableFile(path) {
27
+ try {
28
+ accessSync(path, constants.X_OK);
29
+ return statSync(path).isFile();
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+ function directory(path) {
35
+ try {
36
+ return statSync(path).isDirectory();
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+ function isAndroidCasToolchain(value) {
42
+ return CAS_TOOLCHAIN_FIELDS.every((field) => typeof value[field] === "string");
43
+ }
44
+ function readAndroidCasToolchain(manifest) {
45
+ const parsed = readJsonFile(manifest);
46
+ const toolchain = isJsonObject(parsed) ? parsed : {};
47
+ if (!isAndroidCasToolchain(toolchain)) {
48
+ const missing = CAS_TOOLCHAIN_FIELDS.filter((field) => typeof toolchain[field] !== "string");
49
+ throw new Error(`${manifest} declares no ${missing.join(", ")}.`);
50
+ }
51
+ const notExecutable = CAS_TOOLCHAIN_BINARIES.filter((field) => !executableFile(toolchain[field]));
52
+ if (notExecutable.length > 0) throw new Error(`${manifest} names no executable ${notExecutable.join(", ")}.`);
53
+ if (!directory(toolchain.resourceDir)) throw new Error(`${manifest} names resourceDir ${toolchain.resourceDir}, which is not a directory.`);
54
+ const ndkProperties = readFileSync(join(toolchain.ndk, "source.properties"), "utf8");
55
+ const ndkVersion = /Pkg.Revision\s*=\s*([^\r\n]+)/.exec(ndkProperties)?.[1]?.trim();
56
+ if (!ndkVersion) throw new Error(`Missing NDK version in ${toolchain.ndk}/source.properties.`);
57
+ return {
58
+ toolchain,
59
+ ndkVersion,
60
+ ndkProperties
61
+ };
62
+ }
63
+ function resolveAndroidCompilerCache({ optimizations, use, env = process.env }) {
64
+ if (optimizations.android.compilerCache !== "cas") return {
65
+ cas: null,
66
+ optimizations
67
+ };
68
+ const manifest = optimizations.android.casToolchain;
69
+ try {
70
+ return {
71
+ cas: use(manifest),
72
+ optimizations
73
+ };
74
+ } catch (error) {
75
+ const fromEnvironment = Boolean(env.STIM_ANDROID_CAS_TOOLCHAIN);
76
+ return {
77
+ cas: null,
78
+ optimizations: {
79
+ ...optimizations,
80
+ android: {
81
+ ...optimizations.android,
82
+ compilerCache: "ccache",
83
+ compilerCacheFallback: {
84
+ key: fromEnvironment ? "STIM_ANDROID_CAS_TOOLCHAIN" : "optimizations.android.casToolchain",
85
+ reason: `could not be used: ${error.message.replace(/\.$/, "")}`,
86
+ fromEnvironment,
87
+ manifest
88
+ }
89
+ }
90
+ }
91
+ };
92
+ }
93
+ }
94
+ function resolveAndroidCas(root, env = process.env) {
95
+ const manifest = env.STIM_ANDROID_CAS_TOOLCHAIN;
96
+ if (!manifest) return null;
97
+ const { toolchain, ndkVersion, ndkProperties } = readAndroidCasToolchain(manifest);
98
+ const scripts = [
99
+ "shim/android-cas.gradle",
100
+ "shim/android-cas.toolchain.cmake",
101
+ "shim/android-cas-pch.cmake",
102
+ "dist/android-cas-compiler.mjs"
103
+ ].map((name) => {
104
+ const path = [`../${name}`, `../../${name}`].map((candidate) => fileURLToPath(new URL(candidate, import.meta.url))).find((candidate) => existsSync(candidate));
105
+ if (!path) throw new Error(`Stim installation is missing ${name}.`);
106
+ return path;
107
+ });
108
+ const hash = createHash("sha256").update(JSON.stringify(toolchain));
109
+ for (const path of [
110
+ ...scripts,
111
+ toolchain.clang,
112
+ toolchain.clangxx,
113
+ toolchain.lld,
114
+ toolchain.ar,
115
+ toolchain.ranlib
116
+ ]) hash.update(readFileSync(path));
117
+ hash.update(ndkProperties);
118
+ const id = `apple-cas-${hash.digest("hex")}`;
119
+ const dir = join(getConfigDir(), "android-cas", id);
120
+ const state = join(ensureWorkspaceStorage(root), "android-cas", id);
121
+ const context = join(state, "context.json");
122
+ mkdirSync(state, { recursive: true });
123
+ mkdirSync(dir, { recursive: true });
124
+ withDirLock(join(state, "setup.lock"), () => {
125
+ for (const name of ["clang", "clang++"]) {
126
+ const path = join(state, name);
127
+ const temporary = `${path}.${randomUUID()}.tmp`;
128
+ symlinkSync(scripts[3], temporary);
129
+ renameSync(temporary, path);
130
+ }
131
+ const temporary = `${context}.${process.pid}.tmp`;
132
+ writeFileSync(temporary, JSON.stringify({
133
+ ...toolchain,
134
+ source: realpathSync(root),
135
+ state,
136
+ cache: dir
137
+ }));
138
+ renameSync(temporary, context);
139
+ });
140
+ register({
141
+ dir,
142
+ name: "android-cas",
143
+ prune: "atomic",
144
+ note: "Experimental Android compiler CAS"
145
+ });
146
+ return {
147
+ id,
148
+ dir,
149
+ initScript: scripts[0],
150
+ env: {
151
+ STIM_ANDROID_CAS_CONTEXT: context,
152
+ STIM_ANDROID_CAS_SOURCE_ROOT: realpathSync(root),
153
+ STIM_ANDROID_CAS_STATE: state,
154
+ STIM_ANDROID_CAS_NDK: toolchain.ndk,
155
+ STIM_ANDROID_CAS_NDK_VERSION: ndkVersion,
156
+ STIM_ANDROID_CAS_AR: toolchain.ar,
157
+ STIM_ANDROID_CAS_RANLIB: toolchain.ranlib,
158
+ STIM_ANDROID_CAS_CMAKE_TOOLCHAIN: scripts[1],
159
+ STIM_ANDROID_CAS_CMAKE_PCH: scripts[2],
160
+ CMAKE_C_COMPILER_LAUNCHER: "",
161
+ CMAKE_CXX_COMPILER_LAUNCHER: "",
162
+ CCACHE_DISABLE: "1"
163
+ }
164
+ };
165
+ }
166
+ //#endregion
167
+ export { resolveAndroidCas as n, resolveAndroidCompilerCache as r, readAndroidCasToolchain as t };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
3
+ import { createHash, randomUUID } from "node:crypto";
3
4
  import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
5
  import { join } from "node:path";
5
- import { createHash, randomUUID } from "node:crypto";
6
6
  import { once } from "node:events";
7
7
  //#region bin/android-cas-compiler.ts
8
8
  const context = process.env.STIM_ANDROID_CAS_CONTEXT;
@@ -1,138 +1,6 @@
1
- import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- import { T as uninstallIosApp, c as iosSimulatorFailureAdvice, p as listUserApps } from "./ios-CmEzZiOj.mjs";
3
- import { closeSync, lstatSync, openSync, readSync, readdirSync } from "node:fs";
4
- import { isAbsolute, join } from "node:path";
5
- import { createHash } from "node:crypto";
6
- //#region src/engine/installed-artifact.ts
7
- const READ_CHUNK_BYTES = 1048576;
8
- const DEVICE_PATH_TIMEOUT_MS = 3e4;
9
- const DEVICE_HASH_TIMEOUT_MS = 12e4;
10
- const SHA256_HEX = /^[0-9a-f]{64}$/;
11
- function parseInstalledApkPath(text) {
12
- if (typeof text !== "string") return null;
13
- const paths = [];
14
- for (const raw of text.split("\n")) {
15
- const line = raw.trim();
16
- if (!line.startsWith("package:")) continue;
17
- const path = line.slice(8);
18
- if (path.startsWith("/")) paths.push(path);
19
- }
20
- return paths.length === 1 ? paths[0] : null;
21
- }
22
- function parseDeviceSha256(text) {
23
- if (typeof text !== "string") return null;
24
- const first = text.trim().split(/\s+/)[0] ?? "";
25
- return SHA256_HEX.test(first) ? first : null;
26
- }
27
- function parseAppContainerPath(text) {
28
- if (typeof text !== "string") return null;
29
- const lines = text.split("\n").map((line) => line.trim()).filter(Boolean);
30
- return lines.length === 1 && isAbsolute(lines[0]) ? lines[0] : null;
31
- }
32
- function artifactsMatch(local, installed) {
33
- return Boolean(local) && local === installed;
34
- }
35
- function hashFile(file) {
36
- let fd = null;
37
- try {
38
- fd = openSync(file, "r");
39
- const digest = createHash("sha256");
40
- const buffer = Buffer.allocUnsafe(READ_CHUNK_BYTES);
41
- for (;;) {
42
- const read = readSync(fd, buffer, 0, READ_CHUNK_BYTES, null);
43
- if (read <= 0) break;
44
- digest.update(buffer.subarray(0, read));
45
- }
46
- return digest.digest("hex");
47
- } catch {
48
- return null;
49
- } finally {
50
- if (fd !== null) try {
51
- closeSync(fd);
52
- } catch {}
53
- }
54
- }
55
- function hashBundle(dir) {
56
- const digest = createHash("sha256");
57
- const walk = (abs, rel) => {
58
- let names;
59
- try {
60
- names = readdirSync(abs);
61
- } catch {
62
- return false;
63
- }
64
- for (const name of names.toSorted()) {
65
- const child = join(abs, name);
66
- const path = rel === "" ? name : `${rel}/${name}`;
67
- let stat;
68
- try {
69
- stat = lstatSync(child);
70
- } catch {
71
- return false;
72
- }
73
- if (stat.isDirectory()) {
74
- if (!walk(child, path)) return false;
75
- continue;
76
- }
77
- if (!stat.isFile()) return false;
78
- const file = hashFile(child);
79
- if (file === null) return false;
80
- digest.update(`${path}\0${file}\n`);
81
- }
82
- return true;
83
- };
84
- return walk(dir, "") ? digest.digest("hex") : null;
85
- }
86
- function deviceHoldsApk({ serial, packageName, apkPath }, { exec = null } = {}) {
87
- const e = exec || getExecutor();
88
- let path;
89
- try {
90
- path = parseInstalledApkPath(e.runFile("adb", [
91
- "-s",
92
- serial,
93
- "shell",
94
- "pm",
95
- "path",
96
- packageName
97
- ], { timeoutMs: DEVICE_PATH_TIMEOUT_MS }));
98
- } catch {
99
- return false;
100
- }
101
- if (!path) return false;
102
- let installed;
103
- try {
104
- installed = parseDeviceSha256(e.runFile("adb", [
105
- "-s",
106
- serial,
107
- "shell",
108
- "sha256sum",
109
- path
110
- ], { timeoutMs: DEVICE_HASH_TIMEOUT_MS }));
111
- } catch {
112
- return false;
113
- }
114
- if (!installed) return false;
115
- return artifactsMatch(hashFile(apkPath), installed);
116
- }
117
- function deviceHoldsBundle({ udid, bundleId, appPath }, { exec = null } = {}) {
118
- const e = exec || getExecutor();
119
- let container;
120
- try {
121
- container = parseAppContainerPath(e.runFile("xcrun", [
122
- "simctl",
123
- "get_app_container",
124
- udid,
125
- bundleId
126
- ], { timeoutMs: DEVICE_PATH_TIMEOUT_MS }));
127
- } catch {
128
- return false;
129
- }
130
- if (!container) return false;
131
- const installed = hashBundle(container);
132
- if (!installed) return false;
133
- return artifactsMatch(hashBundle(appPath), installed);
134
- }
135
- //#endregion
1
+ import { t as getExecutor } from "./exec-CaErVv7t.mjs";
2
+ import { D as uninstallIosApp, M as deviceHoldsApk, N as deviceHoldsBundle, l as iosSimulatorFailureAdvice, m as listUserApps } from "./ios-3CtCRhwr.mjs";
3
+ import { t as DEV_MENU_LAUNCH_ARGS } from "./ios-device-Ee7sDXfp.mjs";
136
4
  //#region src/engine/app-install.ts
137
5
  const INSTALL_ERROR = "STIM_INSTALL_FAILED";
138
6
  const LAUNCH_ERROR = "STIM_LAUNCH_FAILED";
@@ -142,12 +10,37 @@ const IOS_SCHEME_APPROVAL_OPENER = "com.apple.CoreSimulator.CoreSimulatorBridge"
142
10
  const IOS_DEV_MENU_OFF_KEYS = ["EXDevMenuShowsAtLaunch", "EXDevMenuShowFloatingActionButton"];
143
11
  const DEV_CLIENT_ONBOARDING_QUERY = "disableOnboarding=1";
144
12
  const DEV_CLIENT_DISABLE_FAB_QUERY = "disableFab=1";
13
+ const DEV_CLIENT_DEV_MENU_OFF_QUERY = "disableFab=1&disableAutoLaunch=1";
14
+ const DEV_CLIENT_RESERVED_DEV_MENU_OFF_QUERY = "__expo_disable_fab=1&__expo_disable_auto_launch=1";
145
15
  const ANDROID_DISABLE_AUTO_LAUNCH_EXTRA = "EXDevMenuDisableAutoLaunch";
16
+ const IOS_DEV_MENU_OFF_DEFAULTS_PLIST = [
17
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
18
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">",
19
+ "<plist version=\"1.0\">",
20
+ "<dict>",
21
+ ...IOS_DEV_MENU_OFF_KEYS.flatMap((key) => [` <key>${key}</key>`, " <false/>"]),
22
+ "</dict>",
23
+ "</plist>",
24
+ ""
25
+ ].join("\n");
26
+ function writeIosDevMenuOffDefaults(udid, bundleId, exec) {
27
+ for (const key of IOS_DEV_MENU_OFF_KEYS) exec.runFile("xcrun", [
28
+ "simctl",
29
+ "spawn",
30
+ udid,
31
+ "defaults",
32
+ "write",
33
+ bundleId,
34
+ key,
35
+ "-bool",
36
+ "false"
37
+ ], { timeoutMs: 6e4 });
38
+ }
146
39
  function describeIosSimulatorFailure(error, exec) {
147
40
  const detail = describe(error);
148
41
  return error?.code === "ETIMEDOUT" ? `${detail}. ${iosSimulatorFailureAdvice(exec)}` : detail;
149
42
  }
150
- function installIosApp({ udid, appPath, bundleId = null, devClientScheme = null, proveInstalled = true }, { exec = null, now = null } = {}) {
43
+ function installIosApp({ udid, appPath, bundleId = null, devClientScheme = null, schemeApprovals = [], proveInstalled = true }, { exec = null, now = null } = {}) {
151
44
  const e = exec || getExecutor();
152
45
  const artifactStartedAt = now?.();
153
46
  const skipped = bundleId && proveInstalled ? deviceHoldsBundle({
@@ -174,20 +67,13 @@ function installIosApp({ udid, appPath, bundleId = null, devClientScheme = null,
174
67
  }
175
68
  const artifactFinishedAt = now?.();
176
69
  const artifactDurationMs = artifactStartedAt !== void 0 && artifactFinishedAt !== void 0 ? artifactFinishedAt - artifactStartedAt : void 0;
177
- const preparationStartedAt = bundleId && devClientScheme ? artifactFinishedAt : void 0;
178
- if (bundleId && devClientScheme) try {
179
- for (const key of IOS_DEV_MENU_OFF_KEYS) e.runFile("xcrun", [
180
- "simctl",
181
- "spawn",
182
- udid,
183
- "defaults",
184
- "write",
185
- bundleId,
186
- key,
187
- "-bool",
188
- "false"
189
- ], { timeoutMs: 6e4 });
190
- for (const key of iosSchemeApprovalKeys(bundleId, devClientScheme)) e.runFile("xcrun", [
70
+ const devMenuKeys = bundleId && devClientScheme && !skipped ? IOS_DEV_MENU_OFF_KEYS : [];
71
+ const missingApprovals = (bundleId && devClientScheme ? iosSchemeApprovalKeys(bundleId, devClientScheme) : []).filter((key) => !schemeApprovals.includes(`${key}=${bundleId}`));
72
+ const preparing = bundleId && (devMenuKeys.length > 0 || missingApprovals.length > 0);
73
+ const preparationStartedAt = preparing ? artifactFinishedAt : void 0;
74
+ if (bundleId && preparing) try {
75
+ if (devMenuKeys.length > 0) writeIosDevMenuOffDefaults(udid, bundleId, e);
76
+ for (const key of missingApprovals) e.runFile("xcrun", [
191
77
  "simctl",
192
78
  "spawn",
193
79
  udid,
@@ -208,7 +94,8 @@ function installIosApp({ udid, appPath, bundleId = null, devClientScheme = null,
208
94
  const devClientPreparationDurationMs = now && preparationStartedAt !== void 0 ? now() - preparationStartedAt : void 0;
209
95
  const timing = {
210
96
  ...artifactDurationMs === void 0 ? {} : { artifactDurationMs },
211
- ...devClientPreparationDurationMs === void 0 ? {} : { devClientPreparationDurationMs }
97
+ ...devClientPreparationDurationMs === void 0 ? {} : { devClientPreparationDurationMs },
98
+ ...missingApprovals.length > 0 ? { schemeApprovals: [...schemeApprovals, ...missingApprovals.map((key) => `${key}=${bundleId}`)] } : {}
212
99
  };
213
100
  return skipped ? {
214
101
  ok: true,
@@ -230,6 +117,7 @@ function clearOtherUserApps({ udid, keep }, { list = listUserApps, uninstall = u
230
117
  } catch {
231
118
  return {
232
119
  listed: false,
120
+ kept: false,
233
121
  removed,
234
122
  failed
235
123
  };
@@ -245,6 +133,7 @@ function clearOtherUserApps({ udid, keep }, { list = listUserApps, uninstall = u
245
133
  }
246
134
  return {
247
135
  listed: true,
136
+ kept: keep ? installed.includes(keep) : false,
248
137
  removed,
249
138
  failed
250
139
  };
@@ -252,16 +141,20 @@ function clearOtherUserApps({ udid, keep }, { list = listUserApps, uninstall = u
252
141
  function jsLocationValue(metroPort) {
253
142
  return `localhost:${metroPort}`;
254
143
  }
255
- function devClientDeepLink(scheme, projectOrigin) {
256
- const projectUrl = `${projectOrigin.replace(/\/+$/, "")}/?${DEV_CLIENT_ONBOARDING_QUERY}`;
257
- return `${scheme}://expo-development-client/?url=${encodeURIComponent(projectUrl)}&${DEV_CLIENT_DISABLE_FAB_QUERY}`;
144
+ function devClientDeepLink(scheme, projectOrigin, { devMenuParams = false } = {}) {
145
+ const projectQuery = devMenuParams ? `${DEV_CLIENT_ONBOARDING_QUERY}&${DEV_CLIENT_DEV_MENU_OFF_QUERY}&${DEV_CLIENT_RESERVED_DEV_MENU_OFF_QUERY}` : DEV_CLIENT_ONBOARDING_QUERY;
146
+ const projectUrl = `${projectOrigin.replace(/\/+$/, "")}/?${projectQuery}`;
147
+ return `${scheme}://expo-development-client/?url=${encodeURIComponent(projectUrl)}&${devMenuParams ? DEV_CLIENT_DEV_MENU_OFF_QUERY : DEV_CLIENT_DISABLE_FAB_QUERY}`;
258
148
  }
259
- function devClientUrl(scheme, metroPort, host = "localhost") {
260
- return devClientDeepLink(scheme, `http://${host}:${metroPort}`);
149
+ function devClientUrl(scheme, metroPort, host = "localhost", options = {}) {
150
+ return devClientDeepLink(scheme, `http://${host}:${metroPort}`, options);
261
151
  }
262
152
  function iosSchemeApprovalKeys(bundleId, devClientScheme) {
263
153
  return [.../* @__PURE__ */ new Set([bundleId, devClientScheme])].map((target) => `${IOS_SCHEME_APPROVAL_OPENER}-->${target}`);
264
154
  }
155
+ function restartedAppNote(restartedPid, lead = " ") {
156
+ return restartedPid ? `${lead}restarted running app (was pid ${restartedPid})` : "";
157
+ }
265
158
  function parseLaunchedPid(text) {
266
159
  if (typeof text !== "string") return null;
267
160
  const match = text.trim().match(/:\s*(\d+)\s*$/);
@@ -296,7 +189,7 @@ function launchedIosAppAfterNoHandle(error, udid, bundleId, exec) {
296
189
  if (!stderr.includes("domain=NSPOSIXErrorDomain, code=3") || !stderr.includes(`Application launch for '${bundleId}' did not return a process handle nor launch error.`)) return null;
297
190
  return iosAppProcess(udid, bundleId, { exec }) ?? null;
298
191
  }
299
- function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, consolePaths }, { exec = null } = {}) {
192
+ function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, devMenuParams = false, consolePaths }, { exec = null } = {}) {
300
193
  const e = exec || getExecutor();
301
194
  const launchArgs = [
302
195
  "simctl",
@@ -305,6 +198,26 @@ function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, conso
305
198
  udid,
306
199
  bundleId
307
200
  ];
201
+ let runningPid = iosAppProcess(udid, bundleId, { exec: e });
202
+ const restart = {};
203
+ if (runningPid) {
204
+ try {
205
+ e.runFile("xcrun", [
206
+ "simctl",
207
+ "terminate",
208
+ udid,
209
+ bundleId
210
+ ], { timeoutMs: 3e4 });
211
+ } catch (err) {
212
+ return {
213
+ failed: true,
214
+ code: LAUNCH_ERROR,
215
+ reason: `simctl terminate ${bundleId} failed, so the running app (pid ${runningPid}) was not restarted: ${describeIosSimulatorFailure(err, e)}`
216
+ };
217
+ }
218
+ restart.restartedPid = runningPid;
219
+ runningPid = null;
220
+ }
308
221
  if (metroPort !== null) {
309
222
  try {
310
223
  e.runFile("xcrun", [
@@ -325,23 +238,35 @@ function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, conso
325
238
  };
326
239
  }
327
240
  if (devClientScheme) {
328
- const url = devClientUrl(devClientScheme, metroPort);
241
+ const url = devClientUrl(devClientScheme, metroPort, "localhost", { devMenuParams });
242
+ const viaInitialUrl = Boolean(consolePaths) && runningPid === null;
243
+ if (!viaInitialUrl) try {
244
+ writeIosDevMenuOffDefaults(udid, bundleId, e);
245
+ } catch (err) {
246
+ return {
247
+ failed: true,
248
+ code: LAUNCH_ERROR,
249
+ reason: `Could not turn off ${bundleId}'s dev menu before opening it (defaults write): ${describeIosSimulatorFailure(err, e)}`
250
+ };
251
+ }
329
252
  let launchedWithInitialUrl = false;
330
253
  try {
331
- if (consolePaths && iosAppProcess(udid, bundleId, { exec: e }) === null) {
254
+ if (viaInitialUrl) {
332
255
  const initialUrl = new URL(url).searchParams.get("url");
333
256
  launchedWithInitialUrl = true;
334
257
  const pid = parseLaunchedPid(e.runFile("xcrun", [
335
258
  ...launchArgs,
336
259
  "--initialUrl",
337
- initialUrl
260
+ initialUrl,
261
+ ...DEV_MENU_LAUNCH_ARGS
338
262
  ], { timeoutMs: 6e4 }));
339
263
  return {
340
264
  ok: true,
341
265
  mode: "launch",
342
266
  url,
343
267
  jsLocation: jsLocationValue(metroPort),
344
- pid
268
+ pid,
269
+ ...restart
345
270
  };
346
271
  }
347
272
  e.runFile("xcrun", [
@@ -354,16 +279,18 @@ function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, conso
354
279
  ok: true,
355
280
  mode: "openurl",
356
281
  url,
357
- jsLocation: jsLocationValue(metroPort)
282
+ jsLocation: jsLocationValue(metroPort),
283
+ ...restart
358
284
  };
359
285
  } catch (err) {
360
286
  const pid = launchedWithInitialUrl ? launchedIosAppAfterNoHandle(err, udid, bundleId, e) : null;
361
- if (pid) return {
287
+ if (pid && pid !== restart.restartedPid) return {
362
288
  ok: true,
363
289
  mode: "launch",
364
290
  url,
365
291
  jsLocation: jsLocationValue(metroPort),
366
- pid
292
+ pid,
293
+ ...restart
367
294
  };
368
295
  return {
369
296
  failed: true,
@@ -373,22 +300,23 @@ function launchIosApp({ udid, bundleId, metroPort, devClientScheme = null, conso
373
300
  }
374
301
  }
375
302
  }
376
- const preLaunchPid = iosAppProcess(udid, bundleId, { exec: e });
377
303
  try {
378
304
  const result = {
379
305
  ok: true,
380
306
  mode: "launch",
381
- pid: parseLaunchedPid(e.runFile("xcrun", launchArgs, { timeoutMs: 6e4 }))
307
+ pid: parseLaunchedPid(e.runFile("xcrun", launchArgs, { timeoutMs: 6e4 })),
308
+ ...restart
382
309
  };
383
310
  if (metroPort !== null) result.jsLocation = jsLocationValue(metroPort);
384
311
  return result;
385
312
  } catch (err) {
386
- const pid = preLaunchPid === null ? launchedIosAppAfterNoHandle(err, udid, bundleId, e) : null;
387
- if (pid) {
313
+ const pid = runningPid === null ? launchedIosAppAfterNoHandle(err, udid, bundleId, e) : null;
314
+ if (pid && pid !== restart.restartedPid) {
388
315
  const result = {
389
316
  ok: true,
390
317
  mode: "launch",
391
- pid
318
+ pid,
319
+ ...restart
392
320
  };
393
321
  if (metroPort !== null) result.jsLocation = jsLocationValue(metroPort);
394
322
  return result;
@@ -533,6 +461,39 @@ function reverseMetroPorts({ serial, metroPort, devicePorts = null }, { exec = n
533
461
  reversed: pairs.map(([device, host]) => `tcp:${device}->tcp:${host}`)
534
462
  };
535
463
  }
464
+ function hasMetroReverse(listing, metroPort) {
465
+ return String(listing ?? "").split("\n").some((line) => {
466
+ const cols = line.trim().split(/\s+/);
467
+ return cols[1] === `tcp:${metroPort}` && cols[2] === `tcp:${metroPort}`;
468
+ });
469
+ }
470
+ /** Re-applies the launch's `metroPort` reverse when the device no longer has it. */
471
+ function ensureMetroReverse({ serial, metroPort }, { exec = null } = {}) {
472
+ const e = exec || getExecutor();
473
+ let listing;
474
+ try {
475
+ listing = e.runFile("adb", [
476
+ "-s",
477
+ serial,
478
+ "reverse",
479
+ "--list"
480
+ ], ADB_SHELL_OPTIONS);
481
+ } catch {
482
+ return {
483
+ failed: true,
484
+ reason: `adb reverse --list failed on ${serial}`
485
+ };
486
+ }
487
+ if (hasMetroReverse(listing, metroPort)) return { restored: false };
488
+ const reversed = reverseMetroPorts({
489
+ serial,
490
+ metroPort
491
+ }, { exec: e });
492
+ return reversed.failed ? {
493
+ failed: true,
494
+ reason: reversed.reason ?? "adb reverse failed"
495
+ } : { restored: true };
496
+ }
536
497
  const EMULATOR_HOST_LOOPBACK = "127.0.0.1";
537
498
  const PHYSICAL_HOST_LOOPBACK = "localhost";
538
499
  function androidMetroHost(physical) {
@@ -631,8 +592,31 @@ function openAndroidDevClientUrl({ serial, url, packageName }, { exec = null } =
631
592
  url
632
593
  };
633
594
  }
595
+ function stopRunningAndroidApp(serial, packageName, exec) {
596
+ const pid = androidAppProcess(serial, packageName, { exec });
597
+ if (!pid) return {};
598
+ try {
599
+ exec.runFile("adb", [
600
+ "-s",
601
+ serial,
602
+ "shell",
603
+ "am",
604
+ "force-stop",
605
+ packageName
606
+ ], ADB_SHELL_OPTIONS);
607
+ } catch (err) {
608
+ return {
609
+ failed: true,
610
+ code: LAUNCH_ERROR,
611
+ reason: `am force-stop ${packageName} failed on ${serial}, so the running app (pid ${pid}) was not restarted: ${describe(err)}`
612
+ };
613
+ }
614
+ return { restartedPid: pid };
615
+ }
634
616
  function launchAndroidApp({ serial, packageName, metroPort, devClientScheme = null, physical = false }, { exec = null } = {}) {
635
617
  const e = exec || getExecutor();
618
+ const restart = stopRunningAndroidApp(serial, packageName, e);
619
+ if (restart.failed) return restart;
636
620
  const reversed = reverseMetroPorts({
637
621
  serial,
638
622
  metroPort
@@ -657,7 +641,8 @@ function launchAndroidApp({ serial, packageName, metroPort, devClientScheme = nu
657
641
  const wiring = {
658
642
  reversed: reversedPairs,
659
643
  debugHttpHost: prefs.ok ? prefs.host : null,
660
- debugHttpHostNote: prefs.ok ? null : prefs.reason
644
+ debugHttpHostNote: prefs.ok ? null : prefs.reason,
645
+ ...restart
661
646
  };
662
647
  let devClientNote = null;
663
648
  if (devClientScheme) {
@@ -725,6 +710,8 @@ function launchAndroidApp({ serial, packageName, metroPort, devClientScheme = nu
725
710
  }
726
711
  function launchAndroidReleaseApp({ serial, packageName }, { exec = null } = {}) {
727
712
  const e = exec || getExecutor();
713
+ const restart = stopRunningAndroidApp(serial, packageName, e);
714
+ if (restart.failed) return restart;
728
715
  const component = resolveLaunchActivity(serial, packageName, { exec: e });
729
716
  if (component) try {
730
717
  e.runFile("adb", [
@@ -739,7 +726,8 @@ function launchAndroidReleaseApp({ serial, packageName }, { exec = null } = {})
739
726
  return {
740
727
  ok: true,
741
728
  mode: "am-start",
742
- component
729
+ component,
730
+ ...restart
743
731
  };
744
732
  } catch (err) {
745
733
  return {
@@ -760,7 +748,8 @@ function launchAndroidReleaseApp({ serial, packageName }, { exec = null } = {})
760
748
  ], ADB_SHELL_OPTIONS);
761
749
  return {
762
750
  ok: true,
763
- mode: "monkey"
751
+ mode: "monkey",
752
+ ...restart
764
753
  };
765
754
  } catch (err) {
766
755
  return {
@@ -816,4 +805,4 @@ function androidAppProcess(serial, packageName, { exec = null } = {}) {
816
805
  }
817
806
  }
818
807
  //#endregion
819
- export { launchAndroidReleaseApp as _, LAUNCH_ERROR as a, clearOtherUserApps as c, deviceShellArg as d, installAndroidApp as f, launchAndroidApp as g, iosAppProcess as h, INSTALL_ERROR as i, devClientDeepLink as l, installIosApp as m, ANDROID_DISABLE_AUTO_LAUNCH_EXTRA as n, androidAppProcess as o, installConflictKind as p, DEFAULT_METRO_PORT as r, androidDevClientUrl as s, ADB_INSTALL_TIMEOUT_MS as t, devClientUrl as u, launchIosApp as v };
808
+ export { restartedAppNote as S, installIosApp as _, IOS_DEV_MENU_OFF_DEFAULTS_PLIST as a, launchAndroidReleaseApp as b, androidDevClientUrl as c, devClientUrl as d, deviceShellArg as f, installConflictKind as g, installAndroidApp as h, INSTALL_ERROR as i, clearOtherUserApps as l, hasMetroReverse as m, ANDROID_DISABLE_AUTO_LAUNCH_EXTRA as n, LAUNCH_ERROR as o, ensureMetroReverse as p, DEFAULT_METRO_PORT as r, androidAppProcess as s, ADB_INSTALL_TIMEOUT_MS as t, devClientDeepLink as u, iosAppProcess as v, launchIosApp as x, launchAndroidApp as y };