@stim-cli/core 1.20.0 → 1.20.2

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
@@ -1,12 +1,12 @@
1
1
  import { _ as releaseClaim, f as isClaimRefusal, g as readClaimSet, x as tryAcquireClaim } from "./ownership-claim-O31Y5iIb.mjs";
2
2
  import { inspectProcessIdentity } from "./process-identity.mjs";
3
- import { M as withDirLock, S as workspaceName, g as rotatedLogPath, h as rotateLog, l as configDir, t as LOG_ROTATE_BYTES, u as ensurePrivateDir, w as workspaceStateDir } from "./core-Btea8jlo.mjs";
3
+ import { C as workspaceName, F as readJsonObject, I as readStateFile, L as withStateReadCache, N as isJsonObject, P as readJsonFile, R as withDirLock, T as workspaceStateDir, _ as rotatedLogPath, d as ensurePrivateDir, g as rotateLog, t as LOG_ROTATE_BYTES, u as configDir } from "./core-BkgfKqJ8.mjs";
4
+ import { n as withGitChip, t as withDerivedFacts } from "./status-derived-C13g6eQt.mjs";
4
5
  import { appendFileSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync } from "node:fs";
5
6
  import { availableParallelism, homedir, loadavg } from "node:os";
6
7
  import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
7
8
  import { createHash, randomBytes } from "node:crypto";
8
9
  import { isIP } from "node:net";
9
- import { AsyncLocalStorage } from "node:async_hooks";
10
10
  import { StringDecoder } from "node:string_decoder";
11
11
  //#region state/agent-actions.ts
12
12
  const EVENTS_VERSION = 1;
@@ -307,48 +307,6 @@ function createAgentActionReader({ sessionsDirs, targets: resolveTargets, sinceT
307
307
  };
308
308
  }
309
309
  //#endregion
310
- //#region state/json-file.ts
311
- const readScope = new AsyncLocalStorage();
312
- /**
313
- * Runs `fn` with each state file read from disk at most once: inside it, including after an `await`, `readStateFile`
314
- * returns the text of the first read of that path, and a path found missing stays missing. Callers still parse every time, so no two
315
- * share a mutable object. Only for computations that write none of the files they read.
316
- */
317
- function withStateReadCache(fn) {
318
- return readScope.run(/* @__PURE__ */ new Map(), fn);
319
- }
320
- function readStateFile(path) {
321
- const cache = readScope.getStore();
322
- if (!cache) return readFileSync(path, "utf-8");
323
- const cached = cache.get(path);
324
- if (cached) {
325
- if ("missing" in cached) throw cached.missing;
326
- return cached.text;
327
- }
328
- try {
329
- const text = readFileSync(path, "utf-8");
330
- cache.set(path, { text });
331
- return text;
332
- } catch (error) {
333
- if (error.code === "ENOENT") cache.set(path, { missing: error });
334
- throw error;
335
- }
336
- }
337
- function readJsonFile(path) {
338
- return JSON.parse(readStateFile(path));
339
- }
340
- function isJsonObject(value) {
341
- return typeof value === "object" && value !== null && !Array.isArray(value);
342
- }
343
- function readJsonObject(path) {
344
- try {
345
- const value = readJsonFile(path);
346
- return isJsonObject(value) ? value : null;
347
- } catch {
348
- return null;
349
- }
350
- }
351
- //#endregion
352
310
  //#region state/agent-device-usage.ts
353
311
  function agentDeviceUsageFile() {
354
312
  return join(configDir(), "agent-device-usage.json");
@@ -403,8 +361,17 @@ function swiftpmCacheUsageFile() {
403
361
  }
404
362
  function readSwiftpmCacheUsage() {
405
363
  const value = readJsonObject(swiftpmCacheUsageFile());
406
- if (!value || value.version !== 1 || typeof value.measuredAt !== "string" || !Number.isFinite(Date.parse(value.measuredAt)) || typeof value.dir !== "string" || typeof value.present !== "boolean" || typeof value.complete !== "boolean" || !(value.bytes === null || typeof value.bytes === "number" && Number.isFinite(value.bytes) && value.bytes >= 0)) return null;
407
- return value;
364
+ if (!value) return null;
365
+ const { version, measuredAt, dir, present, bytes, complete } = value;
366
+ if (version !== 1 || typeof measuredAt !== "string" || !Number.isFinite(Date.parse(measuredAt)) || typeof dir !== "string" || typeof present !== "boolean" || typeof complete !== "boolean" || !(bytes === null || typeof bytes === "number" && Number.isFinite(bytes) && bytes >= 0)) return null;
367
+ return {
368
+ version,
369
+ measuredAt,
370
+ dir,
371
+ present,
372
+ bytes,
373
+ complete
374
+ };
408
375
  }
409
376
  //#endregion
410
377
  //#region state/paths.ts
@@ -802,23 +769,47 @@ function parseHostedMacosChoice(value) {
802
769
  };
803
770
  }
