stim 1.11.0 → 1.12.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/dist/{activity-BtG4Va9l.mjs → activity-CCZJs__P.mjs} +4 -3
  2. package/dist/{android-C4zG2Tuc.mjs → android-75Sk2rIR.mjs} +25 -8
  3. package/dist/{android-C1q4l523.mjs → android-B7X-8H7h.mjs} +75 -32
  4. package/dist/{android-BA2i_KAV.mjs → android-BQiKJYK0.mjs} +1 -1
  5. package/dist/{android-cas-DfJkwCXW.mjs → android-cas-DzLPXiEn.mjs} +7 -7
  6. package/dist/{app-install-DHut6JnV.mjs → app-install-CsZi0SAT.mjs} +1 -1
  7. package/dist/{workspaces-COD2xCz-.mjs → budget-DbzW5VTD.mjs} +641 -32
  8. package/dist/{build-plan-CeAYgKAx.mjs → build-plan-CqntbR7b.mjs} +120 -35
  9. package/dist/{build-progress-CDwogz6R.mjs → build-progress-h60GPV27.mjs} +3 -3
  10. package/dist/{cache-manifest-Pubfp8wV.mjs → cache-manifest-DWPF4RKJ.mjs} +1 -1
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +16 -16
  13. package/dist/collector-run.mjs +4 -4
  14. package/dist/{command-output-D5z2_bcF.mjs → command-output-BWCj5Vh-.mjs} +1 -1
  15. package/dist/{config-BEq0Qw_a.mjs → config-0jCcMM0E.mjs} +10 -1
  16. package/dist/{dependency-state-r9UesA9a.mjs → dependency-state-DNN0yfx6.mjs} +1 -1
  17. package/dist/{deps-OF7CD5Dx.mjs → deps-CO-_7UOm.mjs} +2 -2
  18. package/dist/{device-BwH2iI3O.mjs → device-9r9xRYDa.mjs} +7 -7
  19. package/dist/{device-lease-D83nqeMX.mjs → device-lease-B9LAXIUH.mjs} +5 -5
  20. package/dist/{device-pool-DHj7cdPy.mjs → device-pool-BoezJd-c.mjs} +4 -4
  21. package/dist/{device-remote-BQZSnnmE.mjs → device-remote-C0_o-tJH.mjs} +254 -579
  22. package/dist/{doctor-D8QdMRMf.mjs → doctor-LfDlbR-N.mjs} +19 -18
  23. package/dist/{error-diagnostics-UYFSQwRy.mjs → error-diagnostics-CCxjn31V.mjs} +7 -7
  24. package/dist/{gc-COZteyiq.mjs → gc-C4nQFcTX.mjs} +203 -39
  25. package/dist/{guide-NDvTmMi-.mjs → guide-BPBlh9ML.mjs} +189 -38
  26. package/dist/{guide-status-CWvti2Lg.mjs → guide-status-i9ogHt4v.mjs} +2 -2
  27. package/dist/{idle-NETbeNiQ.mjs → idle-S3tFZ53_.mjs} +7 -7
  28. package/dist/{in-use-DVhlSoyn.mjs → in-use-D9XYEgFD.mjs} +7 -7
  29. package/dist/{ios-CQLKpNfr.mjs → ios-CDzWL1mj.mjs} +30 -29
  30. package/dist/{ios-DArbmwer.mjs → ios-CZWOHTTc.mjs} +23 -19
  31. package/dist/{ios-device-CwDZo0X4.mjs → ios-device-D9cLxVr5.mjs} +1 -1
  32. package/dist/{launch-verify-CuPDGXdr.mjs → launch-verify-B2oR_kFN.mjs} +2 -2
  33. package/dist/{logs-B44a1UeU.mjs → logs-SzuYudOj.mjs} +6 -6
  34. package/dist/{merge-state-DDxS-XIZ.mjs → merge-state-ytFQCeh4.mjs} +38 -8
  35. package/dist/{metro-BWLOJ_Wr.mjs → metro-Dzo30hvJ.mjs} +1 -1
  36. package/dist/{named-ports-Dc7neAlc.mjs → named-ports-Dn1o61D9.mjs} +3 -3
  37. package/dist/{ownership-BiojdtAp.mjs → ownership-B8d4kXBx.mjs} +49 -16
  38. package/dist/{ownership-D2xbLVoz.mjs → ownership-Dqnrjrio.mjs} +2 -2
  39. package/dist/{ports-DwBaRFJs.mjs → ports-Dp_QTwTC.mjs} +3 -3
  40. package/dist/{project-BXZzOABt.mjs → project-B8rbutVC.mjs} +4 -72
  41. package/dist/{reload-By9Dwsrt.mjs → reload-nocmx8KB.mjs} +9 -9
  42. package/dist/remote-cache-BRsRZru5.mjs +526 -0
  43. package/dist/{server-bare-D_RK1RCj.mjs → server-bare-Gn3ssSdK.mjs} +1 -1
  44. package/dist/{server-expo-o6H5gcBc.mjs → server-expo-CeT1nIIk.mjs} +2 -2
  45. package/dist/server-expo-eWi9Coof.mjs +2 -0
  46. package/dist/{settings-B5oFZEri.mjs → settings-BlyDn2Oz.mjs} +2 -2
  47. package/dist/{settings-C0ugALSC.mjs → settings-bE-Gu3Ti.mjs} +23 -11
  48. package/dist/settings.schema.json +22 -2
  49. package/dist/{simslim-CIR3IYJO.mjs → simslim-COtEEP7x.mjs} +6 -5
  50. package/dist/{slot-launch-rggO1Esw.mjs → slot-launch-DIACGEfH.mjs} +4 -4
  51. package/dist/{spawn-claims-BJwXTMPt.mjs → spawn-claims-PT8aQpCa.mjs} +1 -1
  52. package/dist/{start-i8zc9VmS.mjs → start-BFstVBlx.mjs} +1 -1
  53. package/dist/{start-BSsf2tUs.mjs → start-BboE1HIS.mjs} +108 -17
  54. package/dist/{state-WGdIbi_d.mjs → state-DcDgzfu3.mjs} +15 -3
  55. package/dist/{stats-BAgJaLA4.mjs → stats-D8rUTPHd.mjs} +1 -1
  56. package/dist/{stats-DBYJ5bxL.mjs → stats-DiCtmluY.mjs} +4 -4
  57. package/dist/{status-Q-WDEGCB.mjs → status-BUASYyy_.mjs} +73 -28
  58. package/dist/{status-CitcBRsC.mjs → status-DI9Tjo7T.mjs} +41 -29
  59. package/dist/stim-desktop-D0xhpZt8.mjs +29 -0
  60. package/dist/{stop-rst5mL14.mjs → stop-BI7QY76M.mjs} +2 -2
  61. package/dist/{stop-DIhrvu0B.mjs → stop-Bn6v-GvS.mjs} +23 -16
  62. package/dist/supervisor-run.mjs +11 -11
  63. package/dist/{workspace-process-lock-Cx74RSDZ.mjs → workspace-process-lock-BvvJTfo_.mjs} +2 -2
  64. package/dist/{worktree-DhxDTK44.mjs → worktree-B5sTRskL.mjs} +1 -1
  65. package/dist/{worktree-KOjMX3zA.mjs → worktree-ChDL5fO1.mjs} +17 -16
  66. package/dist/{worktree-BlizKDpZ.mjs → worktree-DeBQSVtR.mjs} +3 -1
  67. package/dist/{xcode-B5SPD--o.mjs → xcode-BzplpQzc.mjs} +7 -7
  68. package/package.json +5 -5
  69. package/dist/budget-De3P2rq_.mjs +0 -620
  70. package/dist/native-run-D7yB_AsB.mjs +0 -143
  71. package/dist/server-expo-B-CCUJZj.mjs +0 -2
