stim 1.12.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 (71) hide show
  1. package/README.md +3 -1
  2. package/dist/{activity-CCZJs__P.mjs → activity-DfVKZTEB.mjs} +42 -25
  3. package/dist/{android-BQiKJYK0.mjs → android-BHfAu2mf.mjs} +1 -1
  4. package/dist/{android-B7X-8H7h.mjs → android-CD8pr8Q2.mjs} +62 -47
  5. package/dist/{android-cas-DzLPXiEn.mjs → android-cas-B9Kv9aIy.mjs} +9 -7
  6. package/dist/{android-75Sk2rIR.mjs → android-qx_31wJo.mjs} +395 -116
  7. package/dist/{app-install-CsZi0SAT.mjs → app-install-CDFY2nUL.mjs} +1 -1
  8. package/dist/{budget-DbzW5VTD.mjs → budget-E5o91NR1.mjs} +154 -37
  9. package/dist/{build-plan-CqntbR7b.mjs → build-plan-BTa93o_r.mjs} +21 -88
  10. package/dist/{build-progress-h60GPV27.mjs → build-progress-l7d-X-ZP.mjs} +75 -7
  11. package/dist/cdp-Dq_ypAlJ.mjs +115 -0
  12. package/dist/chrome-B5hWgQJS.mjs +61 -0
  13. package/dist/cli.mjs +16 -15
  14. package/dist/collector-run.mjs +14 -8
  15. package/dist/{command-output-BWCj5Vh-.mjs → command-output-BIL7rlX7.mjs} +1 -1
  16. package/dist/created-devices-Cd558h31.mjs +37 -0
  17. package/dist/{deps-CO-_7UOm.mjs → deps-2Wo81np9.mjs} +1 -1
  18. package/dist/{device-9r9xRYDa.mjs → device-Cf7vl-so.mjs} +6 -6
  19. package/dist/{device-lease-B9LAXIUH.mjs → device-lease-CL9dZf73.mjs} +52 -3
  20. package/dist/{device-pool-BoezJd-c.mjs → device-pool-MuoiyRcu.mjs} +3 -3
  21. package/dist/{device-remote-C0_o-tJH.mjs → device-remote-DT9ngZiD.mjs} +10 -10
  22. package/dist/{doctor-LfDlbR-N.mjs → doctor-D2iysNNH.mjs} +47 -18
  23. package/dist/{error-diagnostics-CCxjn31V.mjs → error-diagnostics-BoiOhck8.mjs} +6 -6
  24. package/dist/{gc-C4nQFcTX.mjs → gc-eA-PRBX8.mjs} +853 -126
  25. package/dist/{guide-BPBlh9ML.mjs → guide-BfZ0OmiP.mjs} +736 -110
  26. package/dist/{guide-status-i9ogHt4v.mjs → guide-status-BaMYu55M.mjs} +1 -1
  27. package/dist/{idle-S3tFZ53_.mjs → idle-DxLi5OkN.mjs} +42 -9
  28. package/dist/{in-use-D9XYEgFD.mjs → in-use-wYEaKQM9.mjs} +9 -5
  29. package/dist/{ios-CDzWL1mj.mjs → ios-CcfCeZ19.mjs} +98 -54
  30. package/dist/{ios-CZWOHTTc.mjs → ios-CmEzZiOj.mjs} +10 -5
  31. package/dist/{ios-device-D9cLxVr5.mjs → ios-device-BW-t_Lkv.mjs} +1 -1
  32. package/dist/{launch-verify-B2oR_kFN.mjs → launch-verify-CuJaBpEa.mjs} +33 -20
  33. package/dist/{logs-SzuYudOj.mjs → logs-DcSRbC2t.mjs} +11 -10
  34. package/dist/{metro-Dzo30hvJ.mjs → metro-BPeY1YMh.mjs} +4 -4
  35. package/dist/{named-ports-Dn1o61D9.mjs → named-ports-n7tnJsI8.mjs} +78 -6
  36. package/dist/native-runtime-CiiFHt0e.mjs +74 -0
  37. package/dist/{ownership-Dqnrjrio.mjs → ownership-Bz2kETAS.mjs} +1 -1
  38. package/dist/{ownership-B8d4kXBx.mjs → ownership-PUP4Dwai.mjs} +134 -209
  39. package/dist/page-BTu7I60K.mjs +29 -0
  40. package/dist/{ports-Dp_QTwTC.mjs → ports-C5UutqpJ.mjs} +4 -4
  41. package/dist/{project-B8rbutVC.mjs → project-DGeclhvO.mjs} +53 -17
  42. package/dist/{reload-nocmx8KB.mjs → reload-C-cV5yy_.mjs} +79 -20
  43. package/dist/{remote-cache-BRsRZru5.mjs → remote-cache--aehr4Pr.mjs} +3 -3
  44. package/dist/{server-bare-Gn3ssSdK.mjs → server-bare-Bq8BpSIo.mjs} +1 -1
  45. package/dist/server-expo-BeYwP_Xy.mjs +2 -0
  46. package/dist/{server-expo-CeT1nIIk.mjs → server-expo-DUCg52-K.mjs} +2 -2
  47. package/dist/{settings-bE-Gu3Ti.mjs → settings-ssVBToDR.mjs} +10 -10
  48. package/dist/{settings-BlyDn2Oz.mjs → settings-xB0Frkg6.mjs} +11 -2
  49. package/dist/settings.schema.json +53 -1
  50. package/dist/{simslim-COtEEP7x.mjs → simslim-Bbg9UWrt.mjs} +12 -6
  51. package/dist/{slot-launch-DIACGEfH.mjs → slot-launch-BIWEW-wI.mjs} +3 -3
  52. package/dist/{start-BboE1HIS.mjs → start-BZhItkiL.mjs} +11 -10
  53. package/dist/{start-BFstVBlx.mjs → start-Rw2GD3nV.mjs} +1 -1
  54. package/dist/{state-DcDgzfu3.mjs → state-DwAU2_-D.mjs} +1 -1
  55. package/dist/state-l1pYwOre.mjs +148 -0
  56. package/dist/{stats-DiCtmluY.mjs → stats-CaSwmsSZ.mjs} +2 -2
  57. package/dist/{status-DI9Tjo7T.mjs → status-TJlL0HWo.mjs} +624 -103
  58. package/dist/{status-BUASYyy_.mjs → status-sszP4XKU.mjs} +59 -2
  59. package/dist/{stim-desktop-D0xhpZt8.mjs → stim-desktop-CXt8-Z3J.mjs} +13 -2
  60. package/dist/{stop-Bn6v-GvS.mjs → stop-BZ2qMiBP.mjs} +37 -12
  61. package/dist/{stop-BI7QY76M.mjs → stop-DskDKNTU.mjs} +2 -2
  62. package/dist/supervisor-run.mjs +10 -10
  63. package/dist/web-run.d.mts +22 -0
  64. package/dist/web-run.mjs +481 -0
  65. package/dist/web-sWXd5iek.mjs +394 -0
  66. package/dist/{worktree-B5sTRskL.mjs → worktree-3cBa-bQt.mjs} +1 -1
  67. package/dist/{worktree-ChDL5fO1.mjs → worktree-D4Do_XiQ.mjs} +226 -19
  68. package/dist/{xcode-BzplpQzc.mjs → xcode-LM6A8cNZ.mjs} +5 -5
  69. package/package.json +5 -5
  70. package/dist/server-expo-eWi9Coof.mjs +0 -2
  71. package/dist/workspace-process-lock-BvvJTfo_.mjs +0 -57
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
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-Dzo30hvJ.mjs";
4
- import { i as listLeaseFiles, r as leaseIsExpired } from "./device-lease-B9LAXIUH.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";
@@ -89,16 +89,20 @@ function agentDeviceLiveness(record, startOf) {
89
89
  if (!record.readable || results.includes("unknown")) return "unknown";
90
90
  return "live";
91
91
  }