804
771
  function parseHostedMacosDevice(value) {
805
- if (!isJsonObject(value) || !parseHostedMacosChoice(value) || !hostedMacosAppSlot(value.appSlot) || Object.keys(value).some((key) => ![
772
+ if (!isJsonObject(value) || !hostedMacosAppSlot(value.appSlot) || Object.keys(value).some((key) => ![
806
773
  "architecture",
807
774
  "macosVersion",
808
775
  "appSlot"
809
776
  ].includes(key))) return null;
810
- return value;
777
+ const choice = parseHostedMacosChoice(value);
778
+ return choice && {
779
+ ...choice,
780
+ appSlot: value.appSlot
781
+ };
811
782
  }
812
783
  const AGENT_PATH = /^\/device-host\/agent\/[a-f0-9-]{36}\/$/;
813
784
  const LEASE_NAME = /^[A-Za-z0-9._-]{1,128}$/;
814
785
  const LEASE_DEVICE_KEY = /^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)+@[1-9][0-9]{0,9}$/;
786
+ function leaseName(value) {
787
+ return typeof value === "string" && LEASE_NAME.test(value);
788
+ }
815
789
  function parseHostedAgentLease(value) {
816
- if (!isJsonObject(value) || Object.keys(value).length !== (value.backend === "ios-instance" || value.backend === "android-instance" ? 5 : 4) || ![
817
- value.tenant,
818
- value.runId,
819
- value.clientId
820
- ].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;
821
- return value;
790
+ if (!isJsonObject(value)) return null;
791
+ const { tenant, runId, clientId, deviceKey, backend } = value;
792
+ if (Object.keys(value).length !== (backend === "ios-instance" || backend === "android-instance" ? 5 : 4) || !leaseName(tenant) || !leaseName(runId) || !leaseName(clientId) || typeof deviceKey !== "string") return null;
793
+ if (backend === "ios-instance") return /^ios:mobile:[a-fA-F0-9-]{36}$/.test(deviceKey) ? {
794
+ tenant,
795
+ runId,
796
+ clientId,
797
+ deviceKey,
798
+ backend
799
+ } : null;
800
+ if (backend === "android-instance") return /^android:mobile:emulator-[0-9]+$/.test(deviceKey) ? {
801
+ tenant,
802
+ runId,
803
+ clientId,
804
+ deviceKey,
805
+ backend
806
+ } : null;
807
+ return backend === void 0 && LEASE_DEVICE_KEY.test(deviceKey) ? {
808
+ tenant,
809
+ runId,
810
+ clientId,
811
+ deviceKey
812
+ } : null;
822
813
  }
823
814
  /** A grant naming a driver this client does not know is not usable; it parses as null. */
824
815
  function parseHostedAgentGrant(value) {
@@ -1010,7 +1001,7 @@ const SETTINGS = [
1010
1001
  key: "ios.scheme",
1011
1002
  type: STRING,
1012
1003
  scopes: ["workspace", "committed"],
1013
- description: "Shared Xcode scheme to build when the workspace has several"
1004
+ description: "Shared Xcode scheme to build when the workspace has several; the --scheme flag overrides it"
1014
1005
  },
1015
1006
  {
1016
1007
  key: "ios.remote",
@@ -1382,6 +1373,13 @@ const SETTINGS = [
1382
1373
  env: "STIM_ARCHIVE_AGENT_ACTIONS_MAX_AGE_DAYS",
1383
1374
  description: "Days to keep archived agent-device sessions; 0 keeps none"
1384
1375
  },
1376
+ {
1377
+ key: "workspace.hidden",
1378
+ type: BOOLEAN,
1379
+ scopes: ["workspace"],
1380
+ default: false,
1381
+ description: "Hide this workspace in Stim Desktop and the phone app; the next command that uses it unhides it"
1382
+ },
1385
1383
  {
1386
1384
  key: "worktree.exclude",
1387
1385
  type: { kind: "strings" },
@@ -2062,16 +2060,19 @@ function liveNativeBuilds() {
2062
2060
  for (const name of names) {
2063
2061
  let active;
2064
2062
  try {
2065
- active = JSON.parse(readFileSync(join(dir, name, "state.json"), "utf8")).activeBuild;
2063
+ const state = JSON.parse(readFileSync(join(dir, name, "state.json"), "utf8"));
2064
+ active = isJsonObject(state) ? state.activeBuild : void 0;
2066
2065
  } catch {
2067
2066
  continue;
2068
2067
  }
2069
- if (!active || typeof active !== "object") continue;
2068
+ if (!isJsonObject(active)) continue;
2070
2069
  const { phase, claim, placement } = active;
2071
2070
  if (typeof phase !== "string" || !NATIVE_PHASES.has(phase) || placement) continue;
2072
- if (typeof claim?.root !== "string" || typeof claim.claimId !== "string") continue;
2071
+ if (!isJsonObject(claim)) continue;
2072
+ const { root, claimId } = claim;
2073
+ if (typeof root !== "string" || typeof claimId !== "string") continue;
2073
2074
  try {
2074
- if (readClaimSet(claim.root).live.some((holder) => holder.claimId === claim.claimId)) count += 1;
2075
+ if (readClaimSet(root).live.some((holder) => holder.claimId === claimId)) count += 1;
2075
2076
  } catch {}
2076
2077
  }
2077
2078
  return count;
@@ -2264,10 +2265,15 @@ function ids(value) {
2264
2265
  function readCreatedDevices() {
2265
2266
  try {
2266
2267
  const parsed = JSON.parse(readStateFile(createdDevicesFile()));
2268
+ if (!isJsonObject(parsed)) return {
2269
+ ios: /* @__PURE__ */ new Set(),
2270
+ android: /* @__PURE__ */ new Set(),
2271
+ web: /* @__PURE__ */ new Set()
2272
+ };
2267
2273
  return {
2268
- ios: new Set(ids(parsed?.ios)),
2269
- android: new Set(ids(parsed?.android)),
2270
- web: new Set(ids(parsed?.web))
2274
+ ios: new Set(ids(parsed.ios)),
2275
+ android: new Set(ids(parsed.android)),
2276
+ web: new Set(ids(parsed.web))
2271
2277
  };
2272
2278
  } catch {
2273
2279
  return {
@@ -3251,154 +3257,6 @@ const MACHINE_OWNER_KINDS = [
3251
3257
  "shared"
3252
3258
  ];
3253
3259
  //#endregion
3254
- //#region state/status-derived.ts
3255
- const PLATFORMS$1 = ["ios", "android"];
3256
- function isRunning(platform, device) {
3257
- if (platform === "ios") return device.state === "Booted";
3258
- return device.state === "detected" && !device.physical;
3259
- }
3260
- function appPresence(env, platform, device) {
3261
- if (!isRunning(platform, device) || device.app?.state === "running") return null;
3262
- const everBuilt = env.builds?.[platform]?.some((entry) => entry.result === "succeeded") ?? true;
3263
- if (env.lastBuilds?.[platform]?.status === "failed" && !everBuilt) return "none";
3264
- return device.app?.state === "stopped" ? "closed" : null;
3265
- }
3266
- function deviceSlots(env) {
3267
- return [{
3268
- slot: "default",
3269
- ios: env.ios,
3270
- android: env.android
3271
- }, ...env.slots ?? []];
3272
- }
3273
- function latestBuild(env) {
3274
- let latest = null;
3275
- for (const platform of PLATFORMS$1) {
3276
- const build = env.lastBuilds?.[platform];
3277
- if (build && (latest === null || Date.parse(build.startedAt) > Date.parse(latest.startedAt))) latest = build;
3278
- }
3279
- return latest;
3280
- }
3281
- function stage(kind, since, platform = null) {
3282
- return {
3283
- kind,
3284
- since: since ?? null,
3285
- platform,
3286
- closedApps: []
3287
- };
3288
- }
3289
- function workspaceStage(env) {
3290
- if (env.macos?.build.state === "running") return stage("building", env.macos.build.startedAt, "macos");
3291
- if (env.macos?.build.state === "failed") return stage("build-failed", env.macos.build.finishedAt ?? env.macos.build.startedAt, "macos");
3292
- if (env.build?.state === "running") return stage("building", env.build.startedAt, env.build.platform);
3293
- if (!env.live && env.phase === "warming") return stage("warming", env.phaseSince);
3294
- if (!env.live && env.phase === "ready") return stage("ready", env.phaseSince);
3295
- const latest = latestBuild(env);
3296
- if (latest?.status === "failed") return stage("build-failed", latest.finishedAt ?? latest.startedAt, latest.platform);
3297
- if (env.live || (env.remoteDevices?.length ?? 0) > 0) {
3298
- const closedApps = deviceSlots(env).flatMap(({ slot, ...devices }) => PLATFORMS$1.flatMap((platform) => {
3299
- const device = devices[platform];
3300
- return device && appPresence(env, platform, device) === "closed" ? [{
3301
- platform,
3302
- slot
3303
- }] : [];
3304
- }));
3305
- return {
3306
- ...stage("running", env.supervisor?.startedAt),
3307
- closedApps
3308
- };
3309
- }
3310
- const lastStop = env.metro?.lastStop;
3311
- return stage("stopped", lastStop && "at" in lastStop ? lastStop.at : null);
3312
- }
3313
- function checksState(checks) {
3314
- if (!checks) return null;
3315
- if (checks.failing > 0) return "failing";
3316
- if (checks.pending > 0) return "pending";
3317
- return checks.passing > 0 ? "passing" : null;
3318
- }
3319
- function gitChip(worktree) {
3320
- const git = worktree.git;
3321
- if (!git) return null;
3322
- const pull = worktree.pullRequest;
3323
- const parts = [];
3324
- const ahead = git.ahead ?? 0;
3325
- const behind = git.behind ?? 0;
3326
- if (ahead || behind) parts.push({
3327
- kind: "arrows",
3328
- ahead,
3329
- behind
3330
- });
3331
- const uncommitted = git.changed + git.untracked;
3332
- if (uncommitted) parts.push({
3333
- kind: "changed",
3334
- count: uncommitted
3335
- });
3336
- if (git.mergedInto !== null) {
3337
- if (pull?.state !== "merged") parts.push({
3338
- kind: "merged",
3339
- into: git.mergedInto
3340
- });
3341
- } else if (git.upstream === null) parts.push({ kind: "no-upstream" });
3342
- return {
3343
- parts,
3344
- ci: pull ? checksState(pull.checks) : null
3345
- };
3346
- }
3347
- function buildCause(build) {
3348
- if (("result" in build ? build.result : build.status) !== "failed") return null;
3349
- const at = build.diagnostics?.find((d) => d.file && d.line !== null && d.line !== void 0);
3350
- if (at) return {
3351
- key: `${at.file}:${at.line}`,
3352
- file: at.file,
3353
- line: at.line
3354
- };
3355
- return {
3356
- key: build.errorCode ?? "failed",
3357
- file: null,
3358
- line: null
3359
- };
3360
- }
3361
- function withCauses(builds) {
3362
- if (!builds) return builds;
3363
- return Object.fromEntries(Object.entries(builds).map(([platform, list]) => [platform, list?.map((build) => withCause(build))]));
3364
- }
3365
- function withCause(build) {
3366
- const cause = buildCause(build);
3367
- return cause ? {
3368
- ...build,
3369
- cause
3370
- } : build;
3371
- }
3372
- function withGitChip(worktree) {
3373
- const chip = gitChip(worktree);
3374
- return chip ? {
3375
- ...worktree,
3376
- gitChip: chip
3377
- } : worktree;
3378
- }
3379
- /** The environment with the conclusions clients draw from it: `stage`, `appPresence`, `gitChip` and `cause`. */
3380
- function withDerivedFacts(env) {
3381
- const device = (platform, record) => record ? {
3382
- ...record,
3383
- appPresence: appPresence(env, platform, record)
3384
- } : record;
3385
- const derived = {
3386
- ...env,
3387
- stage: workspaceStage(env)
3388
- };
3389
- if (env.ios) derived.ios = device("ios", env.ios);
3390
- if (env.android) derived.android = device("android", env.android);
3391
- if (env.slots) derived.slots = env.slots.map((slot) => ({
3392
- ...slot,
3393
- ios: device("ios", slot.ios),
3394
- android: device("android", slot.android)
3395
- }));
3396
- if (env.worktree) derived.worktree = withGitChip(env.worktree);
3397
- if (env.lastBuilds) derived.lastBuilds = Object.fromEntries(Object.entries(env.lastBuilds).map(([platform, build]) => [platform, withCause(build)]));
3398
- if (env.builds) derived.builds = withCauses(env.builds);
3399
- return derived;
3400
- }
3401
- //#endregion
3402
3260
  //#region state/status-measures.ts
3403
3261
  function cacheName(path) {
3404
3262
  return `${createHash("sha256").update(path).digest("hex").slice(0, 32)}.json`;
@@ -3459,7 +3317,7 @@ const REVIEW_DECISIONS = /* @__PURE__ */ new Set([
3459
3317
  ]);
3460
3318
  function pullRequestOf(value) {
3461
3319
  if (value === null) return null;
3462
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
3320
+ if (!isJsonObject(value)) return void 0;
3463
3321
  const pr = value;
3464
3322
  if (!Number.isInteger(pr.number) || typeof pr.url !== "string" || typeof pr.title !== "string") return void 0;
3465
3323
  if (!PR_STATES.has(pr.state) || typeof pr.checkedAt !== "string") return void 0;
@@ -3524,7 +3382,7 @@ function readBuildDetail(root, claimId) {
3524
3382
  const file = readJsonObject(workspaceBuildDetailFile(root));
3525
3383
  if (!file || file.claimId !== claimId) return null;
3526
3384
  const detail = file.detail;
3527
- if (!detail || typeof detail !== "object" || Array.isArray(detail)) return null;
3385
+ if (!isJsonObject(detail)) return null;
3528
3386
  const raw = detail;
3529
3387
  if (typeof raw.updatedAt !== "string") return null;
3530
3388
  return {
@@ -3541,7 +3399,7 @@ function optionalString(value) {
3541
3399
  }
3542
3400
  /** An agent session as Stim wrote it to its cache or workspace state, or null when it is not one. */
3543
3401
  function agentSessionOf(value) {
3544
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3402
+ if (!isJsonObject(value)) return null;
3545
3403
  const raw = value;
3546
3404
  if (!AGENT_TOOLS.includes(raw.tool)) return null;
3547
3405
  if (typeof raw.sessionId !== "string" || !raw.sessionId || typeof raw.cwd !== "string" || !raw.cwd) return null;
@@ -3558,7 +3416,7 @@ function agentSessionOf(value) {
3558
3416
  if (title) session.title = title;
3559
3417
  if (startedAt) session.startedAt = startedAt;
3560
3418
  if (lastActiveAt) session.lastActiveAt = lastActiveAt;
3561
- if (Number.isInteger(raw.pid) && raw.pid > 0) session.pid = raw.pid;
3419
+ if (typeof raw.pid === "number" && Number.isInteger(raw.pid) && raw.pid > 0) session.pid = raw.pid;
3562
3420
  if (openUrl) session.openUrl = openUrl;
3563
3421
  if (webUrl) session.webUrl = webUrl;
3564
3422
  return session;
@@ -3718,7 +3576,7 @@ function missChange(value) {
3718
3576
  }
3719
3577
  /** A recorded miss reason in the shape status reports, without `baseline.cacheKey`; null when malformed. */
3720
3578
  function parseMissReason(value) {
3721
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3579
+ if (!isJsonObject(value)) return null;
3722
3580
  const record = value;
3723
3581
  if (typeof record.kind !== "string" || !MISS_KINDS.has(record.kind) || typeof record.summary !== "string") return null;
3724
3582
  const changes = (Array.isArray(record.changes) ? record.changes : []).map(missChange).filter((change) => change !== null).slice(0, MISS_CHANGE_CAP);
@@ -3727,7 +3585,7 @@ function parseMissReason(value) {
3727
3585
  kind: record.kind,
3728
3586
  summary: record.summary,
3729
3587
  changes,
3730
- changeCount: Number.isInteger(record.changeCount) && record.changeCount >= changes.length ? record.changeCount : changes.length,
3588
+ changeCount: typeof record.changeCount === "number" && Number.isInteger(record.changeCount) && record.changeCount >= changes.length ? record.changeCount : changes.length,
3731
3589
  baseline: baseline && typeof baseline.fingerprint === "string" && (baseline.from === "workspace" || baseline.from === "project") ? {
3732
3590
  fingerprint: baseline.fingerprint,
3733
3591
  from: baseline.from
@@ -3755,7 +3613,7 @@ function buildDiagnostics(value) {
3755
3613
  }).toSorted((a, b) => Number(b.file !== null) - Number(a.file !== null)).slice(0, DIAGNOSTIC_CAP);
3756
3614
  }
3757
3615
  function devicePlacement(value) {
3758
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3616
+ if (!isJsonObject(value)) return null;
3759
3617
  const record = value;
3760
3618
  if (record.decision !== "local" && record.decision !== "hosted" && record.decision !== "waited-locally" && record.decision !== "eas" || typeof record.reason !== "string") return null;
3761
3619
  return {
@@ -3771,7 +3629,7 @@ function readDevicePlacement(state, platform, slot = "default") {
3771
3629
  return devicePlacement(isJsonObject(device) ? device.devicePlacement : void 0);
3772
3630
  }
3773
3631
  function lastBuildReport(platform, value) {
3774
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3632
+ if (!isJsonObject(value)) return null;
3775
3633
  const record = value;
3776
3634
  if (record.platform !== platform || record.status !== "ok" && record.status !== "failed") return null;
3777
3635
  if (typeof record.startedAt !== "string") return null;
@@ -4322,6 +4180,17 @@ function findProjectRoot(startDir) {
4322
4180
  }
4323
4181
  //#endregion
4324
4182
  //#region state/device-host.ts
4183
+ const DEVICE_HOST_LIMITS = {
4184
+ prepareMs: 3e5,
4185
+ offerMs: 3e4,
4186
+ stopMs: 9e4,
4187
+ logsMs: 15e3,
4188
+ killGraceMs: 5e3
4189
+ };
4190
+ /** How long a cancelled hosted worker run can take to settle: SIGTERM, SIGKILL after the grace, then it is abandoned. */
4191
+ function hostedWorkerSettleMs(limits = DEVICE_HOST_LIMITS) {
4192
+ return limits.killGraceMs * 2;
4193
+ }
4325
4194
  function deviceHostRoot() {
4326
4195
  return join(configDir(), "server", "device-host-sessions");
4327
4196
  }
@@ -4331,24 +4200,39 @@ function deviceHostArea(id) {
4331
4200
  }
4332
4201
  function parseHostedChoice(value) {
4333
4202
  if (!isJsonObject(value)) return null;
4334
- if (![
4335
- "deviceTypeId",
4336
- "runtimeId",
4337
- "deviceType",
4338
- "runtime"
4339
- ].every((key) => typeof value[key] === "string" && value[key])) return null;
4340
- if (value.architecture !== "arm64" && value.architecture !== "x86_64") return null;
4341
- return value;
4203
+ const { deviceTypeId, runtimeId, deviceType, runtime, architecture } = value;
4204
+ if (typeof deviceTypeId !== "string" || !deviceTypeId || typeof runtimeId !== "string" || !runtimeId || typeof deviceType !== "string" || !deviceType || typeof runtime !== "string" || !runtime || architecture !== "arm64" && architecture !== "x86_64") return null;
4205
+ return {
4206
+ deviceTypeId,
4207
+ runtimeId,
4208
+ deviceType,
4209
+ runtime,
4210
+ architecture
4211
+ };
4342
4212
  }
4343
4213
  function parseHostedDevice(value) {
4344
- if (!isJsonObject(value) || value.avdName !== void 0 || !parseHostedChoice(value)) return null;
4345
- if (typeof value.udid !== "string" || !/^[a-fA-F0-9-]{36}$/.test(value.udid) || typeof value.name !== "string") return null;
4346
- return value;
4214
+ if (!isJsonObject(value) || value.avdName !== void 0) return null;
4215
+ const choice = parseHostedChoice(value);
4216
+ const { udid, name } = value;
4217
+ if (!choice || typeof udid !== "string" || !/^[a-fA-F0-9-]{36}$/.test(udid) || typeof name !== "string") return null;
4218
+ return {
4219
+ ...choice,
4220
+ udid,
4221
+ name
4222
+ };
4347
4223
  }
4348
4224
  function parseHostedAndroidDevice(value) {
4349
4225
  if (!isJsonObject(value)) return null;
4350
- if (value.udid !== void 0 || typeof value.avdName !== "string" || !/^stim-[A-Za-z0-9._-]+$/.test(value.avdName) || !hostedConsolePort(value.consolePort) || value.serial !== `emulator-${value.consolePort}` || typeof value.systemImage !== "string" || !/^system-images;android-\d+;[^;\s]+;(arm64-v8a|x86_64)$/.test(value.systemImage) || typeof value.deviceProfile !== "string" || !value.deviceProfile || value.architecture !== "arm64-v8a" && value.architecture !== "x86_64" || !value.systemImage.endsWith(`;${value.architecture}`)) return null;
4351
- return value;
4226
+ const { avdName, consolePort, systemImage, deviceProfile, architecture } = value;
4227
+ if (value.udid !== void 0 || typeof avdName !== "string" || !/^stim-[A-Za-z0-9._-]+$/.test(avdName) || !hostedConsolePort(consolePort) || value.serial !== `emulator-${consolePort}` || typeof systemImage !== "string" || !/^system-images;android-\d+;[^;\s]+;(arm64-v8a|x86_64)$/.test(systemImage) || typeof deviceProfile !== "string" || !deviceProfile || architecture !== "arm64-v8a" && architecture !== "x86_64" || !systemImage.endsWith(`;${architecture}`)) return null;
4228
+ return {
4229
+ avdName,
4230
+ serial: `emulator-${consolePort}`,
4231
+ consolePort,
4232
+ systemImage,
4233
+ deviceProfile,
4234
+ architecture
4235
+ };
4352
4236
  }
4353
4237
  /** Android Emulator -help-port defines the supported even console ports as 5554 through 5584. */
4354
4238
  function hostedConsolePort(value) {
@@ -4645,8 +4529,8 @@ function readHostedApp(session, attempt, workerHome) {
4645
4529
  function processRecord(value) {
4646
4530
  if (!value || typeof value !== "object") return void 0;
4647
4531
  const { pid, processToken, startedAtMicros } = value;
4648
- if (!Number.isSafeInteger(pid) || pid <= 0 || typeof processToken !== "string") return void 0;
4649
- if (!Number.isSafeInteger(startedAtMicros) || startedAtMicros <= 0) return void 0;
4532
+ if (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid <= 0 || typeof processToken !== "string") return void 0;
4533
+ if (typeof startedAtMicros !== "number" || !Number.isSafeInteger(startedAtMicros) || startedAtMicros <= 0) return void 0;
4650
4534
  return {
4651
4535
  pid,
4652
4536
  processToken,
@@ -4866,11 +4750,11 @@ const hostedNativeLogsDir = (home, platform) => join(home, `${platform}-logs`);
4866
4750
  function readHostedNativeLogsCheckpoint(home, platform = "ios") {
4867
4751
  try {
4868
4752
  const value = JSON.parse(readFileSync(join(hostedNativeLogsDir(home, platform), "checkpoint.json"), "utf8"));
4869
- 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;
4753
+ if (!isJsonObject(value) || !Number.isSafeInteger(value.until) || value.until < 0 || value.windowMs !== void 0 && (typeof value.windowMs !== "number" || !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;
4870
4754
  return {
4871
4755
  until: value.until,
4872
4756
  boundary: value.boundary,
4873
- ...typeof value.appAttempt === "string" && Number.isSafeInteger(value.pid) && value.pid > 0 ? {
4757
+ ...typeof value.appAttempt === "string" && typeof value.pid === "number" && Number.isSafeInteger(value.pid) && value.pid > 0 ? {
4874
4758
  appAttempt: value.appAttempt,
4875
4759
  pid: value.pid
4876
4760
  } : {},
@@ -5159,7 +5043,7 @@ function parseSetupJournal(value) {
5159
5043
  "ok",
5160
5044
  "skipped",
5161
5045
  "failed"
5162
- ].includes(step.state) && text(step.title) && (step.detail === void 0 || typeof step.detail === "string") && (step.fix === void 0 || typeof step.fix === "string")) || !Array.isArray(value.granted) || !value.granted.every((grant) => isJsonObject(grant) && knownKeys(grant, ["capability", "id"]) && capability(grant.capability) && text(grant.id)) || typeof value.done !== "boolean" || value.exit !== void 0 && (!Number.isInteger(value.exit) || value.exit < 0)) return null;
5046
+ ].includes(step.state) && text(step.title) && (step.detail === void 0 || typeof step.detail === "string") && (step.fix === void 0 || typeof step.fix === "string")) || !Array.isArray(value.granted) || !value.granted.every((grant) => isJsonObject(grant) && knownKeys(grant, ["capability", "id"]) && capability(grant.capability) && text(grant.id)) || typeof value.done !== "boolean" || value.exit !== void 0 && (typeof value.exit !== "number" || !Number.isInteger(value.exit) || value.exit < 0)) return null;
5163
5047
  return value;
5164
5048
  }
5165
5049
  function readSetupJournal(hash) {
@@ -5173,4 +5057,4 @@ function isSetupJournalPrunable(journal, now) {
5173
5057
  return Date.parse(journal.expiresAt) + 36e5 < now;
5174
5058
  }
5175
5059
  //#endregion
5176
- 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, DEBUG_ENV, 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, MAINTENANCE_LOG_NAME, 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, RUN_ID_ENV, 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, automaticMachineEnabled, buildCriteria, buildDiagnostics, buildMachinesFile, buildMachinesLock, buildSlotPath, buildSlotsDir, buildWorkerRoot, bundleMarkerPlatform, capDrops, closedSegmentName, coerceSettingText, compileGrep, configCorruptRepair, configLockPath, countErrorEntries, createAgentActionReader, createDebugLog, createdDevicesFile, createdDevicesLock, debugLogDir, debugLoggingEnabled, decodeStats, deviceHostArea, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, deviceHostRoot, deviceViewersDir, diskUsageCacheDir, diskUsageCacheFile, diskUsageFailureFile, diskUsageWalkClaims, 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, projectRootDirectories, pullRequestCacheDir, pullRequestCacheFile, queryJsonLogs, queryLogs, readAgentDeviceUsage, readAgentDeviceUsageCache, readAgentSessionsCache, readArchive, readArchiveState, readArchives, readBuildDetail, readBuildHistory, readBuildMachines, readCreatedDevices, readDevServerStop, readDevServerStopRequest, readDeviceHostMachines, readDeviceIdleShutdowns, readDevicePlacement, readDiskUsage, readDiskUsageFailure, 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, requireAutomaticMachine, runId, 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, validRunId, validateAutomaticPool, wholePhases, withConfigLock, withDerivedFacts, withGitChip, withStateReadCache, workspaceAgentDeviceDir, workspaceBuildDetailFile, workspaceDerivedData, workspaceEndedAgentsFile, workspaceEndedAgentsLock, workspaceGradleBuild, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceRecordingsDir, workspaceStateFile, workspaceStateLock };
5060
+ 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, DEBUG_ENV, DEVICE_HOST_LIMITS, 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, MAINTENANCE_LOG_NAME, 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, RUN_ID_ENV, 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, automaticMachineEnabled, buildCriteria, buildDiagnostics, buildMachinesFile, buildMachinesLock, buildSlotPath, buildSlotsDir, buildWorkerRoot, bundleMarkerPlatform, capDrops, closedSegmentName, coerceSettingText, compileGrep, configCorruptRepair, configLockPath, countErrorEntries, createAgentActionReader, createDebugLog, createdDevicesFile, createdDevicesLock, debugLogDir, debugLoggingEnabled, decodeStats, deviceHostArea, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, deviceHostRoot, deviceViewersDir, diskUsageCacheDir, diskUsageCacheFile, diskUsageFailureFile, diskUsageWalkClaims, 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, hostedWorkerSettleMs, 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, projectRootDirectories, pullRequestCacheDir, pullRequestCacheFile, queryJsonLogs, queryLogs, readAgentDeviceUsage, readAgentDeviceUsageCache, readAgentSessionsCache, readArchive, readArchiveState, readArchives, readBuildDetail, readBuildHistory, readBuildMachines, readCreatedDevices, readDevServerStop, readDevServerStopRequest, readDeviceHostMachines, readDeviceIdleShutdowns, readDevicePlacement, readDiskUsage, readDiskUsageFailure, 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, requireAutomaticMachine, runId, 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, validRunId, validateAutomaticPool, wholePhases, withConfigLock, withDerivedFacts, withGitChip, withStateReadCache, workspaceAgentDeviceDir, workspaceBuildDetailFile, workspaceDerivedData, workspaceEndedAgentsFile, workspaceEndedAgentsLock, workspaceGradleBuild, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceRecordingsDir, workspaceStateFile, workspaceStateLock };