@@ -904,7 +904,7 @@
904
904
  "additionalProperties": false
905
905
  },
906
906
  "iosSimulatorApp": {
907
- "description": "App that displays an owned iOS simulator",
907
+ "description": "App that displays an owned iOS simulator; stim-desktop by default when Stim Desktop is installed",
908
908
  "type": "string",
909
909
  "enum": [
910
910
  "xcode",
@@ -921,7 +921,7 @@
921
921
  }
922
922
  },
923
923
  "androidEmulatorApp": {
924
- "description": "App that displays an owned Android emulator Stim boots on macOS",
924
+ "description": "App that displays an owned Android emulator Stim boots on macOS; stim-desktop by default when Stim Desktop is installed",
925
925
  "type": "string",
926
926
  "enum": [
927
927
  "emulator",
@@ -1030,6 +1030,26 @@
1030
1030
  },
1031
1031
  "additionalProperties": false
1032
1032
  },
1033
+ "gc": {
1034
+ "type": "object",
1035
+ "properties": {
1036
+ "worktreeGraceMinutes": {
1037
+ "description": "Minutes after a linked worktree last changed, or its branch merged, before gc removes it; 0 removes it at once",
1038
+ "type": "integer",
1039
+ "minimum": 0,
1040
+ "default": 120,
1041
+ "x-stim": {
1042
+ "key": "gc.worktreeGraceMinutes",
1043
+ "kind": "number",
1044
+ "scopes": [
1045
+ "machine"
1046
+ ],
1047
+ "env": "STIM_GC_WORKTREE_GRACE_MINUTES"
1048
+ }
1049
+ }
1050
+ },
1051
+ "additionalProperties": false
1052
+ },
1033
1053
  "pool": {
1034
1054
  "type": "object",
1035
1055
  "properties": {
@@ -1,10 +1,11 @@
1
- import { D as process_identity_exports, H as projectDeviceSlots, g as loadConfig, k as ownership_claim_exports, u as getConfigDir, z as deviceSlotPlatforms } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, B as deviceSlotPlatforms, O as process_identity_exports, U as projectDeviceSlots, _ as loadConfig, d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { n as stripAnsi, r as waitForChild, t as createLineReader } from "./process-output-Fpl8PYi8.mjs";
4
- import { g as releaseBuildLock, m as acquireBuildLock } from "./device-lease-D83nqeMX.mjs";
5
- import { T as listAdbDevices } from "./android-C4zG2Tuc.mjs";
6
- import { l as listAllIosSims, s as iosRuntimeMatches } from "./ios-DArbmwer.mjs";
7
- import { _ as easCliSupport, s as readInstalledEasCliVersion, v as easCliUpgradeRemedy, z as resolveEasCliBin } from "./device-remote-BQZSnnmE.mjs";
4
+ import { g as releaseBuildLock, m as acquireBuildLock } from "./device-lease-B9LAXIUH.mjs";
5
+ import { E as listAdbDevices } from "./android-75Sk2rIR.mjs";
6
+ import { l as listAllIosSims, s as iosRuntimeMatches } from "./ios-CZWOHTTc.mjs";
7
+ import { f as resolveEasCliBin } from "./remote-cache-BRsRZru5.mjs";
8
+ import { O as easCliSupport, k as easCliUpgradeRemedy, s as readInstalledEasCliVersion } from "./device-remote-C0_o-tJH.mjs";
8
9
  import { existsSync, realpathSync, statSync } from "node:fs";
9
10
  import { join } from "node:path";
10
11
  import { createHash } from "node:crypto";
@@ -1,7 +1,7 @@
1
- import { f as getProject } from "./config-BEq0Qw_a.mjs";
2
- import { m as readWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
3
- import { n as fileLeaseIo } from "./device-lease-D83nqeMX.mjs";
4
- import { d as deviceShellArg } from "./app-install-DHut6JnV.mjs";
1
+ import { p as getProject } from "./config-0jCcMM0E.mjs";
2
+ import { m as readWorkspaceState } from "./metro-Dzo30hvJ.mjs";
3
+ import { n as fileLeaseIo } from "./device-lease-B9LAXIUH.mjs";
4
+ import { d as deviceShellArg } from "./app-install-CsZi0SAT.mjs";
5
5
  //#region src/engine/slot-launch.ts
6
6
  function launchSlotScope(root, slot = "default") {
7
7
  if (slot !== "default") return slot;
@@ -1,4 +1,4 @@
1
- import { D as process_identity_exports, k as ownership_claim_exports } from "./config-BEq0Qw_a.mjs";
1
+ import { A as ownership_claim_exports, O as process_identity_exports } from "./config-0jCcMM0E.mjs";
2
2
  //#region src/engine/spawn-claims.ts
3
3
  const declaring = /* @__PURE__ */ new Set();
4
4
  const running = /* @__PURE__ */ new Set();
@@ -1,2 +1,2 @@
1
- import { a as registerStart, c as startFacts, d as wantsExpoOwnTunnel, i as readLogTail, l as supervisorEntry, n as liveSupervisor, o as startCommand, r as parseWait, s as startDevServer, t as failureEvidence, u as tailLines } from "./start-BSsf2tUs.mjs";
1
+ import { a as registerStart, c as startFacts, d as wantsExpoOwnTunnel, i as readLogTail, l as supervisorEntry, n as liveSupervisor, o as startCommand, r as parseWait, s as startDevServer, t as failureEvidence, u as tailLines } from "./start-BboE1HIS.mjs";
2
2
  export { startCommand as default, failureEvidence, liveSupervisor, parseWait, readLogTail, registerStart, startDevServer, startFacts, supervisorEntry, tailLines, wantsExpoOwnTunnel };
@@ -1,23 +1,113 @@
1
- import { D as process_identity_exports, f as getProject, w as upsertProject } from "./config-BEq0Qw_a.mjs";
1
+ import { O as process_identity_exports, T as upsertProject, p as getProject } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { i as levelRank } from "./ndjson-CDY9IkVC.mjs";
4
- import { T as supervisorLogFile, c as signalProcessTree, d as reserveMetroPort, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, p as clearWorkspaceStateKeys, s as resolveProjectMetro, x as ensureWorkspaceStorage, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
5
- import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
6
- import { a as detectIsExpo, i as detectBundleId, n as appProjectProblem, o as findProjectRoot, r as detectAndroidPackage, t as NO_PROJECT_REFUSAL } from "./project-BXZzOABt.mjs";
4
+ import { T as supervisorLogFile, c as signalProcessTree, d as reserveMetroPort, h as recordWorkspaceUse, i as pidExists, j as workspaceLogsDir, m as readWorkspaceState$1, p as clearWorkspaceStateKeys, s as resolveProjectMetro, x as ensureWorkspaceStorage, y as writeWorkspaceState } from "./metro-Dzo30hvJ.mjs";
5
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
6
+ import { c as readAppConfigText, i as findProjectRoot, l as readAppJson, n as appProjectProblem, r as detectIsExpo, t as NO_PROJECT_REFUSAL } from "./project-B8rbutVC.mjs";
7
7
  import { n as windowsLauncherArgs } from "./detached-entry-DJHoca49.mjs";
8
- import { i as clearManagedMetroTunnel, s as readMetroTunnel } from "./state-WGdIbi_d.mjs";
9
- import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-Cx74RSDZ.mjs";
10
- import { _ as stepTimer, l as phaseLine } from "./command-output-D5z2_bcF.mjs";
11
- import { A as resolveCacheProviderConfig, B as planMetroReach, C as ngrokUrlSetting, E as publicUrlSetting, I as tunnelModeSetting, L as unknownSettingKeys, O as remoteAndroidSetting, P as settingShapeErrors, R as PUBLIC_METRO_ENV, a as SETTING_SHAPE_REMEDY, b as metroIdleStopMinutesSetting, d as cacheProviderSettingError, j as resolveSettings, k as remoteIosSetting, x as metroTunnelSettingError, z as detectProviders } from "./settings-B5oFZEri.mjs";
12
- import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-BiojdtAp.mjs";
13
- import { i as stopOwnedMetroForReset, t as budgetGate } from "./budget-De3P2rq_.mjs";
8
+ import { c as readMetroTunnel, i as clearManagedMetroTunnel } from "./state-DcDgzfu3.mjs";
9
+ import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-BvvJTfo_.mjs";
10
+ import { _ as stepTimer, l as phaseLine } from "./command-output-BWCj5Vh-.mjs";
11
+ import { A as resolveCacheProviderConfig, B as planMetroReach, C as ngrokUrlSetting, E as publicUrlSetting, I as tunnelModeSetting, L as unknownSettingKeys, O as remoteAndroidSetting, P as settingShapeErrors, R as PUBLIC_METRO_ENV, a as SETTING_SHAPE_REMEDY, b as metroIdleStopMinutesSetting, d as cacheProviderSettingError, j as resolveSettings, k as remoteIosSetting, x as metroTunnelSettingError, z as detectProviders } from "./settings-BlyDn2Oz.mjs";
12
+ import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-B8d4kXBx.mjs";
13
+ import { d as readProjectConfig } from "./remote-cache-BRsRZru5.mjs";
14
+ import { I as stopOwnedMetroForReset, t as budgetGate } from "./budget-DbzW5VTD.mjs";
14
15
  import { appendFileSync, mkdirSync, openSync, readFileSync } from "node:fs";
16
+ import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "fs";
17
+ import { join } from "path";
15
18
  import { IDLE_STOP_KEY, queryLogs } from "@stim-cli/core/state";
16
- import { basename, dirname, join } from "node:path";
19
+ import { basename as basename$1, dirname as dirname$1, join as join$1 } from "node:path";
17
20
  import { EventEmitter } from "node:events";
18
21
  import { fileURLToPath } from "node:url";
19
22
  import chalk from "chalk";
20
23
  import { CACHE_PROVIDER_ENV, cacheProviderEnv } from "@stim-cli/cache";
24
+ //#region src/workspace/app-id.ts
25
+ function configString(config, platform, key) {
26
+ if (!config || typeof config !== "object") return null;
27
+ const expoField = config.expo;
28
+ const section = (expoField && typeof expoField === "object" ? expoField : config)[platform];
29
+ if (!section || typeof section !== "object") return null;
30
+ const value = section[key];
31
+ return typeof value === "string" && value ? value : null;
32
+ }
33
+ function literalString(text, key) {
34
+ return text?.match(new RegExp(`${key}\\s*:\\s*["']([^"']+)["']`))?.[1] ?? null;
35
+ }
36
+ function idsFromConfig(projectRoot) {
37
+ const read = readProjectConfig(projectRoot);
38
+ if (!read.unavailable) return {
39
+ bundleId: configString(read.config, "ios", "bundleIdentifier"),
40
+ androidPackage: configString(read.config, "android", "package")
41
+ };
42
+ const appJson = readAppJson(projectRoot);
43
+ const text = readAppConfigText(projectRoot);
44
+ return {
45
+ bundleId: configString(appJson, "ios", "bundleIdentifier") ?? literalString(text, "bundleIdentifier"),
46
+ androidPackage: configString(appJson, "android", "package") ?? literalString(text, "package")
47
+ };
48
+ }
49
+ function detectAppIds(projectRoot) {
50
+ const ids = idsFromConfig(projectRoot);
51
+ return {
52
+ bundleId: ids.bundleId ?? detectBundleIdFromPbxproj(projectRoot),
53
+ androidPackage: ids.androidPackage ?? detectAndroidPackageFromGradle(projectRoot)
54
+ };
55
+ }
56
+ function detectBundleId(projectRoot) {
57
+ return detectAppIds(projectRoot).bundleId;
58
+ }
59
+ function detectAndroidPackage(projectRoot) {
60
+ return detectAppIds(projectRoot).androidPackage;
61
+ }
62
+ function detectBundleIdFromPbxproj(projectRoot) {
63
+ const iosDir = join(projectRoot, "ios");
64
+ if (!existsSync$1(iosDir)) return null;
65
+ let entries;
66
+ try {
67
+ entries = readdirSync$1(iosDir, { withFileTypes: true });
68
+ } catch {
69
+ return null;
70
+ }
71
+ for (const entry of entries) {
72
+ if (!entry.isDirectory() || !entry.name.endsWith(".xcodeproj")) continue;
73
+ const pbx = join(iosDir, entry.name, "project.pbxproj");
74
+ if (!existsSync$1(pbx)) continue;
75
+ let text;
76
+ try {
77
+ text = readFileSync$1(pbx, "utf-8");
78
+ } catch {
79
+ continue;
80
+ }
81
+ const concrete = [...text.matchAll(/PRODUCT_BUNDLE_IDENTIFIER\s*=\s*([^;\s"]+)\s*;/g)].map((m) => m[1]).filter((id) => !!id && !id.startsWith("$") && !id.includes("("));
82
+ if (concrete.length === 0) continue;
83
+ const counts = {};
84
+ for (const id of concrete) counts[id] = (counts[id] || 0) + 1;
85
+ let best = null, bestCount = 0, bestLen = Infinity;
86
+ for (const [id, count] of Object.entries(counts)) if (count > bestCount || count === bestCount && id.length < bestLen) {
87
+ best = id;
88
+ bestCount = count;
89
+ bestLen = id.length;
90
+ }
91
+ return best;
92
+ }
93
+ return null;
94
+ }
95
+ function detectAndroidPackageFromGradle(projectRoot) {
96
+ const gradle = join(projectRoot, "android", "app", "build.gradle");
97
+ if (!existsSync$1(gradle)) return null;
98
+ let text;
99
+ try {
100
+ text = readFileSync$1(gradle, "utf-8");
101
+ } catch {
102
+ return null;
103
+ }
104
+ const nsId = text.match(/namespace\s+["']([^"']+)["']/)?.[1];
105
+ if (nsId) return nsId;
106
+ const appId = text.match(/applicationId\s+["']([^"']+)["']/)?.[1];
107
+ if (appId) return appId;
108
+ return null;
109
+ }
110
+ //#endregion
21
111
  //#region src/spawn-entry.ts
22
112
  const DEV_ENTRIES = {
23
113
  "supervisor-run": "./supervisor/run.ts",
@@ -25,8 +115,8 @@ const DEV_ENTRIES = {
25
115
  };
26
116
  function spawnEntry(name) {
27
117
  const here = fileURLToPath(import.meta.url);
28
- if (basename(dirname(here)) === "src") return fileURLToPath(new URL(DEV_ENTRIES[name], import.meta.url));
29
- return join(dirname(here), `${name}.mjs`);
118
+ if (basename$1(dirname$1(here)) === "src") return fileURLToPath(new URL(DEV_ENTRIES[name], import.meta.url));
119
+ return join$1(dirname$1(here), `${name}.mjs`);
30
120
  }
31
121
  //#endregion
32
122
  //#region src/commands/start.ts
@@ -269,9 +359,10 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
269
359
  if (tunnel) note(chalk.dim("note requesting an Expo tunnel for this workspace's dev server"));
270
360
  const managedRemote = remote && !tunnel && !publicUrl && tunnelMode !== "off";
271
361
  const runStart = async () => {
362
+ const appIds = detectAppIds(root);
272
363
  upsertProject(root, {
273
- bundleId: detectBundleId(root) ?? void 0,
274
- androidPackage: detectAndroidPackage(root) ?? void 0,
364
+ bundleId: appIds.bundleId ?? void 0,
365
+ androidPackage: appIds.androidPackage ?? void 0,
275
366
  isExpo
276
367
  });
277
368
  const gateBudget = async () => {
@@ -819,7 +910,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
819
910
  };
820
911
  const startLocked = async () => {
821
912
  try {
822
- return await withWorkspaceProcessLock(dirname(workspaceLogsDir(root)), "metro-start", runStart, { external: true });
913
+ return await withWorkspaceProcessLock(dirname$1(workspaceLogsDir(root)), "metro-start", runStart, { external: true });
823
914
  } catch (error) {
824
915
  if (workspaceProcessLockError(error) !== "timeout") throw error;
825
916
  return fail({
@@ -935,4 +1026,4 @@ function report({ json, out, facts, waited, reclaimed }) {
935
1026
  out(chalk.dim(phaseLine("logs", facts.logsDir)));
936
1027
  }
937
1028
  //#endregion
938
- export { registerStart as a, startFacts as c, wantsExpoOwnTunnel as d, spawnEntry as f, readLogTail as i, supervisorEntry as l, liveSupervisor as n, startCommand as o, parseWait as r, startDevServer as s, failureEvidence as t, tailLines as u };
1029
+ export { registerStart as a, startFacts as c, wantsExpoOwnTunnel as d, spawnEntry as f, detectBundleId as h, readLogTail as i, supervisorEntry as l, detectAppIds as m, liveSupervisor as n, startCommand as o, detectAndroidPackage as p, parseWait as r, startDevServer as s, failureEvidence as t, tailLines as u };
@@ -1,5 +1,5 @@
1
- import { B as parseDeviceSlotKey, D as process_identity_exports, R as deviceSlotKey } from "./config-BEq0Qw_a.mjs";
2
- import { E as supervisorPidFile, N as workspaceStateFile, _ as withWorkspaceStateLock, f as clearWorkspaceStateKey, g as updateWorkspaceState, m as readWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
1
+ import { O as process_identity_exports, V as parseDeviceSlotKey, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
+ import { E as supervisorPidFile, N as workspaceStateFile, _ as withWorkspaceStateLock, f as clearWorkspaceStateKey, g as updateWorkspaceState, m as readWorkspaceState } from "./metro-Dzo30hvJ.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { dirname } from "node:path";
5
5
  //#region src/supervisor/state.ts
@@ -68,6 +68,18 @@ function writeWorkspaceLaunch(root, platform, record, slot = "default") {
68
68
  };
69
69
  });
70
70
  }
71
+ function clearWorkspaceLaunches(root, slot) {
72
+ updateWorkspaceState(root, (state) => {
73
+ if (!state.launches || typeof state.launches !== "object") return state;
74
+ const launches = { ...state.launches };
75
+ delete launches[deviceSlotKey("ios", slot)];
76
+ delete launches[deviceSlotKey("android", slot)];
77
+ return {
78
+ ...state,
79
+ launches
80
+ };
81
+ });
82
+ }
71
83
  function readRemoteSession(root) {
72
84
  const record = readWorkspaceState(root)?.remoteDevice;
73
85
  if (!record || typeof record !== "object") return null;
@@ -130,4 +142,4 @@ function readPidFile(root) {
130
142
  }
131
143
  }
132
144
  //#endregion
133
- export { clearRemoteSession as a, readPidFile as c, readWorkspaceLaunches as d, writePidFile as f, clearManagedMetroTunnel as i, readRemoteSession as l, MODE_EXPO as n, clearWorkspaceSupervisor as o, writeWorkspaceLaunch as p, clearExpoMetroTunnel as r, readMetroTunnel as s, MODE_BARE as t, readRemoteSessionId as u };
145
+ export { clearRemoteSession as a, readMetroTunnel as c, readRemoteSessionId as d, readWorkspaceLaunches as f, clearManagedMetroTunnel as i, readPidFile as l, writeWorkspaceLaunch as m, MODE_EXPO as n, clearWorkspaceLaunches as o, writePidFile as p, clearExpoMetroTunnel as r, clearWorkspaceSupervisor as s, MODE_BARE as t, readRemoteSession as u };
@@ -1,4 +1,4 @@
1
- import { T as withConfigLock, u as getConfigDir } from "./config-BEq0Qw_a.mjs";
1
+ import { E as withConfigLock, d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { basename, dirname, join, relative, resolve } from "node:path";
4
4
  const PLATFORMS = ["ios", "android"];
@@ -1,7 +1,7 @@
1
- import { s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
2
- import { o as findProjectRoot } from "./project-BXZzOABt.mjs";
3
- import { o as formatLongDuration } from "./command-output-D5z2_bcF.mjs";
4
- import { a as statsProjectKey, r as readStats } from "./stats-BAgJaLA4.mjs";
1
+ import { s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
2
+ import { i as findProjectRoot } from "./project-B8rbutVC.mjs";
3
+ import { o as formatLongDuration } from "./command-output-BWCj5Vh-.mjs";
4
+ import { a as statsProjectKey, r as readStats } from "./stats-D8rUTPHd.mjs";
5
5
  import chalk from "chalk";
6
6
  //#region src/commands/stats.ts
7
7
  const PLATFORMS = ["ios", "android"];
@@ -1,5 +1,5 @@
1
- import { H as projectDeviceSlots } from "./config-BEq0Qw_a.mjs";
2
- import { a as formatElapsed, o as formatLongDuration, r as clockTime, u as plural } from "./command-output-D5z2_bcF.mjs";
1
+ import { U as projectDeviceSlots, z as deviceSlotKey } from "./config-0jCcMM0E.mjs";
2
+ import { a as formatElapsed, o as formatLongDuration, r as clockTime, u as plural } from "./command-output-BWCj5Vh-.mjs";
3
3
  import { sep } from "path";
4
4
  //#region src/status.ts
5
5
  const IOS_SIM_MB = 1500;
@@ -22,7 +22,27 @@ function poolLine({ platform, parked, max }) {
22
22
  const what = plural(parked, `parked ${platform === "ios" ? "iOS simulator" : "Android emulator"}`);
23
23
  return max > 0 ? `pool: ${what} (max ${max})` : `pool: ${what} (parking off; gc --delete removes them)`;
24
24
  }
25
- function environmentState(project, { simsByUdid = {}, metro = null, worktrees = [], simsAvailable = true, androidRuntime = null, androidRuntimes = {}, supervisor = null, logs = null, remote = null, idleStop = null } = {}) {
25
+ const RECENT_LAUNCH_MS = 18e5;
26
+ function avdExpected({ slot, serial, launches, leasedIds, running, now }) {
27
+ if (serial && leasedIds.has(serial)) return true;
28
+ const launch = launches[deviceSlotKey("android", slot)];
29
+ if (!launch) return false;
30
+ return running || now - Date.parse(launch.launchedAt) < 18e5;
31
+ }
32
+ function androidStatus(android, androidRuntime, androidDeviceProfile) {
33
+ if (!android) return null;
34
+ return {
35
+ name: android.avdName ?? android.serial,
36
+ owned: Boolean(android.owned),
37
+ physical: Boolean(android.serial && !android.avdName),
38
+ ...androidRuntime ? {
39
+ serial: androidRuntime.serial,
40
+ state: androidRuntime.state
41
+ } : {},
42
+ ...androidDeviceProfile ? { deviceProfile: androidDeviceProfile } : {}
43
+ };
44
+ }
45
+ function environmentState(project, { simsByUdid = {}, metro = null, worktrees = [], simsAvailable = true, androidRuntime = null, androidRuntimes = {}, androidDeviceProfile = null, androidDeviceProfiles = {}, supervisor = null, logs = null, remote = null, idleStop = null, launches = {}, leasedIds = /* @__PURE__ */ new Set(), now = Date.now(), slot = "default", workspaceRunning = false } = {}) {
26
46
  const ios = project.platforms?.ios;
27
47
  const android = project.platforms?.android;
28
48
  const sim = ios ? simsByUdid[ios.deviceUdid] : null;
@@ -34,20 +54,35 @@ function environmentState(project, { simsByUdid = {}, metro = null, worktrees =
34
54
  if (simBooted) memoryMb += IOS_SIM_MB;
35
55
  if (androidDetected) memoryMb += ANDROID_EMULATOR_MB;
36
56
  if (metroRunning) memoryMb += METRO_MB;
37
- const warnings = [];
38
- if (metro?.notOurs) warnings.push(`port ${project.metroPort}: ${metro.notOurs}`);
39
- if (ios && !sim && simsAvailable) warnings.push(`recorded sim ${ios.deviceUdid} no longer exists`);
40
- if (simBooted && project.metroPort && !metroRunning) warnings.push("simulator is booted with no Metro serving it");
57
+ const running = workspaceRunning || metroRunning || supervisor?.status === "ours";
58
+ const issues = [];
59
+ const add = (code, message, remedy, severity = "warning") => issues.push({
60
+ code,
61
+ severity,
62
+ message,
63
+ remedy,
64
+ workspace: project.__path,
65
+ ...slot === "default" ? {} : { slot }
66
+ });
67
+ const slotFlag = slot === "default" ? "" : ` --slot ${slot}`;
68
+ if (metro?.notOurs && slot === "default") add("port-not-ours", `port ${project.metroPort}: ${metro.notOurs}`, "stim guide errors teardown", "error");
69
+ if (ios && !sim && simsAvailable) add("sim-missing", `recorded sim ${ios.deviceUdid} no longer exists`, `stim ios${slotFlag}`);
70
+ if (simBooted && project.metroPort && !metroRunning) add("sim-without-metro", "simulator is booted with no Metro serving it", "stim start");
41
71
  if (androidRuntime && android?.avdName) {
42
72
  const recordedSerial = android.consolePort ? `emulator-${android.consolePort}` : android.serial;
43
- if (androidRuntime.serial && recordedSerial && androidRuntime.serial !== recordedSerial) warnings.push(`owned AVD ${android.avdName} changed serial (${recordedSerial} -> ${androidRuntime.serial}); rerun your \`stim android\` command in this workspace to restore Metro forwarding, then reopen agent-device on ${androidRuntime.serial}`);
44
- if (androidRuntime.state === "missing") warnings.push(`recorded AVD ${android.avdName} no longer exists`);
45
- if (androidRuntime.state === "not-detected") warnings.push(`owned AVD ${android.avdName} is not detected by adb; rerun your \`stim android\` command in this workspace to reconnect`);
46
- if (androidRuntime.error) warnings.push(`could not check owned AVD ${android.avdName}: ${androidRuntime.error}`);
73
+ const expected = avdExpected({
74
+ slot,
75
+ serial: recordedSerial,
76
+ launches,
77
+ leasedIds,
78
+ running,
79
+ now
80
+ });
81
+ for (const [code, message] of androidIssues(android, recordedSerial, androidRuntime, expected)) add(code, message, code === "avd-unchecked" ? "stim doctor" : `stim android${slotFlag}`);
47
82
  }
48
- if (supervisor && supervisor.alive === false) warnings.push(`stale supervisor record for ${project.__path}`);
83
+ if (supervisor?.status === "unverified") add("supervisor-unverified", `supervisor pid ${supervisor.pid} could not be verified${supervisor.reason ? `: ${supervisor.reason}` : ""}`, "stim guide errors teardown", "error");
49
84
  const slots = [];
50
- for (const { slot, platforms } of projectDeviceSlots(project).slice(1)) {
85
+ for (const { slot: name, platforms } of projectDeviceSlots(project).slice(1)) {
51
86
  const deviceState = environmentState({
52
87
  ...project,
53
88
  platforms,
@@ -56,45 +91,44 @@ function environmentState(project, { simsByUdid = {}, metro = null, worktrees =
56
91
  simsByUdid,
57
92
  simsAvailable,
58
93
  metro,
59
- androidRuntime: androidRuntimes[slot]
94
+ androidRuntime: androidRuntimes[name],
95
+ androidDeviceProfile: androidDeviceProfiles[name],
96
+ launches,
97
+ leasedIds,
98
+ now,
99
+ slot: name,
100
+ workspaceRunning: running
60
101
  });
61
102
  slots.push({
62
- slot,
103
+ slot: name,
63
104
  ios: deviceState.ios,
64
105
  android: deviceState.android
65
106
  });
66
107
  memoryMb += deviceState.memoryMb - (metroRunning ? METRO_MB : 0);
67
108
  live ||= deviceState.live;
68
- warnings.push(...deviceState.warnings.map((warning) => `${slot}: ${warning}`));
109
+ issues.push(...deviceState.issues);
69
110
  }
70
111
  return {
71
112
  path: project.__path,
72
113
  ...slots.length ? { slots } : {},
73
114
  live,
74
115
  memoryMb,
75
- warnings,
116
+ warnings: issues.map(issueText),
117
+ issues,
76
118
  ios: ios ? {
77
119
  name: sim?.name ?? null,
78
120
  udid: ios.deviceUdid,
79
121
  owned: Boolean(ios.owned),
80
122
  state: sim?.state ?? (simsAvailable ? "missing" : "unknown")
81
123
  } : null,
82
- android: android ? {
83
- name: android.avdName ?? android.serial,
84
- owned: Boolean(android.owned),
85
- physical: Boolean(android.serial && !android.avdName),
86
- ...androidRuntime ? {
87
- serial: androidRuntime.serial,
88
- state: androidRuntime.state
89
- } : {}
90
- } : null,
124
+ android: androidStatus(android, androidRuntime, androidDeviceProfile),
91
125
  metro: project.metroPort ? {
92
126
  port: project.metroPort,
93
127
  running: metroRunning,
94
128
  pid: metro?.metro?.pid ?? null,
95
129
  ...idleStop && !metroRunning ? { idleStop } : {}
96
130
  } : null,
97
- supervisor: supervisor ? {
131
+ supervisor: supervisor && supervisor.status !== "stale" ? {
98
132
  pid: supervisor.pid ?? null,
99
133
  mode: supervisor.mode ?? null,
100
134
  startedAt: supervisor.startedAt ?? null,
@@ -108,6 +142,17 @@ function environmentState(project, { simsByUdid = {}, metro = null, worktrees =
108
142
  remoteDevices: remote ? [remote] : []
109
143
  };
110
144
  }
145
+ function androidIssues(android, recordedSerial, runtime, expected) {
146
+ const issues = [];
147
+ if (runtime.serial && recordedSerial && runtime.serial !== recordedSerial) issues.push(["avd-serial-changed", `owned AVD ${android.avdName} changed serial (${recordedSerial} -> ${runtime.serial}), so Metro forwarding is lost; rerun with the same build options, then reopen agent-device on ${runtime.serial}`]);
148
+ if (runtime.state === "missing") issues.push(["avd-missing", `recorded AVD ${android.avdName} no longer exists`]);
149
+ if (runtime.state === "not-detected" && expected) issues.push(["avd-not-detected", `owned AVD ${android.avdName} is not detected by adb`]);
150
+ if (runtime.error) issues.push(["avd-unchecked", `could not check owned AVD ${android.avdName}: ${runtime.error}`]);
151
+ return issues;
152
+ }
153
+ function issueText(issue) {
154
+ return `${issue.slot ? `${issue.slot}: ` : ""}${issue.message}; run \`${issue.remedy}\``;
155
+ }
111
156
  function activityLabel(activity, now) {
112
157
  if (!activity) return null;
113
158
  if (activity.state === "driven") {
@@ -227,4 +272,4 @@ function deviceLeaseLines(states, now) {
227
272
  return lines;
228
273
  }
229
274
  //#endregion
230
- export { diskLine as a, gitSummaryText as c, remoteDeviceLine as d, remoteDeviceState as f, deviceLeaseStates as i, parseDfFree as l, unprovisionedWorktrees as m, capacity as n, environmentState as o, tightVolumes as p, deviceLeaseLines as r, formatSpace as s, activityLabel as t, poolLine as u };
275
+ export { deviceLeaseStates as a, formatSpace as c, poolLine as d, remoteDeviceLine as f, unprovisionedWorktrees as h, deviceLeaseLines as i, gitSummaryText as l, tightVolumes as m, activityLabel as n, diskLine as o, remoteDeviceState as p, capacity as r, environmentState as s, RECENT_LAUNCH_MS as t, parseDfFree as u };
@@ -1,22 +1,22 @@
1
- import { F as volumeRootFor, H as projectDeviceSlots, g as loadConfig$1, u as getConfigDir } from "./config-BEq0Qw_a.mjs";
1
+ import { I as volumeRootFor, U as projectDeviceSlots, _ as loadConfig$1, d as getConfigDir } from "./config-0jCcMM0E.mjs";
2
2
  import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
3
3
  import { a as parseNdjsonLine } from "./ndjson-CDY9IkVC.mjs";
4
- import { A as workspaceLogErrorIndex, a as processCwd, j as workspaceLogsDir, l as isMetroRunning, m as readWorkspaceState$1, n as listeningPids, o as processCwds, r as listeningPidsByPort, s as resolveProjectMetro } from "./metro-BWLOJ_Wr.mjs";
5
- import { c as gitCommonDirOnDisk, p as linkedWorktreesOnDisk, s as gitCommonDir, y as repoRoot } from "./worktree-BlizKDpZ.mjs";
6
- import { l as projectShortcut, o as findProjectRoot } from "./project-BXZzOABt.mjs";
7
- import { l as readRemoteSession } from "./state-WGdIbi_d.mjs";
8
- import { i as formatDuration } from "./command-output-D5z2_bcF.mjs";
9
- import { i as listLeaseFiles } from "./device-lease-D83nqeMX.mjs";
10
- import { n as createActivityReader } from "./activity-BtG4Va9l.mjs";
11
- import { I as ownedAvdSerialResolver, l as androidToolPath } from "./android-C4zG2Tuc.mjs";
12
- import { b as readParked, h as POOL_SETTING_REMEDY, t as resolveSupervisorTarget, y as parkedMaxSetting } from "./ownership-BiojdtAp.mjs";
13
- import { _ as parseSimctlList, u as listAllIosSimsAsync } from "./ios-DArbmwer.mjs";
14
- import { a as buildStatusLine, i as buildReport, r as activeBuildState, s as parseActiveBuild, t as ACTIVE_BUILD_KEY } from "./build-progress-CDwogz6R.mjs";
15
- import { m as readEasSessionLedger$1, p as easMachineStateRoot$1 } from "./device-remote-BQZSnnmE.mjs";
16
- import { a as diskLine, c as gitSummaryText, d as remoteDeviceLine, f as remoteDeviceState, i as deviceLeaseStates, l as parseDfFree, m as unprovisionedWorktrees, n as capacity, o as environmentState, p as tightVolumes, r as deviceLeaseLines, t as activityLabel, u as poolLine } from "./status-Q-WDEGCB.mjs";
17
- import { a as statsProjectKey, r as readStats } from "./stats-BAgJaLA4.mjs";
18
- import { n as mergeState } from "./merge-state-DDxS-XIZ.mjs";
19
- import { i as readSupervisorState } from "./stop-DIhrvu0B.mjs";
4
+ import { A as workspaceLogErrorIndex, a as processCwd, j as workspaceLogsDir, l as isMetroRunning, m as readWorkspaceState$1, n as listeningPids, o as processCwds, r as listeningPidsByPort, s as resolveProjectMetro } from "./metro-Dzo30hvJ.mjs";
5
+ import { c as gitCommonDirOnDisk, p as linkedWorktreesOnDisk, s as gitCommonDir, y as repoRoot } from "./worktree-DeBQSVtR.mjs";
6
+ import { i as findProjectRoot, s as projectShortcut } from "./project-B8rbutVC.mjs";
7
+ import { f as readWorkspaceLaunches, u as readRemoteSession } from "./state-DcDgzfu3.mjs";
8
+ import { i as formatDuration } from "./command-output-BWCj5Vh-.mjs";
9
+ import { i as listLeaseFiles } from "./device-lease-B9LAXIUH.mjs";
10
+ import { n as createActivityReader } from "./activity-CCZJs__P.mjs";
11
+ import { L as ownedAvdSerialResolver, N as ownedAvdDeviceProfile, u as androidToolPath } from "./android-75Sk2rIR.mjs";
12
+ import { b as readParked, h as POOL_SETTING_REMEDY, t as resolveSupervisorTarget, y as parkedMaxSetting } from "./ownership-B8d4kXBx.mjs";
13
+ import { _ as parseSimctlList, u as listAllIosSimsAsync } from "./ios-CZWOHTTc.mjs";
14
+ import { a as buildStatusLine, i as buildReport, r as activeBuildState, s as parseActiveBuild, t as ACTIVE_BUILD_KEY } from "./build-progress-h60GPV27.mjs";
15
+ import { T as readEasSessionLedger$1, w as easMachineStateRoot$1 } from "./device-remote-C0_o-tJH.mjs";
16
+ import { a as deviceLeaseStates, d as poolLine, f as remoteDeviceLine, h as unprovisionedWorktrees, i as deviceLeaseLines, l as gitSummaryText, m as tightVolumes, n as activityLabel, o as diskLine, p as remoteDeviceState, r as capacity, s as environmentState, u as parseDfFree } from "./status-BUASYyy_.mjs";
17
+ import { a as statsProjectKey, r as readStats } from "./stats-D8rUTPHd.mjs";
18
+ import { n as mergeState } from "./merge-state-ytFQCeh4.mjs";
19
+ import { i as readSupervisorState } from "./stop-Bn6v-GvS.mjs";
20
20
  import { mkdirSync, readFileSync, readdirSync, renameSync, rmSync, watch, writeFileSync } from "node:fs";
21
21
  import { closeSync as closeSync$1, existsSync as existsSync$1, fstatSync as fstatSync$1, openSync as openSync$1, readFileSync as readFileSync$1, readSync as readSync$1, renameSync as renameSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
22
22
  import { basename, dirname, join } from "path";
@@ -611,7 +611,9 @@ async function statusLines(json, gitMaxAgeMs) {
611
611
  const androidRuntimeOf = androidRuntimeReader();
612
612
  const devices = projects.map(([, proj]) => ({
613
613
  androidRuntimes: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? androidRuntimeOf(platforms.android.avdName) : null])),
614
- androidRuntime: proj.platforms?.android?.owned && proj.platforms.android.avdName ? androidRuntimeOf(proj.platforms.android.avdName) : null
614
+ androidRuntime: proj.platforms?.android?.owned && proj.platforms.android.avdName ? androidRuntimeOf(proj.platforms.android.avdName) : null,
615
+ androidDeviceProfiles: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? ownedAvdDeviceProfile(platforms.android.avdName) : null])),
616
+ androidDeviceProfile: proj.platforms?.android?.owned && proj.platforms.android.avdName ? ownedAvdDeviceProfile(proj.platforms.android.avdName) : null
615
617
  }));
616
618
  const logs = projects.map(([path]) => logFacts(path));
617
619
  const simsByUdid = {};
@@ -629,9 +631,16 @@ async function statusLines(json, gitMaxAgeMs) {
629
631
  const states = [];
630
632
  const labelOnlyRoots = [];
631
633
  const easLedger = readEasSessionLedger$1();
634
+ const leaseNow = Date.now();
635
+ const leaseFiles = listLeaseFiles();
636
+ const leases = deviceLeaseStates(leaseFiles, {
637
+ root: cwdRoot,
638
+ now: leaseNow
639
+ });
632
640
  for (const [i, [path, proj]] of projects.entries()) {
633
641
  const { metro, supervisor } = running[i];
634
642
  const saved = readWorkspaceState$1(path);
643
+ const builds = workspaceBuilds(path, saved, history);
635
644
  states.push(environmentState({
636
645
  ...proj,
637
646
  __path: path
@@ -644,10 +653,16 @@ async function statusLines(json, gitMaxAgeMs) {
644
653
  supervisor,
645
654
  logs: logs[i],
646
655
  remote: remoteDeviceState(readRemoteSession(path), easLedger, path),
647
- idleStop: readIdleStop(saved)
656
+ idleStop: readIdleStop(saved),
657
+ launches: readWorkspaceLaunches(path),
658
+ leasedIds: new Set(deviceLeaseStates(leaseFiles, {
659
+ root: path,
660
+ now: leaseNow
661
+ }).flatMap((lease) => lease.mine && !lease.expired && lease.id ? [lease.id] : [])),
662
+ now: leaseNow
648
663
  }));
649
664
  const state = states[states.length - 1];
650
- if (state) Object.assign(state, workspaceBuilds(path, saved, history));
665
+ if (state) Object.assign(state, builds);
651
666
  labelOnlyRoots.push(Boolean(proj.worktreeRoot && !proj.bundleId && !state?.metro && !state?.ios && !state?.android));
652
667
  }
653
668
  const readActivity = createActivityReader();
@@ -671,11 +686,6 @@ async function statusLines(json, gitMaxAgeMs) {
671
686
  id: device.android.serial
672
687
  });
673
688
  }
674
- const leaseNow = Date.now();
675
- const leases = deviceLeaseStates(listLeaseFiles(), {
676
- root: cwdRoot,
677
- now: leaseNow
678
- });
679
689
  const totalMemoryMb = Math.round(totalmem() / 1048576);
680
690
  const cap = capacity(states, totalMemoryMb);
681
691
  const pools = ["ios", "android"].map((platform) => {
@@ -932,13 +942,14 @@ async function supervisorFacts(path, proj, metroResolution, lookup) {
932
942
  const pid = state?.pid ?? record?.pid ?? null;
933
943
  if (!pid) return null;
934
944
  const port = state?.port ?? record?.port ?? null;
935
- const alive = resolveSupervisorTarget({
945
+ const target = resolveSupervisorTarget({
936
946
  state,
937
947
  record,
938
948
  reservedPort: proj?.metroPort
939
- }).status === "ours";
949
+ });
950
+ const status = target.status === "ours" ? "ours" : target.status === "unverified" ? "unverified" : "stale";
940
951
  let healthy = false;
941
- if (alive && port) {
952
+ if (status === "ours" && port) {
942
953
  const resolution = port === proj?.metroPort && metroResolution ? metroResolution : await resolveOnPort(port, path, lookup);
943
954
  healthy = Boolean(resolution?.metro);
944
955
  }
@@ -946,7 +957,8 @@ async function supervisorFacts(path, proj, metroResolution, lookup) {
946
957
  pid,
947
958
  mode: state?.mode ?? record?.mode ?? null,
948
959
  startedAt: state?.startedAt ?? record?.startedAt ?? null,
949
- alive,
960
+ status,
961
+ ...target.reason ? { reason: target.reason } : {},
950
962
  healthy
951
963
  };
952
964
  }
@@ -0,0 +1,29 @@
1
+ import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
2
+ //#region src/devices/stim-desktop.ts
3
+ const LAUNCH_SERVICES_LOOKUP = `ObjC.import('AppKit'); const url = $.NSWorkspace.sharedWorkspace.URLForApplicationWithBundleIdentifier('dev.stim.desktop'); url.isNil() ? '' : url.path.js`;
4
+ const STIM_DESKTOP_INSTALLED = "Stim Desktop installed";
5
+ function stimDesktopInstalled(platform = process.platform) {
6
+ if (platform !== "darwin") return false;
7
+ const found = getExecutor().runFileQuiet("osascript", [
8
+ "-l",
9
+ "JavaScript",
10
+ "-e",
11
+ LAUNCH_SERVICES_LOOKUP
12
+ ], {
13
+ timeoutMs: 5e3,
14
+ killSignal: "SIGKILL"
15
+ });
16
+ return Boolean(found);
17
+ }
18
+ function settingDefault(setting, desktopInstalled = stimDesktopInstalled) {
19
+ if (setting.desktopDefault !== void 0 && desktopInstalled()) return {
20
+ value: setting.desktopDefault,
21
+ reason: STIM_DESKTOP_INSTALLED
22
+ };
23
+ return {
24
+ value: setting.default,
25
+ reason: null
26
+ };
27
+ }
28
+ //#endregion
29
+ export { stimDesktopInstalled as n, settingDefault as t };