stim 1.34.0 → 1.35.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 (118) hide show
  1. package/dist/{acquire-artifact-B0SWoVNt.mjs → acquire-artifact-0E_iw7Rf.mjs} +1 -1
  2. package/dist/{act-7f7wIvCQ.mjs → act-CyxFP8Vj.mjs} +9 -10
  3. package/dist/{activity-DkS-Ir6V.mjs → activity-BQpJpAjA.mjs} +2 -2
  4. package/dist/{agent-device-usage-output-BVdgKbfz.mjs → agent-device-usage-output-BoOC3ZF9.mjs} +3 -3
  5. package/dist/{android-BU4uBX8I.mjs → android-CjcJE7uA.mjs} +5 -5
  6. package/dist/{android-D7qjT2fq.mjs → android-YRb1UzSy.mjs} +27 -29
  7. package/dist/api.mjs +21 -21
  8. package/dist/{artifact-CNnTZs3R.mjs → artifact-2NIRz6SC.mjs} +19 -15
  9. package/dist/{artifact-DmRtKFXW.mjs → artifact-BG4h_WTC.mjs} +11 -11
  10. package/dist/{auto-placement-DA65VQH7.mjs → auto-placement-CBdWa87P.mjs} +4 -5
  11. package/dist/{browser-web-Dn_hgKZC.mjs → browser-web-CNlRugJv.mjs} +5 -5
  12. package/dist/{build-D7SuVoRX.mjs → build-CNE3Wo5-.mjs} +15 -16
  13. package/dist/{build-cache-Cqj4FGnX.mjs → build-cache-_fkewiwH.mjs} +6 -1
  14. package/dist/{build-plan-Ct1FiA3E.mjs → build-plan-BSgR9yKo.mjs} +5 -5
  15. package/dist/{cli-DjdvQG5U.mjs → cli-DK24VzHi.mjs} +17 -17
  16. package/dist/cli.mjs +1 -1
  17. package/dist/{client-kU37gURU.mjs → client-Dy0eJJtz.mjs} +8 -7
  18. package/dist/{command-output-DjExb_tZ.mjs → command-output-CGxrQ3Bd.mjs} +1 -1
  19. package/dist/{dependencies-CZ7c8XX_.mjs → dependencies-IVl2Ga2D.mjs} +27 -30
  20. package/dist/{dev-client-D3wOllNd.mjs → dev-client-DDApoVvd.mjs} +2 -2
  21. package/dist/{device-android-ChfF5I9A.mjs → device-android-C-biM49_.mjs} +3 -3
  22. package/dist/{ccache-ChBMXlBq.mjs → device-capacity-C0PiTyRb.mjs} +1004 -21
  23. package/dist/device-host-worker.mjs +6 -7
  24. package/dist/{device-CWPFAqs0.mjs → device-mOFYiHiw.mjs} +8 -8
  25. package/dist/{device-DH5yf6TU.mjs → device-p_cp8IzW.mjs} +6 -6
  26. package/dist/{device-pool-EZziQ0uS.mjs → device-pool-nsMvt2X2.mjs} +2 -2
  27. package/dist/{device-provision-CfpEy-Vm.mjs → device-provision-BYYJuRKZ.mjs} +7 -7
  28. package/dist/{doctor-CGBsS_68.mjs → doctor-BBAb8NLe.mjs} +1 -1
  29. package/dist/{doctor-B5uEZiKp.mjs → doctor-BptE4PaK.mjs} +10 -11
  30. package/dist/{doctor-dwRboaXx.mjs → doctor-RosbBfTV.mjs} +11 -12
  31. package/dist/doctor-fingerprint.mjs +1 -1
  32. package/dist/{doctor-watchman-r7M9UPi0.mjs → doctor-watchman-CKOnCINh.mjs} +2 -2
  33. package/dist/{eas-build-BpHIt_M3.mjs → eas-build-BxJdzQnF.mjs} +2 -2
  34. package/dist/{eas-fallback-CNPcjq3K.mjs → eas-fallback-DU2WDF8r.mjs} +2 -2
  35. package/dist/{eas-session-ledger-CXwagcQ7.mjs → eas-session-ledger-DCUfh6m7.mjs} +1 -1
  36. package/dist/{error-diagnostics-Ym2mjmJ0.mjs → error-diagnostics-D6wlK-yX.mjs} +3 -3
  37. package/dist/{gc-C7YxKNci.mjs → gc-BUkonUfz.mjs} +10 -10
  38. package/dist/{gc-B464w_a5.mjs → gc-CvMEytXz.mjs} +2 -2
  39. package/dist/{guide-BFW-cB7R.mjs → guide-BWozWG7D.mjs} +21 -13
  40. package/dist/{hosted-android-B7yfqXEy.mjs → hosted-android-y6K3DKQT.mjs} +2 -2
  41. package/dist/{hosted-client-CQuzZwAu.mjs → hosted-client-Bb89P6an.mjs} +2 -2
  42. package/dist/{hosted-logs-DfYCqrrR.mjs → hosted-logs-DYPsnWMF.mjs} +2 -2
  43. package/dist/{hosted-logs-sync-Dlpa2mQF.mjs → hosted-logs-sync-DfUJ2GpF.mjs} +4 -4
  44. package/dist/{hosted-macos-JKefapEm.mjs → hosted-macos-DsEzYVY_.mjs} +4 -4
  45. package/dist/{hosted-native-B7OFt5gB.mjs → hosted-native-C9xQYYFb.mjs} +4 -4
  46. package/dist/{ios-sUPbWqEh.mjs → ios-BCKxjpRp.mjs} +8 -8
  47. package/dist/{ios-DSBs9c6d.mjs → ios-FhMkDfNC.mjs} +19 -21
  48. package/dist/{ios-device-Drplrgzo.mjs → ios-device-DMOnaH5n.mjs} +1 -1
  49. package/dist/{ios-project-DoTQYghg.mjs → ios-project-PXBDoaii.mjs} +5 -5
  50. package/dist/{ios-signing-R34vbrNU.mjs → ios-signing-CCFNjjWU.mjs} +1 -1
  51. package/dist/{js-swap-DrokhOfo.mjs → js-swap-07ikLRJJ.mjs} +3 -3
  52. package/dist/{launch-Cy-MWEZc.mjs → launch-CTq5gBim.mjs} +13 -13
  53. package/dist/{lightened-ALwQcQtV.mjs → lightened-DikgC3-S.mjs} +2 -2
  54. package/dist/{logs-DuED-01Z.mjs → logs-DwI3Rkpf.mjs} +5 -5
  55. package/dist/{logs-DWT7jGpF.mjs → logs-YDMfEohb.mjs} +3 -3
  56. package/dist/{macos-CtBtA_hW.mjs → macos-BoNM-l6f.mjs} +14 -14
  57. package/dist/{macos-kWGcfLzx.mjs → macos-C_e9f5-5.mjs} +1 -1
  58. package/dist/maintenance-run.mjs +3 -3
  59. package/dist/{native-android-tISP2EVp.mjs → native-android-Mv4YTrVN.mjs} +11 -11
  60. package/dist/{native-gradle-artifact-inputs-DVoeZkrw.mjs → native-gradle-artifact-inputs-C_TU6wPq.mjs} +2 -2
  61. package/dist/{native-runtime-CNgxeOCG.mjs → native-runtime-oDqT4UES.mjs} +3 -3
  62. package/dist/{native-xcode-inputs-DGzkhpu4.mjs → native-xcode-inputs-DsozghTX.mjs} +1 -1
  63. package/dist/{native-xcode-ios-B9nsfId2.mjs → native-xcode-ios-UXnH9NRY.mjs} +13 -13
  64. package/dist/offload-worker.mjs +15 -15
  65. package/dist/{phone-reverses-Bo0EzJ-P.mjs → phone-reverses-B9WyCBKQ.mjs} +1 -1
  66. package/dist/{placement-log-BsGvKLtU.mjs → placement-log-D0DZLcJk.mjs} +1 -1
  67. package/dist/{plan-placement-Am0IjuxB.mjs → plan-placement-DqmLrWoX.mjs} +4 -4
  68. package/dist/{ports-CNzg1LYD.mjs → ports-C1_1Qgdy.mjs} +1 -1
  69. package/dist/{prebuild-BfJII57G.mjs → prebuild-BptrXmh_.mjs} +6 -6
  70. package/dist/{project-DU3jjnBE.mjs → project-Dqqj3IkW.mjs} +11 -11
  71. package/dist/{react-native-android-3dZiJv-4.mjs → react-native-android-Bsm_o4A8.mjs} +18 -18
  72. package/dist/{react-native-build-CuvNPt-q.mjs → react-native-build-BTUcE926.mjs} +4 -4
  73. package/dist/{react-native-doctor-a35BwMUO.mjs → react-native-doctor-CfsCTKZt.mjs} +4 -4
  74. package/dist/{react-native-ios-CqnReM1t.mjs → react-native-ios-_cK2pjZn.mjs} +24 -19
  75. package/dist/{reload-YPnvXGlB.mjs → reload-CXgce4Yo.mjs} +1 -1
  76. package/dist/{reload-CC3sNo10.mjs → reload-DsTMtMDU.mjs} +6 -6
  77. package/dist/{remote-BfaIHnhM.mjs → remote-BsmYHUxH.mjs} +6 -6
  78. package/dist/{result-H-AxY7Ud.mjs → result-DK6nTO-M.mjs} +9 -10
  79. package/dist/{server-command-Bn_gOObU.mjs → server-command-Cu2w-UjB.mjs} +2 -2
  80. package/dist/{server-expo-CUJ2fuv1.mjs → server-expo-CjQwxvIi.mjs} +1 -1
  81. package/dist/server-expo-DbSypdNl.mjs +2 -0
  82. package/dist/{settings-DoWHJopy.mjs → settings-DcmVICCn.mjs} +2 -2
  83. package/dist/{settings-payload-Bxw3hid5.mjs → settings-payload-BoiFMiFq.mjs} +1 -1
  84. package/dist/{settings-write-C6d7EC54.mjs → settings-write-B3LzEVwf.mjs} +2 -2
  85. package/dist/{slot-launch-kq0-7w9C.mjs → slot-launch-DsQmPdlg.mjs} +2 -2
  86. package/dist/{stage-CBfMTUK3.mjs → stage-Dqk0qvaI.mjs} +1 -1
  87. package/dist/{start-WTMumMHi.mjs → start-DIFiT2P5.mjs} +5 -5
  88. package/dist/{start-Diu8q6_U.mjs → start-GkRBR1e3.mjs} +1 -1
  89. package/dist/{stats-D4cW247z.mjs → stats-Dz08IopP.mjs} +3 -3
  90. package/dist/{status-CEwxo-PS.mjs → status-DhKv_e8a.mjs} +11 -12
  91. package/dist/{status-B-oeWS0Z.mjs → status-Dost__Vn.mjs} +1 -1
  92. package/dist/{status-watch-D63R5nSI.mjs → status-watch-UecLnPQD.mjs} +1 -1
  93. package/dist/status-worker.mjs +1 -1
  94. package/dist/{stop-HL2RvhrE.mjs → stop-CcZISot5.mjs} +2 -2
  95. package/dist/{stop-Dm9ON6Os.mjs → stop-QFOqgICJ.mjs} +2 -2
  96. package/dist/{stop-vX4w3_8V.mjs → stop-vRe6TQk5.mjs} +9 -9
  97. package/dist/supervisor-run.mjs +7 -8
  98. package/dist/{support-BNe1_Hg7.mjs → support-CNqJDBrH.mjs} +3 -3
  99. package/dist/support-DW575Dnx.mjs +2050 -0
  100. package/dist/{swiftpm-artifact-inputs-uq5oV7xR.mjs → swiftpm-artifact-inputs-DQTJTczX.mjs} +1 -1
  101. package/dist/{swiftpm-macos-ClF203_2.mjs → swiftpm-macos-BKczZ0k9.mjs} +4 -4
  102. package/dist/{toolchain-CECahBDa.mjs → toolchain-BDlugtoh.mjs} +1 -1
  103. package/dist/{toolchain-CYonNjd_.mjs → toolchain-DRQyCvlp.mjs} +2 -2
  104. package/dist/web-D1m1LKEz.mjs +2 -0
  105. package/dist/{web-BdaMBr2O.mjs → web-TDWjHUT3.mjs} +3 -3
  106. package/dist/web-run.mjs +1 -1
  107. package/dist/{workspaces-B9v5V7Es.mjs → workspaces-CY3KSdC0.mjs} +2 -2
  108. package/dist/{worktree-C4MBOMz7.mjs → worktree-D6myrQ2H.mjs} +1 -1
  109. package/dist/{worktree-C3N86KpI.mjs → worktree-fKKe8j5M.mjs} +10 -10
  110. package/package.json +7 -7
  111. package/dist/device-capacity-CHC3dKWg.mjs +0 -867
  112. package/dist/device-ios-B3-Ah--R.mjs +0 -716
  113. package/dist/device-lease-run-i3FNX4OE.mjs +0 -282
  114. package/dist/idle-shutdown-DPD8oV36.mjs +0 -142
  115. package/dist/selection-CH-MUVGD.mjs +0 -791
  116. package/dist/server-expo-B59N16uT.mjs +0 -2
  117. package/dist/support-ivsfDj0v.mjs +0 -287
  118. package/dist/web-CIpHpGp8.mjs +0 -2
