@stim-cli/core 1.26.0 → 1.28.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
@@ -1,16 +1,15 @@
1
1
  import { S as tryAcquireClaim, _ as releaseClaim, f as isClaimRefusal, g as readClaimSet } from "./ownership-claim-DG2GMIoo.mjs";
2
2
  import { inspectProcessIdentity } from "./process-identity.mjs";
3
- import { $ as withDirLockAsync, C as workspaceName, J as readJsonFile, Q as withDirLock, T as workspaceStateDir, U as ambientContext, W as ambientEnv, X as readStateFile, Y as readJsonObject, Z as withStateReadCache, _ as rotatedLogPath, d as ensurePrivateDir, g as rotateLog, q as isJsonObject, t as LOG_ROTATE_BYTES, u as configDir } from "./core-Cd3b_fBm.mjs";
3
+ import { $ as withDirLockAsync, C as workspaceName, J as readJsonFile, Q as withDirLock, T as workspaceStateDir, U as ambientContext, W as ambientEnv, X as readStateFile, Y as readJsonObject, Z as withStateReadCache, _ as rotatedLogPath, d as ensurePrivateDir, g as rotateLog, q as isJsonObject, t as LOG_ROTATE_BYTES, u as configDir } from "./core-Hohf5Wnt.mjs";
4
4
  import { readOrCreateKeyFile } from "./noise-session.mjs";
5
5
  import { validHomeId } from "./workspace-link.mjs";
6
6
  import { a as workspaceSummary, i as statusViews, n as applyKeyedDelta, o as withDerivedFacts, r as SUMMARY_ARCHIVES, s as withGitChip, t as KeyedEntities } from "./keyed-delta-BBoOeR2J.mjs";
7
- import { appendFileSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync, watch } from "node:fs";
7
+ import { appendFileSync, closeSync, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, statSync, watch, writeFileSync, writeSync } from "node:fs";
8
8
  import { availableParallelism, homedir, loadavg } from "node:os";
9
9
  import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
10
10
  import { createHash, randomBytes } from "node:crypto";
11
11
  import { setImmediate as setImmediate$1 } from "node:timers/promises";
12
12
  import { lstat, open, readFile, readdir, stat } from "node:fs/promises";
13
- import { isIP } from "node:net";
14
13
  import { StringDecoder } from "node:string_decoder";
15
14
  //#region state/log-selection.ts
