@stim-cli/core 1.16.0 → 1.17.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.
package/dist/state.mjs CHANGED
@@ -39,20 +39,21 @@ function parseAgentEvents(lines) {
39
39
  const { kind, command, summary } = entry;
40
40
  const requestId = typeof entry.requestId === "string" ? entry.requestId : null;
41
41
  if (kind === "request.started" && requestId && Number.isFinite(ts)) started.push([requestId, ts]);
42
- if (kind !== "action.recorded" && kind !== "request.finished") continue;
42
+ const scopeChange = kind === "request.started" && (command === "open" || command === "close");
43
+ if (kind !== "action.recorded" && kind !== "request.finished" && !scopeChange) continue;
43
44
  const failed = kind === "request.finished" && entry.status === "error";
44
45
  if (kind === "request.finished" && !failed) {
45
46
  if (requestId) finished.push(requestId);
46
47
  continue;
47
48
  }
48
49
  if (!Number.isFinite(ts) || typeof entry.session !== "string" || typeof command !== "string") continue;
49
- if (typeof summary !== "string") continue;
50
+ if (typeof summary !== "string" && !scopeChange) continue;
50
51
  events.push({
51
52
  ts,
52
53
  session: entry.session,
53
54
  kind,
54
55
  command,
55
- summary,
56
+ summary: typeof summary === "string" ? summary : "",
56
57
  failed,
57
58
  details: object$1(entry.details),
58
59
  requestId
@@ -147,11 +148,14 @@ function readCompleteLines(path, start) {
147
148
  let fd;
148
149
  try {
149
150
  fd = openSync(path, "r");
150
- const size = fstatSync(fd).size;
151
+ const stat = fstatSync(fd);
152
+ const size = stat.size;
153
+ const identity = `${stat.dev}:${stat.ino}`;
151
154
  if (size <= start) return {
152
155
  text: "",
153
156
  next: start,
154
- size
157
+ size,
158
+ identity
155
159
  };
156
160
  const buffer = Buffer.alloc(size - start);
157
161
  const read = readSync(fd, buffer, 0, buffer.length, start);
@@ -159,7 +163,8 @@ function readCompleteLines(path, start) {
159
163
  return {
160
164
  text: end < 0 ? "" : buffer.toString("utf8", 0, end + 1),
161
165
  next: start + end + 1,
162
- size
166
+ size,
167
+ identity
163
168
  };
164
169
  } catch {
165
170
  return null;
@@ -167,16 +172,23 @@ function readCompleteLines(path, start) {
167
172
  if (fd !== void 0) closeSync(fd);
168
173
  }
169
174
  }
175
+ function trackMacosOpen(cursor, event, unknownVersion) {
176
+ const flags = object$1(event.details?.flags);
177
+ if (!event.failed) cursor.macos = event.details?.platform === "macos" || flags?.platform === "macos";
178
+ cursor.bundleId = cursor.macos && !event.failed && !unknownVersion && flags?.surface === "app" && typeof event.details?.appBundleId === "string" ? event.details.appBundleId : null;
179
+ }
170
180
  /**
171
181
  * Reads agent-device session actions incrementally from the supplied sessions directories. With targets,
172
182
  * records are restricted to those devices; without targets, retained session metadata supplies attribution.
173
183
  * Missing directories and unreadable files yield no records.
174
184
  */
175
- function createAgentActionReader({ sessionsDirs, targets, sinceTs = -Infinity, now = Date.now, claimedDevice = () => null }) {
185
+ function createAgentActionReader({ sessionsDirs, targets: resolveTargets, sinceTs = -Infinity, now = Date.now, claimedDevice = () => null }) {
176
186
  const cursors = /* @__PURE__ */ new Map();
177
- const byId = new Map(targets?.map((target) => [target.id, target]));
178
187
  return () => {
188
+ const targets = typeof resolveTargets === "function" ? resolveTargets() : resolveTargets;
179
189
  if (targets && !targets.length) return [];
190
+ const byId = new Map(targets?.map((target) => [target.id, target]));
191
+ const macosByBundle = new Map(targets?.flatMap((target) => target.platform === "macos" ? [[target.bundleId, target]] : []));
180
192
  const sessionDirs = (typeof sessionsDirs === "function" ? sessionsDirs() : sessionsDirs).flatMap((sessionsDir) => {
181
193
  try {
182
194
  return readdirSync(sessionsDir).map((name) => ({
@@ -205,7 +217,10 @@ function createAgentActionReader({ sessionsDirs, targets, sinceTs = -Infinity, n
205
217
  runner: null,
206
218
  session: null,
207
219
  unknownReported: false,
208
- started: /* @__PURE__ */ new Map()
220
+ started: /* @__PURE__ */ new Map(),
221
+ macos: false,
222
+ bundleId: null,
223
+ closing: null
209
224
  };
210
225
  cursors.set(dir, cursor);
211
226
  try {
@@ -213,8 +228,12 @@ function createAgentActionReader({ sessionsDirs, targets, sinceTs = -Infinity, n
213
228
  } catch {}
214
229
  }
215
230
  let chunk = readCompleteLines(eventsPath, cursor.offset);
216
- if (chunk && chunk.size < cursor.offset) chunk = readCompleteLines(eventsPath, 0);
231
+ if (chunk && (chunk.size < cursor.offset || cursor.identity && chunk.identity !== cursor.identity)) {
232
+ cursor.bundleId = null;
233
+ chunk = readCompleteLines(eventsPath, 0);
234
+ }
217
235
  if (!chunk) continue;
236
+ cursor.identity = chunk.identity;
218
237
  cursor.offset = chunk.next;
219
238
  lines.push(...chunk.text.split("\n"));
220
239
  const parsed = parseAgentEvents(lines);
@@ -241,7 +260,7 @@ function createAgentActionReader({ sessionsDirs, targets, sinceTs = -Infinity, n
241
260
  spans: parseRunnerSpans(text)
242
261
  };
243
262
  }
244
- for (const event of parsed.events) if (event.command === "close" && !event.failed) cursor.closes.push(event.ts);
263
+ for (const event of parsed.events) if (event.command === "close" && event.kind === "action.recorded") cursor.closes.push(event.ts);
245
264
  const spans = sessionSpans(cursor.runner.spans, cursor.closes);
246
265
  const deviceAt = (ts) => spans.length ? spanDevice(spans, ts) : session && claimedDevice(session, sessionsDir);
247
266
  cursor.platform ??= parsed.events.map(platformOf).find((platform) => platform !== void 0);
@@ -252,13 +271,30 @@ function createAgentActionReader({ sessionsDirs, targets, sinceTs = -Infinity, n
252
271
  });
253
272
  if (parsed.unknownVersion && !cursor.unknownReported) {
254
273
  const deviceId = spans.at(-1)?.deviceId ?? (session && claimedDevice(session, sessionsDir));
255
- const target = targets ? deviceId ? byId.get(deviceId) : void 0 : retainedTarget();
274
+ const target = !targets ? retainedTarget() : cursor.macos ? cursor.bundleId ? macosByBundle.get(cursor.bundleId) : void 0 : deviceId ? byId.get(deviceId) : void 0;
256
275
  if (target) {
257
276
  cursor.unknownReported = true;
258
277
  out.push(formatUnknownRecord(session ?? name, parsed.unknownVersion, target, now()));
259
278
  }
260
279
  }
280
+ if (parsed.unknownVersion) cursor.bundleId = null;
261
281
  for (const event of parsed.events) {
282
+ if (event.kind === "request.started") {
283
+ cursor.closing = event.command === "close" ? cursor.bundleId : null;
284
+ cursor.bundleId = null;
285
+ continue;
286
+ }
287
+ if (targets && event.command === "open") trackMacosOpen(cursor, event, Boolean(parsed.unknownVersion));
288
+ if (targets && cursor.macos) {
289
+ if (event.command === "screenshot") continue;
290
+ const bundleId = cursor.bundleId ?? (event.command === "close" ? cursor.closing : null);
291
+ cursor.closing = null;
292
+ const target = bundleId ? macosByBundle.get(bundleId) : void 0;
293
+ const startedAt = event.requestId ? matched.get(event.requestId) : void 0;
294
+ if (target?.platform === "macos" && event.ts >= Math.max(sinceTs, target.launchedAt) && (startedAt ?? event.ts) >= target.launchedAt) out.push(agentRecord(event, target.id, target, startedAt));
295
+ if (event.command === "close") cursor.bundleId = null;
296
+ continue;
297
+ }
262
298
  if (event.ts < sinceTs) continue;
263
299
  if (!targets) cursor.platform = platformOf(event) ?? cursor.platform;
264
300
  const deviceId = !targets && cursor.platform === "android" ? null : deviceAt(event.ts);
@@ -591,6 +627,46 @@ function getConcurrencyLimits({ env = process.env } = {}) {
591
627
  maxDevices: resolveLimit(env.STIM_MAX_DEVICES, c.maxDevices)
592
628
  };
593
629
  }
630
+ const MAX_SETTING = {
631
+ ios: {
632
+ key: "iosParkedMax",
633
+ env: "STIM_POOL_IOS_PARKED_MAX"
634
+ },
635
+ android: {
636
+ key: "androidParkedMax",
637
+ env: "STIM_POOL_ANDROID_PARKED_MAX"
638
+ }
639
+ };
640
+ function parseMax(raw, strings) {
641
+ const value = strings && typeof raw === "string" ? /^\d+$/.test(raw.trim()) ? Number(raw.trim()) : NaN : raw;
642
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return null;
643
+ return value;
644
+ }
645
+ function getParkedMax(platform, { config, env = process.env } = {}) {
646
+ const { key, env: envKey } = MAX_SETTING[platform];
647
+ const fromEnv = env[envKey];
648
+ const explicit = fromEnv !== void 0 && fromEnv !== "";
649
+ const pool = (config === void 0 ? loadConfig() : config)?.pool;
650
+ if (!explicit && pool !== void 0 && (pool === null || typeof pool !== "object" || Array.isArray(pool))) return {
651
+ max: 0,
652
+ error: "Invalid pool value. Expected an object with simulator and emulator bounds."
653
+ };
654
+ const fromConfig = pool !== null && typeof pool === "object" && !Array.isArray(pool) ? pool[key] : void 0;
655
+ const raw = explicit ? fromEnv : fromConfig;
656
+ if (raw === void 0) return {
657
+ max: env.STIM_HOME ? 0 : 3,
658
+ error: null
659
+ };
660
+ const parsed = parseMax(raw, explicit);
661
+ if (parsed === null) return {
662
+ max: 0,
663
+ error: `Invalid ${explicit ? envKey : `pool.${key}`} value ${JSON.stringify(raw)}. Expected a whole number of parked ${platform === "ios" ? "simulators" : "emulators"}, 0 or more.`
664
+ };
665
+ return {
666
+ max: explicit ? parsed : env.STIM_HOME ? 0 : parsed,
667
+ error: null
668
+ };
669
+ }
594
670
  function resolveLimit(envVal, cfgVal) {
595
671
  const raw = envVal !== void 0 && envVal !== null && envVal !== "" ? Number(envVal) : typeof cfgVal === "number" ? cfgVal : NaN;
596
672
  if (!Number.isFinite(raw) || raw <= 0) return 0;
@@ -735,11 +811,11 @@ const AGENT_PATH = /^\/device-host\/agent\/[a-f0-9-]{36}\/$/;
735
811
  const LEASE_NAME = /^[A-Za-z0-9._-]{1,128}$/;
736
812
  const LEASE_DEVICE_KEY = /^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)+@[1-9][0-9]{0,9}$/;
737
813
  function parseHostedAgentLease(value) {
738
- if (!isJsonObject(value) || Object.keys(value).length !== (value.backend === "ios-instance" ? 5 : 4) || ![
814
+ if (!isJsonObject(value) || Object.keys(value).length !== (value.backend === "ios-instance" || value.backend === "android-instance" ? 5 : 4) || ![
739
815
  value.tenant,
740
816
  value.runId,
741
817
  value.clientId
742
- ].every((name) => typeof name === "string" && LEASE_NAME.test(name)) || typeof value.deviceKey !== "string" || !(value.backend === "ios-instance" ? /^ios:mobile:[a-fA-F0-9-]{36}$/.test(value.deviceKey) : value.backend === void 0 && LEASE_DEVICE_KEY.test(value.deviceKey))) return null;
818
+ ].every((name) => typeof name === "string" && LEASE_NAME.test(name)) || typeof value.deviceKey !== "string" || !(value.backend === "ios-instance" ? /^ios:mobile:[a-fA-F0-9-]{36}$/.test(value.deviceKey) : value.backend === "android-instance" ? /^android:mobile:emulator-[0-9]+$/.test(value.deviceKey) : value.backend === void 0 && LEASE_DEVICE_KEY.test(value.deviceKey))) return null;
743
819
  return value;
744
820
  }
745
821
  /** A grant naming a driver this client does not know is not usable; it parses as null. */
@@ -852,10 +928,6 @@ const RELATIVE_PATH = {
852
928
  };
853
929
  const BOOLEAN = { kind: "boolean" };
854
930
  const OBJECT = { kind: "object" };
855
- const REMOTE = {
856
- kind: "choice",
857
- choices: REMOTE_DEVICE_BACKENDS
858
- };
859
931
  const PARKED_MAX = {
860
932
  kind: "number",
861
933
  integer: true,
@@ -912,7 +984,7 @@ const SETTINGS = [
912
984
  default: "auto"
913
985
  },
914
986
  optimization("android.gradleBuildCache", "Gradle build cache"),
915
- optimization("android.targetAbiOnly", "Narrow Debug builds to the device ABI"),
987
+ optimization("android.targetAbiOnly", "Narrow Debug and hosted Android builds to the device ABI"),
916
988
  {
917
989
  key: "ios.deviceType",
918
990
  type: STRING,
@@ -940,7 +1012,7 @@ const SETTINGS = [
940
1012
  patternHelp: "eas, proxy, auto, or a tailnet machine name"
941
1013
  },
942
1014
  scopes: PROJECT,
943
- description: "Default iOS remote target: eas, proxy, or an approved Mac in hosting.machines; auto is not available yet"
1015
+ description: "Default iOS remote target: eas, proxy, or an approved Mac in hosting.machines; auto places on an approved Mac when this Mac is full or busy"
944
1016
  },
945
1017
  {
946
1018
  key: "ios.simslimProfile",
@@ -1032,9 +1104,13 @@ const SETTINGS = [
1032
1104
  },
1033
1105
  {
1034
1106
  key: "android.remote",
1035
- type: REMOTE,
1107
+ type: {
1108
+ kind: "string",
1109
+ pattern: TAILNET_MACHINE_PATTERN,
1110
+ patternHelp: "eas, proxy, auto, or a tailnet machine name"
1111
+ },
1036
1112
  scopes: PROJECT,
1037
- description: "Default remote backend for Android"
1113
+ description: "Default Android remote target: eas, proxy, or an approved Mac in hosting.machines; auto places on an approved Mac when this Mac is full or busy"
1038
1114
  },
1039
1115
  {
1040
1116
  key: "metro.tunnel",
@@ -1101,9 +1177,20 @@ const SETTINGS = [
1101
1177
  minimum: 0
1102
1178
  },
1103
1179
  scopes: EVERY,
1104
- default: 0,
1180
+ default: 30,
1105
1181
  description: "Minutes an owned simulator or emulator stays idle before the workspace supervisor shuts it down; 0 never"
1106
1182
  },
1183
+ {
1184
+ key: "devices.reclaimIdleMinutes",
1185
+ type: {
1186
+ kind: "number",
1187
+ integer: true,
1188
+ minimum: 0
1189
+ },
1190
+ scopes: EVERY,
1191
+ default: 10,
1192
+ description: "Minutes an owned simulator or emulator stays idle before a waiting run reclaims its device slot; 0 never"
1193
+ },
1107
1194
  {
1108
1195
  key: "macos.product",
1109
1196
  type: {
@@ -1557,7 +1644,7 @@ const SETTINGS = [
1557
1644
  },
1558
1645
  scopes: MACHINE,
1559
1646
  default: "none",
1560
- description: "Tool this Mac starts so a client's coding agent can drive the macOS apps and iOS simulators it hosts for that client; none starts nothing"
1647
+ description: "Tool this Mac starts so a client's coding agent can drive the macOS apps, iOS simulators and Android emulators it hosts for that client; none starts nothing"
1561
1648
  },
1562
1649
  {
1563
1650
  key: "server.acceptClientBuilds",
@@ -1603,7 +1690,7 @@ const SETTINGS = [
1603
1690
  },
1604
1691
  scopes: MACHINE,
1605
1692
  default: 2,
1606
- description: "Load per core (5-minute load average divided by the CPU count) at which a Mac counts as saturated: a build machine declines offloaded builds, and auto offload stops preferring this Mac"
1693
+ description: "Load per core (5-minute load average divided by the CPU count) at which a Mac counts as saturated: a build machine declines offloaded builds, and auto offload stops preferring this Mac; also the busy threshold for automatic iOS and Android device placement"
1607
1694
  },
1608
1695
  {
1609
1696
  key: "offload.workerRoot",
@@ -2594,7 +2681,7 @@ function listSegments(dir, closedOnly = false) {
2594
2681
  return segments.toSorted((a, b) => a.start - b.start);
2595
2682
  }
2596
2683
  /** Every device slot recorded under a workspace's recordings directory. */
2597
- function listRecordedDevices(recordingsDir) {
2684
+ function listRecordedDevices(recordingsDir, closedOnly = false) {
2598
2685
  return listDir(recordingsDir).flatMap((name) => {
2599
2686
  const match = DEVICE.exec(name);
2600
2687
  if (!match) return [];
@@ -2603,7 +2690,7 @@ function listRecordedDevices(recordingsDir) {
2603
2690
  platform: match[1],
2604
2691
  slot: match[2],
2605
2692
  dir,
2606
- segments: listSegments(dir)
2693
+ segments: listSegments(dir, closedOnly)
2607
2694
  }];
2608
2695
  });
2609
2696
  }
@@ -2840,6 +2927,8 @@ const WORKSPACE_PHASES = [
2840
2927
  "live",
2841
2928
  "idle"
2842
2929
  ];
2930
+ /** The tutorial format version the installed Stim writes into the tutorial app. */
2931
+ const TUTORIAL_VERSION = 1;
2843
2932
  /**
2844
2933
  * Where a memory figure comes from. `footprint` is each process's physical footprint, which Activity Monitor's Memory
2845
2934
  * column shows. `rss` sums resident set sizes, which count pages shared between processes once per process, so a
@@ -3225,6 +3314,7 @@ function readIdleStop(state) {
3225
3314
  idleMinutes: record.idleMinutes
3226
3315
  };
3227
3316
  }
3317
+ const DEVICE_RECLAIM_REASON = "reclaimed for a waiting run";
3228
3318
  const DEVICE_IDLE_SHUTDOWN_KEY = "deviceIdleShutdowns";
3229
3319
  /** The recorded idle shutdowns by device slot key (`ios`, `android`, `ios:<slot>`). */
3230
3320
  function readDeviceIdleShutdowns(state) {
@@ -3235,7 +3325,8 @@ function readDeviceIdleShutdowns(state) {
3235
3325
  const record = value;
3236
3326
  if (typeof record?.at === "string" && typeof record.idleMinutes === "number") found[key] = {
3237
3327
  at: record.at,
3238
- idleMinutes: record.idleMinutes
3328
+ idleMinutes: record.idleMinutes,
3329
+ ...typeof record.reason === "string" ? { reason: record.reason } : {}
3239
3330
  };
3240
3331
  }
3241
3332
  return found;
@@ -3354,6 +3445,22 @@ function buildDiagnostics(value) {
3354
3445
  }];
3355
3446
  }).toSorted((a, b) => Number(b.file !== null) - Number(a.file !== null)).slice(0, DIAGNOSTIC_CAP);
3356
3447
  }
3448
+ function devicePlacement(value) {
3449
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3450
+ const record = value;
3451
+ if (record.decision !== "local" && record.decision !== "hosted" && record.decision !== "waited-locally" || typeof record.reason !== "string") return null;
3452
+ return {
3453
+ decision: record.decision,
3454
+ reason: record.reason,
3455
+ ...typeof record.machine === "string" ? { machine: record.machine } : {}
3456
+ };
3457
+ }
3458
+ function readDevicePlacement(state, platform, slot = "default") {
3459
+ const slots = isJsonObject(state?.deviceSlots) ? state.deviceSlots : {};
3460
+ const saved = isJsonObject(slots[slot]) ? slots[slot] : {};
3461
+ const device = slot === "default" ? state?.[platform] : saved[platform];
3462
+ return devicePlacement(isJsonObject(device) ? device.devicePlacement : void 0);
3463
+ }
3357
3464
  function lastBuildReport(platform, value) {
3358
3465
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3359
3466
  const record = value;
@@ -3363,6 +3470,7 @@ function lastBuildReport(platform, value) {
3363
3470
  const finished = new Date(Date.parse(record.startedAt) + (durationMs ?? NaN));
3364
3471
  const reason = record.cacheHit === "local" || record.cacheHit === "remote" ? null : parseMissReason(record.missReason);
3365
3472
  const diagnostics = record.status === "failed" ? buildDiagnostics(record.diagnostics) : [];
3473
+ const placed = devicePlacement(record.devicePlacement);
3366
3474
  return {
3367
3475
  platform,
3368
3476
  status: record.status,
@@ -3374,6 +3482,7 @@ function lastBuildReport(platform, value) {
3374
3482
  finishedAt: Number.isNaN(finished.getTime()) ? null : finished.toISOString(),
3375
3483
  ...typeof record.errorCode === "string" ? { errorCode: record.errorCode } : {},
3376
3484
  ...reason ? { missReason: reason } : {},
3485
+ ...placed ? { devicePlacement: placed } : {},
3377
3486
  ...typeof record.buildMachine === "string" ? { buildMachine: record.buildMachine } : {},
3378
3487
  ...typeof record.builtOn === "string" ? { builtOn: record.builtOn } : {},
3379
3488
  ...typeof record.offloadedTo === "string" ? { offloadedTo: record.offloadedTo } : {},
@@ -3519,6 +3628,15 @@ const PLACEMENT_DECISIONS = [
3519
3628
  "offloaded",
3520
3629
  "fell-back"
3521
3630
  ];
3631
+ const CAPACITY_REFUSAL_LIMIT = 50;
3632
+ const CAPACITY_REFUSAL_MAX_AGE_MS = 6048e5;
3633
+ function trimCapacityRefusals(events, now) {
3634
+ return events.filter((event) => {
3635
+ const age = now - Date.parse(event.at);
3636
+ return age >= 0 && age <= 6048e5;
3637
+ }).toSorted((a, b) => Date.parse(a.at) - Date.parse(b.at)).slice(-50);
3638
+ }
3639
+ const trimCapacityWaits = trimCapacityRefusals;
3522
3640
  const PLATFORMS = ["ios", "android"];
3523
3641
  const OUTCOMES = ["hit", "cold"];
3524
3642
  const HISTORY_LIMIT = 10;
@@ -3657,6 +3775,8 @@ function normalize(record) {
3657
3775
  if (Object.keys(normalized).length) history[key] = normalized;
3658
3776
  }
3659
3777
  const placements = Array.isArray(record.placements) ? record.placements.flatMap(normalizePlacement) : [];
3778
+ const capacityRefusals = Array.isArray(record.capacityRefusals) ? record.capacityRefusals.flatMap(normalizeCapacityRefusal) : [];
3779
+ const capacityWaits = Array.isArray(record.capacityWaits) ? record.capacityWaits.flatMap(normalizeCapacityWait) : [];
3660
3780
  const buildMachines = {};
3661
3781
  if (isObject(record.buildMachines)) {
3662
3782
  for (const [name, totals] of Object.entries(record.buildMachines)) if (isObject(totals)) buildMachines[name] = normalizeMachineTotals(totals);
@@ -3667,6 +3787,8 @@ function normalize(record) {
3667
3787
  projects,
3668
3788
  ...Object.keys(history).length ? { history } : {},
3669
3789
  ...placements.length ? { placements } : {},
3790
+ ...capacityRefusals.length ? { capacityRefusals } : {},
3791
+ ...capacityWaits.length ? { capacityWaits } : {},
3670
3792
  ...Object.keys(buildMachines).length ? { buildMachines } : {}
3671
3793
  };
3672
3794
  }
@@ -3677,6 +3799,7 @@ function normalizePlacement(value) {
3677
3799
  if (typeof reason !== "string" || typeof project !== "string") return [];
3678
3800
  const buildMs = wholeMs(value.buildMs);
3679
3801
  const slotWaitMs = wholeMs(value.slotWaitMs);
3802
+ const deviceSlotWaitMs = wholeMs(value.deviceSlotWaitMs);
3680
3803
  const localEstimateMs = wholeMs(value.localEstimateMs);
3681
3804
  return [{
3682
3805
  at: timestamp(value.at),
@@ -3687,10 +3810,40 @@ function normalizePlacement(value) {
3687
3810
  ...typeof machine === "string" && machine !== "" ? { machine } : {},
3688
3811
  ...buildMs > 0 ? { buildMs } : {},
3689
3812
  ...slotWaitMs > 0 ? { slotWaitMs } : {},
3813
+ ...deviceSlotWaitMs > 0 ? { deviceSlotWaitMs } : {},
3690
3814
  ...localEstimateMs > 0 ? { localEstimateMs } : {},
3691
3815
  ...value.failed === true ? { failed: true } : {}
3692
3816
  }];
3693
3817
  }
3818
+ function normalizeCapacityRefusal(value) {
3819
+ if (!isObject(value)) return [];
3820
+ const { at, kind, platform, max, workspace } = value;
3821
+ if (kind !== "device" || !PLATFORMS.includes(platform)) return [];
3822
+ if (typeof at !== "string" || !Number.isFinite(Date.parse(at))) return [];
3823
+ if (typeof max !== "number" || !Number.isInteger(max) || max <= 0) return [];
3824
+ if (typeof workspace !== "string" || workspace === "") return [];
3825
+ return [{
3826
+ at: new Date(at).toISOString(),
3827
+ kind,
3828
+ platform,
3829
+ max,
3830
+ workspace
3831
+ }];
3832
+ }
3833
+ function normalizeCapacityWait(value) {
3834
+ if (!isObject(value) || value.kind !== "device-wait") return [];
3835
+ const refusal = normalizeCapacityRefusal({
3836
+ ...value,
3837
+ kind: "device"
3838
+ })[0];
3839
+ if (!refusal || typeof value.ms !== "number" || !Number.isFinite(value.ms) || value.ms < 0) return [];
3840
+ return [{
3841
+ ...refusal,
3842
+ kind: "device-wait",
3843
+ ms: Math.round(value.ms),
3844
+ ...typeof value.reclaimed === "number" && Number.isInteger(value.reclaimed) && value.reclaimed > 0 ? { reclaimed: value.reclaimed } : {}
3845
+ }];
3846
+ }
3694
3847
  function normalizeMachineTotals(totals) {
3695
3848
  const savedMs = Number(totals.savedMs);
3696
3849
  return {
@@ -3810,6 +3963,8 @@ function decodeStats(text) {
3810
3963
  function readStatsReport(key, now) {
3811
3964
  const { record, note } = readStats();
3812
3965
  const project = key ? record?.projects[key] : null;
3966
+ const capacityRefusals = trimCapacityRefusals(record?.capacityRefusals ?? [], now).toReversed();
3967
+ const capacityWaits = trimCapacityWaits(record?.capacityWaits ?? [], now).toReversed();
3813
3968
  return {
3814
3969
  report: {
3815
3970
  version: 1,
@@ -3823,6 +3978,8 @@ function readStatsReport(key, now) {
3823
3978
  android: record?.machine.android ?? null
3824
3979
  },
3825
3980
  offload: offloadSummary(record, now),
3981
+ ...capacityRefusals.length ? { capacityRefusals } : {},
3982
+ ...capacityWaits.length ? { capacityWaits } : {},
3826
3983
  agentDevice: readAgentDeviceUsage(),
3827
3984
  swiftpmCache: readSwiftpmCacheUsage()
3828
3985
  },
@@ -3923,9 +4080,16 @@ function parseHostedOfferRequest(value) {
3923
4080
  ...typeof value.deviceProfile === "string" ? { deviceProfile: value.deviceProfile } : {}
3924
4081
  };
3925
4082
  }
4083
+ function parseHostedLocalDeviceCount(value) {
4084
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value;
4085
+ if (isJsonObject(value) && typeof value.unknown === "string" && value.unknown) return { unknown: value.unknown.slice(0, 4e3) };
4086
+ return null;
4087
+ }
3926
4088
  function parseHostedNativeOffer(value) {
3927
4089
  if (!isJsonObject(value) || !isJsonObject(value.resources)) return null;
3928
4090
  const { resources } = value;
4091
+ const local = parseHostedLocalDeviceCount(resources.localDevices);
4092
+ if (resources.localDevices !== void 0 && local === null) return null;
3929
4093
  if (value.platform !== "ios" && value.platform !== "android" && value.platform !== "macos" || value.declined !== null && (typeof value.declined !== "string" || !value.declined || value.declined.length > 4e3) || !Number.isInteger(resources.cpus) || Number(resources.cpus) < 1 || ["loadPerCore", "memoryFreeBytes"].some((key) => typeof resources[key] !== "number" || !Number.isFinite(resources[key]) || resources[key] < 0) || resources.workerDiskFreeBytes !== null && (typeof resources.workerDiskFreeBytes !== "number" || !Number.isFinite(resources.workerDiskFreeBytes) || resources.workerDiskFreeBytes < 0) || resources.memoryPressure !== null && resources.memoryPressure !== "normal" && resources.memoryPressure !== "warning" && resources.memoryPressure !== "critical") return null;
3930
4094
  let choice = null;
3931
4095
  if (value.choice !== null) {
@@ -3961,7 +4125,8 @@ function parseHostedNativeOffer(value) {
3961
4125
  loadPerCore: resources.loadPerCore,
3962
4126
  memoryFreeBytes: resources.memoryFreeBytes,
3963
4127
  memoryPressure: resources.memoryPressure,
3964
- workerDiskFreeBytes: resources.workerDiskFreeBytes
4128
+ workerDiskFreeBytes: resources.workerDiskFreeBytes,
4129
+ ...local !== null ? { localDevices: local } : {}
3965
4130
  }
3966
4131
  };
3967
4132
  }
@@ -3991,7 +4156,7 @@ function readHostedSessions() {
3991
4156
  "stopping",
3992
4157
  "stopped",
3993
4158
  "unknown"
3994
- ].includes(String(entry.state)) || entry.platform === "android" && !hostedConsolePort(entry.consolePort) || (entry.platform === "macos" ? !hostedMacosAppSlot(entry.appSlot) : entry.appSlot !== void 0) || entry.device !== null && !parseHostedPlatformDevice(entry.device, entry.platform) || entry.platform === "macos" && entry.device !== null && entry.device.appSlot !== entry.appSlot || entry.platform === "android" && entry.device !== null && entry.device.consolePort !== entry.consolePort || entry.state === "ready" && entry.device === null || entry.notice !== void 0 && typeof entry.notice !== "string" || entry.appAttempt !== void 0 && (typeof entry.appAttempt !== "string" || !/^[a-zA-Z0-9_-]{1,128}$/.test(entry.appAttempt)) || entry.metroPort !== void 0 && (typeof entry.metroPort !== "number" || !Number.isInteger(entry.metroPort) || entry.metroPort < 1 || entry.metroPort > 65535)) throw new Error(`Malformed hosted session record: ${root}`);
4159
+ ].includes(String(entry.state)) || entry.platform === "android" && !hostedConsolePort(entry.consolePort) || (entry.platform === "macos" ? !hostedMacosAppSlot(entry.appSlot) : entry.appSlot !== void 0) || entry.device !== null && !parseHostedPlatformDevice(entry.device, entry.platform) || entry.platform === "macos" && entry.device !== null && entry.device.appSlot !== entry.appSlot || entry.platform === "android" && entry.device !== null && entry.device.consolePort !== entry.consolePort || entry.state === "ready" && entry.device === null || entry.parked !== void 0 && (!isJsonObject(entry.parked) || typeof entry.parked.at !== "string" || !Number.isFinite(Date.parse(entry.parked.at)) || new Date(entry.parked.at).toISOString() !== entry.parked.at || entry.state !== "stopped" || entry.platform === "macos") || entry.notice !== void 0 && typeof entry.notice !== "string" || entry.appAttempt !== void 0 && (typeof entry.appAttempt !== "string" || !/^[a-zA-Z0-9_-]{1,128}$/.test(entry.appAttempt)) || entry.clientMetroPort !== void 0 && (typeof entry.clientMetroPort !== "number" || !Number.isInteger(entry.clientMetroPort) || entry.clientMetroPort < 1 || entry.clientMetroPort > 65535 || entry.platform !== "android") || entry.metroPort !== void 0 && (typeof entry.metroPort !== "number" || !Number.isInteger(entry.metroPort) || entry.metroPort < 1 || entry.metroPort > 65535)) throw new Error(`Malformed hosted session record: ${root}`);
3995
4160
  ids.add(entry.id);
3996
4161
  return entry;
3997
4162
  });
@@ -4270,27 +4435,45 @@ function macosAppState(record) {
4270
4435
  };
4271
4436
  }
4272
4437
  //#endregion
4273
- //#region state/hosted-ios.ts
4274
- function parseHostedIosPlacement(value) {
4438
+ //#region state/hosted-native.ts
4439
+ function parseHostedNativePlacement(value, platform) {
4275
4440
  if (!isJsonObject(value) || typeof value.machine !== "string" || !parseMachine(value.machine) || typeof value.session !== "string" || !/^[a-f0-9-]{36}$/.test(value.session)) return null;
4276
- const device = parseHostedDevice(value.device);
4277
4441
  return {
4278
4442
  machine: value.machine,
4279
4443
  session: value.session,
4280
4444
  appAttempt: typeof value.appAttempt === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value.appAttempt) ? value.appAttempt : "",
4281
- selected: value.machine,
4282
- device,
4445
+ selected: typeof value.selected === "string" && parseMachine(value.selected) ? value.selected : value.machine,
4446
+ ...typeof value.reason === "string" ? { reason: value.reason } : {},
4447
+ device: parseHostedPlatformDevice(value.device, platform),
4283
4448
  agent: parseHostedAgentAccess(value.agent) ?? {
4284
4449
  driver: "none",
4285
4450
  setting: "hosting.agentDriver"
4286
4451
  }
4287
4452
  };
4288
4453
  }
4454
+ function hostedNativeRecords(state, platform) {
4455
+ const slots = isJsonObject(state?.deviceSlots) ? state.deviceSlots : {};
4456
+ const records = {
4457
+ default: state?.[platform],
4458
+ ...Object.fromEntries(Object.entries(slots).map(([slot, value]) => [slot, isJsonObject(value) ? value[platform] : void 0]))
4459
+ };
4460
+ return Object.fromEntries(Object.entries(records).flatMap(([slot, record]) => isJsonObject(record) && record.host !== void 0 ? [[slot, record.host]] : []));
4461
+ }
4462
+ function unreadableHostedNative(slot, platform) {
4463
+ const key = slot === "default" ? `${platform}.host` : `deviceSlots.${slot}.${platform}.host`;
4464
+ return `The hosted ${platform === "ios" ? "iOS" : "Android"} placement at workspace-state key ${key} is unreadable. Inspect ${key}.machine and ${key}.session before reconciling it.`;
4465
+ }
4466
+ //#endregion
4467
+ //#region state/hosted-ios.ts
4468
+ function parseHostedIosPlacement(value) {
4469
+ return parseHostedNativePlacement(value, "ios");
4470
+ }
4289
4471
  function hostedIosStatus(placement) {
4290
4472
  return {
4291
4473
  machine: placement.machine,
4292
4474
  session: placement.session,
4293
4475
  selected: placement.selected,
4476
+ ...placement.reason ? { reason: placement.reason } : {},
4294
4477
  agent: placement.agent,
4295
4478
  device: placement.device ? {
4296
4479
  name: placement.device.deviceType,
@@ -4298,18 +4481,11 @@ function hostedIosStatus(placement) {
4298
4481
  } : null
4299
4482
  };
4300
4483
  }
4301
- /** Includes unreadable placements so callers retain every recorded hosting slot. */
4302
4484
  function hostedIosRecords(state) {
4303
- const slots = isJsonObject(state?.deviceSlots) ? state.deviceSlots : {};
4304
- const records = {
4305
- default: state?.ios,
4306
- ...Object.fromEntries(Object.entries(slots).map(([slot, value]) => [slot, isJsonObject(value) ? value.ios : void 0]))
4307
- };
4308
- return Object.fromEntries(Object.entries(records).flatMap(([slot, record]) => isJsonObject(record) && record.host !== void 0 ? [[slot, record.host]] : []));
4485
+ return hostedNativeRecords(state, "ios");
4309
4486
  }
4310
4487
  function unreadableHostedIos(slot) {
4311
- const key = slot === "default" ? "ios.host" : `deviceSlots.${slot}.ios.host`;
4312
- return `The hosted iOS placement at workspace-state key ${key} is unreadable. Inspect ${key}.machine and ${key}.session before reconciling it.`;
4488
+ return unreadableHostedNative(slot, "ios");
4313
4489
  }
4314
4490
  function hostedIosPlacements(state) {
4315
4491
  return Object.assign(Object.create(null), Object.fromEntries(Object.entries(hostedIosRecords(state)).flatMap(([slot, record]) => {
@@ -4318,6 +4494,40 @@ function hostedIosPlacements(state) {
4318
4494
  })));
4319
4495
  }
4320
4496
  //#endregion
4497
+ //#region state/hosted-android.ts
4498
+ function parseHostedAndroidPlacement(value) {
4499
+ return parseHostedNativePlacement(value, "android");
4500
+ }
4501
+ function hostedAndroidStatus(placement) {
4502
+ return {
4503
+ machine: placement.machine,
4504
+ session: placement.session,
4505
+ selected: placement.selected,
4506
+ ...placement.reason ? { reason: placement.reason } : {},
4507
+ agent: placement.agent,
4508
+ device: placement.device ? {
4509
+ name: hostedAndroidDeviceName(placement.device),
4510
+ systemImage: placement.device.systemImage,
4511
+ api: Number(/^system-images;android-(\d+);/.exec(placement.device.systemImage)?.[1])
4512
+ } : null
4513
+ };
4514
+ }
4515
+ function hostedAndroidRecords(state) {
4516
+ return hostedNativeRecords(state, "android");
4517
+ }
4518
+ function unreadableHostedAndroid(slot) {
4519
+ return unreadableHostedNative(slot, "android");
4520
+ }
4521
+ function hostedAndroidPlacements(state) {
4522
+ return Object.assign(Object.create(null), Object.fromEntries(Object.entries(hostedAndroidRecords(state)).flatMap(([slot, record]) => {
4523
+ const placement = parseHostedAndroidPlacement(record);
4524
+ return placement ? [[slot, placement]] : [];
4525
+ })));
4526
+ }
4527
+ function hostedAndroidDeviceName(device) {
4528
+ return `${device.deviceProfile} (API ${/^system-images;android-(\d+);/.exec(device.systemImage)?.[1]})`;
4529
+ }
4530
+ //#endregion
4321
4531
  //#region state/hosted-metro.ts
4322
4532
  const HOSTED_METRO_REQUESTS_KEY = "hostedMetroRequests";
4323
4533
  const HOSTED_METRO_GATEWAYS_KEY = "hostedMetroGateways";
@@ -4360,15 +4570,19 @@ function hostedMacosLogsDir(home) {
4360
4570
  return null;
4361
4571
  }
4362
4572
  }
4363
- const hostedIosLogsDir = (home) => join(home, "ios-logs");
4573
+ const hostedNativeLogsDir = (home, platform) => join(home, `${platform}-logs`);
4364
4574
  /** The completed query window and overlap digests, or null for a missing, malformed or unreadable checkpoint. */
4365
- function readHostedIosLogsCheckpoint(home) {
4575
+ function readHostedNativeLogsCheckpoint(home, platform = "ios") {
4366
4576
  try {
4367
- const value = JSON.parse(readFileSync(join(hostedIosLogsDir(home), "checkpoint.json"), "utf8"));
4577
+ const value = JSON.parse(readFileSync(join(hostedNativeLogsDir(home, platform), "checkpoint.json"), "utf8"));
4368
4578
  if (!isJsonObject(value) || !Number.isSafeInteger(value.until) || value.until < 0 || value.windowMs !== void 0 && (!Number.isSafeInteger(value.windowMs) || value.windowMs < 1e3) || !Array.isArray(value.boundary) || !value.boundary.every((each) => typeof each === "string" && /^[a-f0-9]{64}$/.test(each))) return null;
4369
4579
  return {
4370
4580
  until: value.until,
4371
4581
  boundary: value.boundary,
4582
+ ...typeof value.appAttempt === "string" && Number.isSafeInteger(value.pid) && value.pid > 0 ? {
4583
+ appAttempt: value.appAttempt,
4584
+ pid: value.pid
4585
+ } : {},
4372
4586
  ...typeof value.windowMs === "number" ? { windowMs: value.windowMs } : {}
4373
4587
  };
4374
4588
  } catch {
@@ -4535,6 +4749,7 @@ function readArchive(id) {
4535
4749
  if (!id || id.startsWith(".") || basename(id) !== id || id.includes("\0")) return null;
4536
4750
  try {
4537
4751
  if (!lstatSync(join(archiveRoot(), id)).isDirectory()) return null;
4752
+ if (!lstatSync(join(archiveRoot(), id, "archive.json")).isFile()) return null;
4538
4753
  } catch {
4539
4754
  return null;
4540
4755
  }
@@ -4556,6 +4771,17 @@ function readArchive(id) {
4556
4771
  ].some((key) => typeof bytes[key] !== "number" || !Number.isFinite(bytes[key]) || bytes[key] < 0)) return null;
4557
4772
  return record;
4558
4773
  }
4774
+ function readArchiveState(id) {
4775
+ if (!id || id.startsWith(".") || basename(id) !== id || id.includes("\0")) return null;
4776
+ const file = join(archiveRoot(), id, "state.json");
4777
+ try {
4778
+ if (!lstatSync(join(archiveRoot(), id)).isDirectory()) return null;
4779
+ if (!lstatSync(file).isFile()) return null;
4780
+ } catch {
4781
+ return null;
4782
+ }
4783
+ return readJsonObject(file);
4784
+ }
4559
4785
  function archivedUsage(archives) {
4560
4786
  const usage = {
4561
4787
  count: archives.length,
@@ -4649,4 +4875,4 @@ function isSetupJournalPrunable(journal, now) {
4649
4875
  return Date.parse(journal.expiresAt) + 36e5 < now;
4650
4876
  }
4651
4877
  //#endregion
4652
- export { ACTIVITY_RECENCY_BASES, AGENT_TOOLS, ANDROID_COMPILER_CACHE_CHOICES, ANDROID_EMULATOR_APPS, ANDROID_PCH_CHOICES, APP_PROCESS_STATES, BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, BUILD_RESULTS, DEVICE_IDLE_SHUTDOWN_KEY, DEV_SERVER_STOP_REQUEST_KEY, ENDED_AGENT_RETENTION_MS, ERROR_SOURCES, HISTORY_LIMIT, HOSTED_AGENT_DRIVERS, HOSTED_APP_CHUNK_BYTES, HOSTED_LOGS_FIRST_BYTES, HOSTED_LOGS_PAGE_BYTES, HOSTED_MACOS_APP_SLOTS, HOSTED_METRO_GATEWAYS_KEY, HOSTED_METRO_REQUESTS_KEY, IDLE_STOP_KEY, IOS_SIMULATOR_APPS, LAST_BUILD_KEYS, LEVELS, MACHINE_OWNER_KINDS, MEMORY_SOURCES, NATIVE_BUILD_STEPS, NATIVE_CRASH_LOG_PREFIX, OFFLOAD_MODES, PHYSICAL_DEVICE_CONNECTIONS, PLACEMENT_DECISIONS, READY_PHASE_MS, RECORDING_CAP_BYTES, RECORDING_FOOTAGE_MS, RECORDING_PLATFORMS, REMOTE_DEVICE_BACKENDS, SETTINGS, SETTINGS_SCHEMA_FILE, SETTINGS_SCHEMA_URL, SETTING_GROUPS, SETTING_SCOPES, SOURCES, STATS_VERSION, STATUS_ISSUE_CODES, TAILNET_MACHINE_PATTERN, TUNNEL_MODES, WARM_KEY, WEB_PAGE_STATES, WEB_VIEWPORTS, WORKSPACE_AGENT_KEY, WORKSPACE_PHASES, WORKSPACE_STAGE_KINDS, acceptsShape, advanceTail, agentDeviceStateDirs, agentDeviceUsageFile, agentSessionOf, agentSessionsCacheFile, allMetroPorts, archiveDir, archiveEnabled, archiveLock, archiveRoot, archivedUsage, assertHostedDeviceLedger, attachExpoErrorContext, buildCriteria, buildDiagnostics, buildMachinesFile, buildMachinesLock, buildSlotPath, buildSlotsDir, buildWorkerRoot, bundleMarkerPlatform, capDrops, closedSegmentName, coerceSettingText, compileGrep, configCorruptRepair, configLockPath, countErrorEntries, createAgentActionReader, createdDevicesFile, createdDevicesLock, decodeStats, deviceHostArea, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, deviceHostRoot, deviceViewersDir, diskUsageCacheDir, diskUsageCacheFile, easMachineStateRoot, easSessionLedgerFile, easSessionLedgerLock, emulatorLogFile, endedAgentSessionOf, endpoint, expectedShape, fileSizes, findEnclosingWorktreeRoot, findPeer, findProjectByMetroPort, findProjectRoot, followLogs, footageDrops, getConcurrencyLimits, getConfigPath, getProject, getProjectSetting, getProjectSettings, getRepoSettings, gitMergeCacheDir, hostedAppArea, hostedAppAttempt, hostedAppBlobs, hostedConsolePort, hostedDeviceId, hostedIosLogsDir, hostedIosPlacements, hostedIosRecords, hostedIosStatus, hostedMacosAppSlot, hostedMacosBundleId, hostedMacosLogsDir, hostedMetroGateways, hostedMetroRequests, isJournalExpired, isJsonObject, isLayeredSetting, isPathPrefix, isSensitiveReference, isSetupJournalPrunable, lastUseFrom, levelRank, linkReplacedArchives, listRecordedDevices, listSegments, listStatusCacheEntries, loadConfig, logFiles, machineCapacity, macosAppState, maintenanceAttemptFile, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, markerWindow, offloadSummary, openSegmentName, parseHostedAgentAccess, parseHostedAgentGrant, parseHostedAndroidDevice, parseHostedAppManifest, parseHostedAppOffer, parseHostedChoice, parseHostedDevice, parseHostedIosPlacement, parseHostedLogsCursor, parseHostedMacosChoice, parseHostedMacosDevice, parseHostedMacosPlacement, parseHostedNativeOffer, parseHostedOfferRequest, parseHostedPlatformDevice, parseHostedRequest, parseMachine, parseMacosRecord, parseMaintenanceState, parseMissReason, parseNdjsonLine, parseNdjsonText, parseSetupJournal, parseSince, pinnedEndpoint, pullRequestCacheDir, pullRequestCacheFile, queryJsonLogs, queryLogs, readAgentDeviceUsage, readAgentDeviceUsageCache, readAgentSessionsCache, readArchive, readArchives, readBuildDetail, readBuildHistory, readBuildMachines, readCreatedDevices, readDevServerStop, readDevServerStopRequest, readDeviceHostMachines, readDeviceIdleShutdowns, readDiskUsage, readEasSessionLedger, readEndedAgentSessions, readHostedApp, readHostedAppMetadata, readHostedDevice, readHostedDeviceLedger, readHostedIosLogsCheckpoint, readHostedMacosApp, readHostedSessions, readIdleStop, readJsonFile, readJsonObject, readLastBuilds, readLogRecords, readLogTimeline, readLogsSince, readMacosRecord, readMaintenanceAttempt, readMaintenanceState, readNdjsonGenerations, readPullRequestCache, readRunEstimates, readSetupJournal, readStateFile, readStats, readStatsReport, readSwiftpmCacheUsage, readViewedDevices, readWarmRecord, readWorkspaceAgent, readWorkspaceState, recordMatches, recordedBytes, recordingDeviceName, recordingEnabled, rememberHostedAppBlobRename, saturation, serverSetupDir, settingDefinition, settingValueError, settingsJsonSchema, setupJournalFile, sharedCcache, sharedCompilationCache, sharedGradle, sharedPods, sortByTs, statsFile, statsProjectKey, stimBuildDigest, supervisorLogFile, supervisorPidFile, swiftpmCacheUsageFile, tailRead, trimSamples, tryAcquireBuildSlotClaim, unreadableHostedIos, validEasSessionClaim, validHostedAppArguments, validHostedAppBlob, wholePhases, withConfigLock, withDerivedFacts, withGitChip, withStateReadCache, workspaceAgentDeviceDir, workspaceBuildDetailFile, workspaceDerivedData, workspaceEndedAgentsFile, workspaceEndedAgentsLock, workspaceGradleBuild, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceRecordingsDir, workspaceStateFile, workspaceStateLock };
4878
+ export { ACTIVITY_RECENCY_BASES, AGENT_TOOLS, ANDROID_COMPILER_CACHE_CHOICES, ANDROID_EMULATOR_APPS, ANDROID_PCH_CHOICES, APP_PROCESS_STATES, BUILD_HISTORY_KEY, BUILD_HISTORY_LIMIT, BUILD_PHASES, BUILD_RESULTS, CAPACITY_REFUSAL_LIMIT, CAPACITY_REFUSAL_MAX_AGE_MS, DEVICE_IDLE_SHUTDOWN_KEY, DEVICE_RECLAIM_REASON, DEV_SERVER_STOP_REQUEST_KEY, ENDED_AGENT_RETENTION_MS, ERROR_SOURCES, HISTORY_LIMIT, HOSTED_AGENT_DRIVERS, HOSTED_APP_CHUNK_BYTES, HOSTED_LOGS_FIRST_BYTES, HOSTED_LOGS_PAGE_BYTES, HOSTED_MACOS_APP_SLOTS, HOSTED_METRO_GATEWAYS_KEY, HOSTED_METRO_REQUESTS_KEY, IDLE_STOP_KEY, IOS_SIMULATOR_APPS, LAST_BUILD_KEYS, LEVELS, MACHINE_OWNER_KINDS, MEMORY_SOURCES, NATIVE_BUILD_STEPS, NATIVE_CRASH_LOG_PREFIX, OFFLOAD_MODES, PHYSICAL_DEVICE_CONNECTIONS, PLACEMENT_DECISIONS, READY_PHASE_MS, RECORDING_CAP_BYTES, RECORDING_FOOTAGE_MS, RECORDING_PLATFORMS, REMOTE_DEVICE_BACKENDS, SETTINGS, SETTINGS_SCHEMA_FILE, SETTINGS_SCHEMA_URL, SETTING_GROUPS, SETTING_SCOPES, SOURCES, STATS_VERSION, STATUS_ISSUE_CODES, TAILNET_MACHINE_PATTERN, TUNNEL_MODES, TUTORIAL_VERSION, WARM_KEY, WEB_PAGE_STATES, WEB_VIEWPORTS, WORKSPACE_AGENT_KEY, WORKSPACE_PHASES, WORKSPACE_STAGE_KINDS, acceptsShape, advanceTail, agentDeviceStateDirs, agentDeviceUsageFile, agentSessionOf, agentSessionsCacheFile, allMetroPorts, archiveDir, archiveEnabled, archiveLock, archiveRoot, archivedUsage, assertHostedDeviceLedger, attachExpoErrorContext, buildCriteria, buildDiagnostics, buildMachinesFile, buildMachinesLock, buildSlotPath, buildSlotsDir, buildWorkerRoot, bundleMarkerPlatform, capDrops, closedSegmentName, coerceSettingText, compileGrep, configCorruptRepair, configLockPath, countErrorEntries, createAgentActionReader, createdDevicesFile, createdDevicesLock, decodeStats, deviceHostArea, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, deviceHostRoot, deviceViewersDir, diskUsageCacheDir, diskUsageCacheFile, easMachineStateRoot, easSessionLedgerFile, easSessionLedgerLock, emulatorLogFile, endedAgentSessionOf, endpoint, expectedShape, fileSizes, findEnclosingWorktreeRoot, findPeer, findProjectByMetroPort, findProjectRoot, followLogs, footageDrops, getConcurrencyLimits, getConfigPath, getParkedMax, getProject, getProjectSetting, getProjectSettings, getRepoSettings, gitMergeCacheDir, hostedAndroidDeviceName, hostedAndroidPlacements, hostedAndroidRecords, hostedAndroidStatus, hostedAppArea, hostedAppAttempt, hostedAppBlobs, hostedConsolePort, hostedDeviceId, hostedIosPlacements, hostedIosRecords, hostedIosStatus, hostedMacosAppSlot, hostedMacosBundleId, hostedMacosLogsDir, hostedMetroGateways, hostedMetroRequests, hostedNativeLogsDir, hostedNativeRecords, isJournalExpired, isJsonObject, isLayeredSetting, isPathPrefix, isSensitiveReference, isSetupJournalPrunable, lastUseFrom, levelRank, linkReplacedArchives, listRecordedDevices, listSegments, listStatusCacheEntries, loadConfig, logFiles, machineCapacity, macosAppState, maintenanceAttemptFile, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, markerWindow, offloadSummary, openSegmentName, parseHostedAgentAccess, parseHostedAgentGrant, parseHostedAndroidDevice, parseHostedAndroidPlacement, parseHostedAppManifest, parseHostedAppOffer, parseHostedChoice, parseHostedDevice, parseHostedIosPlacement, parseHostedLocalDeviceCount, parseHostedLogsCursor, parseHostedMacosChoice, parseHostedMacosDevice, parseHostedMacosPlacement, parseHostedNativeOffer, parseHostedNativePlacement, parseHostedOfferRequest, parseHostedPlatformDevice, parseHostedRequest, parseMachine, parseMacosRecord, parseMaintenanceState, parseMissReason, parseNdjsonLine, parseNdjsonText, parseSetupJournal, parseSince, pinnedEndpoint, pullRequestCacheDir, pullRequestCacheFile, queryJsonLogs, queryLogs, readAgentDeviceUsage, readAgentDeviceUsageCache, readAgentSessionsCache, readArchive, readArchiveState, readArchives, readBuildDetail, readBuildHistory, readBuildMachines, readCreatedDevices, readDevServerStop, readDevServerStopRequest, readDeviceHostMachines, readDeviceIdleShutdowns, readDevicePlacement, readDiskUsage, readEasSessionLedger, readEndedAgentSessions, readHostedApp, readHostedAppMetadata, readHostedDevice, readHostedDeviceLedger, readHostedMacosApp, readHostedNativeLogsCheckpoint, readHostedSessions, readIdleStop, readJsonFile, readJsonObject, readLastBuilds, readLogRecords, readLogTimeline, readLogsSince, readMacosRecord, readMaintenanceAttempt, readMaintenanceState, readNdjsonGenerations, readPullRequestCache, readRunEstimates, readSetupJournal, readStateFile, readStats, readStatsReport, readSwiftpmCacheUsage, readViewedDevices, readWarmRecord, readWorkspaceAgent, readWorkspaceState, recordMatches, recordedBytes, recordingDeviceName, recordingEnabled, rememberHostedAppBlobRename, saturation, serverSetupDir, settingDefinition, settingValueError, settingsJsonSchema, setupJournalFile, sharedCcache, sharedCompilationCache, sharedGradle, sharedPods, sortByTs, statsFile, statsProjectKey, stimBuildDigest, supervisorLogFile, supervisorPidFile, swiftpmCacheUsageFile, tailRead, trimCapacityRefusals, trimCapacityWaits, trimSamples, tryAcquireBuildSlotClaim, unreadableHostedAndroid, unreadableHostedIos, unreadableHostedNative, validEasSessionClaim, validHostedAppArguments, validHostedAppBlob, wholePhases, withConfigLock, withDerivedFacts, withGitChip, withStateReadCache, workspaceAgentDeviceDir, workspaceBuildDetailFile, workspaceDerivedData, workspaceEndedAgentsFile, workspaceEndedAgentsLock, workspaceGradleBuild, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceRecordingsDir, workspaceStateFile, workspaceStateLock };