stim 1.11.0 → 1.13.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 (82) hide show
  1. package/README.md +3 -1
  2. package/dist/{activity-BtG4Va9l.mjs → activity-DfVKZTEB.mjs} +44 -26
  3. package/dist/{android-BA2i_KAV.mjs → android-BHfAu2mf.mjs} +1 -1
  4. package/dist/{android-C1q4l523.mjs → android-CD8pr8Q2.mjs} +112 -54
  5. package/dist/{android-cas-DfJkwCXW.mjs → android-cas-B9Kv9aIy.mjs} +12 -10
  6. package/dist/{android-C4zG2Tuc.mjs → android-qx_31wJo.mjs} +414 -118
  7. package/dist/{app-install-DHut6JnV.mjs → app-install-CDFY2nUL.mjs} +1 -1
  8. package/dist/budget-E5o91NR1.mjs +1739 -0
  9. package/dist/{build-plan-CeAYgKAx.mjs → build-plan-BTa93o_r.mjs} +125 -107
  10. package/dist/{build-progress-CDwogz6R.mjs → build-progress-l7d-X-ZP.mjs} +76 -8
  11. package/dist/{cache-manifest-Pubfp8wV.mjs → cache-manifest-DWPF4RKJ.mjs} +1 -1
  12. package/dist/cache-manifest.mjs +1 -1
  13. package/dist/cdp-Dq_ypAlJ.mjs +115 -0
  14. package/dist/chrome-B5hWgQJS.mjs +61 -0
  15. package/dist/cli.mjs +17 -16
  16. package/dist/collector-run.mjs +15 -9
  17. package/dist/{command-output-D5z2_bcF.mjs → command-output-BIL7rlX7.mjs} +1 -1
  18. package/dist/{config-BEq0Qw_a.mjs → config-0jCcMM0E.mjs} +10 -1
  19. package/dist/created-devices-Cd558h31.mjs +37 -0
  20. package/dist/{dependency-state-r9UesA9a.mjs → dependency-state-DNN0yfx6.mjs} +1 -1
  21. package/dist/{deps-OF7CD5Dx.mjs → deps-2Wo81np9.mjs} +2 -2
  22. package/dist/{device-BwH2iI3O.mjs → device-Cf7vl-so.mjs} +7 -7
  23. package/dist/{device-lease-D83nqeMX.mjs → device-lease-CL9dZf73.mjs} +55 -6
  24. package/dist/{device-pool-DHj7cdPy.mjs → device-pool-MuoiyRcu.mjs} +4 -4
  25. package/dist/{device-remote-BQZSnnmE.mjs → device-remote-DT9ngZiD.mjs} +254 -579
  26. package/dist/{doctor-D8QdMRMf.mjs → doctor-D2iysNNH.mjs} +50 -20
  27. package/dist/{error-diagnostics-UYFSQwRy.mjs → error-diagnostics-BoiOhck8.mjs} +7 -7
  28. package/dist/{gc-COZteyiq.mjs → gc-eA-PRBX8.mjs} +1022 -131
  29. package/dist/{guide-NDvTmMi-.mjs → guide-BfZ0OmiP.mjs} +909 -132
  30. package/dist/{guide-status-CWvti2Lg.mjs → guide-status-BaMYu55M.mjs} +2 -2
  31. package/dist/{idle-NETbeNiQ.mjs → idle-DxLi5OkN.mjs} +43 -10
  32. package/dist/{in-use-DVhlSoyn.mjs → in-use-wYEaKQM9.mjs} +11 -7
  33. package/dist/{ios-CQLKpNfr.mjs → ios-CcfCeZ19.mjs} +103 -58
  34. package/dist/{ios-DArbmwer.mjs → ios-CmEzZiOj.mjs} +31 -22
  35. package/dist/{ios-device-CwDZo0X4.mjs → ios-device-BW-t_Lkv.mjs} +1 -1
  36. package/dist/{launch-verify-CuPDGXdr.mjs → launch-verify-CuJaBpEa.mjs} +33 -20
  37. package/dist/{logs-B44a1UeU.mjs → logs-DcSRbC2t.mjs} +12 -11
  38. package/dist/{merge-state-DDxS-XIZ.mjs → merge-state-ytFQCeh4.mjs} +38 -8
  39. package/dist/{metro-BWLOJ_Wr.mjs → metro-BPeY1YMh.mjs} +5 -5
  40. package/dist/{named-ports-Dc7neAlc.mjs → named-ports-n7tnJsI8.mjs} +78 -6
  41. package/dist/native-runtime-CiiFHt0e.mjs +74 -0
  42. package/dist/{ownership-D2xbLVoz.mjs → ownership-Bz2kETAS.mjs} +2 -2
  43. package/dist/{ownership-BiojdtAp.mjs → ownership-PUP4Dwai.mjs} +175 -217
  44. package/dist/page-BTu7I60K.mjs +29 -0
  45. package/dist/{ports-DwBaRFJs.mjs → ports-C5UutqpJ.mjs} +5 -5
  46. package/dist/{project-BXZzOABt.mjs → project-DGeclhvO.mjs} +55 -87
  47. package/dist/{reload-By9Dwsrt.mjs → reload-C-cV5yy_.mjs} +80 -21
  48. package/dist/remote-cache--aehr4Pr.mjs +526 -0
  49. package/dist/{server-bare-D_RK1RCj.mjs → server-bare-Bq8BpSIo.mjs} +1 -1
  50. package/dist/server-expo-BeYwP_Xy.mjs +2 -0
  51. package/dist/{server-expo-o6H5gcBc.mjs → server-expo-DUCg52-K.mjs} +2 -2
  52. package/dist/{settings-C0ugALSC.mjs → settings-ssVBToDR.mjs} +29 -17
  53. package/dist/{settings-B5oFZEri.mjs → settings-xB0Frkg6.mjs} +13 -4
  54. package/dist/settings.schema.json +74 -2
  55. package/dist/{simslim-CIR3IYJO.mjs → simslim-Bbg9UWrt.mjs} +13 -6
  56. package/dist/{slot-launch-rggO1Esw.mjs → slot-launch-BIWEW-wI.mjs} +4 -4
  57. package/dist/{spawn-claims-BJwXTMPt.mjs → spawn-claims-PT8aQpCa.mjs} +1 -1
  58. package/dist/{start-BSsf2tUs.mjs → start-BZhItkiL.mjs} +110 -18
  59. package/dist/{start-i8zc9VmS.mjs → start-Rw2GD3nV.mjs} +1 -1
  60. package/dist/{state-WGdIbi_d.mjs → state-DwAU2_-D.mjs} +15 -3
  61. package/dist/state-l1pYwOre.mjs +148 -0
  62. package/dist/{stats-DBYJ5bxL.mjs → stats-CaSwmsSZ.mjs} +4 -4
  63. package/dist/{stats-BAgJaLA4.mjs → stats-D8rUTPHd.mjs} +1 -1
  64. package/dist/{status-CitcBRsC.mjs → status-TJlL0HWo.mjs} +649 -116
  65. package/dist/{status-Q-WDEGCB.mjs → status-sszP4XKU.mjs} +130 -28
  66. package/dist/stim-desktop-CXt8-Z3J.mjs +40 -0
  67. package/dist/{stop-DIhrvu0B.mjs → stop-BZ2qMiBP.mjs} +50 -18
  68. package/dist/{stop-rst5mL14.mjs → stop-DskDKNTU.mjs} +2 -2
  69. package/dist/supervisor-run.mjs +11 -11
  70. package/dist/web-run.d.mts +22 -0
  71. package/dist/web-run.mjs +481 -0
  72. package/dist/web-sWXd5iek.mjs +394 -0
  73. package/dist/{worktree-DhxDTK44.mjs → worktree-3cBa-bQt.mjs} +1 -1
  74. package/dist/{worktree-KOjMX3zA.mjs → worktree-D4Do_XiQ.mjs} +229 -21
  75. package/dist/{worktree-BlizKDpZ.mjs → worktree-DeBQSVtR.mjs} +3 -1
  76. package/dist/{xcode-B5SPD--o.mjs → xcode-LM6A8cNZ.mjs} +7 -7
  77. package/package.json +5 -5
  78. package/dist/budget-De3P2rq_.mjs +0 -620
  79. package/dist/native-run-D7yB_AsB.mjs +0 -143
  80. package/dist/server-expo-B-CCUJZj.mjs +0 -2
  81. package/dist/workspace-process-lock-Cx74RSDZ.mjs +0 -57
  82. package/dist/workspaces-COD2xCz-.mjs +0 -1013