92
+ const HOST_PROCESS_COLUMNS = "pid=,ppid=,rss=,%cpu=,lstart=,command=";
92
93
  function parseProcessTable(output) {
93
94
  const rows = [];
94
95
  for (const line of output.split("\n")) {
95
- 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);
96
97
  if (!match) continue;
97
- const at = Date.parse(match[2]);
98
+ const at = Date.parse(match[5]);
98
99
  rows.push({
99
100
  pid: Number(match[1]),
101
+ ppid: Number(match[2]),
102
+ rssKb: Number(match[3]),
103
+ cpuPercent: Number(match[4].replace(",", ".")),
100
104
  startedAt: Number.isFinite(at) ? new Date(at).toISOString() : null,
101
- command: match[3]
105
+ command: match[6]
102
106
  });
103
107
  }
104
108
  return rows;
@@ -204,11 +208,39 @@ function readAgentDeviceRecords(home) {
204
208
  });
205
209
  });
206
210
  }
207
- function createActivityReader({ now = Date.now(), home = homedir(), startOf = process_identity_exports.inspectProcessStart, leaseFiles = listLeaseFiles } = {}) {
211
+ function createDeviceProcessTables() {
208
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() } = {}) {
209
242
  let agentDevice;
210
243
  let stimLeases;
211
- let processes;
212
244
  const logs = /* @__PURE__ */ new Map();
213
245
  const log = (path) => {
214
246
  if (!logs.has(path)) logs.set(path, tailLines(path));
@@ -251,14 +283,7 @@ function createActivityReader({ now = Date.now(), home = homedir(), startOf = pr
251
283
  since: entry.lease.grantedAt
252
284
  });
253
285
  }
254
- if (processes === void 0) {
255
- const output = exec.runFileQuiet("ps", [
256
- "-axww",
257
- "-o",
258
- "pid=,lstart=,command="
259
- ], { timeoutMs: 5e3 });
260
- processes = output === null ? null : parseProcessTable(output);
261
- }
286
+ const processes = tables.host();
262
287
  if (processes === null) evidence.unknown.push("driver-process");
263
288
  for (const row of processes ?? []) {
264
289
  const tool = driverTool(row.command, target.id);
@@ -270,15 +295,7 @@ function createActivityReader({ now = Date.now(), home = homedir(), startOf = pr
270
295
  });
271
296
  }
272
297
  if (target.platform === "android") {
273
- const output = exec.runFileQuiet("adb", [
274
- "-s",
275
- target.id,
276
- "shell",
277
- "ps",
278
- "-A",
279
- "-o",
280
- "PID,ARGS"
281
- ], { timeoutMs: 5e3 });
298
+ const output = tables.android(target.id);
282
299
  if (output === null) evidence.unknown.push("instrumentation");
283
300
  for (const { pid, tool } of parseAndroidInstrumentation(output ?? "")) evidence.drivers.push({
284
301
  basis: "instrumentation",
@@ -336,4 +353,4 @@ function workspaceActivity(workspace, now = Date.now()) {
336
353
  }, now);
337
354
  }
338
355
  //#endregion
339
- 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 { l as androidToolCwd } from "./android-75Sk2rIR.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
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-Dzo30hvJ.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
5
  import { D as makeTemporaryDirectory, O as removeTemporaryEntry, s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
6
- import { i as findProjectRoot, n as appProjectProblem, r as detectIsExpo, s as projectShortcut, t as NO_PROJECT_REFUSAL } from "./project-B8rbutVC.mjs";
7
- import { m as writeWorkspaceLaunch, n as MODE_EXPO, t as MODE_BARE } from "./state-DcDgzfu3.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-BWCj5Vh-.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-B9LAXIUH.mjs";
11
- import { B as pickDefaultSystemImage, D as listAvdDeviceProfiles, E as listAdbDevices, G as resolvePhysicalDevice, H as profileNeedsFoldFeature, J as systemImageSupportsFold, N as ownedAvdDeviceProfile, O as listAvds, P as ownedAvdDirectory, R as ownedAvdSystemImage, S as findBuildTool, U as resetAdoptedAvd, V as probeEmulatorSerial, W as resolveOwnedAvdSerial, X as waitForBoot, a as androidHome, b as emulatorFailureRemedy, c as androidSystemImageAbi, i as androidDeviceAbi, j as memoizeEmulatorProbe, k as listInstalledSystemImages, l as androidToolCwd, o as androidPoolCandidates, r as androidBuildToolName, s as androidPoolNoCandidatesRefusal, t as DEFAULT_AVD_DEVICE_PROFILE, tt as configuredAndroidEmulatorApp, w as hostSystemImageArch, x as extractEmulatorFailure, y as emulatorDiskSpaceRemedy, z as physicalDeviceModel } from "./android-75Sk2rIR.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-BlyDn2Oz.mjs";
13
- import { y as parkedMaxSetting } from "./ownership-B8d4kXBx.mjs";
14
- import { c as startBuildProgress, n as NO_BUILD_PROGRESS } from "./build-progress-h60GPV27.mjs";
15
- import { a as acquireBuildSlot, s as releaseBuildSlot } from "./in-use-D9XYEgFD.mjs";
16
- import { n as verifyCollectorOwnership, r as readCollectors } from "./ownership-Dqnrjrio.mjs";
17
- import { t as cleanLine } from "./server-expo-CeT1nIIk.mjs";
18
- 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-BRsRZru5.mjs";
19
- 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-C0_o-tJH.mjs";
20
- 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-CsZi0SAT.mjs";
21
- 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-B2oR_kFN.mjs";
22
- import { f as isEasBuildFailure, m as resolveEasDevelopmentBuild, o as unknownAndroidDeviceProfileRefusal, p as planEasDevelopmentBuild, r as checkDeviceCapacity, s as unknownAndroidSystemImageRefusal } from "./simslim-COtEEP7x.mjs";
23
- import { f as spawnEntry, m as detectAppIds, p as detectAndroidPackage, s as startDevServer } from "./start-BboE1HIS.mjs";
24
- 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-BoezJd-c.mjs";
25
- 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-CqntbR7b.mjs";
26
- import { t as budgetGate } from "./budget-DbzW5VTD.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
27
  import { a as statsProjectKey, i as recordRunStats, n as readRunEstimates, t as createRunRecorder } from "./stats-D8rUTPHd.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-DzLPXiEn.mjs";
29
- import { d as startBuildHeartbeat, f as tailLines, n as HEARTBEAT_INTERVAL_MS } from "./xcode-BzplpQzc.mjs";
30
- import { n as nativeRunCommand, t as launchSlotScope } from "./slot-launch-DIACGEfH.mjs";
31
- import { a as printNativeCrashReport, r as captureNativeCrashes, t as errorDiagnostics } from "./error-diagnostics-CCxjn31V.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";
@@ -984,17 +984,19 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
984
984
  phase("build", chalk.yellow(`could not take a build slot: ${err?.message || err}; building anyway`));
985
985
  }
986
986
  const rekeyedBy = [];
987
+ let editedConfig = [];
987
988
  const prebuildPlan = planPrebuildFor(root, PLATFORM, {
988
989
  isExpo,
989
990
  fingerprint: hash,
990
991
  sources: fingerprintSources
991
992
  });
993
+ const prebuildRan = prebuildPlan === "generate" || prebuildPlan === "regenerate";
992
994
  if (prebuildPlan === "refuse") {
993
995
  const refusal = staleNativeDirRefusal(PLATFORM);
994
996
  phaseFailure = fail$1(refusal.code, refusal.message, refusal.remedy, { lastBuildStatus: true });
995
997
  return false;
996
998
  }
997
- if (prebuildPlan === "generate" || prebuildPlan === "regenerate") {
999
+ if (prebuildRan) {
998
1000
  step("prebuild");
999
1001
  recordPrebuild(root, PLATFORM, null);
1000
1002
  const pre = await prebuild(root, PLATFORM, writer, {
@@ -1018,8 +1020,9 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
1018
1020
  previousHash: hash,
1019
1021
  fingerprint
1020
1022
  });
1021
- if (after) recordPrebuild(root, PLATFORM, after.hash);
1022
- 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) {
1023
1026
  rekeyedBy.push("prebuild");
1024
1027
  storeHash = after.hash;
1025
1028
  storeSources = after.sources;
@@ -1078,6 +1081,7 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
1078
1081
  phaseFailure = fail$1(built.code, built.reason, diagnostics.find((d) => d.remedy)?.remedy || built.remedy || null, {
1079
1082
  lastBuildStatus: true,
1080
1083
  diagnostics: extracted,
1084
+ buildDiagnostics: diagnostics,
1081
1085
  lines: extracted.length ? [] : tail(built.lastLines),
1082
1086
  logPath: displayPath(root, buildLog)
1083
1087
  });
@@ -1088,16 +1092,23 @@ async function acquireAndroidArtifact({ root, buildLog, writer, settings, isExpo
1088
1092
  phase("build", `ok (${formatDuration(built.durationMs)})`);
1089
1093
  if (built.apkNote) phase("build", chalk.yellow(built.apkNote));
1090
1094
  const beforeBuildHash = storeHash;
1091
- const afterBuild = await refingerprintAfterMutation({
1095
+ const afterBuild = editedConfig.length ? null : await refingerprintAfterMutation({
1092
1096
  projectRoot: root,
1093
1097
  platform: PLATFORM,
1094
1098
  previousHash: beforeBuildHash,
1095
1099
  fingerprint
1096
1100
  });
1097
- 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) {
1098
1109
  record.fingerprint = null;
1099
1110
  record.cacheKey = null;
1100
- 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"));
1101
1112
  } else {
1102
1113
  if (afterBuild.moved) {
1103
1114
  storeHash = afterBuild.hash;
@@ -1208,7 +1219,7 @@ function androidFacts({ slot, serial, avdName = null, deviceName = null, systemI
1208
1219
  ...devServer ? { devServer } : {}
1209
1220
  };
1210
1221
  }
1211
- 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 }) {
1212
1223
  const record = {
1213
1224
  platform: PLATFORM,
1214
1225
  avdName: avdName ?? null,
@@ -1221,10 +1232,13 @@ function lastBuildRecord({ fingerprint, cacheKey, cacheHit, cacheSkipped = false
1221
1232
  appPath: appPath ?? null,
1222
1233
  bundleId: bundleId ?? null,
1223
1234
  startedAt,
1224
- status
1235
+ status,
1236
+ configuration: configuration ?? null
1225
1237
  };
1226
1238
  if (errorCode) record.errorCode = errorCode;
1227
1239
  if (missReason && !cacheLevel(cacheHit)) record.missReason = missReason;
1240
+ const recorded = status === "failed" ? buildDiagnostics(diagnostics) : [];
1241
+ if (recorded.length) record.diagnostics = recorded;
1228
1242
  return record;
1229
1243
  }
1230
1244
  async function finishAndroidUpload(uploadPending, remote, phase) {
@@ -1306,19 +1320,17 @@ function cacheOutcome(cacheHit, providerName = null) {
1306
1320
  if (cacheHit === "local") return "cache hit";
1307
1321
  return "built";
1308
1322
  }
1309
- 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 }) {
1310
1324
  const lastBuild = lastBuildRecord({
1311
1325
  ...record,
1312
1326
  startedAt,
1313
1327
  durationMs,
1314
1328
  status,
1315
- errorCode
1329
+ errorCode,
1330
+ diagnostics
1316
1331
  });
1317
1332
  try {
1318
- writeState(root, {
1319
- lastBuild,
1320
- [LAST_BUILD_KEYS[PLATFORM]]: lastBuild
1321
- });
1333
+ recordBuild(root, lastBuild);
1322
1334
  } catch (err) {
1323
1335
  out(phaseLine("state", chalk.yellow(`could not record lastBuild: ${err?.message || err}`)));
1324
1336
  }
@@ -1547,7 +1559,7 @@ async function resolveInstallSerial({ root, slot, device, physical, remoteDevice
1547
1559
  });
1548
1560
  return resolved.serial;
1549
1561
  }
1550
- 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 }) {
1551
1563
  let androidPackage = initialPackage;
1552
1564
  let leaseWarned = false;
1553
1565
  const raiseLeaseFor = (boundMs, beforeInstall) => {
@@ -1737,7 +1749,7 @@ async function finishAndroidRun({ lease, releaseLease, root, slot, json, metroCh
1737
1749
  const providerOutcome = providerUploadOutcome(providerUpload ? await providerUpload : null, providerName);
1738
1750
  if (providerOutcome) phase("cache", providerOutcome.warn ? chalk.yellow(providerOutcome.line) : providerOutcome.line);
1739
1751
  persistLastBuild({
1740
- writeState,
1752
+ recordBuild,
1741
1753
  root,
1742
1754
  record,
1743
1755
  startedAt,
@@ -2284,7 +2296,7 @@ function registerAndroid(program) {
2284
2296
  }, { write: (line) => console.error(chalk.dim(phaseLine("lock", line))) })).ok) process.exit(runCancellation() ? 130 : 1);
2285
2297
  });
2286
2298
  }
2287
- 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) } = {}) {
2288
2300
  return {
2289
2301
  root,
2290
2302
  json,
@@ -2363,6 +2375,7 @@ function resolveRunAndroidOptions({ root, json = false, remoteDevice: commandRem
2363
2375
  createWriter,
2364
2376
  writeLaunch,
2365
2377
  writeState,
2378
+ recordBuild,
2366
2379
  recordStats,
2367
2380
  readEstimates,
2368
2381
  now,
@@ -2423,7 +2436,7 @@ function avdSetupFailure(error, root, logFile) {
2423
2436
  };
2424
2437
  }
2425
2438
  async function runAndroid(options = {}) {
2426
- 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);
2427
2440
  const progress = options.progress ?? NO_BUILD_PROGRESS;
2428
2441
  const slot = validateDeviceSlot(options.slot);
2429
2442
  const started = now();
@@ -2495,20 +2508,21 @@ async function runAndroid(options = {}) {
2495
2508
  const recordRun = stats.record;
2496
2509
  let ccacheActivity = CCACHE_NOT_RUN;
2497
2510
  let reclaimed = [];
2498
- 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 } = {}) => {
2499
2512
  const cancellation = cancelledFailure(PLATFORM, {
2500
2513
  code,
2501
2514
  message
2502
2515
  });
2503
2516
  if (cancellation) ({code, message, remedy, lines} = cancellation);
2504
2517
  if (lastBuildStatus) persistLastBuild({
2505
- writeState,
2518
+ recordBuild,
2506
2519
  root,
2507
2520
  record,
2508
2521
  startedAt,
2509
2522
  durationMs: now() - started,
2510
2523
  status: "failed",
2511
2524
  errorCode: code,
2525
+ diagnostics: rawDiagnostics,
2512
2526
  out
2513
2527
  });
2514
2528
  out(phaseLine("error", chalk.red(`${code}: ${message}`)));
@@ -2580,6 +2594,7 @@ async function runAndroid(options = {}) {
2580
2594
  const { plan } = planned;
2581
2595
  const { build: buildPlan, target, isExpo, cacheProviderConfig } = plan;
2582
2596
  const { variant, release, cache: cachePolicy } = buildPlan;
2597
+ record.configuration = variant ?? "debug";
2583
2598
  const useBuildCache = cachePolicy.read;
2584
2599
  const physical = target.kind === "physical";
2585
2600
  const remoteBackend = target.kind === "remote" ? target.backend : null;
@@ -2953,7 +2968,7 @@ async function runAndroid(options = {}) {
2953
2968
  pidAlive,
2954
2969
  verifyCollector,
2955
2970
  writeLaunch,
2956
- writeState,
2971
+ recordBuild,
2957
2972
  now,
2958
2973
  out,
2959
2974
  emit,
@@ -1,12 +1,12 @@
1
1
  import { d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { r as register } from "./cache-manifest-DWPF4RKJ.mjs";
4
- import { C as sharedCcache, P as withDirLock, j as workspaceLogsDir, x as ensureWorkspaceStorage } from "./metro-Dzo30hvJ.mjs";
4
+ import { F as withDirLock, M as workspaceLogsDir, S as ensureWorkspaceStorage, w as sharedCcache } from "./metro-BPeY1YMh.mjs";
5
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-BWCj5Vh-.mjs";
8
- import { a as androidHome } from "./android-75Sk2rIR.mjs";
9
- import { d as startBuildHeartbeat, n as HEARTBEAT_INTERVAL_MS } from "./xcode-BzplpQzc.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 };