@@ -1,282 +0,0 @@
1
- import { C as operationState } from "./exec-CGuDzt40.mjs";
2
- import { a as formatElapsed, r as clockTime } from "./command-output-DjExb_tZ.mjs";
3
- import { dt as deviceSlotKey } from "./config-BW0fAtoK.mjs";
4
- import { Xt as APP_READINESS_TIMEOUT_MS, zt as MANIFEST_VERIFY_TIMEOUT_MS } from "./ccache-ChBMXlBq.mjs";
5
- import { E as releaseRunLease, S as parseLease, T as raiseLease, b as leaseIsExpired, j as takeLease, v as deviceLeasePath, y as fileLeaseIo } from "./activity-DkS-Ir6V.mjs";
6
- //#region src/engine/device-lease-run.ts
7
- const LEASE_STEP_FLOOR_MS = 6e4;
8
- const DEBUG_VERIFY_STEP_MS = MANIFEST_VERIFY_TIMEOUT_MS + APP_READINESS_TIMEOUT_MS;
9
- const DEVICE_WAIT_POLL_MS = 2e3;
10
- const DEVICE_WAIT_LINE_MS = 3e4;
11
- const DEVICE_BUSY = "STIM_DEVICE_BUSY";
12
- const DEVICE_LOST = "STIM_DEVICE_LOST";
13
- function leaseStepMs(boundMs = 0) {
14
- return Math.max(LEASE_STEP_FLOOR_MS, boundMs);
15
- }
16
- function parseDeviceWait(value) {
17
- if (value === void 0 || value === null) return { seconds: 60 };
18
- const seconds = String(value).trim() === "" ? NaN : Number(value);
19
- if (!Number.isInteger(seconds) || seconds < 0) return { error: `Invalid --wait value ${JSON.stringify(value)}. Pass a whole number of seconds, e.g. --wait 90.` };
20
- return { seconds };
21
- }
22
- function waitFlagConflict(argv) {
23
- return argv.some((arg) => arg === "--wait" || arg.startsWith("--wait=")) && argv.includes("--no-wait");
24
- }
25
- function leaseExpiryText(expiresAt, now) {
26
- const remaining = Date.parse(expiresAt) - now;
27
- return `${clockTime(expiresAt)} (${formatElapsed(Math.max(0, remaining))} from now)`;
28
- }
29
- function describeDevice(lease) {
30
- return lease.deviceName ? `${lease.deviceName} (${lease.id})` : lease.id;
31
- }
32
- function facts(lease) {
33
- return {
34
- platform: lease.platform,
35
- id: lease.id,
36
- deviceName: lease.deviceName,
37
- holder: lease.holder,
38
- expiresAt: lease.expiresAt
39
- };
40
- }
41
- function waitingLine(lease, now) {
42
- return `waiting for ${lease.holder} to release ${describeDevice(lease)}; its lease runs until ${leaseExpiryText(lease.expiresAt, now)} -- stim guide lifecycle lease`;
43
- }
44
- function appIdMatch(ours, theirs) {
45
- if (!ours || !theirs) return "unknown";
46
- return ours === theirs ? "same" : "different";
47
- }
48
- function bypassLines(lease, now, match) {
49
- const consequence = {
50
- same: "Both workspaces build the same app id, so this install terminates the app that workspace is running.",
51
- different: "The other workspace's app id differs, so the launch below backgrounds it rather than ending it.",
52
- unknown: "Stim cannot tell whether the two workspaces build the same app id; if they do, this install terminates the holder's running app."
53
- }[match];
54
- return [`--no-wait: ${lease.holder} holds ${describeDevice(lease)} until ${leaseExpiryText(lease.expiresAt, now)}, and this run is proceeding without a lease.`, consequence];
55
- }
56
- function busyRefusal({ lease, now, idLabel, waitSeconds }) {
57
- return {
58
- code: DEVICE_BUSY,
59
- message: `${lease.holder} holds ${describeDevice(lease)} until ${leaseExpiryText(lease.expiresAt, now)}` + (waitSeconds > 0 ? `, and this command waited ${waitSeconds}s for it.` : "."),
60
- remedy: `Wait longer with \`--wait <seconds>\`, pick another device with \`--device <${idLabel}>\`, or pass \`--no-wait\` to install anyway -- which takes no lease and, when both workspaces build the same app id, terminates the holder's running app.`,
61
- lease: facts(lease)
62
- };
63
- }
64
- function unreadableRefusal(path) {
65
- return {
66
- code: DEVICE_BUSY,
67
- message: `The lease file at ${path} does not parse, so Stim cannot tell who holds that device.`,
68
- remedy: `Read ${path} and, once you know no run depends on it, delete it. \`stim gc\` reports it on every run.`,
69
- lease: {
70
- platform: null,
71
- id: null,
72
- deviceName: null,
73
- holder: null,
74
- expiresAt: null
75
- }
76
- };
77
- }
78
- function untokenedRefusal(lease, now) {
79
- return {
80
- code: DEVICE_BUSY,
81
- message: `This workspace holds ${describeDevice(lease)} until ${leaseExpiryText(lease.expiresAt, now)}, but its own record of that lease is gone, so this run cannot prove the lease is still its own.`,
82
- remedy: "Run `stim device unlock`, which releases by holder, then run this command again.",
83
- lease: facts(lease)
84
- };
85
- }
86
- function otherDeviceRefusal(leasedId, requestedId) {
87
- return {
88
- code: "STIM_NO_DEVICE",
89
- message: `This workspace already leases ${leasedId}, and this run asked for ${requestedId}.`,
90
- remedy: `Run \`stim device unlock\` to give up ${leasedId}, or use it with \`--device ${leasedId}\`.`,
91
- lease: null
92
- };
93
- }
94
- function lostLine(holder, expiresAt, now) {
95
- return `${holder ?? "another workspace"} took this device's lease${expiresAt ? ` until ${leaseExpiryText(expiresAt, now)}` : ""}. The app is already installed, so this run continues without one.`;
96
- }
97
- function lostRefusal(holder, expiresAt, now) {
98
- const who = holder ?? "another workspace";
99
- const until = expiresAt ? ` until ${leaseExpiryText(expiresAt, now)}` : "";
100
- return {
101
- code: DEVICE_LOST,
102
- message: `${who} took this device's lease${until} before this run could install.`,
103
- remedy: "Run this command again; it waits for that lease with `--wait <seconds>`.",
104
- lease: null
105
- };
106
- }
107
- function runLease({ root, platform, slot = "default", kind, expiresAt, io = fileLeaseIo }) {
108
- const handle = {
109
- kind,
110
- expiresAt,
111
- lost: false,
112
- raise(boundMs) {
113
- if (handle.kind === null || handle.lost) return {
114
- ok: !handle.lost,
115
- holder: null,
116
- expiresAt: handle.expiresAt
117
- };
118
- const result = raiseLease({
119
- root,
120
- platform,
121
- slot,
122
- minMs: leaseStepMs(boundMs)
123
- }, io);
124
- if (result.status === "raised") {
125
- handle.expiresAt = result.lease.expiresAt;
126
- return {
127
- ok: true,
128
- holder: result.lease.holder,
129
- expiresAt: result.lease.expiresAt
130
- };
131
- }
132
- handle.lost = true;
133
- const taken = result.status === "lost" ? result.lease : null;
134
- return {
135
- ok: false,
136
- holder: taken?.holder ?? null,
137
- expiresAt: taken?.expiresAt ?? null
138
- };
139
- },
140
- release() {
141
- if (handle.kind === null) return;
142
- releaseRunLease({
143
- root,
144
- platform,
145
- slot
146
- }, io);
147
- },
148
- facts() {
149
- if (handle.kind === null || handle.lost || handle.expiresAt === null) return null;
150
- return {
151
- kind: handle.kind,
152
- expiresAt: handle.expiresAt
153
- };
154
- }
155
- };
156
- return handle;
157
- }
158
- /** Release the run's lease as soon as `context`'s operation is aborted; returns a function that stops listening. */
159
- function releaseLeaseOnAbort(context, release) {
160
- const onAbort = () => {
161
- operationState(context).handled = true;
162
- release();
163
- };
164
- if (context.signal.aborted) onAbort();
165
- else context.signal.addEventListener("abort", onAbort, { once: true });
166
- return () => context.signal.removeEventListener("abort", onAbort);
167
- }
168
- async function waitForDevice({ root, platform, slot = "default", id, idLabel, waitSeconds, noWait = false, appId = null, holderAppId = () => null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo, deadline, lastLine }) {
169
- const path = deviceLeasePath(platform, id);
170
- for (;;) {
171
- const raw = io.readLease(path);
172
- const current = parseLease(raw);
173
- if (raw !== null && !current) return {
174
- status: "refused",
175
- refusal: unreadableRefusal(path)
176
- };
177
- if (!current || leaseIsExpired(current, now())) return { status: "free" };
178
- if (current.holder === root && (current.slot ?? "default") === slot) return {
179
- status: "ours",
180
- lease: current
181
- };
182
- if (noWait) {
183
- for (const line of bypassLines(current, now(), appIdMatch(appId, holderAppId(current.holder)))) warn(line);
184
- return {
185
- status: "bypassed",
186
- lease: current
187
- };
188
- }
189
- if (now() >= deadline) return {
190
- status: "refused",
191
- refusal: busyRefusal({
192
- lease: current,
193
- now: now(),
194
- idLabel,
195
- waitSeconds
196
- })
197
- };
198
- if (lastLine.at === null || now() - lastLine.at >= 3e4) {
199
- lastLine.at = now();
200
- warn(waitingLine(current, now()));
201
- }
202
- await sleep(DEVICE_WAIT_POLL_MS);
203
- }
204
- }
205
- async function acquireRunLease({ root, platform, slot = "default", id, deviceName = null, idLabel, waitSeconds, noWait, installBoundMs, appId = null, holderAppId = () => null, now = Date.now, sleep = (ms) => new Promise((r) => setTimeout(r, ms)), warn = () => {}, io = fileLeaseIo }) {
206
- const recorded = io.readHolder(root)[deviceSlotKey(platform, slot)];
207
- let held = recorded;
208
- if (recorded && recorded.id !== id) {
209
- const other = parseLease(io.readLease(deviceLeasePath(platform, recorded.id)));
210
- if (other && other.token === recorded.token && !leaseIsExpired(other, now())) return {
211
- status: "refused",
212
- refusal: otherDeviceRefusal(recorded.id, id)
213
- };
214
- held = void 0;
215
- }
216
- const path = deviceLeasePath(platform, id);
217
- const deadline = now() + waitSeconds * 1e3;
218
- const lastLine = { at: null };
219
- for (;;) {
220
- const current = parseLease(io.readLease(path));
221
- const mine = current && held && current.token === held.token ? {
222
- lease: current,
223
- record: held
224
- } : null;
225
- if (mine && (mine.record.kind === "run" || !leaseIsExpired(mine.lease, now()))) {
226
- const raised = raiseLease({
227
- root,
228
- platform,
229
- slot,
230
- minMs: leaseStepMs(installBoundMs)
231
- }, io);
232
- if (raised.status === "raised") return {
233
- status: "leased",
234
- kind: mine.record.kind,
235
- expiresAt: raised.lease.expiresAt
236
- };
237
- }
238
- const outcome = await waitForDevice({
239
- root,
240
- platform,
241
- slot,
242
- id,
243
- idLabel,
244
- waitSeconds,
245
- noWait,
246
- appId,
247
- holderAppId,
248
- now,
249
- sleep,
250
- warn,
251
- io,
252
- deadline,
253
- lastLine
254
- });
255
- if (outcome.status === "refused") return outcome;
256
- if (outcome.status === "bypassed") return { status: "unleased" };
257
- if (outcome.status === "ours") return {
258
- status: "refused",
259
- refusal: untokenedRefusal(outcome.lease, now())
260
- };
261
- const taken = takeLease({
262
- root,
263
- platform,
264
- slot,
265
- id,
266
- deviceName,
267
- kind: "run",
268
- durationMs: leaseStepMs(installBoundMs)
269
- }, io);
270
- if (taken.status === "unreadable") return {
271
- status: "refused",
272
- refusal: unreadableRefusal(taken.path)
273
- };
274
- if (taken.status === "taken" || taken.status === "set") return {
275
- status: "leased",
276
- kind: taken.status === "set" ? held?.kind ?? "run" : "run",
277
- expiresAt: taken.lease.expiresAt
278
- };
279
- }
280
- }
281
- //#endregion
282
- export { acquireRunLease as a, lostRefusal as c, runLease as d, waitFlagConflict as f, DEVICE_WAIT_POLL_MS as i, parseDeviceWait as l, DEVICE_BUSY as n, leaseExpiryText as o, waitForDevice as p, DEVICE_WAIT_LINE_MS as r, lostLine as s, DEBUG_VERIFY_STEP_MS as t, releaseLeaseOnAbort as u };
@@ -1,142 +0,0 @@
1
- import { k as workspaceLogsDir$1, r as readWorkspaceState$1, s as updateWorkspaceStateAsync } from "./workspace-state-BdZ-QgmB.mjs";
2
- import { o as formatLongDuration } from "./command-output-DjExb_tZ.mjs";
3
- import { dt as deviceSlotKey, v as loadConfig$1 } from "./config-BW0fAtoK.mjs";
4
- import { i as createNdjsonWriter } from "./ndjson-CrjIsGzw.mjs";
5
- import { B as workspaceBuildInProgress, P as collectOwnedDeviceActivity, ht as teardownOwnedIosSim, pt as teardownOwnedAvd } from "./workspaces-B9v5V7Es.mjs";
6
- import { t as canonicalPath } from "./paths-BsJMoPP2.mjs";
7
- import { _ as workspaceDeviceLastUseAt } from "./activity-DkS-Ir6V.mjs";
8
- import { d as listAllIosSims } from "./ios-BdZdNsAj.mjs";
9
- import { join } from "node:path";
10
- import { LOG_ROTATE_BYTES } from "@stim-cli/core";
11
- import { DEVICE_IDLE_SHUTDOWN_KEY, DEVICE_RECLAIM_REASON, readDeviceIdleShutdowns } from "@stim-cli/core/state";
12
- //#region src/devices/idle-shutdown.ts
13
- const SIM_LIST_TIMEOUT_MS = 1e4;
14
- const MINUTE_MS = 6e4;
15
- /**
16
- * How long a booted owned device has been idle, when that is at least `idleMs` and nothing keeps it in use: no
17
- * driver, Stim or agent-device lock, or unreadable activity evidence, no build in the workspace, and no activity
18
- * (including an open stim-server viewer) for `idleMs`. Null keeps the device running.
19
- */
20
- function idleShutdownDueMs(activity, { idleMs, now, buildInProgress, platform = process.platform }) {
21
- if (buildInProgress || activity.state === "driven") return null;
22
- const unknown = platform === "win32" ? activity.basis.filter((basis) => basis !== "driver-process") : activity.basis;
23
- if (activity.state === "unknown" && unknown.length > 0) return null;
24
- const last = Date.parse(activity.lastActivityAt ?? "");
25
- if (!Number.isFinite(last)) return null;
26
- const idle = now - last;
27
- return idle >= idleMs ? idle : null;
28
- }
29
- function listSims() {
30
- try {
31
- return listAllIosSims({ timeoutMs: SIM_LIST_TIMEOUT_MS });
32
- } catch {
33
- return [];
34
- }
35
- }
36
- /** Booted owned devices idle for `idleMs`, in one workspace or all registered workspaces when root is absent. */
37
- function dueIdleDevices(root, idleMs, now = Date.now()) {
38
- const config = loadConfig$1();
39
- if (!config) return [];
40
- const self = root === void 0 ? void 0 : canonicalPath(root);
41
- const projects = Object.fromEntries(Object.entries(config.projects).filter(([path]) => {
42
- if (self !== void 0 && canonicalPath(path) !== self) return false;
43
- const usedAt = workspaceDeviceLastUseAt(path);
44
- return !Number.isFinite(usedAt) || now - usedAt >= idleMs;
45
- }));
46
- if (!Object.keys(projects).length) return [];
47
- const builds = new Map(Object.keys(projects).map((path) => [path, workspaceBuildInProgress(path)]));
48
- return collectOwnedDeviceActivity({
49
- ...config,
50
- projects
51
- }, listSims(), now).flatMap((device) => {
52
- const idleForMs = idleShutdownDueMs(device.activity, {
53
- idleMs,
54
- now,
55
- buildInProgress: builds.get(device.project) ?? true
56
- });
57
- return idleForMs === null ? [] : [{
58
- device,
59
- idleForMs
60
- }];
61
- });
62
- }
63
- /** Appends an idle shutdown record to the workspace's metro.ndjson, where the supervisor writes its own. */
64
- function writeIdleShutdownEvent(root, event) {
65
- const writer = createNdjsonWriter(join(workspaceLogsDir$1(root), "metro.ndjson"), { maxBytes: LOG_ROTATE_BYTES });
66
- writer.write({
67
- src: "metro",
68
- ...event
69
- });
70
- writer.close();
71
- }
72
- /**
73
- * Shuts down, through centralized teardown, each of the workspace's owned devices that is still idle for `idleMs`,
74
- * and records why. The caller holds the workspace's native-run lock, so no `ios` or `android` run is booting or
75
- * installing on them.
76
- */
77
- async function shutDownIdleDevices(root, idleMs, log, now = Date.now(), { only, reason } = {}) {
78
- let shutDown = 0;
79
- for (const { device, idleForMs } of dueIdleDevices(root, idleMs, now)) {
80
- if (only && (device.kind !== only.kind || device.id !== only.id || device.project !== only.project || device.slot !== only.slot)) continue;
81
- const what = `${device.kind === "ios" ? "simulator" : "emulator"} ${device.name}`;
82
- const outcome = device.kind === "ios" ? await teardownOwnedIosSim(device.id, {
83
- label: device.name,
84
- workspace: root
85
- }) : await teardownOwnedAvd(device.id, {
86
- owner: {
87
- projectPath: device.project,
88
- slot: device.slot
89
- },
90
- workspace: root
91
- });
92
- if (outcome.status === "torn-down") {
93
- shutDown++;
94
- const idleMinutes = Math.floor(idleForMs / MINUTE_MS);
95
- try {
96
- await updateWorkspaceStateAsync(root, (state) => ({
97
- ...state,
98
- [DEVICE_IDLE_SHUTDOWN_KEY]: {
99
- ...readDeviceIdleShutdowns(state),
100
- [deviceSlotKey(device.kind, device.slot)]: {
101
- at: new Date(now).toISOString(),
102
- idleMinutes,
103
- ...reason ? { reason } : {}
104
- }
105
- }
106
- }));
107
- } catch (error) {
108
- log({
109
- level: "warn",
110
- event: "device_idle_shutdown_failed",
111
- msg: `shut down idle ${what} but could not record it: ${error?.message || error}`
112
- });
113
- }
114
- log({
115
- level: "info",
116
- event: "device_idle_shutdown",
117
- msg: `shut down ${what}, idle ${formatLongDuration(idleForMs)}${reason === DEVICE_RECLAIM_REASON ? ", reclaimed for a waiting run" : ""}`
118
- });
119
- } else if (outcome.status !== "missing") log({
120
- level: "warn",
121
- event: "device_idle_shutdown_failed",
122
- msg: `could not shut down idle ${what}: ${outcome.reason}`,
123
- ...outcome.status === "skipped" ? { skipped: true } : {}
124
- });
125
- }
126
- return shutDown;
127
- }
128
- /** Forgets the slot's idle shutdown once a run boots its device again. */
129
- async function clearDeviceIdleShutdown(root, platform, slot = "default") {
130
- const key = deviceSlotKey(platform, slot);
131
- if (!(key in readDeviceIdleShutdowns(readWorkspaceState$1(root)))) return;
132
- await updateWorkspaceStateAsync(root, (state) => {
133
- const { [key]: _cleared, ...rest } = readDeviceIdleShutdowns(state);
134
- const { [DEVICE_IDLE_SHUTDOWN_KEY]: _all, ...others } = state;
135
- return Object.keys(rest).length ? {
136
- ...others,
137
- [DEVICE_IDLE_SHUTDOWN_KEY]: rest
138
- } : others;
139
- });
140
- }
141
- //#endregion
142
- export { writeIdleShutdownEvent as i, dueIdleDevices as n, shutDownIdleDevices as r, clearDeviceIdleShutdown as t };