16
15
  var BoundedSelection = class {
@@ -645,6 +644,10 @@ function supervisorPidFile(projectRoot) {
645
644
  function workspaceStateFile(projectRoot) {
646
645
  return join(workspaceStateDir(projectRoot), "state.json");
647
646
  }
647
+ /** The dependency directories `gc --delete` deleted from the workspace's worktree, apart from state.json so writing it is not workspace activity. */
648
+ function workspaceLightenedFile(projectRoot) {
649
+ return join(workspaceStateDir(projectRoot), "lightened.json");
650
+ }
648
651
  function workspaceStateLock(projectRoot) {
649
652
  return join(workspaceStateDir(projectRoot), "state.lock");
650
653
  }
@@ -719,6 +722,12 @@ function easSessionLedgerLock(root = easMachineStateRoot()) {
719
722
  function deviceViewersDir() {
720
723
  return join(configDir(), "viewers");
721
724
  }
725
+ function budgetSweepFile() {
726
+ return join(configDir(), "budget-sweep.json");
727
+ }
728
+ function budgetSweepLock() {
729
+ return join(configDir(), "budget-sweep.lock");
730
+ }
722
731
  function statsFile() {
723
732
  return join(configDir(), "stats.json");
724
733
  }
@@ -740,6 +749,15 @@ function gcLogDir() {
740
749
  function gcLogFile() {
741
750
  return join(gcLogDir(), "gc.ndjson");
742
751
  }
752
+ function buildLedgerDir() {
753
+ return join(configDir(), "builds");
754
+ }
755
+ function buildLedgerFile() {
756
+ return join(buildLedgerDir(), "builds.ndjson");
757
+ }
758
+ function buildLedgerLock() {
759
+ return join(buildLedgerDir(), "builds.lock");
760
+ }
743
761
  function maintenanceChildLogFile() {
744
762
  return join(maintenanceDir(), "child.log");
745
763
  }
@@ -759,6 +777,10 @@ function archiveDir(id) {
759
777
  function archiveLock() {
760
778
  return join(archiveRoot(), ".lock");
761
779
  }
780
+ /** Uncommitted changes of removed worktrees: `<repository>/<branch-or-dir>-<timestamp>/` holding `manifest.json`. */
781
+ function worktreeArchiveRoot() {
782
+ return join(archiveRoot(), "worktrees");
783
+ }
762
784
  /** This machine's own long-term X25519 key as a client of other machines' stim-servers. */
763
785
  function clientIdentityKeyFile() {
764
786
  return join(configDir(), "client-identity.key");
@@ -1166,11 +1188,20 @@ const IOS_SIMULATOR_APPS = [
1166
1188
  "stim-desktop"
1167
1189
  ];
1168
1190
  const ANDROID_EMULATOR_APPS = ["emulator", "stim-desktop"];
1169
- const OFFLOAD_MODES = [
1170
- "auto",
1171
- "force",
1172
- "off"
1173
- ];
1191
+ const REPLACED_SETTINGS = { "remote.buildMode": {
1192
+ key: "remote.build",
1193
+ env: "STIM_REMOTE_BUILD_MODE",
1194
+ value: (old) => old === "auto" ? "auto" : old === "force" ? "remote" : old === "off" ? "local" : null
1195
+ } };
1196
+ function replacementAdvice(key, old) {
1197
+ const replaced = REPLACED_SETTINGS[key];
1198
+ if (!replaced) return null;
1199
+ const value = replaced.value(old);
1200
+ return {
1201
+ key: replaced.key,
1202
+ command: value ? `stim settings set ${replaced.key} ${value}` : null
1203
+ };
1204
+ }
1174
1205
  const WEB_VIEWPORTS = ["desktop", "phone"];
1175
1206
  const PROJECT = [
1176
1207
  "workspace",
@@ -1288,10 +1319,10 @@ const SETTINGS = [
1288
1319
  type: {
1289
1320
  kind: "string",
1290
1321
  pattern: TAILNET_MACHINE_PATTERN,
1291
- patternHelp: "eas, proxy, auto, local, or a tailnet machine name"
1322
+ patternHelp: "eas, proxy, local, auto, remote, remote-only, or a tailnet machine name"
1292
1323
  },
1293
1324
  scopes: EVERY,
1294
- description: "Default iOS remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this machine is full or busy; local runs here, overriding a lower layer"
1325
+ description: "Where the iOS simulator runs: local here (overriding a lower layer); auto here first, then a remote.machines entry when this machine is full or busy; remote on a remote.machines entry in order, here only when none takes it; remote-only the same but never here; a machine name exactly that machine; eas or proxy a remote device backend"
1295
1326
  },
1296
1327
  {
1297
1328
  key: "ios.projectPath",
@@ -1467,10 +1498,10 @@ const SETTINGS = [
1467
1498
  type: {
1468
1499
  kind: "string",
1469
1500
  pattern: TAILNET_MACHINE_PATTERN,
1470
- patternHelp: "eas, proxy, auto, local, or a tailnet machine name"
1501
+ patternHelp: "eas, proxy, local, auto, remote, remote-only, or a tailnet machine name"
1471
1502
  },
1472
1503
  scopes: EVERY,
1473
- description: "Default Android remote target: eas, proxy, or an approved Mac in remote.machines; auto places on an approved Mac when this machine is full or busy; local runs here, overriding a lower layer"
1504
+ description: "Where the Android emulator runs: local here (overriding a lower layer); auto here first, then a remote.machines entry when this machine is full or busy; remote on a remote.machines entry in order, here only when none takes it; remote-only the same but never here; a machine name exactly that machine; eas or proxy a remote device backend"
1474
1505
  },
1475
1506
  {
1476
1507
  key: "metro.tunnel",
@@ -1585,6 +1616,16 @@ const SETTINGS = [
1585
1616
  scopes: PROJECT,
1586
1617
  description: "Arguments passed directly to the owned macOS development executable."
1587
1618
  },
1619
+ {
1620
+ key: "macos.remote",
1621
+ type: {
1622
+ kind: "string",
1623
+ pattern: `^(?![Ee][Aa][Ss]$|[Pp][Rr][Oo][Xx][Yy]$)${TAILNET_MACHINE_PATTERN.slice(1)}`,
1624
+ patternHelp: "local, auto, remote, remote-only, or a tailnet machine name (macOS has no eas or proxy backend)"
1625
+ },
1626
+ scopes: EVERY,
1627
+ description: "Where stim macos launches the app: local here; auto here unless this machine is busy, then a remote.machines entry; remote on a remote.machines entry in order, here only when none takes it; remote-only the same but never here; a machine name exactly that machine. The --remote flag overrides it"
1628
+ },
1588
1629
  {
1589
1630
  key: "macos.assetCatalog",
1590
1631
  type: RELATIVE_PATH,
@@ -1639,7 +1680,7 @@ const SETTINGS = [
1639
1680
  default: true,
1640
1681
  env: "STIM_ARCHIVE_ENABLED",
1641
1682
  scopedHomeValue: false,
1642
- description: "Keep workspace history on removal; false under STIM_HOME unless explicitly enabled"
1683
+ description: "Keep workspace history on removal, and archive a dirty finished worktree's changes before gc removes it; false keeps such worktrees, and is the default under STIM_HOME unless explicitly enabled"
1643
1684
  },
1644
1685
  {
1645
1686
  key: "archive.maxAgeDays",
@@ -1647,7 +1688,7 @@ const SETTINGS = [
1647
1688
  scopes: MACHINE,
1648
1689
  default: 30,
1649
1690
  env: "STIM_ARCHIVE_MAX_AGE_DAYS",
1650
- description: "Days to keep archived workspace records; 0 keeps nothing"
1691
+ description: "Days to keep archived workspace records and worktree change archives; 0 keeps nothing"
1651
1692
  },
1652
1693
  {
1653
1694
  key: "archive.maxCount",
@@ -1663,7 +1704,7 @@ const SETTINGS = [
1663
1704
  scopes: MACHINE,
1664
1705
  default: 5,
1665
1706
  env: "STIM_ARCHIVE_MAX_TOTAL_GB",
1666
- description: "Total archived bytes in binary GB; 0 keeps no artifacts"
1707
+ description: "Total archived bytes in binary GB, and separately the worktree change archives; 0 keeps no artifacts"
1667
1708
  },
1668
1709
  {
1669
1710
  key: "archive.logs.maxAgeDays",
@@ -2041,7 +2082,7 @@ const SETTINGS = [
2041
2082
  scopes: MACHINE,
2042
2083
  default: 10,
2043
2084
  env: "STIM_MAINTENANCE_PRESSURE_PROTECT_MINUTES",
2044
- description: "Protection window, in minutes, that replaces maintenance.protectRecentHours at disk pressure levels 2 and 3"
2085
+ description: "Protection window, in minutes, that replaces maintenance.protectRecentHours at disk pressure levels 2 and 3, except for workspace build outputs and build directories, which level 2 keeps for 15 minutes after the last ios, android or macos run"
2045
2086
  },
2046
2087
  {
2047
2088
  key: "maintenance.gradleVersionIdleDays",
@@ -2061,7 +2102,7 @@ const SETTINGS = [
2061
2102
  scopes: MACHINE,
2062
2103
  default: true,
2063
2104
  env: "STIM_MAINTENANCE_REMOVE_FINISHED_WORKTREES",
2064
- description: "Remove clean linked worktrees whose branch or pull request finished, under gc.worktreeGraceMinutes, and at disk pressure level 3 clean, pushed ones with no commits of their own"
2105
+ description: "Remove linked worktrees whose branch or pull request finished, under gc.worktreeGraceMinutes, archiving a dirty one's uncommitted files first, and clean, pushed ones with no commits of their own once idle"
2065
2106
  },
2066
2107
  {
2067
2108
  key: "maintenance.removeIdleWorktrees",
@@ -2202,7 +2243,7 @@ const SETTINGS = [
2202
2243
  key: "remote.machines",
2203
2244
  type: { kind: "strings" },
2204
2245
  scopes: MACHINE,
2205
- description: "Tailscale names of the remote machines this machine may build on and host owned simulators on, each optionally with :<port> of its tailscale serve route (default 7443); what each is used for follows the build and device-host approvals it grants, which doctor --fix asks for separately"
2246
+ description: "Tailscale names of the remote machines this machine may build on and host owned simulators, emulators and macOS apps on, each optionally with :<port> of its tailscale serve route (default 7443). The order is the placement priority: each workload goes to the first machine with room and a load under its own limit. What each is used for follows the build and device-host approvals it grants, which doctor --fix asks for separately"
2206
2247
  },
2207
2248
  {
2208
2249
  key: "remote.buildPoolDisabled",
@@ -2223,7 +2264,7 @@ const SETTINGS = [
2223
2264
  type: BOOLEAN,
2224
2265
  scopes: EVERY,
2225
2266
  default: false,
2226
- description: "When ios.remote or android.remote is auto, this machine is at its concurrency.maxDevices cap and no remote.machines entry takes the run, run the simulator or emulator on a billed EAS Simulator instead of waiting or refusing, when eas-cli can"
2267
+ description: "When ios.remote or android.remote is auto or remote, this machine is at its concurrency.maxDevices cap and no remote.machines entry takes the run, run the simulator or emulator on a billed EAS Simulator instead of waiting or refusing, when eas-cli can; remote-only never uses it"
2227
2268
  },
2228
2269
  {
2229
2270
  key: "remote.easMaxDurationMinutes",
@@ -2241,23 +2282,12 @@ const SETTINGS = [
2241
2282
  type: {
2242
2283
  kind: "string",
2243
2284
  pattern: TAILNET_MACHINE_PATTERN,
2244
- patternHelp: "auto, local, or a tailnet machine name"
2285
+ patternHelp: "local, auto, remote, remote-only, or a tailnet machine name"
2245
2286
  },
2246
2287
  scopes: MACHINE,
2247
2288
  default: "auto",
2248
2289
  env: "STIM_REMOTE_BUILD",
2249
- description: "Build placement: auto follows remote.buildMode within enabled automatic pool members; local always builds here; a name in remote.machines requires that remote machine without fallback. The ios, android and macos --remote-build flag overrides this setting and its environment override"
2250
- },
2251
- {
2252
- key: "remote.buildMode",
2253
- type: {
2254
- kind: "choice",
2255
- choices: OFFLOAD_MODES
2256
- },
2257
- scopes: MACHINE,
2258
- default: "auto",
2259
- env: "STIM_REMOTE_BUILD_MODE",
2260
- description: "When remote.build is auto, where iOS simulator Debug, Android emulator debug and macOS SwiftPM Debug builds run: auto builds here while this machine has a free concurrency.maxBuilds slot and its load is under server.maxLoadPerCore, and otherwise builds on a less loaded machine in remote.machines; force builds on an enabled remote machine whenever one can take the build; off builds here when local is enabled in remote.buildPoolDisabled"
2290
+ description: "Where iOS simulator Debug, Android emulator debug and macOS SwiftPM Debug builds run: local here; auto here while it has a free concurrency.maxBuilds slot and load under server.maxLoadPerCore, otherwise on a remote.machines entry; remote on a remote.machines entry in order, here only when none takes the build; remote-only the same but never here; a machine name exactly that machine without fallback. The ios, android and macos --remote-build flag overrides this setting and its environment override"
2261
2291
  },
2262
2292
  {
2263
2293
  key: "server.maxLoadPerCore",
@@ -2267,7 +2297,7 @@ const SETTINGS = [
2267
2297
  },
2268
2298
  scopes: MACHINE,
2269
2299
  default: 2,
2270
- description: "Load per core (5-minute load average divided by the CPU count) at which this machine counts as saturated: it declines builds other machines send it, automatic build placement stops preferring it, and automatic iOS and Android device placement treats it as busy"
2300
+ description: "Load per core (5-minute load average divided by the CPU count) at which this machine counts as saturated: it declines builds other machines send it, reports the limit in its device offers so other machines skip it like a full one, stops preferring itself for automatic placement, and automatic iOS, Android and macOS placement treats it as busy"
2271
2301
  },
2272
2302
  {
2273
2303
  key: "server.workerRoot",
@@ -2503,11 +2533,21 @@ function liveNativeBuilds() {
2503
2533
  }
2504
2534
  return count;
2505
2535
  }
2506
- function machineCapacity() {
2536
+ /** The 5-minute load average per CPU, rounded to one decimal, and the CPU count it divides by. */
2537
+ function loadPerCore() {
2507
2538
  const cpus = Math.max(1, availableParallelism());
2508
2539
  return {
2509
2540
  cpus,
2510
- loadPerCore: Math.round(loadavg()[1] / cpus * 10) / 10,
2541
+ loadPerCore: Math.round(loadavg()[1] / cpus * 10) / 10
2542
+ };
2543
+ }
2544
+ function loadState(load, busyAt, limit) {
2545
+ if (limit !== null && limit > 0 && load >= limit) return "holding";
2546
+ return load >= busyAt ? "busy" : "free";
2547
+ }
2548
+ function machineCapacity() {
2549
+ return {
2550
+ ...loadPerCore(),
2511
2551
  builds: liveNativeBuilds() + liveOffloadedSlots(),
2512
2552
  maxBuilds: getConcurrencyLimits().maxBuilds,
2513
2553
  maxLoadPerCore: maxLoadPerCore()
@@ -2698,6 +2738,282 @@ function createDebugLog(component, { env, now = Date.now, base = () => ({}) } =
2698
2738
  };
2699
2739
  }
2700
2740
  //#endregion
2741
+ //#region state/trace.ts
2742
+ const TRACE_ENV = "STIM_TRACE";
2743
+ const OWNER_ENV = "STIM_TRACE_OWNER";
2744
+ const PHASE_TID_BASE = 1e3;
2745
+ const MAX_ARGS = 60;
2746
+ const MAX_ARG_CHARS = 240;
2747
+ const MAX_LINE_CHARS = 500;
2748
+ const SCAN_ARG_CHARS = 1e3;
2749
+ const SCAN_LINE_CHARS = 2e3;
2750
+ const SECRET_WORDS = "token|secret|ticket|pass|pwd|otp|credential|cookie|api[-_]?key|access[-_]?key|private[-_]?key|auth";
2751
+ const SECRET_NAME = new RegExp(SECRET_WORDS, "i");
2752
+ const SECRET_FLAG = String.raw`--?[A-Za-z0-9_.-]*(?:${SECRET_WORDS})[A-Za-z0-9_.-]*`;
2753
+ const SECRET_FLAG_VALUE = new RegExp(String.raw`(${SECRET_FLAG})(=|\s+)(?:'[^']*'|"[^"]*"|\S+)`, "gi");
2754
+ const SECRET_ASSIGNMENT = new RegExp(String.raw`([A-Za-z0-9_]*(?:${SECRET_WORDS})[A-Za-z0-9_]*)=(?:'[^']*'|"[^"]*"|[^\s&]+)`, "gi");
2755
+ const URL_USERINFO = /(\/\/)[^/\s?#]*@/g;
2756
+ const SECRET_HEADER = new RegExp(String.raw`(\b[A-Za-z-]*(?:${SECRET_WORDS})[A-Za-z-]*:\s*)[^'"\r\n]+`, "gi");
2757
+ const AUTH_SCHEME = /\b(Bearer|Basic)\s+[A-Za-z0-9._~+/=-]{8,}/gi;
2758
+ const TOKEN_SHAPE = /\b(?:(?:gh[pousr]_|github_pat_|sk-|[sr]k_(?:live|test)_|xox[abprs]-|AKIA|AIza|glpat-)[A-Za-z0-9_-]{10,}|npm_[A-Za-z0-9]{36}|eyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]*)/g;
2759
+ const CREDENTIAL_FLAGS = {
2760
+ curl: { "": [
2761
+ "-u",
2762
+ "-U",
2763
+ "--user",
2764
+ "--proxy-user"
2765
+ ] },
2766
+ security: {
2767
+ "unlock-keychain": ["-p"],
2768
+ "create-keychain": ["-p"],
2769
+ import: ["-P"],
2770
+ export: ["-P"]
2771
+ }
2772
+ };
2773
+ function credentialFlagsOf(program, subcommand) {
2774
+ const name = basename(program);
2775
+ const flags = Object.hasOwn(CREDENTIAL_FLAGS, name) ? CREDENTIAL_FLAGS[name] : void 0;
2776
+ const key = flags && Object.hasOwn(flags, "") ? "" : subcommand ?? "";
2777
+ return new Set(flags && Object.hasOwn(flags, key) ? flags[key] : []);
2778
+ }
2779
+ function scrubText(text, exact) {
2780
+ return exact.filter(Boolean).reduce((acc, value) => acc.split(value).join("***"), text).replace(URL_USERINFO, "$1[redacted]@").replace(SECRET_ASSIGNMENT, "$1=[redacted]").replace(SECRET_HEADER, "$1[redacted]").replace(AUTH_SCHEME, "$1 [redacted]").replace(TOKEN_SHAPE, "[redacted]");
2781
+ }
2782
+ /**
2783
+ * `args` with the value of any flag or assignment that looks like a secret, credentials in URLs, token shapes and
2784
+ * the `exact` values replaced. `program` selects the flags that carry a credential without a secret-looking name,
2785
+ * such as `curl -u`.
2786
+ */
2787
+ function redactArgv(args, exact = [], program = "") {
2788
+ const out = [];
2789
+ const credentialFlags = credentialFlagsOf(program, args[0]);
2790
+ let redactNext = false;
2791
+ for (const arg of args.slice(0, MAX_ARGS)) {
2792
+ const flag = /^(--?[A-Za-z0-9_.-]+)=/.exec(arg)?.[1];
2793
+ const assignment = /^([A-Za-z_][A-Za-z0-9_]*)=/.exec(arg)?.[1];
2794
+ const attached = arg.length > 2 && credentialFlags.has(arg.slice(0, 2)) ? arg.slice(0, 2) : null;
2795
+ if (redactNext) {
2796
+ out.push("[redacted]");
2797
+ redactNext = false;
2798
+ } else if (credentialFlags.has(arg)) {
2799
+ out.push(arg);
2800
+ redactNext = true;
2801
+ } else if (attached) out.push(`${attached}[redacted]`);
2802
+ else if (flag) out.push(SECRET_NAME.test(flag) || credentialFlags.has(flag) ? `${flag}=[redacted]` : clip(scrubText(arg.slice(0, SCAN_ARG_CHARS), exact)));
2803
+ else if (/^--?[A-Za-z0-9_.-]+$/.test(arg) && SECRET_NAME.test(arg)) {
2804
+ out.push(arg);
2805
+ redactNext = true;
2806
+ } else if (assignment && SECRET_NAME.test(assignment)) out.push(`${assignment}=[redacted]`);
2807
+ else if (/\s/.test(arg)) out.push(redactCommandLine(arg, exact));
2808
+ else out.push(clip(scrubText(arg.slice(0, SCAN_ARG_CHARS), exact)));
2809
+ }
2810
+ if (args.length > MAX_ARGS) out.push(`[+${args.length - MAX_ARGS} more]`);
2811
+ return out;
2812
+ }
2813
+ function clip(text, max = MAX_ARG_CHARS) {
2814
+ return text.length > max ? `${text.slice(0, max)}...` : text;
2815
+ }
2816
+ /** A shell command line with the same redactions as `redactArgv`, clipped to a fixed length. */
2817
+ function redactCommandLine(command, exact = []) {
2818
+ return clip(scrubText(command.slice(0, SCAN_LINE_CHARS).replace(SECRET_FLAG_VALUE, "$1$2[redacted]"), exact), MAX_LINE_CHARS);
2819
+ }
2820
+ const microseconds = () => Math.round((performance.timeOrigin + performance.now()) * 1e3);
2821
+ let current$1 = null;
2822
+ let attempted = null;
2823
+ function emit(sink, event) {
2824
+ try {
2825
+ const line = Buffer.from(`${JSON.stringify({
2826
+ ...event,
2827
+ pid: process.pid
2828
+ })},\n`);
2829
+ for (let written = 0; written < line.length;) written += writeSync(sink.fd, line, written);
2830
+ } catch {
2831
+ sink.fd = -1;
2832
+ }
2833
+ }
2834
+ function nameThread(sink, tid, name) {
2835
+ if (sink.named.has(tid)) return;
2836
+ sink.named.add(tid);
2837
+ emit(sink, {
2838
+ ph: "M",
2839
+ name: "thread_name",
2840
+ tid,
2841
+ args: { name }
2842
+ });
2843
+ }
2844
+ function finish(sink, span, args) {
2845
+ if (!sink.open.delete(span)) return;
2846
+ if (span.lane !== null) sink.lanes[span.lane] = false;
2847
+ if (sink.fd < 0) return;
2848
+ const end = microseconds();
2849
+ emit(sink, {
2850
+ name: span.name,
2851
+ cat: span.cat,
2852
+ ph: "X",
2853
+ ts: span.ts,
2854
+ dur: Math.max(0, end - span.ts),
2855
+ tid: span.tid,
2856
+ ...args || Object.keys(span.args).length ? { args: {
2857
+ ...span.args,
2858
+ ...args
2859
+ } } : {}
2860
+ });
2861
+ }
2862
+ function claimRoot() {
2863
+ const path = process.env[TRACE_ENV];
2864
+ if (!path) return;
2865
+ try {
2866
+ const absolute = resolve(path);
2867
+ if (process.env[OWNER_ENV] === absolute) return;
2868
+ mkdirSync(dirname(absolute), { recursive: true });
2869
+ writeFileSync(absolute, "[\n");
2870
+ process.env[OWNER_ENV] = absolute;
2871
+ } catch {}
2872
+ }
2873
+ function openSink(path) {
2874
+ try {
2875
+ const absolute = resolve(path);
2876
+ mkdirSync(dirname(absolute), { recursive: true });
2877
+ try {
2878
+ writeFileSync(absolute, "[\n", { flag: "wx" });
2879
+ } catch (error) {
2880
+ if (!(error instanceof Error && "code" in error && error.code === "EEXIST")) throw error;
2881
+ }
2882
+ process.env[TRACE_ENV] = absolute;
2883
+ const sink = {
2884
+ path: absolute,
2885
+ fd: openSync(absolute, "a"),
2886
+ lanes: [],
2887
+ named: /* @__PURE__ */ new Set(),
2888
+ open: /* @__PURE__ */ new Set(),
2889
+ tracks: /* @__PURE__ */ new Map()
2890
+ };
2891
+ emit(sink, {
2892
+ ph: "M",
2893
+ name: "process_name",
2894
+ args: { name: `${basename(process.argv[1] ?? "node").replace(/\.[cm]?[jt]s$/, "")} ${process.pid}` }
2895
+ });
2896
+ process.on("exit", (code) => {
2897
+ for (const span of sink.open) finish(sink, span, span.cat === "command" ? { exit: code } : { unfinished: true });
2898
+ });
2899
+ return sink;
2900
+ } catch {
2901
+ return null;
2902
+ }
2903
+ }
2904
+ function active() {
2905
+ const path = process.env[TRACE_ENV];
2906
+ if (!path) return null;
2907
+ if (path === attempted || path === current$1?.path) return current$1 && current$1.fd >= 0 ? current$1 : null;
2908
+ attempted = path;
2909
+ current$1 = openSink(path);
2910
+ return current$1;
2911
+ }
2912
+ function begin(name, args, cat = "span") {
2913
+ const sink = active();
2914
+ if (!sink) return NO_END;
2915
+ let lane = sink.lanes.indexOf(false);
2916
+ if (lane < 0) lane = sink.lanes.length;
2917
+ sink.lanes[lane] = true;
2918
+ const tid = lane + 1;
2919
+ nameThread(sink, tid, `spans ${tid}`);
2920
+ const span = {
2921
+ name,
2922
+ cat,
2923
+ tid,
2924
+ lane,
2925
+ ts: microseconds(),
2926
+ args: args ?? {}
2927
+ };
2928
+ sink.open.add(span);
2929
+ return (endArgs) => finish(sink, span, endArgs);
2930
+ }
2931
+ const NO_END = () => {};
2932
+ const NO_PHASES = {
2933
+ enter: () => {},
2934
+ end: () => {}
2935
+ };
2936
+ function phases(track) {
2937
+ const sink = active();
2938
+ if (!sink) return NO_PHASES;
2939
+ const tid = sink.tracks.get(track) ?? PHASE_TID_BASE + sink.tracks.size;
2940
+ sink.tracks.set(track, tid);
2941
+ nameThread(sink, tid, `phases: ${track}`);
2942
+ let open = null;
2943
+ const close = (args) => {
2944
+ if (open) finish(sink, open, args);
2945
+ open = null;
2946
+ };
2947
+ return {
2948
+ enter(name, args) {
2949
+ if (open?.name === name) return;
2950
+ close();
2951
+ open = {
2952
+ name,
2953
+ cat: "phase",
2954
+ tid,
2955
+ lane: null,
2956
+ ts: microseconds(),
2957
+ args: args ?? {}
2958
+ };
2959
+ sink.open.add(open);
2960
+ },
2961
+ end: close
2962
+ };
2963
+ }
2964
+ /**
2965
+ * Timing spans for one stim process tree, written as Chrome trace events (open the file in Perfetto or
2966
+ * chrome://tracing) when `STIM_TRACE=<path>` is set. Unset, every call is one environment check. A stim command
2967
+ * (`trace.command`) truncates the file and writes `[`; every other process that inherits the variable appends one
2968
+ * event per line, creating the file if it is missing, so the file has no closing bracket. Child process arguments are written through `redactArgv`.
2969
+ */
2970
+ const trace = {
2971
+ enabled: () => active() !== null,
2972
+ begin: (name, args) => begin(name, args),
2973
+ command(name, args) {
2974
+ claimRoot();
2975
+ begin(name, args, "command");
2976
+ },
2977
+ beginExec: (name, args) => begin(name, args, "exec"),
2978
+ span(name, fn, args) {
2979
+ const end = begin(name, args);
2980
+ try {
2981
+ const result = fn();
2982
+ end();
2983
+ return result;
2984
+ } catch (error) {
2985
+ end({ error: true });
2986
+ throw error;
2987
+ }
2988
+ },
2989
+ async spanAsync(name, fn, args) {
2990
+ const end = begin(name, args);
2991
+ try {
2992
+ const result = await fn();
2993
+ end();
2994
+ return result;
2995
+ } catch (error) {
2996
+ end({ error: true });
2997
+ throw error;
2998
+ }
2999
+ },
3000
+ mark(name, args) {
3001
+ const sink = active();
3002
+ if (!sink) return;
3003
+ nameThread(sink, 1, "spans 1");
3004
+ emit(sink, {
3005
+ name,
3006
+ cat: "mark",
3007
+ ph: "i",
3008
+ s: "t",
3009
+ ts: microseconds(),
3010
+ tid: 1,
3011
+ ...args ? { args } : {}
3012
+ });
3013
+ },
3014
+ phases
3015
+ };
3016
+ //#endregion
2701
3017
  //#region state/home-identity.ts
2702
3018
  /** The persistent, nonsecret identity of this Stim home; null until the CLI initializes it. */
2703
3019
  function readHomeIdentity(config = loadConfig()) {
@@ -2898,7 +3214,8 @@ const SOURCES = [
2898
3214
  "agent",
2899
3215
  "maintenance",
2900
3216
  "placement",
2901
- "gc"
3217
+ "gc",
3218
+ "builds"
2902
3219
  ];
2903
3220
  function levelRank(level) {
2904
3221
  const i = LEVELS.indexOf(level);
@@ -3926,6 +4243,130 @@ async function withErrorContext(generations, { extra = [], ...options }, selecte
3926
4243
  return matched.map((record) => contextual.get(record) ?? record);
3927
4244
  }
3928
4245
  //#endregion
4246
+ //#region state/ndjson-tail.ts
4247
+ const HEAD_BYTES = 64;
4248
+ function generation(path) {
4249
+ return {
4250
+ path,
4251
+ id: null,
4252
+ offset: 0,
4253
+ head: Buffer.alloc(0),
4254
+ records: []
4255
+ };
4256
+ }
4257
+ function reset(gen) {
4258
+ gen.id = null;
4259
+ gen.offset = 0;
4260
+ gen.head = Buffer.alloc(0);
4261
+ gen.records = [];
4262
+ }
4263
+ function fileId(stats) {
4264
+ return `${stats.dev}:${stats.ino}`;
4265
+ }
4266
+ function readAt(fd, length, position) {
4267
+ const buffer = Buffer.allocUnsafe(length);
4268
+ let filled = 0;
4269
+ while (filled < length) {
4270
+ const n = readSync(fd, buffer, filled, length - filled, position + filled);
4271
+ if (n === 0) break;
4272
+ filled += n;
4273
+ }
4274
+ return buffer.subarray(0, filled);
4275
+ }
4276
+ function advance(gen) {
4277
+ let fd;
4278
+ try {
4279
+ fd = openSync(gen.path, "r");
4280
+ } catch {
4281
+ const had = gen.id !== null;
4282
+ reset(gen);
4283
+ return had;
4284
+ }
4285
+ try {
4286
+ const stats = fstatSync(fd, { bigint: true });
4287
+ const id = fileId(stats);
4288
+ const size = Number(stats.size);
4289
+ let changed = false;
4290
+ if (gen.id !== id || size < gen.offset || gen.head.length > 0 && !readAt(fd, gen.head.length, 0).equals(gen.head)) {
4291
+ changed = gen.id !== null || gen.records.length > 0;
4292
+ reset(gen);
4293
+ gen.id = id;
4294
+ }
4295
+ const length = size - gen.offset;
4296
+ if (length <= 0) return changed;
4297
+ const buffer = readAt(fd, length, gen.offset);
4298
+ const end = buffer.lastIndexOf(10);
4299
+ if (end < 0) return changed;
4300
+ const added = parseNdjsonText(buffer.toString("utf-8", 0, end + 1));
4301
+ for (const record of added) gen.records.push(record);
4302
+ if (gen.head.length < HEAD_BYTES) gen.head = Buffer.concat([gen.head, buffer.subarray(0, end + 1)]).subarray(0, HEAD_BYTES);
4303
+ gen.offset += end + 1;
4304
+ return changed || added.length > 0;
4305
+ } finally {
4306
+ closeSync(fd);
4307
+ }
4308
+ }
4309
+ function statId(path) {
4310
+ try {
4311
+ return fileId(statSync(path, { bigint: true }));
4312
+ } catch {
4313
+ return null;
4314
+ }
4315
+ }
4316
+ /**
4317
+ * Returns a reader of `file` and its rotated generation that yields, on every call, the records a full
4318
+ * `readNdjsonGenerations(file)` would, while reading only the bytes appended since the previous call. A file renamed
4319
+ * to its rotated generation between two calls is finished from there; any other replacement or a shrunk file is
4320
+ * read again from its start. A file rewritten in place to at least its previous length is not detected.
4321
+ */
4322
+ function createNdjsonTail(file) {
4323
+ const rotated = generation(rotatedLogPath(file));
4324
+ const current = generation(file);
4325
+ let all = [];
4326
+ return () => {
4327
+ let changed = false;
4328
+ if (current.id !== null && statId(file) !== current.id && statId(rotated.path) === current.id) {
4329
+ rotated.id = current.id;
4330
+ rotated.offset = current.offset;
4331
+ rotated.head = current.head;
4332
+ rotated.records = current.records;
4333
+ reset(current);
4334
+ changed = true;
4335
+ }
4336
+ changed = advance(rotated) || changed;
4337
+ changed = advance(current) || changed;
4338
+ if (changed) all = rotated.records.concat(current.records);
4339
+ return all;
4340
+ };
4341
+ }
4342
+ //#endregion
4343
+ //#region state/placement.ts
4344
+ /**
4345
+ * The placement words every workload shares (`remote.build`, `ios.remote`, `android.remote`, `macos.remote` and their
4346
+ * flags). Anything else a setting holds is a machine name, or for devices `eas` or `proxy`.
4347
+ *
4348
+ * - `local`: this machine only.
4349
+ * - `auto`: this machine first, a remote machine when this one is full or busy.
4350
+ * - `remote`: remote machines first, in `remote.machines` order; this machine only when none takes the run.
4351
+ * - `remote-only`: remote machines in `remote.machines` order, never this machine.
4352
+ */
4353
+ const PLACEMENT_WORDS = [
4354
+ "local",
4355
+ "auto",
4356
+ "remote",
4357
+ "remote-only"
4358
+ ];
4359
+ function placementWord(value) {
4360
+ const word = value.trim().toLowerCase();
4361
+ return PLACEMENT_WORDS.find((each) => each === word) ?? null;
4362
+ }
4363
+ function prefersRemote(word) {
4364
+ return word === "remote" || word === "remote-only";
4365
+ }
4366
+ function mayRunHere(word) {
4367
+ return word !== "remote-only";
4368
+ }
4369
+ //#endregion
3929
4370
  //#region state/recordings.ts
3930
4371
  /** The footage stim-server keeps per device: the last 15 minutes recorded, however long ago. */
3931
4372
  const RECORDING_FOOTAGE_MS = 9e5;
@@ -4802,6 +5243,14 @@ function lastUseFrom(state, logMtimes) {
4802
5243
  ].filter(Number.isFinite);
4803
5244
  return candidates.length ? Math.max(...candidates) : NaN;
4804
5245
  }
5246
+ /**
5247
+ * When an ios, android or macos run last finished in the workspace, from its recorded builds (a cache hit counts),
5248
+ * in epoch milliseconds; NaN when it records none. Dev server starts, reloads and logs do not count.
5249
+ */
5250
+ function lastNativeUseFrom(state) {
5251
+ const times = [...Object.values(readLastBuilds(state)), ...Object.values(readBuildHistory(state)).flatMap((entries) => entries.slice(0, 1))].map((run) => Date.parse(run.finishedAt ?? run.startedAt)).filter(Number.isFinite);
5252
+ return times.length ? Math.max(...times) : NaN;
5253
+ }
4805
5254
  const MAINTENANCE_LOG_NAME = "maintenance.ndjson";
4806
5255
  /**
4807
5256
  * When the workspace was last used, in epoch milliseconds. A workspace that recorded no use falls back to the mtime
@@ -4911,8 +5360,8 @@ function trimCapacityRefusals(events, now) {
4911
5360
  }).toSorted((a, b) => Date.parse(a.at) - Date.parse(b.at)).slice(-50);
4912
5361
  }
4913
5362
  const trimCapacityWaits = trimCapacityRefusals;
4914
- const PLATFORMS = ["ios", "android"];
4915
- const OUTCOMES = ["hit", "cold"];
5363
+ const PLATFORMS$1 = ["ios", "android"];
5364
+ const OUTCOMES$1 = ["hit", "cold"];
4916
5365
  const HISTORY_LIMIT = 10;
4917
5366
  function statsProjectKey({ root, commonDir, repoRoot }) {
4918
5367
  if (commonDir && repoRoot && basename(commonDir) === ".git") return canonical$1(join(canonical$1(dirname(commonDir)), relative(canonical$1(repoRoot), canonical$1(root))));
@@ -5069,7 +5518,7 @@ function normalize$1(record) {
5069
5518
  function normalizePlacement(value) {
5070
5519
  if (!isJsonObject(value)) return [];
5071
5520
  const { decision, platform, reason, project, machine } = value;
5072
- if (!PLACEMENT_DECISIONS.includes(decision) || !PLATFORMS.includes(platform)) return [];
5521
+ if (!PLACEMENT_DECISIONS.includes(decision) || !PLATFORMS$1.includes(platform)) return [];
5073
5522
  if (typeof reason !== "string" || typeof project !== "string") return [];
5074
5523
  const buildMs = wholeMs(value.buildMs);
5075
5524
  const slotWaitMs = wholeMs(value.slotWaitMs);
@@ -5092,7 +5541,7 @@ function normalizePlacement(value) {
5092
5541
  function normalizeCapacityRefusal(value) {
5093
5542
  if (!isJsonObject(value)) return [];
5094
5543
  const { at, kind, platform, max, workspace } = value;
5095
- if (kind !== "device" || !PLATFORMS.includes(platform)) return [];
5544
+ if (kind !== "device" || !PLATFORMS$1.includes(platform)) return [];
5096
5545
  if (typeof at !== "string" || !Number.isFinite(Date.parse(at))) return [];
5097
5546
  if (typeof max !== "number" || !Number.isInteger(max) || max <= 0) return [];
5098
5547
  if (typeof workspace !== "string" || workspace === "") return [];
@@ -5132,11 +5581,11 @@ function normalizeMachineTotals(totals) {
5132
5581
  function normalizeHistory(scope) {
5133
5582
  const history = {};
5134
5583
  if (!isJsonObject(scope)) return history;
5135
- for (const platform of PLATFORMS) {
5584
+ for (const platform of PLATFORMS$1) {
5136
5585
  const lists = scope[platform];
5137
5586
  if (!isJsonObject(lists)) continue;
5138
5587
  const normalized = {};
5139
- for (const outcome of OUTCOMES) {
5588
+ for (const outcome of OUTCOMES$1) {
5140
5589
  const samples = lists[outcome];
5141
5590
  if (!Array.isArray(samples)) continue;
5142
5591
  const kept = samples.filter(isJsonObject).flatMap((sample) => {
@@ -5167,7 +5616,7 @@ function wholePhases(phases) {
5167
5616
  function normalizeScope(scope) {
5168
5617
  const normalized = {};
5169
5618
  if (!scope || typeof scope !== "object" || Array.isArray(scope)) return normalized;
5170
- for (const platform of PLATFORMS) {
5619
+ for (const platform of PLATFORMS$1) {
5171
5620
  const bucket = scope[platform];
5172
5621
  if (bucket && typeof bucket === "object" && !Array.isArray(bucket)) normalized[platform] = normalizeBucket(bucket);
5173
5622
  }
@@ -5426,6 +5875,7 @@ function parseHostedNativeOffer(value) {
5426
5875
  resources: {
5427
5876
  cpus: resources.cpus,
5428
5877
  loadPerCore: resources.loadPerCore,
5878
+ ...typeof resources.maxLoadPerCore === "number" && Number.isFinite(resources.maxLoadPerCore) && resources.maxLoadPerCore > 0 ? { maxLoadPerCore: resources.maxLoadPerCore } : {},
5429
5879
  memoryFreeBytes: resources.memoryFreeBytes,
5430
5880
  memoryPressure: resources.memoryPressure,
5431
5881
  workerDiskFreeBytes: resources.workerDiskFreeBytes,
@@ -5808,21 +6258,21 @@ function hostedAndroidDeviceName(device) {
5808
6258
  //#endregion
5809
6259
  //#region state/hosted-metro.ts
5810
6260
  const HOSTED_METRO_REQUESTS_KEY = "hostedMetroRequests";
5811
- const HOSTED_METRO_GATEWAYS_KEY = "hostedMetroGateways";
6261
+ const HOSTED_METRO_LINKS_KEY = "hostedMetroLinks";
5812
6262
  function hostedMetroRequests(state) {
5813
6263
  const raw = state?.[HOSTED_METRO_REQUESTS_KEY];
5814
6264
  if (!isJsonObject(raw)) return {};
5815
6265
  return Object.fromEntries(Object.entries(raw).filter((entry) => {
5816
6266
  const [session, value] = entry;
5817
- return /^[a-f0-9-]{36}$/.test(session) && isJsonObject(value) && typeof value.id === "string" && typeof value.machine === "string" && typeof value.address === "string" && isIP(value.address) !== 0 && typeof value.peer === "string" && isIP(value.peer) !== 0 && typeof value.secret === "string" && /^[a-f0-9]{64}$/.test(value.secret);
6267
+ return /^[a-f0-9-]{36}$/.test(session) && isJsonObject(value) && typeof value.id === "string" && typeof value.machine === "string";
5818
6268
  }));
5819
6269
  }
5820
- function hostedMetroGateways(state) {
5821
- const raw = state?.[HOSTED_METRO_GATEWAYS_KEY];
6270
+ function hostedMetroLinks(state) {
6271
+ const raw = state?.[HOSTED_METRO_LINKS_KEY];
5822
6272
  if (!isJsonObject(raw)) return {};
5823
6273
  return Object.fromEntries(Object.entries(raw).filter((entry) => {
5824
6274
  const value = entry[1];
5825
- return isJsonObject(value) && typeof value.id === "string" && typeof value.processToken === "string" && (value.port === void 0 || typeof value.port === "number" && Number.isInteger(value.port) && value.port > 0 && value.port <= 65535) && (value.error === void 0 || typeof value.error === "string");
6275
+ return isJsonObject(value) && typeof value.id === "string" && typeof value.processToken === "string" && (value.ready === void 0 || value.ready === true) && (value.error === void 0 || typeof value.error === "string");
5826
6276
  }));
5827
6277
  }
5828
6278
  //#endregion
@@ -6033,6 +6483,33 @@ function readGcLog(file = gcLogFile()) {
6033
6483
  return readNdjsonGenerations(file).filter(isGcLogRecord).toSorted((a, b) => a.ts - b.ts);
6034
6484
  }
6035
6485
  //#endregion
6486
+ //#region state/build-ledger.ts
6487
+ const BUILD_LEDGER_CAP = 500;
6488
+ const PLATFORMS = [
6489
+ "ios",
6490
+ "android",
6491
+ "macos"
6492
+ ];
6493
+ const OUTCOMES = [
6494
+ "succeeded",
6495
+ "failed",
6496
+ "cancelled",
6497
+ "interrupted"
6498
+ ];
6499
+ function isBuildLedgerRecord(record) {
6500
+ return record.src === "builds" && record.event === "build" && typeof record.ts === "number" && typeof record.id === "string" && typeof record.platform === "string" && PLATFORMS.includes(record.platform) && typeof record.outcome === "string" && OUTCOMES.includes(record.outcome) && typeof record.placement === "object" && record.placement !== null && typeof record.cache === "object" && record.cache !== null;
6501
+ }
6502
+ /** The ledger's records, oldest first. A missing or unreadable ledger is empty. */
6503
+ function readBuildLedger(file = buildLedgerFile()) {
6504
+ let text;
6505
+ try {
6506
+ text = readStateFile(file);
6507
+ } catch {
6508
+ return [];
6509
+ }
6510
+ return parseNdjsonText(text).filter(isBuildLedgerRecord).toSorted((a, b) => a.ts - b.ts);
6511
+ }
6512
+ //#endregion
6036
6513
  //#region state/agent-device.ts
6037
6514
  function agentDeviceStateDirs(home = ambientEnv().HOME || ambientEnv().USERPROFILE || homedir(), env = ambientEnv()) {
6038
6515
  const override = env.AGENT_DEVICE_STATE_DIR?.trim();
@@ -6252,4 +6729,4 @@ function isSetupJournalPrunable(journal, now) {
6252
6729
  return Date.parse(journal.expiresAt) + 36e5 < now;
6253
6730
  }
6254
6731
  //#endregion
6255
- 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, FINGERPRINT_MEMO_SCHEMA, 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, HOSTED_PARKED_CANDIDATES, IDLE_STOP_KEY, IOS_SIMULATOR_APPS, KeyedEntities, LAST_BUILD_KEYS, LEVELS, MACHINE_CREDENTIALS_VERSION, 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, SUMMARY_ARCHIVES, 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, agentDeviceStateDirsAsync, agentDeviceUsageFile, agentSessionOf, agentSessionsCacheFile, allMetroPorts, applyKeyedDelta, archiveDir, archiveEnabled, archiveLock, archiveRoot, archivedUsage, assertHostedDeviceLedger, attachExpoErrorContext, automaticMachineEnabled, buildCriteria, buildDiagnostics, buildMachinesFile, buildMachinesLock, buildSlotPath, buildSlotsDir, buildWorkerRoot, bundleMarkerPlatform, cannotHost, capDrops, clientIdentity, clientIdentityKeyFile, closedSegmentName, coerceSettingText, compileGrep, configCorruptRepair, configLockPath, countErrorEntries, createAgentActionReader, createAsyncAgentActionReader, createDebugLog, createdDevicesFile, createdDevicesLock, debugLogDir, debugLoggingEnabled, decodeStats, deviceHostArea, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, deviceHostRoot, deviceViewersDir, diskUsageCacheDir, diskUsageCacheFile, diskUsageFailureFile, diskUsageWalkClaims, easMachineStateRoot, easSessionLedgerFile, easSessionLedgerLock, emulatorLogFile, endedAgentSessionOf, endpoint, expectedShape, fileIdentity, fileSizes, findEnclosingWorktreeRoot, findPeer, findProjectRoot, fingerprintMemoDir, fingerprintMemoFile, fingerprintMemoLock, followLogs, footageDrops, gcLogDir, gcLogFile, getConcurrencyLimits, getConfigPath, getParkedMax, getProject, getProjectSettings, getRepoSettings, gitMergeCacheDir, hostedAgentDriverName, hostedAndroidDeviceName, hostedAndroidPlacements, hostedAndroidRecords, hostedAndroidStatus, hostedAppArea, hostedAppAttempt, hostedAppBlobs, hostedConsolePort, hostedDeviceId, hostedIosPlacements, hostedIosRecords, hostedIosStatus, hostedMacosAppSlot, hostedMacosBundleId, hostedMacosLogsDir, hostedMetroGateways, hostedMetroRequests, hostedNativeLogsDir, hostedNativeRecords, hostedWorkerSettleMs, isExpoErrorContext, isGcLogRecord, isJournalExpired, isJsonObject, isLayeredSetting, isPathPrefix, isSensitiveReference, isSetupJournalPrunable, lastUseFrom, levelRank, linkReplacedArchives, listRecordedDevices, listRecordedDevicesAsync, listSegments, listSegmentsAsync, listStatusCacheEntries, loadConfig, logFiles, machineCacheUsageFile, machineCapacity, machineEndpoint, macosAppState, maintenanceAttemptFile, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, markerWindow, offloadSummary, openLogDir, openSegmentName, parseHostedAgentAccess, parseHostedAgentGrant, parseHostedAndroidDevice, parseHostedAndroidPlacement, parseHostedAppManifest, parseHostedAppOffer, parseHostedChoice, parseHostedDevice, parseHostedIosPlacement, parseHostedLocalDeviceCount, parseHostedLogsCursor, parseHostedMacosChoice, parseHostedMacosDevice, parseHostedMacosPlacement, parseHostedNativeOffer, parseHostedNativePlacement, parseHostedOfferRequest, parseHostedPlatformDevice, parseHostedRequest, parseMachine, parseMachineCredential, parseMacosRecord, parseMaintenanceState, parseMissReason, parseNdjsonLine, parseNdjsonText, parseSetupJournal, parseSince, planLogQuery, projectRootDirectories, pullRequestCacheDir, pullRequestCacheFile, queryJsonLogs, queryLogs, readAgentDeviceUsage, readAgentDeviceUsageCache, readAgentSessionsCache, readArchive, readArchiveAsync, readArchiveState, readArchives, readArchivesAsync, readBuildDetail, readBuildHistory, readBuildMachines, readCreatedDevices, readDevServerStop, readDevServerStopRequest, readDeviceHostMachines, readDeviceIdleShutdowns, readDevicePlacement, readDiskUsage, readDiskUsageFailure, readEasSessionLedger, readEndedAgentSessions, readFingerprintMemo, readGcLog, readHomeIdentity, readHostedApp, readHostedAppMetadata, readHostedDevice, readHostedDeviceLedger, readHostedMacosApp, readHostedNativeLogsCheckpoint, readHostedSessions, readIdleStop, readJsonFile, readJsonObject, readLastBuilds, readLogRecords, readLogTimeline, readLogsSince, readMachineCacheUsage, readMacosRecord, readMaintenanceAttempt, readMaintenanceState, readNdjsonGenerations, readPullRequestCache, readRunEstimates, readSetupJournal, readStateFile, readStats, readStatsReport, readSwiftpmCacheUsage, readViewedDevices, readWarmRecord, readWorkspaceAgent, readWorkspaceState, recordMatches, recordedBytes, recordingDeviceName, recordingEnabled, rememberHostedAppBlobRename, requireAutomaticMachine, runId, saturation, serverLocalSocket, serverSetupDir, settingDefinition, settingValueError, settingsJsonSchema, setupJournalFile, sharedCcache, sharedCompilationCache, sharedGradle, sharedPods, sortByTs, statsFile, statsProjectKey, statusViews, stimBuildDigest, supervisorLogFile, supervisorPidFile, swiftpmCacheUsageFile, tailRead, trashRoot, trimCapacityRefusals, trimCapacityWaits, trimSamples, tryAcquireBuildSlotClaim, unreadableHostedAndroid, unreadableHostedIos, unreadableHostedNative, validEasSessionClaim, validHostedAppArguments, validHostedAppBlob, validRunId, validateAutomaticPool, wholePhases, windowsShortDir, windowsShortDirKey, withConfigLock, withConfigLockAsync, withDerivedFacts, withGitChip, withStateReadCache, workspaceAgentDeviceDir, workspaceBuildDetailFile, workspaceDerivedData, workspaceEndedAgentsFile, workspaceEndedAgentsLock, workspaceGradleBuild, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceRecordingsDir, workspaceStateFile, workspaceStateLock, workspaceSummary };
6732
+ 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_LEDGER_CAP, 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, FINGERPRINT_MEMO_SCHEMA, HISTORY_LIMIT, HOSTED_AGENT_DRIVERS, HOSTED_APP_CHUNK_BYTES, HOSTED_LOGS_FIRST_BYTES, HOSTED_LOGS_PAGE_BYTES, HOSTED_MACOS_APP_SLOTS, HOSTED_METRO_LINKS_KEY, HOSTED_METRO_REQUESTS_KEY, HOSTED_PARKED_CANDIDATES, IDLE_STOP_KEY, IOS_SIMULATOR_APPS, KeyedEntities, LAST_BUILD_KEYS, LEVELS, MACHINE_CREDENTIALS_VERSION, MACHINE_OWNER_KINDS, MAINTENANCE_LOG_NAME, MEMORY_SOURCES, NATIVE_BUILD_STEPS, NATIVE_CRASH_LOG_PREFIX, PHYSICAL_DEVICE_CONNECTIONS, PLACEMENT_DECISIONS, PLACEMENT_WORDS, READY_PHASE_MS, RECORDING_CAP_BYTES, RECORDING_FOOTAGE_MS, RECORDING_PLATFORMS, REMOTE_DEVICE_BACKENDS, REPLACED_SETTINGS, RUN_ID_ENV, SETTINGS, SETTINGS_SCHEMA_FILE, SETTINGS_SCHEMA_URL, SETTING_GROUPS, SETTING_SCOPES, SOURCES, STATS_VERSION, STATUS_ISSUE_CODES, SUMMARY_ARCHIVES, TAILNET_MACHINE_PATTERN, TRACE_ENV, TUNNEL_MODES, TUTORIAL_VERSION, WARM_KEY, WEB_PAGE_STATES, WEB_VIEWPORTS, WORKSPACE_AGENT_KEY, WORKSPACE_PHASES, WORKSPACE_STAGE_KINDS, acceptsShape, advanceTail, agentDeviceStateDirs, agentDeviceStateDirsAsync, agentDeviceUsageFile, agentSessionOf, agentSessionsCacheFile, allMetroPorts, applyKeyedDelta, archiveDir, archiveEnabled, archiveLock, archiveRoot, archivedUsage, assertHostedDeviceLedger, attachExpoErrorContext, automaticMachineEnabled, budgetSweepFile, budgetSweepLock, buildCriteria, buildDiagnostics, buildLedgerDir, buildLedgerFile, buildLedgerLock, buildMachinesFile, buildMachinesLock, buildSlotPath, buildSlotsDir, buildWorkerRoot, bundleMarkerPlatform, cannotHost, capDrops, clientIdentity, clientIdentityKeyFile, closedSegmentName, coerceSettingText, compileGrep, configCorruptRepair, configLockPath, countErrorEntries, createAgentActionReader, createAsyncAgentActionReader, createDebugLog, createNdjsonTail, createdDevicesFile, createdDevicesLock, debugLogDir, debugLoggingEnabled, decodeStats, deviceHostArea, deviceHostMachinesClaims, deviceHostMachinesFile, deviceHostMachinesLock, deviceHostRoot, deviceViewersDir, diskUsageCacheDir, diskUsageCacheFile, diskUsageFailureFile, diskUsageWalkClaims, easMachineStateRoot, easSessionLedgerFile, easSessionLedgerLock, emulatorLogFile, endedAgentSessionOf, endpoint, expectedShape, fileIdentity, fileSizes, findEnclosingWorktreeRoot, findPeer, findProjectRoot, fingerprintMemoDir, fingerprintMemoFile, fingerprintMemoLock, followLogs, footageDrops, gcLogDir, gcLogFile, getConcurrencyLimits, getConfigPath, getParkedMax, getProject, getProjectSettings, getRepoSettings, gitMergeCacheDir, hostedAgentDriverName, hostedAndroidDeviceName, hostedAndroidPlacements, hostedAndroidRecords, hostedAndroidStatus, hostedAppArea, hostedAppAttempt, hostedAppBlobs, hostedConsolePort, hostedDeviceId, hostedIosPlacements, hostedIosRecords, hostedIosStatus, hostedMacosAppSlot, hostedMacosBundleId, hostedMacosLogsDir, hostedMetroLinks, hostedMetroRequests, hostedNativeLogsDir, hostedNativeRecords, hostedWorkerSettleMs, isBuildLedgerRecord, isExpoErrorContext, isGcLogRecord, isJournalExpired, isJsonObject, isLayeredSetting, isPathPrefix, isSensitiveReference, isSetupJournalPrunable, lastNativeUseFrom, lastUseFrom, levelRank, linkReplacedArchives, listRecordedDevices, listRecordedDevicesAsync, listSegments, listSegmentsAsync, listStatusCacheEntries, loadConfig, loadPerCore, loadState, logFiles, machineCacheUsageFile, machineCapacity, machineEndpoint, macosAppState, maintenanceAttemptFile, maintenanceChildLogFile, maintenanceDir, maintenanceNdjsonFile, maintenanceRunClaims, maintenanceStateFile, markerWindow, maxLoadPerCore, mayRunHere, offloadSummary, openLogDir, openSegmentName, parseHostedAgentAccess, parseHostedAgentGrant, parseHostedAndroidDevice, parseHostedAndroidPlacement, parseHostedAppManifest, parseHostedAppOffer, parseHostedChoice, parseHostedDevice, parseHostedIosPlacement, parseHostedLocalDeviceCount, parseHostedLogsCursor, parseHostedMacosChoice, parseHostedMacosDevice, parseHostedMacosPlacement, parseHostedNativeOffer, parseHostedNativePlacement, parseHostedOfferRequest, parseHostedPlatformDevice, parseHostedRequest, parseMachine, parseMachineCredential, parseMacosRecord, parseMaintenanceState, parseMissReason, parseNdjsonLine, parseNdjsonText, parseSetupJournal, parseSince, placementWord, planLogQuery, prefersRemote, projectRootDirectories, pullRequestCacheDir, pullRequestCacheFile, queryJsonLogs, queryLogs, readAgentDeviceUsage, readAgentDeviceUsageCache, readAgentSessionsCache, readArchive, readArchiveAsync, readArchiveState, readArchives, readArchivesAsync, readBuildDetail, readBuildHistory, readBuildLedger, readBuildMachines, readCreatedDevices, readDevServerStop, readDevServerStopRequest, readDeviceHostMachines, readDeviceIdleShutdowns, readDevicePlacement, readDiskUsage, readDiskUsageFailure, readEasSessionLedger, readEndedAgentSessions, readFingerprintMemo, readGcLog, readHomeIdentity, readHostedApp, readHostedAppMetadata, readHostedDevice, readHostedDeviceLedger, readHostedMacosApp, readHostedNativeLogsCheckpoint, readHostedSessions, readIdleStop, readJsonFile, readJsonObject, readLastBuilds, readLogRecords, readLogTimeline, readLogsSince, readMachineCacheUsage, readMacosRecord, readMaintenanceAttempt, readMaintenanceState, readNdjsonGenerations, readPullRequestCache, readRunEstimates, readSetupJournal, readStateFile, readStats, readStatsReport, readSwiftpmCacheUsage, readViewedDevices, readWarmRecord, readWorkspaceAgent, readWorkspaceState, recordMatches, recordedBytes, recordingDeviceName, recordingEnabled, redactArgv, redactCommandLine, rememberHostedAppBlobRename, replacementAdvice, requireAutomaticMachine, runId, saturation, serverLocalSocket, serverSetupDir, settingDefinition, settingValueError, settingsJsonSchema, setupJournalFile, sharedCcache, sharedCompilationCache, sharedGradle, sharedPods, sortByTs, statsFile, statsProjectKey, statusViews, stimBuildDigest, supervisorLogFile, supervisorPidFile, swiftpmCacheUsageFile, tailRead, trace, trashRoot, trimCapacityRefusals, trimCapacityWaits, trimSamples, tryAcquireBuildSlotClaim, unreadableHostedAndroid, unreadableHostedIos, unreadableHostedNative, validEasSessionClaim, validHostedAppArguments, validHostedAppBlob, validRunId, validateAutomaticPool, wholePhases, windowsShortDir, windowsShortDirKey, withConfigLock, withConfigLockAsync, withDerivedFacts, withGitChip, withStateReadCache, workspaceAgentDeviceDir, workspaceBuildDetailFile, workspaceDerivedData, workspaceEndedAgentsFile, workspaceEndedAgentsLock, workspaceGradleBuild, workspaceLastUsed, workspaceLightenedFile, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceRecordingsDir, workspaceStateFile, workspaceStateLock, workspaceSummary, worktreeArchiveRoot };