package/README.md CHANGED
@@ -27,7 +27,7 @@ npx stim <command>
27
27
  ```bash
28
28
  stim doctor
29
29
  stim start
30
- stim ios # or: stim android
30
+ stim ios # or: stim android, or: stim web
31
31
  stim logs --errors
32
32
  stim stop
33
33
  ```
@@ -43,6 +43,8 @@ reference:
43
43
 
44
44
  - [Getting started](https://stim.appandflow.com/docs/getting-started): terms,
45
45
  the first run, parallel worktrees, and what to do when a run fails.
46
+ - [Web in an owned Chrome](https://stim.appandflow.com/docs/web): `stim web`
47
+ for Expo web and other web servers, page logs, and attaching browser tools.
46
48
  - [Worktrees](https://stim.appandflow.com/docs/worktrees): `worktree warm`,
47
49
  `--refresh`, `worktree remove`, and `gc --worktrees` to remove finished
48
50
  worktrees in bulk.
@@ -1,7 +1,7 @@
1
- import { D as process_identity_exports } from "./config-BEq0Qw_a.mjs";
1
+ import { O as process_identity_exports } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { j as workspaceLogsDir, m as readWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
4
- import { i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-D83nqeMX.mjs";
3
+ import { M as workspaceLogsDir, h as readWorkspaceState } from "./metro-BPeY1YMh.mjs";
4
+ import { i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-CL9dZf73.mjs";
5
5
  import { closeSync, fstatSync, openSync, readFileSync, readSync, readdirSync } from "node:fs";
6
6
  import { basename, join, resolve } from "node:path";
7
7
  import { homedir } from "node:os";
@@ -67,6 +67,7 @@ function parseAgentDeviceRecord(kind, path, raw) {
67
67
  kind,
68
68
  deviceId,
69
69
  session: kind === "claim" && typeof entry?.session === "string" && entry.session ? entry.session : null,
70
+ workspace: kind === "claim" && typeof entry?.workspace === "string" && entry.workspace ? entry.workspace : null,
70
71
  deviceName: kind === "claim" && typeof device?.name === "string" ? device.name : null,
71
72
  readable: Boolean(entry && deviceId),
72
73
  owner: entry ? field(entry, "ownerPid", "ownerStartTime") : null,
@@ -88,16 +89,20 @@ function agentDeviceLiveness(record, startOf) {
88
89
  if (!record.readable || results.includes("unknown")) return "unknown";
89
90
  return "live";
90
91
  }
92
+ const HOST_PROCESS_COLUMNS = "pid=,ppid=,rss=,%cpu=,lstart=,command=";
91
93
  function parseProcessTable(output) {
92
94
  const rows = [];
93
95
  for (const line of output.split("\n")) {
94
- const match = /^\s*(\d+)\s+(\w{3}\s+\w{3}\s+\d+\s+\d{1,2}:\d{2}:\d{2}\s+\d{4})\s+(.*)$/.exec(line);
96
+ const match = /^\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+(?:[.,]\d+)?)\s+(\w{3}\s+\w{3}\s+\d+\s+\d{1,2}:\d{2}:\d{2}\s+\d{4})\s+(.*)$/.exec(line);
95
97
  if (!match) continue;
96
- const at = Date.parse(match[2]);
98
+ const at = Date.parse(match[5]);
97
99
  rows.push({
98
100
  pid: Number(match[1]),
101
+ ppid: Number(match[2]),
102
+ rssKb: Number(match[3]),
103
+ cpuPercent: Number(match[4].replace(",", ".")),
99
104
  startedAt: Number.isFinite(at) ? new Date(at).toISOString() : null,
100
- command: match[3]
105
+ command: match[6]
101
106
  });
102
107
  }
103
108
  return rows;
@@ -203,11 +208,39 @@ function readAgentDeviceRecords(home) {
203
208
  });
204
209
  });
205
210
  }
206
- function createActivityReader({ now = Date.now(), home = homedir(), startOf = process_identity_exports.inspectProcessStart, leaseFiles = listLeaseFiles } = {}) {
211
+ function createDeviceProcessTables() {
207
212
  const exec = getExecutor();
213
+ let host;
214
+ const android = /* @__PURE__ */ new Map();
215
+ return {
216
+ host() {
217
+ if (host === void 0) {
218
+ const output = exec.runFileQuiet("ps", [
219
+ "-axww",
220
+ "-o",
221
+ HOST_PROCESS_COLUMNS
222
+ ], { timeoutMs: 5e3 });
223
+ host = output === null ? null : parseProcessTable(output);
224
+ }
225
+ return host;
226
+ },
227
+ android(serial) {
228
+ if (!android.has(serial)) android.set(serial, exec.runFileQuiet("adb", [
229
+ "-s",
230
+ serial,
231
+ "shell",
232
+ "ps",
233
+ "-A",
234
+ "-o",
235
+ "PID,ARGS"
236
+ ], { timeoutMs: 5e3 }));
237
+ return android.get(serial) ?? null;
238
+ }
239
+ };
240
+ }
241
+ function createActivityReader({ now = Date.now(), home = homedir(), startOf = process_identity_exports.inspectProcessStart, leaseFiles = listLeaseFiles, tables = createDeviceProcessTables() } = {}) {
208
242
  let agentDevice;
209
243
  let stimLeases;
210
- let processes;
211
244
  const logs = /* @__PURE__ */ new Map();
212
245
  const log = (path) => {
213
246
  if (!logs.has(path)) logs.set(path, tailLines(path));
@@ -250,14 +283,7 @@ function createActivityReader({ now = Date.now(), home = homedir(), startOf = pr
250
283
  since: entry.lease.grantedAt
251
284
  });
252
285
  }
253
- if (processes === void 0) {
254
- const output = exec.runFileQuiet("ps", [
255
- "-axww",
256
- "-o",
257
- "pid=,lstart=,command="
258
- ], { timeoutMs: 5e3 });
259
- processes = output === null ? null : parseProcessTable(output);
260
- }
286
+ const processes = tables.host();
261
287
  if (processes === null) evidence.unknown.push("driver-process");
262
288
  for (const row of processes ?? []) {
263
289
  const tool = driverTool(row.command, target.id);
@@ -269,15 +295,7 @@ function createActivityReader({ now = Date.now(), home = homedir(), startOf = pr
269
295
  });
270
296
  }
271
297
  if (target.platform === "android") {
272
- const output = exec.runFileQuiet("adb", [
273
- "-s",
274
- target.id,
275
- "shell",
276
- "ps",
277
- "-A",
278
- "-o",
279
- "PID,ARGS"
280
- ], { timeoutMs: 5e3 });
298
+ const output = tables.android(target.id);
281
299
  if (output === null) evidence.unknown.push("instrumentation");
282
300
  for (const { pid, tool } of parseAndroidInstrumentation(output ?? "")) evidence.drivers.push({
283
301
  basis: "instrumentation",
@@ -335,4 +353,4 @@ function workspaceActivity(workspace, now = Date.now()) {
335
353
  }, now);
336
354
  }
337
355
  //#endregion
338
- export { workspaceActivity as a, readAgentDeviceRecords as i, createActivityReader as n, idleForMs as r, agentDeviceLiveness as t };
356
+ export { readAgentDeviceRecords as a, idleForMs as i, createActivityReader as n, workspaceActivity as o, createDeviceProcessTables as r, agentDeviceLiveness as t };
@@ -1,5 +1,5 @@
1
1
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
- import { c as androidToolCwd } from "./android-C4zG2Tuc.mjs";
2
+ import { l as androidToolCwd } from "./android-qx_31wJo.mjs";
3
3
  //#region src/collector/android.ts
4
4
  const LEVEL_BY_LETTER = {
5
5
  V: "debug",
@@ -1,37 +1,37 @@
1
- import { L as deviceSlotFileKey, R as deviceSlotKey, S as setDevice, T as withConfigLock$1, V as parseDeviceSlotOption, W as validateDeviceSlot, f as getProject, g as loadConfig$1, k as ownership_claim_exports, l as getConcurrencyLimits, w as upsertProject, x as saveConfig, z as deviceSlotPlatforms } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, B as deviceSlotPlatforms, C as setDevice, E as withConfigLock$1, G as validateDeviceSlot, H as parseDeviceSlotOption, R as deviceSlotFileKey, S as saveConfig, T as upsertProject, _ as loadConfig$1, p as getProject, u as getConcurrencyLimits, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { r as createNdjsonWriter } from "./ndjson-CDY9IkVC.mjs";
4
- import { O as workspaceDir, b as emulatorLogFile, c as signalProcessTree, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, s as resolveProjectMetro, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
5
- import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
6
- import { a as detectIsExpo, i as detectBundleId, l as projectShortcut, n as appProjectProblem, o as findProjectRoot, r as detectAndroidPackage, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
7
- import { n as MODE_EXPO, p as writeWorkspaceLaunch, t as MODE_BARE } from "./state-WGdIbi_d.mjs";
4
+ import { M as workspaceLogsDir, a as pidExists, b as writeWorkspaceState, c as resolveProjectMetro, g as recordWorkspaceUse, h as readWorkspaceState$1, k as workspaceDir, l as signalProcessTree, x as emulatorLogFile } from "./metro-BPeY1YMh.mjs";
5
+ import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
6
+ import { a as findProjectRoot, l as projectShortcut, n as appProjectProblem, r as detectIsExpo, t as NO_PROJECT_REFUSAL } from "./project-DGeclhvO.mjs";
7
+ import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-DwAU2_-D.mjs";
8
8
  import { r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
9
- import { _ as stepTimer, c as launchErrorReport, f as refuseNoProject, g as stepClock, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-D5z2_bcF.mjs";
10
- import { A as resolveBuild, C as filesystemBuildCapability, D as providerDownloadPath, E as prepareProviderDownloadDir, F as untrackedNativeFiles, I as assetDiffReason, L as captureAssetManifest, M as storedAssetManifest, O as providerUploadOutcome, P as untrackedMissLine, R as compareAssetManifests, T as fingerprintProject, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as storeBuild, k as refingerprintAfterMutation, m as acquireBuildLock, v as waitForSharedBuild, w as fingerprintDiffRecord, z as readAssetManifest } from "./device-lease-D83nqeMX.mjs";
11
- import { A as memoizeEmulatorProbe, B as probeEmulatorSerial, C as hostSystemImageArch, D as listAvds, E as listAvdDeviceProfiles, H as resolveOwnedAvdSerial, L as ownedAvdSystemImage, N as ownedAvdDirectory, O as listInstalledSystemImages, Q as configuredAndroidEmulatorApp, R as physicalDeviceModel, T as listAdbDevices, U as resolvePhysicalDevice, V as resetAdoptedAvd, a as androidPoolCandidates, b as extractEmulatorFailure, c as androidToolCwd, i as androidHome, n as androidBuildToolName, o as androidPoolNoCandidatesRefusal, q as waitForBoot, r as androidDeviceAbi, s as androidSystemImageAbi, v as emulatorDiskSpaceRemedy, x as findBuildTool, y as emulatorFailureRemedy, z as pickDefaultSystemImage } from "./android-C4zG2Tuc.mjs";
12
- import { A as resolveCacheProviderConfig, E as publicUrlSetting, H as compilerCacheFallbackMessage, I as tunnelModeSetting, L as unknownSettingKeys, M as settingFile, O as remoteAndroidSetting, P as settingShapeErrors, S as metroWarmupUrlSetting, U as optimizationBuildProfile, V as artifactCachePolicy, W as resolveOptimizations, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, j as resolveSettings, r as REMOTE_DEVICE_BACKENDS, s as androidAvdConfigSettingError, u as androidDataPartitionSizeGbSettingError, z as detectProviders } from "./settings-B5oFZEri.mjs";
13
- import { y as parkedMaxSetting } from "./ownership-BiojdtAp.mjs";
14
- import { c as startBuildProgress, n as NO_BUILD_PROGRESS } from "./build-progress-CDwogz6R.mjs";
15
- import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-DVhlSoyn.mjs";
16
- import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-D2xbLVoz.mjs";
17
- import { t as cleanLine } from "./server-expo-o6H5gcBc.mjs";
18
- import { A as UPLOAD_TIMEOUT_MS, B as resolveRemote, F as isEasAuthFailureText, I as loadProjectProvider, M as checkEasAuth, N as easAuthNote, P as exitAfterFlush, V as uploadRemote, a as ensureMetroReachable, c as remoteAndroidDeps, j as cacheLevel, k as RESOLVE_TIMEOUT_MS, n as binOnPath, o as ensureRemoteBootOwned, u as resolveRemoteContext, w as ownedSessionName, z as resolveEasCliBin } from "./device-remote-BQZSnnmE.mjs";
19
- import { _ as launchAndroidReleaseApp, d as deviceShellArg, f as installAndroidApp, g as launchAndroidApp, o as androidAppProcess, p as installConflictKind, r as DEFAULT_METRO_PORT, s as androidDevClientUrl, t as ADB_INSTALL_TIMEOUT_MS } from "./app-install-DHut6JnV.mjs";
20
- import { a as VERIFY_TIMEOUT_MS, d as verifyLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unverifiedLaunchLines, n as LAUNCH_FATAL, r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING, u as verifyAndroidReleaseLaunch } from "./launch-verify-CuPDGXdr.mjs";
21
- import { f as isEasBuildFailure, m as resolveEasDevelopmentBuild, o as unknownAndroidDeviceProfileRefusal, p as planEasDevelopmentBuild, r as checkDeviceCapacity, s as unknownAndroidSystemImageRefusal } from "./simslim-CIR3IYJO.mjs";
22
- import { d as withNativeBuildRun, r as cancelledFailure, u as runCancellation } from "./native-run-D7yB_AsB.mjs";
23
- import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-DHj7cdPy.mjs";
24
- import { C as ensureDevServer, E as launchOutcomeRecord, O as warmMetro, T as isPhysicalDeviceRequest, _ as staleNativeDirRefusal, a as refusePlan, b as AvdBootError, c as skippedMissReason, f as detectEntryFile, g as runPrebuild, h as recordPrebuild, i as printPlan, l as devClientScheme, m as planPrebuild, n as planFlagRefusal, o as explainBuildMiss, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as pickDevClientScheme, v as ensureBooted, w as ensureWorkspaceStorageSafely, x as AvdRecoveryError, y as ensureOwnedDevice } from "./build-plan-CeAYgKAx.mjs";
25
- import { t as budgetGate } from "./budget-De3P2rq_.mjs";
26
- import { f as spawnEntry, s as startDevServer } from "./start-BSsf2tUs.mjs";
27
- import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-BAgJaLA4.mjs";
28
- import { a as buildAndroid, c as CCACHE_NOT_RUN, f as resolveCcache, l as CCACHE_UNAVAILABLE, n as resolveAndroidCas, o as productFlavorRefusal, p as formatDiagnostic, r as resolveAndroidCompilerCache, s as readProductFlavors, u as ccacheActivityLine } from "./android-cas-DfJkwCXW.mjs";
29
- import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-B5SPD--o.mjs";
30
- import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-rggO1Esw.mjs";
31
- import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-UYFSQwRy.mjs";
9
+ import { _ as stepTimer, c as launchErrorReport, f as refuseNoProject, g as stepClock, i as formatDuration, l as phaseLine, m as shortHash, n as appReadinessMessage, v as launchErrorPreview } from "./command-output-BIL7rlX7.mjs";
10
+ import { A as providerDownloadPath, B as captureAssetManifest, D as fingerprintProject, E as fingerprintDiffRecord, F as storedAssetManifest, H as readAssetManifest, L as untrackedMissLine, M as refingerprintAfterMutation, N as resolveBuild, O as inputsChangedDuringBuild, P as storeBuild, R as untrackedNativeFiles, S as configInputsChanged, T as filesystemBuildCapability, V as compareAssetManifests, _ as waitForBuild, b as buildCacheKey, g as releaseBuildLock, j as providerUploadOutcome, k as prepareProviderDownloadDir, m as acquireBuildLock, v as waitForSharedBuild, x as changedDuringBuildLine, z as assetDiffReason } from "./device-lease-CL9dZf73.mjs";
11
+ import { $ as waitForBoot, A as listInstalledSystemImages, C as extractEmulatorFailure, D as listAdbDevices, E as hostSystemImageArch, F as ownedAvdDirectory, G as profileNeedsFoldFeature, H as physicalDeviceModel, J as resolvePhysicalDevice, K as resetAdoptedAvd, M as memoizeEmulatorProbe, O as listAvdDeviceProfiles, P as ownedAvdDeviceProfile, S as emulatorFailureRemedy, U as pickDefaultSystemImage, W as probeEmulatorSerial, Z as systemImageSupportsFold, a as androidHome, c as androidSystemImageAbi, ct as parkedMaxSetting, ft as configuredAndroidEmulatorApp, i as androidDeviceAbi, k as listAvds, l as androidToolCwd, o as androidPoolCandidates, q as resolveOwnedAvdSerial, r as androidBuildToolName, s as androidPoolNoCandidatesRefusal, t as DEFAULT_AVD_DEVICE_PROFILE, w as findBuildTool, x as emulatorDiskSpaceRemedy, z as ownedAvdSystemImage } from "./android-qx_31wJo.mjs";
12
+ import { A as resolveCacheProviderConfig, B as detectProviders, E as publicUrlSetting, G as resolveOptimizations, H as artifactCachePolicy, I as tunnelModeSetting, L as unknownSettingKeys, M as settingFile, O as remoteAndroidSetting, P as settingShapeErrors, S as metroWarmupUrlSetting, U as compilerCacheFallbackMessage, W as optimizationBuildProfile, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, j as resolveSettings, r as REMOTE_DEVICE_BACKENDS, s as androidAvdConfigSettingError, u as androidDataPartitionSizeGbSettingError } from "./settings-xB0Frkg6.mjs";
13
+ import { c as recordFinishedBuild, l as startBuildProgress, n as NO_BUILD_PROGRESS } from "./build-progress-l7d-X-ZP.mjs";
14
+ import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-wYEaKQM9.mjs";
15
+ import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-Bz2kETAS.mjs";
16
+ import { t as cleanLine } from "./server-expo-DUCg52-K.mjs";
17
+ import { a as easAuthNote, c as loadProjectProvider, f as resolveEasCliBin, i as checkEasAuth, m as uploadRemote, n as UPLOAD_TIMEOUT_MS, o as exitAfterFlush, p as resolveRemote, r as cacheLevel, s as isEasAuthFailureText, t as RESOLVE_TIMEOUT_MS } from "./remote-cache--aehr4Pr.mjs";
18
+ import { F as ownedSessionName, S as withNativeBuildRun, a as ensureMetroReachable, c as remoteAndroidDeps, m as cancelledFailure, n as binOnPath, o as ensureRemoteBootOwned, u as resolveRemoteContext, x as runCancellation } from "./device-remote-DT9ngZiD.mjs";
19
+ import { _ as launchAndroidReleaseApp, d as deviceShellArg, f as installAndroidApp, g as launchAndroidApp, o as androidAppProcess, p as installConflictKind, r as DEFAULT_METRO_PORT, s as androidDevClientUrl, t as ADB_INSTALL_TIMEOUT_MS } from "./app-install-CDFY2nUL.mjs";
20
+ import { a as VERIFY_TIMEOUT_MS, d as verifyLaunch, i as RELEASE_VERIFY_WAIT_MS, l as unverifiedLaunchLines, n as LAUNCH_FATAL, r as LAUNCH_UNVERIFIED, t as LAUNCH_BUNDLING, u as verifyAndroidReleaseLaunch } from "./launch-verify-CuJaBpEa.mjs";
21
+ import { c as unknownAndroidSystemImageRefusal, h as resolveEasDevelopmentBuild, m as planEasDevelopmentBuild, p as isEasBuildFailure, r as checkDeviceCapacity, s as unknownAndroidDeviceProfileRefusal } from "./simslim-Bbg9UWrt.mjs";
22
+ import { f as spawnEntry, m as detectAppIds, p as detectAndroidPackage, s as startDevServer } from "./start-BZhItkiL.mjs";
23
+ import { a as lostLine, c as releaseLeaseOnSignal, i as leaseExpiryText, l as runLease, n as DEBUG_VERIFY_STEP_MS, o as lostRefusal, r as acquireRunLease, s as parseDeviceWait, t as selectFromPool, u as waitFlagConflict } from "./device-pool-MuoiyRcu.mjs";
24
+ import { C as warmMetro, _ as staleNativeDirRefusal, a as refusePlan, b as AvdBootError, c as skippedMissReason, f as detectEntryFile, g as runPrebuild, h as recordPrebuild, i as printPlan, l as devClientScheme, m as planPrebuild, n as planFlagRefusal, o as explainBuildMiss, r as planPayload, s as fingerprintErrorMissReason, t as planCachedBuild, u as pickDevClientScheme, v as ensureBooted, x as AvdRecoveryError, y as ensureOwnedDevice } from "./build-plan-BTa93o_r.mjs";
25
+ import { t as budgetGate } from "./budget-E5o91NR1.mjs";
26
+ import { i as launchOutcomeRecord, n as ensureWorkspaceStorageSafely, r as isPhysicalDeviceRequest, t as ensureDevServer } from "./native-runtime-CiiFHt0e.mjs";
27
+ import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-D8rUTPHd.mjs";
28
+ import { c as readProductFlavors, d as ccacheActivityLine, l as CCACHE_NOT_RUN, m as formatDiagnostic, n as resolveAndroidCas, o as buildAndroid, p as resolveCcache, r as resolveAndroidCompilerCache, s as productFlavorRefusal, u as CCACHE_UNAVAILABLE } from "./android-cas-B9Kv9aIy.mjs";
29
+ import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-LM6A8cNZ.mjs";
30
+ import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-BIWEW-wI.mjs";
31
+ import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-BoiOhck8.mjs";
32
32
  import { constants, copyFileSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync } from "node:fs";
33
33
  import { InvalidArgumentError } from "commander";
34
- import { LAST_BUILD_KEYS } from "@stim-cli/core/state";
34
+ import { buildDiagnostics } from "@stim-cli/core/state";
35
35
  import { basename, dirname, isAbsolute, join, relative } from "node:path";
36
36
  import chalk from "chalk";
37
37
  import { createWarnOnce, loadCacheProvider, resolveTieredBuild, storeTieredBuild } from "@stim-cli/cache";
@@ -467,6 +467,21 @@ function deviceProfileRefusal({ flag, resolved, physical, remoteBackend, listPro
467
467
  remedy: refusal.remedy
468
468
  } : null;
469
469
  }
470
+ function foldableImageRefusal({ profile, image, avdName, images, supportsFold }) {
471
+ if (!profileNeedsFoldFeature(profile) || !image || supportsFold(image)) return null;
472
+ const compatible = pickDefaultSystemImage(images().filter((candidate) => supportsFold(candidate.pkg)))?.pkg;
473
+ const message = `${avdName ? `This workspace's emulator ${avdName} uses device profile ${profile} on ${image}` : `Device profile ${profile} with system image ${image}`}, which the emulator refuses to boot: ${profile} needs a system image with foldable support (SupportPixelFold in its advancedFeatures.ini).`;
474
+ if (!compatible) return {
475
+ code: "STIM_BAD_ARG",
476
+ message,
477
+ remedy: `Install an image with foldable support, e.g. \`sdkmanager "system-images;android-36;google_apis;${hostSystemImageArch()}"\`, then pass it with \`--system-image\`, or pick another \`--device-profile\`.`
478
+ };
479
+ return {
480
+ code: "STIM_BAD_ARG",
481
+ message,
482
+ remedy: avdName ? `Pass \`--system-image "${compatible}"\`: it replaces ${avdName} if that emulator never finished a boot. Otherwise add \`--slot <name>\` to create the foldable beside it.` : `Pass \`--system-image "${compatible}"\` (or set android.systemImage to it), or pick another \`--device-profile\`.`
483
+ };
484
+ }
470
485
  function isReleaseVariant(variant) {
471
486
  return typeof variant === "string" && /release$/i.test(variant.trim());
472
487
  }
@@ -969,17 +984,19 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
969
984
  phase("build", chalk.yellow(`could not take a build slot: ${err?.message || err}; building anyway`));
970
985
  }
971
986
  const rekeyedBy = [];
987
+ let editedConfig = [];
972
988
  const prebuildPlan = planPrebuildFor(root, PLATFORM, {
973
989
  isExpo,
974
990
  fingerprint: hash,
975
991
  sources: fingerprintSources
976
992
  });
993
+ const prebuildRan = prebuildPlan === "generate" || prebuildPlan === "regenerate";
977
994
  if (prebuildPlan === "refuse") {
978
995
  const refusal = staleNativeDirRefusal(PLATFORM);
979
996
  phaseFailure = fail$1(refusal.code, refusal.message, refusal.remedy, { lastBuildStatus: true });
980
997
  return false;
981
998
  }
982
- if (prebuildPlan === "generate" || prebuildPlan === "regenerate") {
999
+ if (prebuildRan) {
983
1000
  step("prebuild");
984
1001
  recordPrebuild(root, PLATFORM, null);
985
1002
  const pre = await prebuild(root, PLATFORM, writer, {
@@ -1003,8 +1020,9 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
1003
1020
  previousHash: hash,
1004
1021
  fingerprint
1005
1022
  });
1006
- if (after) recordPrebuild(root, PLATFORM, after.hash);
1007
- if (after?.moved) {
1023
+ editedConfig = after ? configInputsChanged(fingerprintSources, after.sources, { prebuildRan }) : [];
1024
+ if (after && !editedConfig.length) recordPrebuild(root, PLATFORM, after.hash);
1025
+ if (after?.moved && !editedConfig.length) {
1008
1026
  rekeyedBy.push("prebuild");
1009
1027
  storeHash = after.hash;
1010
1028
  storeSources = after.sources;
@@ -1063,6 +1081,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
1063
1081
  phaseFailure = fail$1(built.code, built.reason, diagnostics.find((d) => d.remedy)?.remedy || built.remedy || null, {
1064
1082
  lastBuildStatus: true,
1065
1083
  diagnostics: extracted,
1084
+ buildDiagnostics: diagnostics,
1066
1085
  lines: extracted.length ? [] : tail(built.lastLines),
1067
1086
  logPath: displayPath(root, buildLog)
1068
1087
  });
@@ -1073,16 +1092,23 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
1073
1092
  phase("build", `ok (${formatDuration(built.durationMs)})`);
1074
1093
  if (built.apkNote) phase("build", chalk.yellow(built.apkNote));
1075
1094
  const beforeBuildHash = storeHash;
1076
- const afterBuild = await refingerprintAfterMutation({
1095
+ const afterBuild = editedConfig.length ? null : await refingerprintAfterMutation({
1077
1096
  projectRoot: root,
1078
1097
  platform: PLATFORM,
1079
1098
  previousHash: beforeBuildHash,
1080
1099
  fingerprint
1081
1100
  });
1082
- if (!afterBuild) {
1101
+ const changedDuringBuild = afterBuild ? inputsChangedDuringBuild({
1102
+ platform: PLATFORM,
1103
+ lookup: fingerprintSources,
1104
+ prebuildRan,
1105
+ compiled: storeSources,
1106
+ current: afterBuild.sources
1107
+ }) : editedConfig;
1108
+ if (!afterBuild || changedDuringBuild.length) {
1083
1109
  record.fingerprint = null;
1084
1110
  record.cacheKey = null;
1085
- phase("fingerprint", chalk.yellow("unavailable after Gradle; the build will be installed but not cached"));
1111
+ phase("fingerprint", chalk.yellow(changedDuringBuild.length ? changedDuringBuildLine(changedDuringBuild) : "unavailable after Gradle; the build will be installed but not cached"));
1086
1112
  } else {
1087
1113
  if (afterBuild.moved) {
1088
1114
  storeHash = afterBuild.hash;
@@ -1193,7 +1219,7 @@ function androidFacts({ slot, serial, avdName = null, deviceName = null, systemI
1193
1219
  ...devServer ? { devServer } : {}
1194
1220
  };
1195
1221
  }
1196
- function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null }) {
1222
+ function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false, durationMs, appPath, bundleId, startedAt, status, errorCode = null, avdName = null, deviceName = null, missReason = null, diagnostics = null, configuration = null }) {
1197
1223
  const record = {
1198
1224
  platform: PLATFORM,
1199
1225
  avdName: avdName ?? null,
@@ -1206,10 +1232,13 @@ function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false
1206
1232
  appPath: appPath ?? null,
1207
1233
  bundleId: bundleId ?? null,
1208
1234
  startedAt,
1209
- status
1235
+ status,
1236
+ configuration: configuration ?? null
1210
1237
  };
1211
1238
  if (errorCode) record.errorCode = errorCode;
1212
1239
  if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
1240
+ const recorded = status === "failed" ? buildDiagnostics(diagnostics) : [];
1241
+ if (recorded.length) record.diagnostics = recorded;
1213
1242
  return record;
1214
1243
  }
1215
1244
  async function finishAndroidUpload(uploadPending, remote, phase) {
@@ -1291,19 +1320,17 @@ function cacheOutcome(cacheHit, providerName = null) {
1291
1320
  if (cacheHit === "local") return "cache hit";
1292
1321
  return "built";
1293
1322
  }
1294
- function persistLastBuild({ writeState, root, record, startedAt, durationMs, status, errorCode = null, out }) {
1323
+ function persistLastBuild({ recordBuild = recordFinishedBuild, root, record, startedAt, durationMs, status, errorCode = null, diagnostics = null, out }) {
1295
1324
  const lastBuild = lastBuildRecord({
1296
1325
  ...record,
1297
1326
  startedAt,
1298
1327
  durationMs,
1299
1328
  status,
1300
- errorCode
1329
+ errorCode,
1330
+ diagnostics
1301
1331
  });
1302
1332
  try {
1303
- writeState(root, {
1304
- lastBuild,
1305
- [LAST_BUILD_KEYS[PLATFORM]]: lastBuild
1306
- });
1333
+ recordBuild(root, lastBuild);
1307
1334
  } catch (err) {
1308
1335
  out(phaseLine("state", chalk.yellow(`could not record lastBuild: ${err?.message || err}`)));
1309
1336
  }
@@ -1532,7 +1559,7 @@ async function resolveInstallSerial({ root, slot, device, physical, remoteDevice
1532
1559
  });
1533
1560
  return resolved.serial;
1534
1561
  }
1535
- async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCheck, useBuildCache, variant, release, isExpo, metroPort, logsDir, emuLog, device, physical, remoteDevice, bootPromise, resolveAvdSerial, waitForDeviceBoot, bootDuration, apkPath, androidPackage: initialPackage, swapDir, record, waitedForBuild, ccache, uploadPending, providerUpload, providerName, remote, abandonedRemote: remoteWasAbandoned, started, startedAt, writer, phase, fail, readApkPackage, install, launch, launchRelease, resolveDevClientScheme, verifyLaunched, verifyReleaseLaunched, spawn, kill, pidAlive, verifyCollector, writeLaunch, writeState, now, out, emit, recordRun, reclaimed, devServer, enterPhase }) {
1562
+ async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCheck, useBuildCache, variant, release, isExpo, metroPort, logsDir, emuLog, device, physical, remoteDevice, bootPromise, resolveAvdSerial, waitForDeviceBoot, bootDuration, apkPath, androidPackage: initialPackage, swapDir, record, waitedForBuild, ccache, uploadPending, providerUpload, providerName, remote, abandonedRemote: remoteWasAbandoned, started, startedAt, writer, phase, fail, readApkPackage, install, launch, launchRelease, resolveDevClientScheme, verifyLaunched, verifyReleaseLaunched, spawn, kill, pidAlive, verifyCollector, writeLaunch, recordBuild, now, out, emit, recordRun, reclaimed, devServer, enterPhase }) {
1536
1563
  let androidPackage = initialPackage;
1537
1564
  let leaseWarned = false;
1538
1565
  const raiseLeaseFor = (boundMs, beforeInstall) => {
@@ -1722,7 +1749,7 @@ async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCh
1722
1749
  const providerOutcome = providerUploadOutcome(providerUpload ? await providerUpload : null, providerName);
1723
1750
  if (providerOutcome) phase("cache", providerOutcome.warn ? chalk.yellow(providerOutcome.line) : providerOutcome.line);
1724
1751
  persistLastBuild({
1725
- writeState,
1752
+ recordBuild,
1726
1753
  root,
1727
1754
  record,
1728
1755
  startedAt,
@@ -1868,6 +1895,16 @@ function diagnoseBootFailure(booted, logFile, runCommand, physical) {
1868
1895
  }
1869
1896
  //#endregion
1870
1897
  //#region src/commands/android/plan.ts
1898
+ function slotOwnedAvd(projectPath, slot) {
1899
+ const android = deviceSlotPlatforms(getProject(projectPath), slot)?.android;
1900
+ if (!android?.owned || !android.avdName || android.setupIncomplete) return null;
1901
+ const systemImage = ownedAvdSystemImage(android.avdName);
1902
+ return systemImage ? {
1903
+ avdName: android.avdName,
1904
+ systemImage,
1905
+ deviceProfile: ownedAvdDeviceProfile(android.avdName)
1906
+ } : null;
1907
+ }
1871
1908
  function fail(code, message, remedy, { lines = [] } = {}) {
1872
1909
  return {
1873
1910
  ok: false,
@@ -1901,7 +1938,7 @@ function androidCompilerCache({ root, optimizations, settingsContext }) {
1901
1938
  })}`
1902
1939
  };
1903
1940
  }
1904
- function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, variant: variantFlag, systemImage: systemImageFlag, deviceProfile: deviceProfileFlag, device: deviceFlag, wait: waitFlag, waitConflict, remote: commandRemoteBackend, buildCache: requestedBuildCache }, { warn, resolveCompilerCache = androidCompilerCache, resolveCacheProvider = resolveCacheProviderConfig, validateAvdConfig = androidAvdConfigSettingError, readFlavors = readProductFlavors, detectExpo = detectIsExpo, listSystemImages = listInstalledSystemImages, listDeviceProfiles = listAvdDeviceProfiles, parkedLimit = parkedMaxSetting }) {
1941
+ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, variant: variantFlag, systemImage: systemImageFlag, deviceProfile: deviceProfileFlag, device: deviceFlag, wait: waitFlag, waitConflict, remote: commandRemoteBackend, buildCache: requestedBuildCache }, { warn, resolveCompilerCache = androidCompilerCache, resolveCacheProvider = resolveCacheProviderConfig, validateAvdConfig = androidAvdConfigSettingError, readFlavors = readProductFlavors, detectExpo = detectIsExpo, listSystemImages = listInstalledSystemImages, listDeviceProfiles = listAvdDeviceProfiles, parkedLimit = parkedMaxSetting, supportsFold = systemImageSupportsFold, ownedAvd = slotOwnedAvd }) {
1905
1942
  const root = settingsContext.projectPath;
1906
1943
  const [shapeError, ...moreShapeErrors] = [parkedLimit("android").error, ...settingShapeErrors(settings)].filter((error) => Boolean(error));
1907
1944
  if (shapeError) return fail("STIM_BAD_ARG", shapeError, SETTING_SHAPE_REMEDY, { lines: moreShapeErrors });
@@ -1967,6 +2004,21 @@ function resolveAndroidRunPlan({ settings, settingsContext, slot, easProfile, va
1967
2004
  listProfiles: listDeviceProfiles
1968
2005
  });
1969
2006
  if (profileRefusal) return fail(profileRefusal.code, profileRefusal.message, profileRefusal.remedy);
2007
+ if (!physical && !remoteBackend) {
2008
+ const flagImage = typeof systemImageFlag === "string" && systemImageFlag.trim() ? systemImageFlag.trim() : null;
2009
+ const existing = ownedAvd(root, slot);
2010
+ const profile = deviceProfile ?? existing?.deviceProfile ?? DEFAULT_AVD_DEVICE_PROFILE;
2011
+ const image = () => flagImage ?? existing?.systemImage ?? systemImage ?? pickDefaultSystemImage(listSystemImages())?.pkg ?? null;
2012
+ const checked = profileNeedsFoldFeature(profile) ? image() : null;
2013
+ const foldRefusal = checked !== null && foldableImageRefusal({
2014
+ profile,
2015
+ image: checked,
2016
+ avdName: existing && existing.systemImage === checked && existing.deviceProfile === profile ? existing.avdName : null,
2017
+ images: listSystemImages,
2018
+ supportsFold
2019
+ });
2020
+ if (foldRefusal) return fail(foldRefusal.code, foldRefusal.message, foldRefusal.remedy);
2021
+ }
1970
2022
  const target = physical ? {
1971
2023
  kind: "physical",
1972
2024
  serial: typeof deviceFlag === "string" ? deviceFlag : null,
@@ -2244,7 +2296,7 @@ function registerAndroid(program) {
2244
2296
  }, { write: (line) => console.error(chalk.dim(phaseLine("lock", line))) })).ok) process.exit(runCancellation() ? 130 : 1);
2245
2297
  });
2246
2298
  }
2247
- function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRemoteBackend = null, resolveSettingsFor = resolveSettings, resolveRemoteDeviceContext = resolveRemoteContext, remoteDeviceDeps: makeRemoteDeviceDeps = remoteAndroidDeps, resolveEasBin = resolveEasCliBin, ensureMetroReachable: ensureRemoteMetro = ensureMetroReachable, ensureRemoteBootOwned: ensureRemoteOwned = ensureRemoteBootOwned, detectRemoteProviders = detectProviders, metroCheck = true, useBuildCache = true, easProfile, resolveEasDevelopmentBuild: resolveEasBuild = resolveEasDevelopmentBuild, variant: variantFlag = null, systemImage: systemImageFlag = null, deviceProfile: deviceProfileFlag, device: deviceFlag = null, wait: waitFlag = void 0, waitConflict = false, acquireLease = acquireRunLease, makeRunLease = runLease, selectPool = selectFromPool, onLeaseSignal = releaseLeaseOnSignal, listDevices = listAdbDevices, deviceModel = physicalDeviceModel, deviceAbi = androidDeviceAbi, isEmulatorDevice = probeEmulatorSerial, readApkPackage = (apkPath) => apkPackage(dumpApkManifest(apkPath)), getLimits = getConcurrencyLimits, checkCapacity = checkDeviceCapacity, acquireSlot = acquireBuildSlot, releaseSlot = releaseBuildSlot, ensureDevice = ensureOwnedDevice, listSystemImages = listInstalledSystemImages, listDeviceProfiles, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, startServer = startDevServer, readState = readWorkspaceState$1, pidAlive = pidExists, verifyCollector = verifyCollectorOwnership, verifyLaunched = verifyLaunch, ensureStorage = ensureWorkspaceStorageSafely, fingerprint = fingerprintProject, untracked = untrackedNativeFiles, resolveCached = resolveBuild, storeCached = storeBuild, storedAssets = storedAssetManifest, captureAssets = captureAssetManifest, acquireLock = acquireBuildLock, releaseLock = releaseBuildLock, waitForBuild: waitForBuild$1 = waitForBuild, loadProvider = loadProjectProvider, easAuth = checkEasAuth, resolveRemoteBuild = resolveRemote, uploadRemoteBuild = uploadRemote, resolveCacheProvider = resolveCacheProviderConfig, loadCacheProviderModule = loadCacheProvider, planPrebuildFor = planPrebuild, prebuild = runPrebuild, build = buildAndroid, ccacheFor = resolveCcache, install = installAndroidApp, launch = launchAndroidApp, launchRelease = launchAndroidReleaseApp, verifyReleaseLaunched = verifyAndroidReleaseLaunch, swapApk = swapApkBundle, resolveDevClientScheme = androidDevClientScheme, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), createWriter = createNdjsonWriter, writeLaunch = writeWorkspaceLaunch, writeState = writeWorkspaceState, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
2299
+ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRemoteBackend = null, resolveSettingsFor = resolveSettings, resolveRemoteDeviceContext = resolveRemoteContext, remoteDeviceDeps: makeRemoteDeviceDeps = remoteAndroidDeps, resolveEasBin = resolveEasCliBin, ensureMetroReachable: ensureRemoteMetro = ensureMetroReachable, ensureRemoteBootOwned: ensureRemoteOwned = ensureRemoteBootOwned, detectRemoteProviders = detectProviders, metroCheck = true, useBuildCache = true, easProfile, resolveEasDevelopmentBuild: resolveEasBuild = resolveEasDevelopmentBuild, variant: variantFlag = null, systemImage: systemImageFlag = null, deviceProfile: deviceProfileFlag, device: deviceFlag = null, wait: waitFlag = void 0, waitConflict = false, acquireLease = acquireRunLease, makeRunLease = runLease, selectPool = selectFromPool, onLeaseSignal = releaseLeaseOnSignal, listDevices = listAdbDevices, deviceModel = physicalDeviceModel, deviceAbi = androidDeviceAbi, isEmulatorDevice = probeEmulatorSerial, readApkPackage = (apkPath) => apkPackage(dumpApkManifest(apkPath)), getLimits = getConcurrencyLimits, checkCapacity = checkDeviceCapacity, acquireSlot = acquireBuildSlot, releaseSlot = releaseBuildSlot, ensureDevice = ensureOwnedDevice, listSystemImages = listInstalledSystemImages, listDeviceProfiles, ensureDeviceBooted = ensureBooted, resolveAvdSerial = resolveOwnedAvdSerial, waitForDeviceBoot = waitForBoot, resolveMetro = resolveProjectMetro, warmMetro: prewarmMetro = warmMetro, startServer = startDevServer, readState = readWorkspaceState$1, pidAlive = pidExists, verifyCollector = verifyCollectorOwnership, verifyLaunched = verifyLaunch, ensureStorage = ensureWorkspaceStorageSafely, fingerprint = fingerprintProject, untracked = untrackedNativeFiles, resolveCached = resolveBuild, storeCached = storeBuild, storedAssets = storedAssetManifest, captureAssets = captureAssetManifest, acquireLock = acquireBuildLock, releaseLock = releaseBuildLock, waitForBuild: waitForBuild$1 = waitForBuild, loadProvider = loadProjectProvider, easAuth = checkEasAuth, resolveRemoteBuild = resolveRemote, uploadRemoteBuild = uploadRemote, resolveCacheProvider = resolveCacheProviderConfig, loadCacheProviderModule = loadCacheProvider, planPrebuildFor = planPrebuild, prebuild = runPrebuild, build = buildAndroid, ccacheFor = resolveCcache, install = installAndroidApp, launch = launchAndroidApp, launchRelease = launchAndroidReleaseApp, verifyReleaseLaunched = verifyAndroidReleaseLaunch, swapApk = swapApkBundle, resolveDevClientScheme = androidDevClientScheme, spawn = (cmd, args, opts) => getExecutor().spawn(cmd, args, opts), kill = (pid, signal) => process.kill(pid, signal), createWriter = createNdjsonWriter, writeLaunch = writeWorkspaceLaunch, writeState = writeWorkspaceState, recordBuild, recordStats = recordRunStats, readEstimates = readRunEstimates, now = Date.now, out = (line) => console.error(line), emit = (line) => console.log(line) } = {}) {
2248
2300
  return {
2249
2301
  root,
2250
2302
  json,
@@ -2323,6 +2375,7 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
2323
2375
  createWriter,
2324
2376
  writeLaunch,
2325
2377
  writeState,
2378
+ recordBuild,
2326
2379
  recordStats,
2327
2380
  readEstimates,
2328
2381
  now,
@@ -2383,7 +2436,7 @@ function avdSetupFailure(error, root, logFile) {
2383
2436
  };
2384
2437
  }
2385
2438
  async function runAndroid(options = {}) {
2386
- let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceProfileFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, listDeviceProfiles, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, resolveMetro, prewarmMetro, startServer, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, planPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordStats, readEstimates, now, out, emit } = androidSlotOptions(options);
2439
+ let { root, json, commandRemoteBackend, resolveSettingsFor, resolveRemoteDeviceContext, makeRemoteDeviceDeps, resolveEasBin, ensureRemoteMetro, ensureRemoteOwned, detectRemoteProviders, metroCheck, useBuildCache: requestedBuildCache, easProfile, resolveEasBuild, variantFlag, systemImageFlag, deviceProfileFlag, deviceFlag, waitFlag, waitConflict, acquireLease, makeRunLease, selectPool, onLeaseSignal, listDevices, deviceModel, deviceAbi, isEmulatorDevice, readApkPackage, getLimits, checkCapacity, acquireSlot, releaseSlot, ensureDevice, listSystemImages, listDeviceProfiles, ensureDeviceBooted, resolveAvdSerial, waitForDeviceBoot, resolveMetro, prewarmMetro, startServer, readState, pidAlive, verifyCollector, verifyLaunched, ensureStorage, fingerprint, untracked, resolveCached, storeCached, storedAssets, captureAssets, acquireLock, releaseLock, waitForBuild, loadProvider, easAuth, resolveRemoteBuild, uploadRemoteBuild, resolveCacheProvider, loadCacheProviderModule, planPrebuildFor, prebuild, build, ccacheFor, install, launch, launchRelease, verifyReleaseLaunched, swapApk, resolveDevClientScheme, spawn, kill, createWriter, writeLaunch, writeState, recordBuild, recordStats, readEstimates, now, out, emit } = androidSlotOptions(options);
2387
2440
  const progress = options.progress ?? NO_BUILD_PROGRESS;
2388
2441
  const slot = validateDeviceSlot(options.slot);
2389
2442
  const started = now();
@@ -2455,20 +2508,21 @@ async function runAndroid(options = {}) {
2455
2508
  const recordRun = stats.record;
2456
2509
  let ccacheActivity = CCACHE_NOT_RUN;
2457
2510
  let reclaimed = [];
2458
- const fail = (code, message, remedy, { lastBuildStatus = false, diagnostics = [], lines = [], logPath = null, lease } = {}) => {
2511
+ const fail = (code, message, remedy, { lastBuildStatus = false, diagnostics = [], buildDiagnostics: rawDiagnostics = [], lines = [], logPath = null, lease } = {}) => {
2459
2512
  const cancellation = cancelledFailure(PLATFORM, {
2460
2513
  code,
2461
2514
  message
2462
2515
  });
2463
2516
  if (cancellation) ({code, message, remedy, lines} = cancellation);
2464
2517
  if (lastBuildStatus) persistLastBuild({
2465
- writeState,
2518
+ recordBuild,
2466
2519
  root,
2467
2520
  record,
2468
2521
  startedAt,
2469
2522
  durationMs: now() - started,
2470
2523
  status: "failed",
2471
2524
  errorCode: code,
2525
+ diagnostics: rawDiagnostics,
2472
2526
  out
2473
2527
  });
2474
2528
  out(phaseLine("error", chalk.red(`${code}: ${message}`)));
@@ -2540,6 +2594,7 @@ async function runAndroid(options = {}) {
2540
2594
  const { plan } = planned;
2541
2595
  const { build: buildPlan, target, isExpo, cacheProviderConfig } = plan;
2542
2596
  const { variant, release, cache: cachePolicy } = buildPlan;
2597
+ record.configuration = variant ?? "debug";
2543
2598
  const useBuildCache = cachePolicy.read;
2544
2599
  const physical = target.kind === "physical";
2545
2600
  const remoteBackend = target.kind === "remote" ? target.backend : null;
@@ -2567,10 +2622,11 @@ async function runAndroid(options = {}) {
2567
2622
  buildCache: requestedBuildCache
2568
2623
  });
2569
2624
  if (isEasBuildFailure(easBuild)) return fail(easBuild.code, easBuild.message, easBuild.remedy);
2570
- let androidPackage = detectAndroidPackage(root);
2625
+ const appIds = detectAppIds(root);
2626
+ let androidPackage = appIds.androidPackage;
2571
2627
  record.bundleId = androidPackage;
2572
2628
  const registerProject = () => upsertProject(root, {
2573
- bundleId: detectBundleId(root) ?? void 0,
2629
+ bundleId: appIds.bundleId ?? void 0,
2574
2630
  androidPackage: androidPackage ?? void 0,
2575
2631
  isExpo
2576
2632
  });
@@ -2686,6 +2742,7 @@ async function runAndroid(options = {}) {
2686
2742
  settings,
2687
2743
  flags: {
2688
2744
  systemImage: target.systemImage,
2745
+ systemImageFlag: systemImageFlag?.trim() || null,
2689
2746
  deviceProfile: target.deviceProfile
2690
2747
  },
2691
2748
  note: out,
@@ -2721,7 +2778,8 @@ async function runAndroid(options = {}) {
2721
2778
  abandonCreatedSession: remoteDevice.abandonCreatedSession,
2722
2779
  webPreviewUrl: remoteDevice.webPreviewUrl,
2723
2780
  writeState,
2724
- register: registerProject
2781
+ register: registerProject,
2782
+ notice: (line) => out(chalk.dim(phaseLine("lock", line)))
2725
2783
  }) : boot()).then((result) => {
2726
2784
  bootDuration = bootTimer();
2727
2785
  return result;
@@ -2910,7 +2968,7 @@ async function runAndroid(options = {}) {
2910
2968
  pidAlive,
2911
2969
  verifyCollector,
2912
2970
  writeLaunch,
2913
- writeState,
2971
+ recordBuild,
2914
2972
  now,
2915
2973
  out,
2916
2974
  emit,
@@ -1,12 +1,12 @@
1
- import { u as getConfigDir } from "./config-BEq0Qw_a.mjs";
1
+ import { d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
- import { r as register } from "./cache-manifest-Pubfp8wV.mjs";
4
- import { C as sharedCcache, P as withDirLock, j as workspaceLogsDir, x as ensureWorkspaceStorage } from "./metro-BWLOJ_Wr.mjs";
5
- import { a as spawnDeclared } from "./spawn-claims-BJwXTMPt.mjs";
3
+ import { r as register } from "./cache-manifest-DWPF4RKJ.mjs";
4
+ import { F as withDirLock, M as workspaceLogsDir, S as ensureWorkspaceStorage, w as sharedCcache } from "./metro-BPeY1YMh.mjs";
5
+ import { a as spawnDeclared } from "./spawn-claims-PT8aQpCa.mjs";
6
6
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
7
- import { l as phaseLine } from "./command-output-D5z2_bcF.mjs";
8
- import { i as androidHome } from "./android-C4zG2Tuc.mjs";
9
- import { d as startBuildHeartbeat, n as HEARTBEAT_INTERVAL_MS } from "./xcode-B5SPD--o.mjs";
7
+ import { l as phaseLine } from "./command-output-BIL7rlX7.mjs";
8
+ import { a as androidHome } from "./android-qx_31wJo.mjs";
9
+ import { d as startBuildHeartbeat, n as HEARTBEAT_INTERVAL_MS } from "./xcode-LM6A8cNZ.mjs";
10
10
  import { accessSync, constants, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
11
11
  import { isJsonObject, readJsonFile } from "@stim-cli/core/state";
12
12
  import { dirname, isAbsolute, join, relative, sep } from "node:path";
@@ -749,10 +749,11 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
749
749
  lastLines: [],
750
750
  durationMs: 0
751
751
  };
752
- const sdk = androidHome();
752
+ const sdk = androidHome(env);
753
+ const sdkExists = existsSync(sdk);
753
754
  const refusal = androidSdkRefusal({
754
755
  sdkPath: sdk,
755
- sdkExists: existsSync(sdk),
756
+ sdkExists,
756
757
  hasLocalProperties: existsSync(join(project.androidDir, "local.properties"))
757
758
  });
758
759
  if (refusal) return {
@@ -844,6 +845,7 @@ async function buildAndroid({ root, logWriter, variant = null, abi = null }, { s
844
845
  ],
845
846
  env: {
846
847
  ...env,
848
+ ...sdkExists && !env.ANDROID_HOME && !env.ANDROID_SDK_ROOT ? { ANDROID_HOME: sdk } : {},
847
849
  ...ccache?.env,
848
850
  ...cas?.env,
849
851
  ...nativeEnv,
@@ -1122,4 +1124,4 @@ function resolveAndroidCas(root, env = process.env) {
1122
1124
  };
1123
1125
  }
1124
1126
  //#endregion
1125
- export { buildAndroid as a, CCACHE_NOT_RUN as c, projectCmakeLauncher as d, resolveCcache as f, androidPathRoomRemedy as g, androidPathRoomMessage as h, apkOutputsDir as i, CCACHE_UNAVAILABLE as l, androidPathRoom as m, resolveAndroidCas as n, productFlavorRefusal as o, formatDiagnostic as p, resolveAndroidCompilerCache as r, readProductFlavors as s, readAndroidCasToolchain as t, ccacheActivityLine as u };
1127
+ export { androidPathRoomRemedy as _, apkOutputsDir as a, readProductFlavors as c, ccacheActivityLine as d, projectCmakeLauncher as f, androidPathRoomMessage as g, androidPathRoom as h, androidSdkRefusal as i, CCACHE_NOT_RUN as l, formatDiagnostic as m, resolveAndroidCas as n, buildAndroid as o, resolveCcache as p, resolveAndroidCompilerCache as r, productFlavorRefusal as s, readAndroidCasToolchain as t, CCACHE_UNAVAILABLE as u };