@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.
@@ -160,613 +160,690 @@ interface MachineCacheUsage {
160
160
  declare function machineCacheUsageFile(): string;
161
161
  declare function readMachineCacheUsage(): MachineCacheUsage | null;
162
162
  //#endregion
163
- //#region state/build-capacity.d.ts
164
- declare function buildSlotsDir(): string;
165
- declare function buildSlotPath(index: number): string;
163
+ //#region state/hosted-app.d.ts
164
+ interface HostedAppFile {
165
+ path: string;
166
+ kind: "file" | "exec" | "link";
167
+ size: number;
168
+ sha256: string;
169
+ }
170
+ interface HostedAppOffer {
171
+ session: string;
172
+ attempt: string;
173
+ bundleId: string;
174
+ mode: "development" | "release" | "process";
175
+ devClientScheme?: string;
176
+ arguments?: string[];
177
+ manifest: {
178
+ sha256: string;
179
+ size: number;
180
+ };
181
+ }
182
+ interface HostedAppDelivery extends Omit<HostedAppOffer, "manifest"> {
183
+ state: "receiving" | "installing" | "installed" | "unknown";
184
+ launched: true | "unverified" | null;
185
+ notice?: string;
186
+ }
187
+ interface HostedAppRecord extends HostedAppDelivery {
188
+ manifest: HostedAppOffer["manifest"];
189
+ files: HostedAppFile[];
190
+ }
191
+ declare const HOSTED_APP_CHUNK_BYTES: number;
192
+ declare function hostedAppAttempt(value: unknown): value is string;
193
+ declare function hostedAppArea(session: string, attempt: string, workerHome?: string): string;
194
+ declare function hostedAppBlobs(session: string, workerHome?: string): string;
195
+ /** Transfers cached verification after a rename, only for the same inode, size, mtime and digest. */
196
+ declare function rememberHostedAppBlobRename(from: string, to: string, file: {
197
+ size: number;
198
+ sha256: string;
199
+ }): void;
200
+ /** Checks regular blob bytes, including their size, before content-addressed reuse. */
201
+ declare function validHostedAppBlob(path: string, file: {
202
+ size: number;
203
+ sha256: string;
204
+ }): boolean;
205
+ /** At most 32 plain arguments of 1024 characters (8192 in total), with no NUL, CR or LF. */
206
+ declare function validHostedAppArguments(value: unknown): value is string[];
207
+ declare function parseHostedAppOffer(value: unknown): HostedAppOffer | null;
208
+ /** Relative normalized paths, with no file or link as another entry's ancestor. */
209
+ declare function parseHostedAppManifest(value: unknown): HostedAppFile[] | null;
210
+ /** Reads a server-written receipt; malformed or missing established state remains unresolved. */
211
+ declare function readHostedAppMetadata(session: string, attempt: string, workerHome?: string): Omit<HostedAppRecord, "files">;
212
+ declare function readHostedApp(session: string, attempt: string, workerHome?: string): HostedAppRecord;
213
+ //#endregion
214
+ //#region state/hosted-macos.d.ts
215
+ /** App slots one host offers; a slot names the host-assigned bundle id `<bundleId>.hosted<slot>`. */
216
+ declare const HOSTED_MACOS_APP_SLOTS = 64;
217
+ /** The drivers `hosting.agentDriver` can name: `none` and the first-party driver packages stim-server ships. */
218
+ declare const HOSTED_AGENT_DRIVERS: readonly ["none", "agent-device"];
219
+ type HostedAgentDriverName = (typeof HOSTED_AGENT_DRIVERS)[number];
220
+ /** A driver name a grant or access record can carry; a client resolves only the drivers it knows. */
221
+ declare function hostedAgentDriverName(value: unknown): value is string;
222
+ /** What a host reports in a macOS offer: no simulator is created, so the choice is the host itself. */
223
+ interface HostedMacosChoice {
224
+ architecture: "arm64" | "x86_64";
225
+ macosVersion: string;
226
+ }
227
+ /** A ready hosted macOS session's identity: the host it runs on and the app slot reserved for it. */
228
+ interface HostedMacosDevice extends HostedMacosChoice {
229
+ appSlot: number;
230
+ }
166
231
  /**
167
- * Takes the first free one of `max` `concurrency.maxBuilds` slots, recording `details` and the slot `index`. Returns
168
- * null while every slot is held; throws the claim refusal when no slot is busy but one cannot be resolved.
232
+ * The agent-device lease owner scope a client names on every request. `deviceKey` is `<bundleId>@<pid>`
233
+ * for a macOS app, or `ios:mobile:<udid>` with `backend: ios-instance` for a hosted simulator, or `android:mobile:<serial>` with `backend: android-instance` for a hosted emulator.
169
234
  */
170
- declare function tryAcquireBuildSlotClaim({ max, details }: {
171
- max: number;
172
- details: Record<string, unknown>;
173
- }): {
174
- claim: ClaimHandle;
175
- index: number;
176
- path: string;
177
- } | null;
235
+ interface HostedAgentLease {
236
+ tenant: string;
237
+ runId: string;
238
+ clientId: string;
239
+ deviceKey: string;
240
+ backend?: "ios-instance" | "android-instance";
241
+ }
178
242
  /**
179
- * How busy this machine is for native builds. `loadPerCore` is the 5-minute load average divided by the CPU count,
180
- * rounded to one decimal. `builds` counts this Stim home's runs that hold a live native-run claim and are in
181
- * prebuild, pods or compile here, not on a remote machine, plus the build slots this machine holds for other machines'
182
- * offloaded builds. `maxBuilds` is `concurrency.maxBuilds`, 0 when unlimited.
243
+ * Agent control a driver issues for one installed hosted app. `path` is the session's base route on the host,
244
+ * `scope` the driver's handle that limits it to this one app, and `lease`, for a driver that allocates leases,
245
+ * the scope that pins the allocation.
183
246
  */
184
- interface MachineCapacity {
185
- cpus: number;
186
- loadPerCore: number;
187
- builds: number;
188
- maxBuilds: number;
189
- maxLoadPerCore: number;
247
+ interface HostedAgentIssuedGrant {
248
+ driver: string;
249
+ path: string;
250
+ token: string;
251
+ scope: string;
252
+ lease?: HostedAgentLease;
190
253
  }
191
- declare function machineCapacity(): MachineCapacity;
192
- /** Why a machine with this capacity should not take another native build; null when it can. */
193
- declare function saturation(capacity: MachineCapacity): string | null;
194
- //#endregion
195
- //#region state/build-machines.d.ts
196
254
  /**
197
- * What this machine keeps about a remote machine it asked for access. `machine` is the `remote.machines` entry and
198
- * `address` the name it resolved to. Once approved, `serverKey` is the worker's pinned stim-server key: every later
199
- * connection must prove it holds that key. While pending, `ticket` is the setup ticket this machine generated or was
200
- * given, and `expiresAt` its expiry when known. Records of protocol 1, which pinned a tailnet node, are not read.
255
+ * Agent control the host grants a client for one installed hosted app, sent only over that client's approved
256
+ * device-host connection and never journaled. `none` means the host's `hosting.agentDriver` starts no driver.
201
257
  */
202
- interface MachineCredential {
258
+ type HostedAgentGrant = {
259
+ driver: "none";
260
+ } | HostedAgentIssuedGrant;
261
+ /** `app.launch` and `app.attach` results; a host includes `agent` once the app is installed. */
262
+ type HostedAppLaunch = HostedAppDelivery & {
263
+ agent?: HostedAgentGrant;
264
+ };
265
+ /**
266
+ * Agent control as the client hands it to a coding agent: secrets stay in files Stim writes with mode
267
+ * 0600, and `command` shows how to address the hosted app. Never carries a token inline. `setting` names
268
+ * the hosting Mac's setting that turns a driver on.
269
+ */
270
+ type HostedAgentAccess = {
271
+ driver: "none";
272
+ setting: "hosting.agentDriver";
273
+ } | {
274
+ driver: string;
275
+ remoteConfig: string;
276
+ command: string;
277
+ };
278
+ /** Where a workspace's macOS app runs when `stim macos --remote` placed it on another Mac. */
279
+ interface HostedMacosPlacement {
203
280
  machine: string;
204
- transport: "tailscale";
205
- address: string;
206
- state: "pending" | "approved";
207
- requestedAt: string;
208
- serverKey?: string;
209
- deviceId?: string;
210
- ticket?: string;
211
- expiresAt?: string;
281
+ session: string;
282
+ appSlot: number;
283
+ appAttempt: string;
284
+ /** The host-assigned id the running app uses, `hostedMacosBundleId(<offered id>, appSlot)`. */
285
+ bundleId: string;
286
+ agent: HostedAgentAccess;
212
287
  }
213
- type BuildMachineCredential = MachineCredential;
214
- declare const MACHINE_CREDENTIALS_VERSION = 2;
215
- /** A stored credential, or null when it is malformed or from an older version. */
216
- declare function parseMachineCredential(value: unknown): MachineCredential | null;
217
- declare function readBuildMachines(): BuildMachineCredential[];
218
- //#endregion
219
- //#region state/client-identity.d.ts
220
- /** This machine's long-term X25519 key as a client of other machines, in `$STIM_HOME/client-identity.key`. */
221
- declare function clientIdentity(): NoiseKeyPair;
288
+ declare function hostedMacosAppSlot(value: unknown): value is number;
289
+ declare function hostedMacosBundleId(bundleId: string, appSlot: number): string;
290
+ declare function parseHostedMacosChoice(value: unknown): HostedMacosChoice | null;
291
+ declare function parseHostedMacosDevice(value: unknown): HostedMacosDevice | null;
292
+ /** A grant naming a driver this client does not know is not usable; it parses as null. */
293
+ declare function parseHostedAgentGrant(value: unknown): HostedAgentGrant | null;
294
+ declare function parseHostedAgentAccess(value: unknown): HostedAgentAccess | null;
295
+ declare function parseHostedMacosPlacement(value: unknown): HostedMacosPlacement | null;
222
296
  //#endregion
223
- //#region state/config-types.d.ts
224
- type SettingsObject = Record<string, unknown>;
225
- interface SupervisorRecord {
226
- processToken?: string;
227
- pid?: number;
228
- port?: number;
229
- startedAt?: string;
230
- serverPid?: number;
231
- mode?: string;
232
- [key: string]: unknown;
297
+ //#region state/device-host.d.ts
298
+ type HostedDevicePlatform = "ios" | "android" | "macos";
299
+ /** Deadlines stim-server gives each hosted worker run. Clients derive their waits from these. */
300
+ interface DeviceHostLimits {
301
+ prepareMs: number;
302
+ offerMs: number;
303
+ stopMs: number;
304
+ logsMs: number;
305
+ killGraceMs: number;
233
306
  }
234
- interface IosDeviceRecord {
235
- deviceUdid?: string;
236
- deviceName?: string | null;
237
- owned?: boolean;
238
- serial?: string;
239
- simslimManaged?: boolean;
240
- simslimApplied?: {
241
- profile: string;
242
- springBoardPid: number;
243
- };
244
- schemeApprovals?: string[];
245
- [key: string]: unknown;
307
+ declare const DEVICE_HOST_LIMITS: Readonly<DeviceHostLimits>;
308
+ /** How many parked sessions one reserve inspects, and possibly retires, before it creates a device. */
309
+ declare const HOSTED_PARKED_CANDIDATES: number;
310
+ /** How long a cancelled hosted worker run can take to settle: SIGTERM, SIGKILL after the grace, then it is abandoned. */
311
+ declare function hostedWorkerSettleMs(limits?: Pick<DeviceHostLimits, "killGraceMs">): number;
312
+ interface HostedIosChoice {
313
+ deviceTypeId: string;
314
+ runtimeId: string;
315
+ deviceType: string;
316
+ runtime: string;
317
+ architecture: "arm64" | "x86_64";
246
318
  }
247
- interface AndroidDeviceRecord {
248
- avdName?: string;
249
- consolePort?: number;
250
- serial?: string;
251
- kind?: string;
252
- deviceName?: string | null;
253
- owned?: boolean;
254
- setupIncomplete?: boolean;
255
- bootPending?: boolean;
256
- [key: string]: unknown;
319
+ interface HostedIosDevice extends HostedIosChoice {
320
+ udid: string;
321
+ name: string;
257
322
  }
258
- type DeviceRecord = IosDeviceRecord | AndroidDeviceRecord;
259
- interface PlatformRecords {
260
- ios?: IosDeviceRecord;
261
- android?: AndroidDeviceRecord;
262
- [platform: string]: DeviceRecord | undefined;
323
+ interface HostedAndroidChoice {
324
+ systemImage: string;
325
+ deviceProfile: string;
326
+ architecture: "arm64-v8a" | "x86_64";
263
327
  }
264
- interface ProjectRecord {
265
- ports?: Record<string, number>;
266
- metroPort?: number | null;
267
- platforms?: PlatformRecords;
268
- deviceSlots?: Record<string, PlatformRecords>;
269
- supervisor?: SupervisorRecord;
270
- settings?: SettingsObject;
271
- worktreeRoot?: boolean;
272
- worktreeBranch?: string;
273
- worktreeBranchOwned?: boolean;
274
- worktreeMainRoot?: string;
275
- worktreeRemovalComplete?: boolean;
276
- worktreePendingBranchSha?: string;
277
- label?: string;
278
- bundleId?: string;
279
- androidPackage?: string;
280
- isExpo?: boolean;
281
- lastBuild?: Record<string, unknown>;
282
- doctorRuns?: Partial<Record<"ios" | "android", DoctorRunRecord>>;
283
- [key: string]: unknown;
284
- }
285
- interface DoctorRunRecord {
286
- at: string;
287
- version: string;
328
+ interface HostedAndroidDevice extends HostedAndroidChoice {
329
+ avdName: string;
330
+ serial: string;
331
+ consolePort: number;
288
332
  }
289
- interface RepoRecord {
290
- settings?: SettingsObject;
291
- [key: string]: unknown;
333
+ type HostedDevice = HostedIosDevice | HostedAndroidDevice | HostedMacosDevice;
334
+ interface HostedDeviceSelectors {
335
+ deviceType?: string;
336
+ runtime?: string;
337
+ systemImage?: string;
338
+ deviceProfile?: string;
292
339
  }
293
- interface ConcurrencyLimits {
294
- maxBuilds: number;
295
- maxDevices: number;
340
+ interface HostedDeviceOfferRequest extends HostedDeviceSelectors {
341
+ platform: HostedDevicePlatform;
296
342
  }
297
- interface StimConfig {
298
- version?: number;
299
- homeId?: string;
300
- projects: Record<string, ProjectRecord>;
301
- repos: Record<string, RepoRecord>;
302
- tempDir?: unknown;
303
- iosSimulatorApp?: unknown;
304
- androidEmulatorApp?: unknown;
305
- optimizations?: unknown;
306
- concurrency?: {
307
- maxBuilds?: unknown;
308
- maxDevices?: unknown;
343
+ type HostedNativeOffer = {
344
+ resources: {
345
+ cpus: number;
346
+ /** Five-minute system load divided by available CPU count. */
347
+ loadPerCore: number;
348
+ maxLoadPerCore?: number;
349
+ memoryFreeBytes: number;
350
+ memoryPressure: "normal" | "warning" | "critical" | null;
351
+ /** Available bytes on the Stim home volume, not necessarily the Android AVD volume. */
352
+ workerDiskFreeBytes: number | null;
353
+ localDevices?: number | {
354
+ unknown: string;
355
+ };
309
356
  };
310
- pool?: {
311
- iosParkedMax?: unknown;
312
- androidParkedMax?: unknown;
357
+ declined: string | null;
358
+ } & ({
359
+ platform: "ios";
360
+ choice: HostedIosChoice | null;
361
+ } | {
362
+ platform: "android";
363
+ choice: HostedAndroidChoice | null;
364
+ } | {
365
+ platform: "macos";
366
+ choice: HostedMacosChoice | null;
367
+ });
368
+ type HostedDeviceOffer = HostedNativeOffer & {
369
+ capacity: {
370
+ running: number;
371
+ max: number;
372
+ available: number | null;
373
+ local?: number | {
374
+ unknown: string;
375
+ };
313
376
  };
377
+ };
378
+ interface HostedDeviceRequest extends HostedDeviceOfferRequest {
379
+ workspace: string;
380
+ slot: string;
381
+ attempt: string;
382
+ }
383
+ type HostedDevicePhase = "preparing" | "ready" | "stopping" | "stopped" | "unknown";
384
+ interface HostedDeviceSession extends HostedDeviceRequest {
385
+ id: string;
386
+ client: string;
387
+ state: HostedDevicePhase;
388
+ device: HostedDevice | null;
389
+ consolePort?: number;
390
+ appSlot?: number;
391
+ createdAt: string;
314
392
  parked?: {
315
- ios?: unknown;
316
- android?: unknown;
317
- };
318
- caches?: {
319
- buildCache?: unknown;
320
- metroCache?: unknown;
321
- };
322
- hosting?: {
323
- agentDriver?: unknown;
324
- };
325
- debug?: {
326
- logs?: unknown;
327
- };
328
- server?: {
329
- buildsPaused?: unknown;
330
- devicesPaused?: unknown;
331
- acceptClientBuilds?: unknown;
332
- maxLoadPerCore?: unknown;
333
- workerRoot?: unknown;
334
- gradleDaemonIdleMinutes?: unknown;
335
- };
336
- remote?: {
337
- machines?: unknown;
338
- easMaxDurationMinutes?: unknown;
339
- build?: unknown;
340
- buildMode?: unknown;
341
- buildPoolDisabled?: unknown;
342
- devicePoolDisabled?: unknown;
393
+ at: string;
343
394
  };
344
- [key: string]: unknown;
395
+ notice?: string;
396
+ appAttempt?: string;
397
+ agent?: HostedAgentGrant;
398
+ metroPort?: number;
399
+ clientMetroPort?: number;
345
400
  }
346
- type Config = StimConfig;
347
- //#endregion
348
- //#region state/automatic-pools.d.ts
349
- type AutomaticPoolRole = "build" | "device";
350
- declare function automaticMachineEnabled(role: AutomaticPoolRole, machine: string, config?: StimConfig | null): boolean;
351
- declare function requireAutomaticMachine(role: AutomaticPoolRole, machine: string): void;
352
- /**
353
- * Refuses a pool with no enabled member: local, or a configured remote approved for the role. `canHost` excludes
354
- * device-pool remotes that can never host, such as a Linux machine.
355
- */
356
- declare function validateAutomaticPool(role: AutomaticPoolRole, config: StimConfig, canHost?: (machine: string) => boolean): void;
401
+ declare function deviceHostRoot(): string;
402
+ declare function deviceHostArea(id: string): string;
403
+ declare function parseHostedChoice(value: unknown): HostedIosChoice | null;
404
+ declare function parseHostedDevice(value: unknown): HostedIosDevice | null;
405
+ declare function parseHostedAndroidDevice(value: unknown): HostedAndroidDevice | null;
406
+ /** Android Emulator -help-port defines the supported even console ports as 5554 through 5584. */
407
+ declare function hostedConsolePort(value: unknown): value is number;
408
+ declare function parseHostedPlatformDevice(value: unknown, platform: HostedDevicePlatform): HostedDevice | null;
409
+ declare function hostedDeviceId(device: HostedDevice): string;
410
+ declare function parseHostedRequest(value: unknown): HostedDeviceRequest | null;
411
+ declare function parseHostedOfferRequest(value: unknown): HostedDeviceOfferRequest | null;
412
+ declare function parseHostedLocalDeviceCount(value: unknown): number | {
413
+ unknown: string;
414
+ } | null;
415
+ declare function parseHostedNativeOffer(value: unknown): HostedNativeOffer | null;
416
+ /** A missing established journal or malformed record is a refusal, never an empty reservation set. */
417
+ declare function readHostedSessions(): HostedDeviceSession[];
418
+ /** The private worker's exact device record; an absent record is unresolved after creation started. */
419
+ declare function readHostedDevice(home: string): HostedIosDevice;
420
+ declare function readHostedDevice(home: string, platform: "android"): HostedAndroidDevice;
421
+ declare function readHostedDevice(home: string, platform: "macos"): HostedMacosDevice;
422
+ declare function readHostedDevice(home: string, platform: HostedDevicePlatform): HostedDevice;
423
+ declare function readHostedDeviceLedger(home: string, options?: {
424
+ required?: boolean;
425
+ }): {
426
+ ios: string[];
427
+ android: string[];
428
+ web: string[];
429
+ } | null;
430
+ /** Hosted sessions use isolated homes: only one exact device of their platform may appear in this ledger. */
431
+ declare function assertHostedDeviceLedger(home: string, id: string, platform?: HostedDevicePlatform, options?: {
432
+ allowEmpty?: boolean;
433
+ }): "listed" | "empty";
357
434
  //#endregion
358
- //#region state/config.d.ts
359
- declare function withConfigLock<T>(fn: () => T): T;
360
- /** Waits for the config lock without blocking the event loop. The signal cancels acquisition; `fn` runs synchronously. */
361
- declare function withConfigLockAsync<T>(fn: () => T, signal?: AbortSignal): Promise<T>;
362
- declare function configCorruptRepair(path?: string): string;
363
- /** The build worker root: `server.workerRoot` when it is absolute, else `$STIM_HOME/build-worker`. */
364
- declare function buildWorkerRoot(config?: Config | null): string;
365
- /**
366
- * A short directory at the drive root that stands in for the build worker directory `path` on Windows. The NDK's
367
- * ninja is not long-path aware (STIM_PATH_TOO_LONG), and it opens paths under the checkout and under the Gradle user
368
- * home's transforms cache, both of which are too long under the worker root. A subst drive does not help: Node's
369
- * native realpath, which expo-modules-autolinking uses, resolves it back to the long path.
370
- */
371
- declare function windowsShortDir(path: string, systemDrive?: string): string;
372
- /** The ASCII key a Windows build worker records beside a `windowsShortDir` to tell which `kind` and `path` it serves. */
373
- declare function windowsShortDirKey(kind: "checkout" | "gradle", path: string): string;
374
- declare function loadConfig(): Config | null;
375
- declare function getProject(projectPath: string): ProjectRecord | null;
376
- declare function getConcurrencyLimits({ env }?: {
377
- env?: NodeJS.ProcessEnv;
378
- }): ConcurrencyLimits;
379
- interface ParkedMax {
380
- max: number;
381
- error: string | null;
435
+ //#region state/workspace-state.d.ts
436
+ interface WorkspaceState {
437
+ supervisor?: Record<string, unknown>;
438
+ collectors?: Record<string, unknown>;
439
+ lastBuild?: Record<string, unknown>;
440
+ launches?: Record<string, unknown>;
441
+ remoteDevice?: Record<string, unknown>;
442
+ metroTunnel?: Record<string, unknown>;
443
+ [key: string]: unknown;
382
444
  }
383
- declare function getParkedMax(platform: "ios" | "android", { config, env }?: {
384
- config?: Config | null;
385
- env?: NodeJS.ProcessEnv;
386
- }): ParkedMax;
387
- declare function getProjectSettings(projectPath: string): Record<string, unknown>;
388
- declare function getRepoSettings(gitCommonDir: string): Record<string, unknown>;
389
- declare function isPathPrefix(prefix: string, path: string): boolean;
390
- declare function findEnclosingWorktreeRoot(projectPath: string): string | null;
391
- declare function allMetroPorts(): number[];
392
- //#endregion
393
- //#region state/debug-log.d.ts
394
- declare const DEBUG_ENV = "STIM_DEBUG";
395
- declare function debugLogDir(): string;
396
- /** The `STIM_DEBUG` override (1/true on, 0/false off, anything else off), else the machine setting `debug.logs`. Never throws. */
397
- declare function debugLoggingEnabled(env?: NodeJS.ProcessEnv): boolean;
398
- interface DebugLog {
399
- /** Whether debug logging is on right now; re-read every few seconds so a long-running process follows the setting. */
400
- enabled(): boolean;
401
- /** Appends one record to `$STIM_HOME/logs/debug/<component>.ndjson` when enabled. Never throws; keys that look like secrets are redacted. */
402
- log(event: string, fields?: Record<string, unknown>): void;
445
+ declare const IDLE_STOP_KEY = "devServerStop";
446
+ /** Why the supervisor last stopped the dev server on its own: `metro.idleStopMinutes` with no use. */
447
+ interface IdleStopRecord {
448
+ reason: "idle";
449
+ at: string;
450
+ idleMinutes: number;
451
+ }
452
+ declare function readIdleStop(state: WorkspaceState | null | undefined): IdleStopRecord | null;
453
+ declare const DEVICE_RECLAIM_REASON = "reclaimed for a waiting run";
454
+ declare const DEVICE_IDLE_SHUTDOWN_KEY = "deviceIdleShutdowns";
455
+ /** An owned simulator or emulator shut down after being idle. */
456
+ interface DeviceIdleShutdownRecord {
457
+ at: string;
458
+ idleMinutes: number;
459
+ reason?: string;
460
+ }
461
+ /** The recorded idle shutdowns by device slot key (`ios`, `android`, `ios:<slot>`). */
462
+ declare function readDeviceIdleShutdowns(state: WorkspaceState | null | undefined): Record<string, DeviceIdleShutdownRecord>;
463
+ declare const DEV_SERVER_STOP_REQUEST_KEY = "devServerStopRequest";
464
+ /** A Stim component's intent to stop the supervisor with `processToken`, written before it signals. */
465
+ interface DevServerStopRequest {
466
+ processToken: string;
467
+ by: string;
468
+ pid: number;
469
+ at: string;
470
+ workspace?: string;
403
471
  }
472
+ declare function readDevServerStopRequest(state: WorkspaceState | null | undefined): DevServerStopRequest | null;
404
473
  /**
405
- * Debug-level records for one component (`cli` or `server`). Off by default; `STIM_DEBUG=1` or `debug.logs` turns it
406
- * on. Callers pass names, durations and codes, never arguments, environment values, tokens or tickets.
474
+ * Why the dev server last stopped, stored under `IDLE_STOP_KEY`. `requested` names the Stim component that
475
+ * asked; `signal` is a SIGTERM or SIGINT no Stim component asked for; `server-exited` is the dev server
476
+ * process exiting on its own.
407
477
  */
408
- declare function createDebugLog(component: "cli" | "server", { env, now, base }?: {
409
- env?: NodeJS.ProcessEnv;
410
- now?: () => number;
411
- base?: () => Record<string, unknown>;
412
- }): DebugLog;
413
- //#endregion
414
- //#region state/home-identity.d.ts
415
- /** The persistent, nonsecret identity of this Stim home; null until the CLI initializes it. */
416
- declare function readHomeIdentity(config?: Config | null): string | null;
417
- //#endregion
418
- //#region state/json-file.d.ts
478
+ type DevServerStopRecord = IdleStopRecord | {
479
+ reason: "requested";
480
+ at: string;
481
+ by: string;
482
+ byPid: number;
483
+ byWorkspace?: string;
484
+ } | {
485
+ reason: "signal";
486
+ at: string;
487
+ signal: string;
488
+ } | {
489
+ reason: "server-exited";
490
+ at: string;
491
+ mode: string;
492
+ code: number | null;
493
+ signal: string | null;
494
+ };
495
+ /** A stopped dev server's last cause in status; `vanished` is a supervisor proven gone that recorded none. */
496
+ type MetroLastStop = DevServerStopRecord | {
497
+ reason: "vanished";
498
+ pid: number;
499
+ startedAt: string | null;
500
+ };
501
+ declare function readDevServerStop(state: WorkspaceState | null | undefined): DevServerStopRecord | null;
502
+ /** Each platform's latest run; `lastBuild` holds whichever platform ran last. */
503
+ declare const LAST_BUILD_KEYS: Readonly<Record<StatsPlatform, string>>;
504
+ declare const BUILD_HISTORY_KEY = "buildHistory";
505
+ declare const BUILD_HISTORY_LIMIT = 10;
506
+ /** A recorded miss reason in the shape status reports, without `baseline.cacheKey`; null when malformed. */
507
+ declare function parseMissReason(value: unknown): BuildMissReason | null;
419
508
  /**
420
- * Runs `fn` with each state file read from disk at most once: inside it, including after an `await`, `readStateFile`
421
- * 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
422
- * share a mutable object. Only for computations that write none of the files they read.
509
+ * The first diagnostics of a failed build in the shape a last-build record stores and `status` reports, the
510
+ * ones with a source position first.
423
511
  */
424
- declare function withStateReadCache<T>(fn: () => T): T;
425
- declare function readStateFile(path: string): string;
426
- declare function readJsonFile(path: string): unknown;
427
- declare function isJsonObject(value: unknown): value is Record<string, unknown>;
428
- declare function readJsonObject(path: string): Record<string, unknown> | null;
429
- //#endregion
430
- //#region state/ledgers.d.ts
431
- type CreatedDevicePlatform = "ios" | "android" | "web";
432
- /** `web` lists the absolute paths of browser profile directories Stim created. */
433
- interface CreatedDevices {
434
- ios: ReadonlySet<string>;
435
- android: ReadonlySet<string>;
436
- web: ReadonlySet<string>;
437
- }
438
- declare function readCreatedDevices(): CreatedDevices;
439
- interface EasSessionClaim {
440
- sessionId: string;
441
- name: string;
442
- platform: "ios" | "android";
443
- workspaceRoot: string;
444
- workspaceHome: string;
445
- stateFile: string;
446
- }
447
- interface EasSessionLedgerRead {
448
- claims: Map<string, EasSessionClaim>;
449
- notice: string | null;
450
- safe: boolean;
451
- }
452
- /** Returns the claim normalized to canonical paths, or null when it is not a valid claim for `id`. */
453
- declare function validEasSessionClaim(id: string, value: unknown): EasSessionClaim | null;
454
- declare function readEasSessionLedger(root?: string): EasSessionLedgerRead;
455
- //#endregion
456
- //#region state/error-entries.d.ts
512
+ declare function buildDiagnostics(value: unknown): BuildDiagnostic[];
513
+ declare function readDevicePlacement(state: WorkspaceState | null, platform: StatsPlatform, slot?: string): DevicePlacement | null;
514
+ declare function readLastBuilds(state: WorkspaceState | null | undefined): Partial<Record<StatsPlatform, LastBuildReport>>;
515
+ /** Each platform's recorded runs, newest first, at most `BUILD_HISTORY_LIMIT` each. */
516
+ declare function readBuildHistory(state: WorkspaceState | null | undefined): Partial<Record<BuildPlatform, BuildHistoryEntry[]>>;
517
+ declare function readWorkspaceState(root: string): WorkspaceState | null;
518
+ declare function lastUseFrom(state: WorkspaceState | null, logMtimes: readonly number[]): number;
457
519
  /**
458
- * The number of rows a log list shows for `records`, an error query's result in log order. Stim Desktop's
459
- * `LogEntryList` and the phone's `groupRecords` group the same way and replay the same vectors: in Expo's dev
460
- * server one failed bundle is a `Bundling failed` marker line, the error line and a failed bundle response,
461
- * which the apps list as one row, and every other record is its own row.
520
+ * When an ios, android or macos run last finished in the workspace, from its recorded builds (a cache hit counts),
521
+ * in epoch milliseconds; NaN when it records none. Dev server starts, reloads and logs do not count.
462
522
  */
463
- declare function countErrorEntries(records: readonly NdjsonRecord[]): number;
464
- //#endregion
465
- //#region state/fingerprint-memo.d.ts
466
- declare const FINGERPRINT_MEMO_SCHEMA = 1;
467
- /** Full native fingerprints shared by every workspace of this Stim home, one file per platform and static digest. */
468
- declare function fingerprintMemoDir(platform?: string): string;
469
- declare function fingerprintMemoFile(platform: string, digest: string): string;
470
- declare function fingerprintMemoLock(): string;
471
- /** The full fingerprint a tree with this static digest produced, written by the CLI. */
472
- interface FingerprintMemoRecord {
473
- schema: typeof FINGERPRINT_MEMO_SCHEMA;
474
- platform: string;
475
- digest: string;
476
- recordedAt: number;
477
- hash: string;
478
- sources: unknown[];
479
- /** The packages the static check counted as native, to name the ones a disagreeing check found it missed. */
480
- nativePackages: string[];
481
- }
482
- declare function readFingerprintMemo(platform: string, digest: string): FingerprintMemoRecord | null;
483
- //#endregion
484
- //#region state/logs-query.d.ts
485
- interface SinceResult {
486
- ms?: number;
487
- error?: string;
488
- }
489
- interface GrepResult {
490
- re?: RegExp;
491
- error?: string;
492
- }
493
- interface MarkerWindow {
494
- launchTs: number | null;
495
- bundleTs: number | null;
496
- pageLoadTs: number | null;
497
- }
498
- interface QueryCriteria {
499
- slot?: string;
500
- includeAppDeviceErrors?: boolean;
501
- sources?: string[];
502
- minLevel?: string;
503
- grep?: RegExp;
504
- sinceTs?: number;
505
- errorsOnly?: boolean;
506
- markerTs?: number;
507
- bundleMarkerTs?: number;
508
- }
509
- interface TailState {
510
- offset: number;
511
- partial: string;
512
- }
513
- declare function parseSince(text: unknown): SinceResult;
514
- declare function compileGrep(pattern: unknown): GrepResult;
515
- declare const ERROR_SOURCES: string[];
516
- declare function markerWindow(records: NdjsonRecord[]): MarkerWindow;
523
+ declare function lastNativeUseFrom(state: WorkspaceState | null): number;
524
+ declare const MAINTENANCE_LOG_NAME = "maintenance.ndjson";
517
525
  /**
518
- * The platform a bundle marker speaks for, lowercased: its `platform` field, or the tag @expo/cli prints before
519
- * "Bundled" ("iOS", "Android", "Web", "RSC(iOS)" as ios, or an environment tag such as "DOM"). Null when unknown.
526
+ * When the workspace was last used, in epoch milliseconds. A workspace that recorded no use falls back to the mtime
527
+ * of its workspace.json, which is written once when the workspace is created, so it is a lower bound on the last
528
+ * use. NaN when its state.json exists but does not parse, or when workspace.json cannot be read either.
520
529
  */
521
- declare function bundleMarkerPlatform(record: NdjsonRecord): string | null;
522
- declare function recordMatches(record: NdjsonRecord | null | undefined, criteria?: QueryCriteria): boolean;
523
- declare function buildCriteria({ slot, sources, minLevel, since, grep, errorsOnly, markerTs, bundleMarkerTs, now }?: {
524
- slot?: string;
525
- sources?: string[];
526
- minLevel?: string;
527
- since?: string | null;
528
- grep?: string | RegExp | null;
529
- errorsOnly?: boolean;
530
- markerTs?: number;
531
- bundleMarkerTs?: number;
532
- now?: number;
533
- }): QueryCriteria;
534
- declare function logFiles(dir: string): string[];
535
- declare function fileSizes(dir: string): Record<string, number>;
536
- declare function readLogRecords(dir: string, include?: (name: string) => boolean): NdjsonRecord[];
537
- declare const NATIVE_CRASH_LOG_PREFIX = "native-crash-";
538
- /** Reads the CLI timeline with retained native crash records after other records at the same timestamp. */
539
- declare function readLogTimeline(dir: string, records?: NdjsonRecord[]): NdjsonRecord[];
540
- declare function isExpoErrorContext(record: NdjsonRecord, event: unknown): boolean;
541
- type ExpoContextTarget = "msg" | "field";
530
+ declare function workspaceLastUsed(root: string): number;
531
+ declare const WARM_KEY = "warm";
532
+ /** How long a successful warm keeps a workspace `ready` when nothing runs in it. */
533
+ declare const READY_PHASE_MS: number;
542
534
  /**
543
- * Adds the code frame and stack lines Expo printed after each Expo error record, either joined into
544
- * `msg` or as a `context` string array.
535
+ * What `stim worktree warm` last recorded in a workspace: a warm in progress, held by the ownership claim
536
+ * `claim` names, or a successful warm that finished at `at`.
545
537
  */
546
- declare function attachExpoErrorContext(all: NdjsonRecord[], matched: NdjsonRecord[], into?: ExpoContextTarget): NdjsonRecord[];
547
- interface LogQueryOptions {
548
- slot?: string;
549
- sources?: string[];
550
- minLevel?: string;
551
- since?: string;
552
- grep?: string | RegExp;
553
- errorsOnly?: boolean;
554
- now?: number;
555
- }
556
- interface LogQueryPlan {
557
- /** Whether a record belongs to the queried slot's timeline, before any other filter. */
558
- inTimeline: (record: NdjsonRecord) => boolean;
559
- matches: (record: NdjsonRecord) => boolean;
560
- launchTs: number | null;
561
- sinceTs: number | undefined;
562
- /**
563
- * Whether no record with a timestamp at most `maxTs`, or without one when `maxTs` is Infinity, can match.
564
- * `slots` lists every `slot ?? 'default'` value the records can carry; without it, a query that depends on
565
- * per-slot launch markers cannot rule out any timestamp.
566
- */
567
- excludesUpTo: (maxTs: number, slots?: ReadonlySet<unknown>) => boolean;
568
- }
569
- /** Decides which records a query matches from the timeline's marker records alone. */
570
- declare function planLogQuery(markers: readonly NdjsonRecord[], { slot, sources, minLevel, since, grep, errorsOnly, now }?: LogQueryOptions): LogQueryPlan;
571
- declare function queryLogs({ slot, dir, records, sources, minLevel, since, grep, tail, errorsOnly, errorContext, now }?: LogQueryOptions & {
572
- dir?: string;
573
- records?: NdjsonRecord[];
574
- tail?: number;
575
- errorContext?: boolean;
576
- }): NdjsonRecord[];
577
- /** Queries the JSON timeline, including Expo context fields on errors as `stim logs --json` does. */
578
- declare function queryJsonLogs(options?: Parameters<typeof queryLogs>[0]): NdjsonRecord[];
579
- declare function tailRead(prev: TailState | null | undefined, size: number): {
580
- start: number;
581
- prev: TailState;
582
- };
583
- declare function advanceTail(prev: TailState | null | undefined, chunk: string | null | undefined, size: number): {
584
- state: TailState;
585
- records: NdjsonRecord[];
538
+ type WarmRecord = {
539
+ phase: "warming";
540
+ step: WarmStep;
541
+ startedAt: string;
542
+ claim: {
543
+ root: string;
544
+ claimId: string;
545
+ };
546
+ } | {
547
+ phase: "ready";
548
+ at: string;
586
549
  };
587
- declare function followLogs({ dir, onRecord, criteria, intervalMs, offsets, identities: seededIdentities, errorContext }: {
588
- dir: string;
589
- onRecord: (record: NdjsonRecord) => void;
590
- criteria?: QueryCriteria;
591
- /** An explicit polling interval. Omit for filesystem hints with a ten-second repair scan. */
592
- intervalMs?: number;
593
- offsets?: Record<string, number> | null;
594
- /** `fileIdentity` of each file `offsets` was read from, so a replacement made since is recognized. */
595
- identities?: Record<string, string> | null;
596
- /** Holds each Expo error until its code frame and stack stop growing, then attaches them. */
597
- errorContext?: ExpoContextTarget;
598
- }): () => void;
599
- declare function fileIdentity(stat: BigIntStats): string | undefined;
600
- declare function sortByTs(records: NdjsonRecord[]): NdjsonRecord[];
601
- //#endregion
602
- //#region state/log-reader.d.ts
603
- interface LogDirQuery extends LogQueryOptions {
604
- tail?: number;
605
- /** Records from outside the directory, such as agent-device actions; they follow its records at equal timestamps. */
606
- extra?: readonly NdjsonRecord[];
607
- }
550
+ declare function readWarmRecord(state: WorkspaceState | null | undefined): WarmRecord | null;
551
+ declare const WORKSPACE_AGENT_KEY = "agentSession";
608
552
  /**
609
- * An indexed view of a workspace log directory, read in timestamp order without loading whole files. Each file
610
- * generation is indexed once per process (block timestamp bounds, markers, slots and launch attempts) and later
611
- * views read only what was appended since. Close it to release the open files.
553
+ * The coding-agent session whose shell ran the Stim command that last recorded `lastUsedAt`, with that command's
554
+ * working directory as `cwd` and its time as `lastActiveAt`.
612
555
  */
613
- interface LogDir {
614
- /** Bytes read from each current `.ndjson` file, through its last complete line. */
615
- readonly sizes: Record<string, number>;
616
- /** `fileIdentity` of each current `.ndjson` file that `sizes` was read from. */
617
- readonly identities: Record<string, string>;
618
- /** The oldest timestamp in the directory. */
619
- readonly firstTs: number | undefined;
620
- /** Launch attempt records outside native crash files, in timeline order. */
621
- launchAttempts(): NdjsonRecord[];
622
- /** The records `queryJsonLogs` returns for this directory's timeline followed by `extra`. */
623
- query(query?: LogDirQuery): Promise<NdjsonRecord[]>;
624
- /** Every matching record in timestamp order, in batches of at most 500, with the same filters and context as query. */
625
- batches(query?: Omit<LogDirQuery, "tail">): AsyncIterable<NdjsonRecord[]>;
626
- /** Prepares the directory marker predicate for records without markers, such as attributed agent actions. */
627
- filter(query?: LogQueryOptions): (record: NdjsonRecord) => boolean;
628
- close(): Promise<void>;
556
+ declare function readWorkspaceAgent(state: WorkspaceState | null | undefined): AgentSession | null;
557
+ //#endregion
558
+ //#region state/hosted-native.d.ts
559
+ interface HostedNativePlacement<D> {
560
+ machine: string;
561
+ session: string;
562
+ appAttempt: string;
563
+ device: D | null;
564
+ selected: string;
565
+ reason?: string;
566
+ agent: HostedAgentAccess;
629
567
  }
630
- /**
631
- * Opens `dir` for reading. With `order: 'timeline'`, native crash files follow every other file at equal
632
- * timestamps, as `readLogTimeline` orders them; with `'name'`, every file is ranked by name, as `readLogRecords`.
633
- */
634
- declare function openLogDir(dir: string, { order, signal }?: {
635
- order?: "timeline" | "name";
636
- signal?: AbortSignal;
637
- }): Promise<LogDir>;
568
+ declare function parseHostedNativePlacement(value: unknown, platform: "ios"): HostedNativePlacement<HostedIosDevice> | null;
569
+ declare function parseHostedNativePlacement(value: unknown, platform: "android"): HostedNativePlacement<HostedAndroidDevice> | null;
570
+ declare function parseHostedNativePlacement(value: unknown, platform: "ios" | "android"): HostedNativePlacement<HostedIosDevice | HostedAndroidDevice> | null;
571
+ declare function hostedNativeRecords(state: WorkspaceState | null, platform: "ios" | "android"): Record<string, unknown>;
572
+ declare function unreadableHostedNative(slot: string, platform: "ios" | "android"): string;
638
573
  //#endregion
639
- //#region state/paths.d.ts
640
- declare function getConfigPath(): string;
641
- declare function configLockPath(): string;
642
- declare function workspaceMetadataFile(projectRoot: string): string;
643
- declare function workspaceAgentDeviceDir(projectRoot: string): string;
644
- declare function workspaceLogsDir(projectRoot: string): string;
645
- /** Device screen footage stim-server records for the workspace, one directory per platform and slot. */
646
- declare function workspaceRecordingsDir(projectRoot: string): string;
647
- declare function workspaceLogErrorIndex(projectRoot: string): string;
648
- declare function workspaceDerivedData(projectRoot: string): string;
649
- declare function workspaceGradleBuild(projectRoot: string): string;
650
- declare function workspaceBuildDetailFile(projectRoot: string): string;
651
- /** The agent sessions that stopped running in the workspace in the last `ENDED_AGENT_RETENTION_MS`. */
652
- declare function workspaceEndedAgentsFile(projectRoot: string): string;
653
- declare function workspaceEndedAgentsLock(projectRoot: string): string;
654
- declare function supervisorPidFile(projectRoot: string): string;
655
- declare function workspaceStateFile(projectRoot: string): string;
656
- declare function workspaceStateLock(projectRoot: string): string;
657
- declare function supervisorLogFile(projectRoot: string): string;
658
- declare function emulatorLogFile(projectRoot: string): string;
659
- declare function sharedCompilationCache(): string;
660
- declare function sharedCcache(): string;
661
- declare function sharedGradle(): string;
662
- declare function sharedPods(): string;
663
- declare function createdDevicesFile(): string;
664
- declare function gitMergeCacheDir(): string;
665
- declare function pullRequestCacheDir(): string;
666
- declare function agentSessionsCacheFile(): string;
667
- declare function diskUsageCacheDir(): string;
668
- /** The ownership claim root that admits one disk-usage walk at a time on this machine. */
669
- declare function diskUsageWalkClaims(): string;
670
- /** The remote machines this machine asked for build access, each with its pinned stim-server key once approved. */
671
- declare function buildMachinesFile(): string;
672
- declare function buildMachinesLock(): string;
673
- /** The remote machines this machine asked for access, separate from build credentials. */
674
- declare function deviceHostMachinesFile(): string;
675
- declare function deviceHostMachinesLock(): string;
676
- declare function deviceHostMachinesClaims(): string;
677
- declare function createdDevicesLock(): string;
678
- /** The EAS session ledger lives under the real home directory, never under STIM_HOME. */
679
- declare function easMachineStateRoot(): string;
680
- declare function easSessionLedgerFile(root?: string): string;
681
- declare function easSessionLedgerLock(root?: string): string;
682
- /** Where stim-server records, one file per server process, the devices whose frames a client subscribes to. */
683
- declare function deviceViewersDir(): string;
684
- declare function statsFile(): string;
685
- declare function maintenanceDir(): string;
686
- declare function maintenanceStateFile(): string;
687
- declare function maintenanceAttemptFile(): string;
688
- declare function maintenanceNdjsonFile(): string;
689
- declare function gcLogDir(): string;
690
- declare function gcLogFile(): string;
691
- declare function maintenanceChildLogFile(): string;
692
- declare function maintenanceRunClaims(): string;
693
- /** Dependency trees `worktree remove` moved out of a worktree before git removed it; gc deletes what is left. */
694
- declare function trashRoot(): string;
695
- declare function archiveRoot(): string;
696
- declare function archiveDir(id: string): string;
697
- declare function archiveLock(): string;
698
- /** This machine's own long-term X25519 key as a client of other machines' stim-servers. */
699
- declare function clientIdentityKeyFile(): string;
700
- /**
701
- * The local Unix socket. sun_path permits 103 UTF-8 bytes on macOS and 107 on Linux. Longer paths use
702
- * /tmp/stim-sockets-<uid>/<SHA-256 of the normalized absolute socket path>.sock.
703
- */
704
- declare function serverLocalSocket(): string;
705
- declare function serverSetupDir(): string;
706
- declare function setupJournalFile(hash: string): string | null;
574
+ //#region state/hosted-android.d.ts
575
+ /** A workspace slot's placement; null device means its reservation has not reached ready yet. */
576
+ interface HostedAndroidPlacement extends HostedNativePlacement<HostedAndroidDevice> {}
577
+ /** Public hosting facts; the host's serial, AVD name and private Metro links are excluded. */
578
+ type HostedAndroidStatus = {
579
+ machine: string;
580
+ session: string;
581
+ selected: string;
582
+ reason?: string;
583
+ agent: HostedAgentAccess;
584
+ device: {
585
+ name: string;
586
+ systemImage: string;
587
+ api: number;
588
+ } | null;
589
+ /** The latest session probe in status, independent of a conflicting local emulator's state. */
590
+ state?: string;
591
+ };
592
+ declare function parseHostedAndroidPlacement(value: unknown): HostedAndroidPlacement | null;
593
+ declare function hostedAndroidStatus(placement: HostedAndroidPlacement): HostedAndroidStatus;
594
+ declare function hostedAndroidRecords(state: WorkspaceState | null): Record<string, unknown>;
595
+ declare function unreadableHostedAndroid(slot: string): string;
596
+ declare function hostedAndroidPlacements(state: WorkspaceState | null): Record<string, HostedAndroidPlacement>;
597
+ declare function hostedAndroidDeviceName(device: HostedAndroidDevice): string;
707
598
  //#endregion
708
- //#region state/recordings.d.ts
709
- /** The footage stim-server keeps per device: the last 15 minutes recorded, however long ago. */
710
- declare const RECORDING_FOOTAGE_MS: number;
711
- /** The recordings of every workspace of one Stim home together; past it the oldest footage goes first. */
712
- declare const RECORDING_CAP_BYTES: number;
713
- /** The platforms stim-server records: owned simulators and emulators, and the Stim-owned Chrome page. */
714
- declare const RECORDING_PLATFORMS: readonly ["ios", "android", "web"];
715
- type RecordingPlatform = (typeof RECORDING_PLATFORMS)[number];
599
+ //#region state/hosted-ios.d.ts
600
+ /** A workspace slot's placement; null device means its reservation has not reached ready yet. */
601
+ interface HostedIosPlacement extends HostedNativePlacement<HostedIosDevice> {}
602
+ /** Public hosting facts; the host's UDID and private Metro links are excluded. */
603
+ type HostedIosStatus = {
604
+ machine: string;
605
+ session: string;
606
+ selected: string;
607
+ reason?: string;
608
+ agent: HostedAgentAccess;
609
+ device: {
610
+ name: string;
611
+ runtime: string;
612
+ } | null;
613
+ /** The latest session probe in status, independent of a conflicting local simulator's state. */
614
+ state?: string;
615
+ };
616
+ declare function parseHostedIosPlacement(value: unknown): HostedIosPlacement | null;
617
+ declare function hostedIosStatus(placement: HostedIosPlacement): HostedIosStatus;
618
+ declare function hostedIosRecords(state: WorkspaceState | null): Record<string, unknown>;
619
+ declare function unreadableHostedIos(slot: string): string;
620
+ declare function hostedIosPlacements(state: WorkspaceState | null): Record<string, HostedIosPlacement>;
621
+ //#endregion
622
+ //#region state/maintenance.d.ts
623
+ type MaintenanceMode = "off" | "report" | "on";
624
+ type MaintenanceCheck = "pressure" | "size" | "worktree" | "sweep" | "idle";
625
+ type MaintenanceActionKind = "would-clear-outputs" | "would-trim-cache" | "would-empty-cache" | "would-shutdown-device" | "would-stop-workspace" | "would-remove-worktree" | "would-remove-orphan" | "would-unregister-cache" | "would-delete-parked-device" | "would-delete-devices" | "would-clear-build-dirs" | "would-delete-dependencies" | "would-stop-gradle-daemons" | "would-delete-gradle-version" | "would-delete-temp-leftovers";
626
+ /** Disk pressure: 0 above every threshold, 1 under the budget floor, 2 under the urgent threshold, 3 under the critical threshold or the hard floor. */
627
+ type DiskPressureLevel = 0 | 1 | 2 | 3;
628
+ interface MaintenanceAction {
629
+ kind: MaintenanceActionKind;
630
+ target: string;
631
+ bytes: number;
632
+ reason: string;
633
+ workspace?: string;
634
+ dir?: string;
635
+ olderThanDays?: number;
636
+ check?: "worktree" | "sweep" | "disk";
637
+ /** The disk pressure level that planned the action; it runs only while free disk stays under that level's floor. */
638
+ level?: 2 | 3;
639
+ }
640
+ interface MaintenanceSize {
641
+ name: string;
642
+ dir: string;
643
+ bytes: number;
644
+ measuredAt: number;
645
+ category: "workspace-outputs" | "build-cache" | "metro-cache" | "compilation-cache" | "ccache" | "owned-devices" | "other";
646
+ workspace?: string;
647
+ idleDays?: number | null;
648
+ blocked?: string;
649
+ }
716
650
  /**
717
- * One file of H.264 footage. A closed segment is named `<start>-<end>.seg`, in epoch milliseconds of its first and
718
- * last access unit; the segment being written is `<start>.part`, and its end is its modification time.
651
+ * A process whose physical footprint, as `top` reports it, is abnormally large. `command` is the one command that
652
+ * safely restarts or stops it, null when Stim knows none; `note` says what that command does.
719
653
  */
720
- interface RecordedSegment {
721
- file: string;
722
- start: number;
723
- end: number;
654
+ interface MemoryCulprit {
655
+ pid: number;
656
+ name: string;
724
657
  bytes: number;
725
- open: boolean;
658
+ command: string | null;
659
+ note: string | null;
660
+ }
661
+ interface MaintenancePressure {
662
+ disk: {
663
+ volume: string;
664
+ freeMb: number;
665
+ }[];
666
+ memory: {
667
+ level: "normal" | "warning" | "critical" | null;
668
+ availableBytes: number | null;
669
+ pressured: boolean;
670
+ /** Read only while the level is warning or critical; absent otherwise. */
671
+ culprits?: MemoryCulprit[];
672
+ };
673
+ warningSince: number | null;
674
+ diskLevel?: DiskPressureLevel;
675
+ }
676
+ interface MaintenancePass {
677
+ startedAt: number;
678
+ durationMs: number;
679
+ trigger: string;
680
+ mode: "report" | "on";
681
+ freedBytes: number;
682
+ actions: number;
683
+ stopped: 0;
684
+ blocked: string[];
685
+ }
686
+ interface MaintenanceRecord extends NdjsonRecord {
687
+ ts: number;
688
+ src: "maintenance";
689
+ level: "debug" | "info" | "warn" | "error";
690
+ msg: string;
691
+ event: "maintenance_pass" | "maintenance_action" | "maintenance_skip" | "maintenance_failure" | "maintenance_check";
692
+ pass: string;
693
+ trigger: string;
694
+ mode: "report" | "on";
695
+ }
696
+ interface MaintenanceState {
697
+ version: 1;
698
+ lastAt: Partial<Record<MaintenanceCheck, number>>;
699
+ deferredAt?: Partial<Record<MaintenanceCheck, number>>;
700
+ pressure: MaintenancePressure | null;
701
+ sizes: MaintenanceSize[];
702
+ lastPass: MaintenancePass | null;
703
+ recent: MaintenanceRecord[];
704
+ plan: MaintenanceAction[];
705
+ skipKeys?: string[];
706
+ }
707
+ interface MaintenanceStatus {
708
+ mode: MaintenanceMode;
709
+ invalid?: string;
710
+ claim?: {
711
+ unresolved: string;
712
+ removeCommand: string;
713
+ };
714
+ lastChecks: {
715
+ pressure: number | null;
716
+ size: number | null;
717
+ worktree: number | null;
718
+ sweep: number | null;
719
+ };
720
+ pressure: MaintenancePressure | null;
721
+ sizes: MaintenanceSize[];
722
+ lastPass: MaintenancePass | null;
723
+ running: {
724
+ startedAt: string;
725
+ trigger: string;
726
+ } | null;
727
+ recent: MaintenanceRecord[];
728
+ plan: MaintenanceAction[];
729
+ }
730
+ /** Rejects missing, corrupt or unsupported payloads without throwing. */
731
+ declare function parseMaintenanceState(value: unknown): MaintenanceState | null;
732
+ declare function readMaintenanceState(): MaintenanceState | null;
733
+ declare function readMaintenanceAttempt(): number | undefined;
734
+ //#endregion
735
+ //#region state/archive.d.ts
736
+ interface ArchivedBytes {
737
+ logs: number;
738
+ recordings: number;
739
+ agentActions: number;
740
+ record: number;
741
+ total: number;
742
+ }
743
+ interface ArchivedWorkspace {
744
+ id: string;
745
+ projectRoot: string;
746
+ project: string;
747
+ workspace: string;
748
+ worktree: {
749
+ repository: string | null;
750
+ branch: string | null;
751
+ head: string | null;
752
+ subject: string | null;
753
+ merged: boolean | null;
754
+ pullRequest: {
755
+ number: number;
756
+ state: string;
757
+ title: string;
758
+ url: string;
759
+ } | null;
760
+ };
761
+ removedAt: string;
762
+ removedBy: string;
763
+ lastUsedAt: string | null;
764
+ builds: {
765
+ count: number;
766
+ last: LastBuildReport | null;
767
+ lastErrorCount: number;
768
+ };
769
+ agents: EndedAgentSession[];
770
+ bytes: ArchivedBytes;
771
+ expires: {
772
+ logs: string | null;
773
+ recordings: string | null;
774
+ agentActions: string | null;
775
+ record: string | null;
776
+ };
777
+ version: number;
778
+ replacedBy?: string;
726
779
  }
727
- interface RecordedDevice {
728
- platform: RecordingPlatform;
729
- slot: string;
730
- dir: string;
731
- segments: RecordedSegment[];
780
+ interface ArchivedUsage {
781
+ count: number;
782
+ bytes: number;
783
+ byKind: {
784
+ logs: number;
785
+ recordings: number;
786
+ agentActions: number;
787
+ record: number;
788
+ };
732
789
  }
733
- /** The directory under a workspace's recordings that holds one device slot's footage. */
734
- declare function recordingDeviceName(platform: RecordingPlatform, slot: string): string;
735
- /** Segment names hold whole milliseconds: the start rounded down and the end rounded up. */
736
- declare function closedSegmentName(start: number, end: number): string;
737
- declare function openSegmentName(start: number): string;
738
- /** The segments in one device directory, oldest first. Files that are not segments are left out; `closedOnly` excludes files still being written. */
739
- declare function listSegments(dir: string, closedOnly?: boolean): RecordedSegment[];
740
- /** Reads current segment files asynchronously, oldest first; cancellation propagates. */
741
- declare function listSegmentsAsync(dir: string, closedOnly?: boolean, signal?: AbortSignal): Promise<RecordedSegment[]>;
742
- /** Every device slot recorded under a workspace's recordings directory. */
743
- declare function listRecordedDevices(recordingsDir: string, closedOnly?: boolean): RecordedDevice[];
744
- /** Reads current device slots and their segment files asynchronously; cancellation propagates. */
745
- declare function listRecordedDevicesAsync(recordingsDir: string, closedOnly?: boolean, signal?: AbortSignal): Promise<RecordedDevice[]>;
746
- declare function recordedBytes(devices: readonly RecordedDevice[]): number;
747
- /**
748
- * The oldest closed segments to delete so that one device keeps at most `footageMs` of footage. Time between
749
- * segments, while nothing was recorded, does not count. The open segment is never chosen.
750
- */
751
- declare function footageDrops(segments: readonly RecordedSegment[], footageMs: number): RecordedSegment[];
752
- /** The oldest closed segments across all devices to delete so that together they hold at most `capBytes`. */
753
- declare function capDrops(devices: readonly RecordedDevice[], capBytes: number): RecordedSegment[];
754
- /**
755
- * Whether stim-server records a workspace's devices: `STIM_RECORDING`, then `recording.enabled` in the workspace,
756
- * repo and machine layers, in that order, and true by default.
757
- */
758
- declare function recordingEnabled(env: NodeJS.ProcessEnv, layers: readonly unknown[]): boolean;
790
+ declare function readArchives(): ArchivedWorkspace[];
791
+ /** Reads current archive files asynchronously, outside the synchronous state-read cache; cancellation propagates. */
792
+ declare function readArchivesAsync(signal?: AbortSignal): Promise<ArchivedWorkspace[]>;
793
+ declare function readArchive(id: string): ArchivedWorkspace | null;
794
+ /** Reads a current archive without the synchronous state-read cache; invalid or missing records return null. */
795
+ declare function readArchiveAsync(id: string, signal?: AbortSignal): Promise<ArchivedWorkspace | null>;
796
+ declare function readArchiveState(id: string): WorkspaceState | null;
797
+ declare function archivedUsage(archives: readonly ArchivedWorkspace[]): ArchivedUsage;
798
+ declare function linkReplacedArchives(archives: readonly ArchivedWorkspace[], paths: readonly string[]): ArchivedWorkspace[];
799
+ declare function archiveEnabled(env: NodeJS.ProcessEnv, layers: readonly unknown[]): boolean;
759
800
  //#endregion
760
- //#region state/run-id.d.ts
761
- declare const RUN_ID_ENV = "STIM_RUN_ID";
762
- /** A run id as the CLI and stim-server accept it: letters, digits, `.`, `_` and `-`, at most 64. Null otherwise. */
763
- declare function validRunId(value: unknown): string | null;
764
- /**
765
- * The run id of the ambient operation context, else of this CLI invocation: `STIM_RUN_ID` when it holds a valid id
766
- * (Stim Desktop passes one), else a random one. The CLI entry exports it back to `STIM_RUN_ID` so processes the run
767
- * starts inherit it; this function does not.
768
- */
769
- declare function runId(env?: NodeJS.ProcessEnv): string;
801
+ //#region state/macos.d.ts
802
+ interface MacosProcess {
803
+ pid: number;
804
+ processToken: string;
805
+ startedAtMicros: number;
806
+ }
807
+ interface MacosBuild {
808
+ state: "running" | "ok" | "failed";
809
+ startedAt: string;
810
+ finishedAt?: string;
811
+ durationMs?: number;
812
+ fingerprint?: string;
813
+ cacheKey?: string;
814
+ cacheHit?: boolean;
815
+ cacheSource?: "local" | "provider" | "peer";
816
+ error?: string;
817
+ errorCode?: string;
818
+ buildMachine?: string;
819
+ builtOn?: string;
820
+ offloadedTo?: string;
821
+ offloadFallback?: string;
822
+ }
823
+ interface MacosAppRecord {
824
+ launchId: string;
825
+ arguments: string[];
826
+ product: string;
827
+ /** The app's visible name: the product and the workspace label. Absent in older records. */
828
+ displayName?: string;
829
+ bundle: string;
830
+ bundleId: string;
831
+ executable: string;
832
+ build: MacosBuild;
833
+ supervisor?: MacosProcess;
834
+ app?: MacosProcess;
835
+ /** Set when `stim macos --remote` reserved a session on another Mac; the app then has no local process. */
836
+ host?: HostedMacosPlacement;
837
+ /** Host launch evidence: true for a live app; status can override it in memory after probing the session. */
838
+ hostLaunched?: boolean | "unverified";
839
+ }
840
+ interface MacosAppState extends MacosAppRecord {
841
+ state: "running" | "orphaned" | "stopped" | "unverified";
842
+ }
843
+ declare function parseMacosRecord(value: unknown): MacosAppRecord | null;
844
+ declare function readMacosRecord(root: string): MacosAppRecord | null;
845
+ declare function readHostedMacosApp(home: string): MacosAppRecord | null;
846
+ declare function macosAppState(record: MacosAppRecord | null): MacosAppState | null;
770
847
  //#endregion
771
848
  //#region state/settings-registry.d.ts
772
849
  declare const ANDROID_COMPILER_CACHE_CHOICES: readonly ["auto", "ccache", "cas", "none"];
@@ -834,1470 +911,1547 @@ interface SettingEntry {
834
911
  value: string;
835
912
  };
836
913
  sensitive?: true;
837
- defaultReason?: string;
838
- }
839
- /** The payload `stim settings --json` prints. */
840
- type SettingsPayload = {
841
- project: string | null;
842
- files: Partial<Record<SettingScope, string>>;
843
- settings: SettingEntry[];
844
- unknown: Array<{
845
- key: string;
846
- scope: SettingScope;
847
- file: string;
848
- value: unknown;
849
- }>;
850
- };
851
- /** The masked JSON result of a settings set or unset. */
852
- interface SettingWriteResult {
853
- key: string;
854
- scope: SettingScope;
855
- file: string;
856
- changed: boolean;
857
- setting: SettingEntry;
858
- recordingsDeleted?: string[];
859
- }
860
- declare const REMOTE_DEVICE_BACKENDS: readonly RemoteDeviceBackend[];
861
- declare const IOS_SIMULATOR_APPS: readonly ["xcode", "siniulator", "stim-desktop"];
862
- declare const ANDROID_EMULATOR_APPS: readonly ["emulator", "stim-desktop"];
863
- declare const OFFLOAD_MODES: readonly ["auto", "force", "off"];
864
- type OffloadMode = (typeof OFFLOAD_MODES)[number];
865
- declare const WEB_VIEWPORTS: readonly ["desktop", "phone"];
866
- type WebViewport = (typeof WEB_VIEWPORTS)[number];
867
- declare const SETTINGS: readonly SettingDefinition[];
868
- declare function settingDefinition(key: string): SettingDefinition | null;
869
- declare function isLayeredSetting(setting: SettingDefinition): boolean;
870
- declare const SETTING_GROUPS: readonly string[];
871
- declare function expectedShape(type: SettingType): string;
872
- declare function acceptsShape(setting: SettingDefinition, value: unknown): boolean;
873
- declare function settingValueError(setting: SettingDefinition, value: unknown): string | null;
874
- declare function isSensitiveReference(value: unknown): boolean;
875
- /**
876
- * Coerces raw text (a CLI argument or an environment variable) through a setting's
877
- * registry type, the same way for both sources. Types whose values are not written
878
- * as bare text (boolean, number, strings, object) are read as JSON; a value that
879
- * fails to parse is left as the original string so `settingValueError` reports it. A boolean also reads `1` and `0`.
880
- */
881
- declare function coerceSettingText(setting: SettingDefinition, raw: string): unknown;
882
- //#endregion
883
- //#region state/settings-schema.d.ts
884
- declare const SETTINGS_SCHEMA_FILE = "settings.schema.json";
885
- declare const SETTINGS_SCHEMA_URL: string;
886
- type JsonSchema = Record<string, unknown>;
887
- /**
888
- * The published settings schema. The root describes a committed `.stim.json`;
889
- * `$defs.machine` describes the settings keys of `$STIM_HOME/config.json`.
890
- * Every leaf carries `x-stim` with its dotted key, kind, writable scopes,
891
- * environment override, and sensitivity.
892
- */
893
- declare function settingsJsonSchema(): JsonSchema;
894
- //#endregion
895
- //#region state/hosted-app.d.ts
896
- interface HostedAppFile {
897
- path: string;
898
- kind: "file" | "exec" | "link";
899
- size: number;
900
- sha256: string;
901
- }
902
- interface HostedAppOffer {
903
- session: string;
904
- attempt: string;
905
- bundleId: string;
906
- mode: "development" | "release" | "process";
907
- devClientScheme?: string;
908
- arguments?: string[];
909
- manifest: {
910
- sha256: string;
911
- size: number;
912
- };
913
- }
914
- interface HostedAppDelivery extends Omit<HostedAppOffer, "manifest"> {
915
- state: "receiving" | "installing" | "installed" | "unknown";
916
- launched: true | "unverified" | null;
917
- notice?: string;
918
- }
919
- interface HostedAppRecord extends HostedAppDelivery {
920
- manifest: HostedAppOffer["manifest"];
921
- files: HostedAppFile[];
922
- }
923
- declare const HOSTED_APP_CHUNK_BYTES: number;
924
- declare function hostedAppAttempt(value: unknown): value is string;
925
- declare function hostedAppArea(session: string, attempt: string, workerHome?: string): string;
926
- declare function hostedAppBlobs(session: string, workerHome?: string): string;
927
- /** Transfers cached verification after a rename, only for the same inode, size, mtime and digest. */
928
- declare function rememberHostedAppBlobRename(from: string, to: string, file: {
929
- size: number;
930
- sha256: string;
931
- }): void;
932
- /** Checks regular blob bytes, including their size, before content-addressed reuse. */
933
- declare function validHostedAppBlob(path: string, file: {
934
- size: number;
935
- sha256: string;
936
- }): boolean;
937
- /** At most 32 plain arguments of 1024 characters (8192 in total), with no NUL, CR or LF. */
938
- declare function validHostedAppArguments(value: unknown): value is string[];
939
- declare function parseHostedAppOffer(value: unknown): HostedAppOffer | null;
940
- /** Relative normalized paths, with no file or link as another entry's ancestor. */
941
- declare function parseHostedAppManifest(value: unknown): HostedAppFile[] | null;
942
- /** Reads a server-written receipt; malformed or missing established state remains unresolved. */
943
- declare function readHostedAppMetadata(session: string, attempt: string, workerHome?: string): Omit<HostedAppRecord, "files">;
944
- declare function readHostedApp(session: string, attempt: string, workerHome?: string): HostedAppRecord;
945
- //#endregion
946
- //#region state/hosted-macos.d.ts
947
- /** App slots one host offers; a slot names the host-assigned bundle id `<bundleId>.hosted<slot>`. */
948
- declare const HOSTED_MACOS_APP_SLOTS = 64;
949
- /** The drivers `hosting.agentDriver` can name: `none` and the first-party driver packages stim-server ships. */
950
- declare const HOSTED_AGENT_DRIVERS: readonly ["none", "agent-device"];
951
- type HostedAgentDriverName = (typeof HOSTED_AGENT_DRIVERS)[number];
952
- /** A driver name a grant or access record can carry; a client resolves only the drivers it knows. */
953
- declare function hostedAgentDriverName(value: unknown): value is string;
954
- /** What a host reports in a macOS offer: no simulator is created, so the choice is the host itself. */
955
- interface HostedMacosChoice {
956
- architecture: "arm64" | "x86_64";
957
- macosVersion: string;
914
+ defaultReason?: string;
958
915
  }
959
- /** A ready hosted macOS session's identity: the host it runs on and the app slot reserved for it. */
960
- interface HostedMacosDevice extends HostedMacosChoice {
961
- appSlot: number;
916
+ /** The payload `stim settings --json` prints. */
917
+ type SettingsPayload = {
918
+ project: string | null;
919
+ files: Partial<Record<SettingScope, string>>;
920
+ settings: SettingEntry[];
921
+ unknown: Array<{
922
+ key: string;
923
+ scope: SettingScope;
924
+ file: string;
925
+ value: unknown;
926
+ replacement?: string;
927
+ }>;
928
+ };
929
+ /** The masked JSON result of a settings set or unset. */
930
+ interface SettingWriteResult {
931
+ key: string;
932
+ scope: SettingScope;
933
+ file: string;
934
+ changed: boolean;
935
+ setting: SettingEntry;
936
+ recordingsDeleted?: string[];
962
937
  }
938
+ declare const REMOTE_DEVICE_BACKENDS: readonly RemoteDeviceBackend[];
939
+ declare const IOS_SIMULATOR_APPS: readonly ["xcode", "siniulator", "stim-desktop"];
940
+ declare const ANDROID_EMULATOR_APPS: readonly ["emulator", "stim-desktop"];
941
+ declare const REPLACED_SETTINGS: Readonly<Record<string, {
942
+ key: string;
943
+ env?: string;
944
+ value: (old: unknown) => string | null;
945
+ }>>;
946
+ declare function replacementAdvice(key: string, old: unknown): {
947
+ key: string;
948
+ command: string | null;
949
+ } | null;
950
+ declare const WEB_VIEWPORTS: readonly ["desktop", "phone"];
951
+ type WebViewport = (typeof WEB_VIEWPORTS)[number];
952
+ declare const SETTINGS: readonly SettingDefinition[];
953
+ declare function settingDefinition(key: string): SettingDefinition | null;
954
+ declare function isLayeredSetting(setting: SettingDefinition): boolean;
955
+ declare const SETTING_GROUPS: readonly string[];
956
+ declare function expectedShape(type: SettingType): string;
957
+ declare function acceptsShape(setting: SettingDefinition, value: unknown): boolean;
958
+ declare function settingValueError(setting: SettingDefinition, value: unknown): string | null;
959
+ declare function isSensitiveReference(value: unknown): boolean;
963
960
  /**
964
- * The agent-device lease owner scope a client names on every request. `deviceKey` is `<bundleId>@<pid>`
965
- * for a macOS app, or `ios:mobile:<udid>` with `backend: ios-instance` for a hosted simulator, or `android:mobile:<serial>` with `backend: android-instance` for a hosted emulator.
961
+ * Coerces raw text (a CLI argument or an environment variable) through a setting's
962
+ * registry type, the same way for both sources. Types whose values are not written
963
+ * as bare text (boolean, number, strings, object) are read as JSON; a value that
964
+ * fails to parse is left as the original string so `settingValueError` reports it. A boolean also reads `1` and `0`.
966
965
  */
967
- interface HostedAgentLease {
968
- tenant: string;
969
- runId: string;
970
- clientId: string;
971
- deviceKey: string;
972
- backend?: "ios-instance" | "android-instance";
973
- }
966
+ declare function coerceSettingText(setting: SettingDefinition, raw: string): unknown;
967
+ //#endregion
968
+ //#region state/status.d.ts
969
+ type StatsPlatform = "ios" | "android";
970
+ /** A platform whose build reports phases: the stats platforms and `macos`. */
971
+ type BuildPlatform = StatsPlatform | "macos";
972
+ type RunOutcomeKind = "hit" | "cold";
973
+ declare const BUILD_PHASES: readonly ["prepare", "cache-lookup", "wait", "prebuild", "pods", "compile", "device", "install", "launch"];
974
+ type BuildPhase = (typeof BUILD_PHASES)[number];
975
+ type ActiveBuildState = "running" | "stale" | "unknown";
974
976
  /**
975
- * Agent control a driver issues for one installed hosted app. `path` is the session's base route on the host,
976
- * `scope` the driver's handle that limits it to this one app, and `lease`, for a driver that allocates leases,
977
- * the scope that pins the allocation.
977
+ * Where a running build compiles: `local`, or the remote machine it was offloaded to, with the phase it is in there
978
+ * (`sync`, `deps`, `prebuild`, `pods`, `build` or `fetch`) and when the offload and that phase started.
978
979
  */
979
- interface HostedAgentIssuedGrant {
980
- driver: string;
981
- path: string;
982
- token: string;
983
- scope: string;
984
- lease?: HostedAgentLease;
980
+ type BuildPlacement = "local" | {
981
+ host: string;
982
+ phase: string;
983
+ startedAt: string;
984
+ phaseStartedAt: string;
985
+ };
986
+ interface BuildWaitingFor {
987
+ kind: "build-slot" | "device-slot";
988
+ inUse: number;
989
+ max: number;
990
+ since: string;
991
+ }
992
+ interface BuildReport {
993
+ platform: BuildPlatform;
994
+ slot: string;
995
+ state: ActiveBuildState;
996
+ phase: BuildPhase;
997
+ startedAt: string;
998
+ phaseStartedAt: string;
999
+ outcome: RunOutcomeKind | null;
1000
+ /** Whether `outcome` is this run's own; before its cache lookup resolves it is the project's latest outcome. */
1001
+ outcomeKnown: boolean;
1002
+ /** The resolved lookup result; absent before resolution and when the run skips cache lookup. */
1003
+ cacheLookupOutcome?: "hit" | "miss";
1004
+ expectedMs: number | null;
1005
+ expectedPhaseMs: number | null;
1006
+ /** Milliseconds spent in phases already left; sums repeat visits, excludes the current visit, and is omitted before any phase completes and by older Stim. */
1007
+ completedPhaseMs?: Partial<Record<BuildPhase, number>>;
1008
+ basis: number;
1009
+ /**
1010
+ * The phases a run like this one goes through, in order, with each one's median in milliseconds, from the same
1011
+ * runs as `expectedMs`; null without comparable runs. The current phase can be one the plan does not list.
1012
+ */
1013
+ plannedPhases: PlannedPhase[] | null;
1014
+ /** Why the run's cache lookup missed, once the run knows; `baseline` omits `cacheKey`. */
1015
+ missReason?: BuildMissReason;
1016
+ /**
1017
+ * True while `missReason` is the miss of the key the run looked up first and the run will prebuild or install pods,
1018
+ * then look the key up again. A hit on the second lookup removes `missReason` and sets `outcome` to `hit`.
1019
+ */
1020
+ missProvisional?: true;
1021
+ /** What the native build tool is doing now, once it printed a line Stim recognizes. */
1022
+ detail?: BuildDetail;
1023
+ /** What the `device` or `launch` phase is waiting on, once Stim observed it; absent otherwise and from older Stim. */
1024
+ activity?: BuildActivity;
1025
+ placement: BuildPlacement;
1026
+ /** While `phase` is `wait`: the workspace whose build of the same artifact this run waits on, when it is known. */
1027
+ waitingOn?: {
1028
+ path: string;
1029
+ };
1030
+ waitingFor?: BuildWaitingFor;
985
1031
  }
986
1032
  /**
987
- * Agent control the host grants a client for one installed hosted app, sent only over that client's approved
988
- * device-host connection and never journaled. `none` means the host's `hosting.agentDriver` starts no driver.
1033
+ * What a run's `device` or `launch` phase is waiting on. `booting` lasts while the run waits for the owned simulator or
1034
+ * emulator it started booting. `bundling` starts when the app's bundle request reaches this workspace's
1035
+ * Metro and ends when Metro delivered it; `percent` is Metro's own progress for that request, present only once Metro
1036
+ * reported one. `waiting-ready` lasts while the app reports its readiness pending. `startedAt` is when the evidence was
1037
+ * recorded.
989
1038
  */
990
- type HostedAgentGrant = {
991
- driver: "none";
992
- } | HostedAgentIssuedGrant;
993
- /** `app.launch` and `app.attach` results; a host includes `agent` once the app is installed. */
994
- type HostedAppLaunch = HostedAppDelivery & {
995
- agent?: HostedAgentGrant;
996
- };
1039
+ interface BuildActivity {
1040
+ name: "booting" | "bundling" | "waiting-ready";
1041
+ startedAt: string;
1042
+ percent?: number;
1043
+ }
1044
+ /** One phase a running build is expected to go through, and its median duration in comparable runs. */
1045
+ interface PlannedPhase {
1046
+ phase: BuildPhase;
1047
+ expectedMs: number;
1048
+ }
1049
+ /** The native build tool's step inside a build's `compile` phase. */
1050
+ declare const NATIVE_BUILD_STEPS: readonly ["configure", "compile", "link", "resources", "script", "dex", "package", "sign"];
1051
+ type NativeBuildStep = (typeof NATIVE_BUILD_STEPS)[number];
997
1052
  /**
998
- * Agent control as the client hands it to a coding agent: secrets stay in files Stim writes with mode
999
- * 0600, and `command` shows how to address the hosted app. Never carries a token inline. `setting` names
1000
- * the hosting Mac's setting that turns a driver on.
1053
+ * A running build's progress as its tool reports it. `unit` is `targets` for xcodebuild, `tasks` for Gradle and
1054
+ * `steps` for SwiftPM. xcodebuild's `done` counts targets it finished and `total` the targets in its dependency graph,
1055
+ * which includes targets with nothing to do; Gradle's `done` counts the tasks it reported, with a null `total`;
1056
+ * SwiftPM's `done` and `total` are the `[done/total]` of its latest progress line, and its total can grow while it
1057
+ * builds. They are counts, not a completion fraction. `status` reports the detail only during the `compile` phase. `line` is
1058
+ * the latest compile, link or task line with paths shortened to file names.
1001
1059
  */
1002
- type HostedAgentAccess = {
1003
- driver: "none";
1004
- setting: "hosting.agentDriver";
1005
- } | {
1006
- driver: string;
1007
- remoteConfig: string;
1008
- command: string;
1009
- };
1010
- /** Where a workspace's macOS app runs when `stim macos --remote` placed it on another Mac. */
1011
- interface HostedMacosPlacement {
1012
- machine: string;
1013
- session: string;
1014
- appSlot: number;
1015
- appAttempt: string;
1016
- /** The host-assigned id the running app uses, `hostedMacosBundleId(<offered id>, appSlot)`. */
1017
- bundleId: string;
1018
- agent: HostedAgentAccess;
1060
+ interface BuildDetail {
1061
+ step: NativeBuildStep | null;
1062
+ unit: "targets" | "tasks" | "steps" | null;
1063
+ done: number | null;
1064
+ total: number | null;
1065
+ line: string | null;
1066
+ updatedAt: string;
1019
1067
  }
1020
- declare function hostedMacosAppSlot(value: unknown): value is number;
1021
- declare function hostedMacosBundleId(bundleId: string, appSlot: number): string;
1022
- declare function parseHostedMacosChoice(value: unknown): HostedMacosChoice | null;
1023
- declare function parseHostedMacosDevice(value: unknown): HostedMacosDevice | null;
1024
- /** A grant naming a driver this client does not know is not usable; it parses as null. */
1025
- declare function parseHostedAgentGrant(value: unknown): HostedAgentGrant | null;
1026
- declare function parseHostedAgentAccess(value: unknown): HostedAgentAccess | null;
1027
- declare function parseHostedMacosPlacement(value: unknown): HostedMacosPlacement | null;
1028
- //#endregion
1029
- //#region state/device-host.d.ts
1030
- type HostedDevicePlatform = "ios" | "android" | "macos";
1031
- /** Deadlines stim-server gives each hosted worker run. Clients derive their waits from these. */
1032
- interface DeviceHostLimits {
1033
- prepareMs: number;
1034
- offerMs: number;
1035
- stopMs: number;
1036
- logsMs: number;
1037
- killGraceMs: number;
1068
+ /** Where a build's app came from: a cache tier, or `false` when it compiled or failed before one was found. */
1069
+ type BuildCacheHit = "local" | "remote" | false;
1070
+ /** A platform's most recent `ios` or `android` run in one workspace. */
1071
+ interface DevicePlacement {
1072
+ decision: "local" | "hosted" | "waited-locally" | "eas";
1073
+ reason: string;
1074
+ machine?: string;
1038
1075
  }
1039
- declare const DEVICE_HOST_LIMITS: Readonly<DeviceHostLimits>;
1040
- /** How many parked sessions one reserve inspects, and possibly retires, before it creates a device. */
1041
- declare const HOSTED_PARKED_CANDIDATES: number;
1042
- /** How long a cancelled hosted worker run can take to settle: SIGTERM, SIGKILL after the grace, then it is abandoned. */
1043
- declare function hostedWorkerSettleMs(limits?: Pick<DeviceHostLimits, "killGraceMs">): number;
1044
- interface HostedIosChoice {
1045
- deviceTypeId: string;
1046
- runtimeId: string;
1047
- deviceType: string;
1048
- runtime: string;
1049
- architecture: "arm64" | "x86_64";
1076
+ interface LastBuildReport {
1077
+ devicePlacement?: DevicePlacement;
1078
+ platform: BuildPlatform;
1079
+ status: "ok" | "failed";
1080
+ cacheHit: BuildCacheHit;
1081
+ cacheSkipped: boolean;
1082
+ durationMs: number | null;
1083
+ fingerprint: string | null;
1084
+ startedAt: string;
1085
+ finishedAt: string | null;
1086
+ errorCode?: string;
1087
+ missReason?: BuildMissReason;
1088
+ /** The selected auto, local, or configured machine entry; present on new build records, including cache hits. */
1089
+ buildMachine?: string;
1090
+ /** Where compilation ran: here or a machine name; absent when no build ran. */
1091
+ builtOn?: string;
1092
+ /** The remote machine that compiled the app when the build was offloaded. */
1093
+ offloadedTo?: string;
1094
+ /** Why the run built here after it considered offloading; absent when it offloaded or never considered it. */
1095
+ offloadFallback?: string;
1096
+ /** The first compiler diagnostics of a failed build, when the build tool reported any. */
1097
+ diagnostics?: BuildDiagnostic[];
1098
+ /** Present on a failed run: what failed, from `buildCause`. */
1099
+ cause?: BuildCause;
1050
1100
  }
1051
- interface HostedIosDevice extends HostedIosChoice {
1052
- udid: string;
1053
- name: string;
1101
+ /**
1102
+ * A failed run's cause: the first diagnostic with a file and a line, keyed `file:line`, else the run's error code
1103
+ * (or `failed`), with null `file` and `line`. Consecutive failures with the same `key` failed the same way.
1104
+ */
1105
+ interface BuildCause {
1106
+ key: string;
1107
+ file: string | null;
1108
+ line: number | null;
1054
1109
  }
1055
- interface HostedAndroidChoice {
1056
- systemImage: string;
1057
- deviceProfile: string;
1058
- architecture: "arm64-v8a" | "x86_64";
1110
+ /** How a recorded build ended. `interrupted` is a run whose process ended without recording a result. */
1111
+ declare const BUILD_RESULTS: readonly ["succeeded", "failed", "cancelled", "interrupted"];
1112
+ type BuildResult = (typeof BUILD_RESULTS)[number];
1113
+ /**
1114
+ * One run in a workspace's recent build history. `configuration` is the iOS configuration or the Android
1115
+ * variant the run built, `Debug` or `debug` by default, and null when the run ended before resolving it.
1116
+ * `phases` holds the milliseconds spent in each phase the run entered. An interrupted run has null
1117
+ * `durationMs` and `finishedAt`, no cache facts, and 0 for the phase it stopped in.
1118
+ */
1119
+ interface BuildHistoryEntry extends LastBuildReport {
1120
+ result: BuildResult;
1121
+ slot: string;
1122
+ configuration: string | null;
1123
+ cacheKey: string | null;
1124
+ phases: Partial<Record<BuildPhase, number>>;
1125
+ /** A `stim macos` run's SwiftPM step total; absent for other runs and when the build reported none. */
1126
+ compileSteps?: number;
1059
1127
  }
1060
- interface HostedAndroidDevice extends HostedAndroidChoice {
1061
- avdName: string;
1062
- serial: string;
1063
- consolePort: number;
1128
+ /** One compiler error from a failed build: where it is, when the tool said, and its message. */
1129
+ interface BuildDiagnostic {
1130
+ file: string | null;
1131
+ line: number | null;
1132
+ column: number | null;
1133
+ message: string;
1064
1134
  }
1065
- type HostedDevice = HostedIosDevice | HostedAndroidDevice | HostedMacosDevice;
1066
- interface HostedDeviceSelectors {
1067
- deviceType?: string;
1068
- runtime?: string;
1069
- systemImage?: string;
1070
- deviceProfile?: string;
1135
+ /** What kind of native input a changed fingerprint source is. */
1136
+ type BuildMissCategory = "native-dependency" | "config-plugin" | "app-config" | "app-asset" | "package" | "native-dir" | "autolinking" | "package-scripts" | "file" | "other";
1137
+ interface BuildMissChange {
1138
+ source: string;
1139
+ change: "added" | "removed" | "changed";
1140
+ category: BuildMissCategory;
1071
1141
  }
1072
- interface HostedDeviceOfferRequest extends HostedDeviceSelectors {
1073
- platform: HostedDevicePlatform;
1142
+ /**
1143
+ * Why a run compiled instead of installing a cached app. `changes` holds at most 20 entries,
1144
+ * ordered by importance; `changeCount` is the full number of changed fingerprint sources.
1145
+ * Only a plan reports `prebuild-pending`: the run would prebuild before compiling, so the changes
1146
+ * compare the fingerprint before that prebuild.
1147
+ */
1148
+ interface BuildMissReason {
1149
+ kind: "changed" | "no-baseline" | "same-sources" | "cache-skipped" | "fingerprint-error" | "prebuild-pending";
1150
+ summary: string;
1151
+ changes: BuildMissChange[];
1152
+ changeCount: number;
1153
+ /** `cacheKey` is kept in workspace state so a later miss can find this baseline; status omits it. */
1154
+ baseline: {
1155
+ fingerprint: string;
1156
+ cacheKey?: string;
1157
+ from: "workspace" | "project";
1158
+ } | null;
1159
+ rekeyedBy: string[];
1074
1160
  }
1075
- type HostedNativeOffer = {
1076
- resources: {
1077
- cpus: number;
1078
- /** Five-minute system load divided by available CPU count. */
1079
- loadPerCore: number;
1080
- memoryFreeBytes: number;
1081
- memoryPressure: "normal" | "warning" | "critical" | null;
1082
- /** Available bytes on the Stim home volume, not necessarily the Android AVD volume. */
1083
- workerDiskFreeBytes: number | null;
1084
- localDevices?: number | {
1085
- unknown: string;
1086
- };
1087
- };
1088
- declined: string | null;
1089
- } & ({
1090
- platform: "ios";
1091
- choice: HostedIosChoice | null;
1092
- } | {
1093
- platform: "android";
1094
- choice: HostedAndroidChoice | null;
1095
- } | {
1096
- platform: "macos";
1097
- choice: HostedMacosChoice | null;
1098
- });
1099
- type HostedDeviceOffer = HostedNativeOffer & {
1100
- capacity: {
1101
- running: number;
1102
- max: number;
1103
- available: number | null;
1104
- local?: number | {
1105
- unknown: string;
1106
- };
1161
+ /** The payload `stim ios --plan --json` and `stim android --plan --json` print. */
1162
+ interface BuildPlanPayload {
1163
+ platform: StatsPlatform;
1164
+ slot?: string;
1165
+ fingerprint: string;
1166
+ cacheKey: string | null;
1167
+ cacheHit: BuildCacheHit;
1168
+ provider: string | null;
1169
+ cacheSkipped: boolean;
1170
+ prebuild: "none" | "generate" | "regenerate" | "refuse" | null;
1171
+ outcome: RunOutcomeKind | null;
1172
+ expectedMs: number | null;
1173
+ basis: number;
1174
+ /** On a predicted miss with cache reads on, why the cache has no app; `baseline` omits `cacheKey`. */
1175
+ missReason?: BuildMissReason;
1176
+ refusal?: {
1177
+ code: string;
1178
+ message: string;
1179
+ remedy: string;
1107
1180
  };
1108
- };
1109
- interface HostedDeviceRequest extends HostedDeviceOfferRequest {
1110
- workspace: string;
1111
- slot: string;
1112
- attempt: string;
1181
+ /** With ios.remote or android.remote set to auto or a Mac, where the plan assumes the device runs, such as `this machine; auto may use janics-mac-mini`. */
1182
+ placement?: string;
1113
1183
  }
1114
- type HostedDevicePhase = "preparing" | "ready" | "stopping" | "stopped" | "unknown";
1115
- interface HostedDeviceSession extends HostedDeviceRequest {
1116
- id: string;
1117
- client: string;
1118
- state: HostedDevicePhase;
1119
- device: HostedDevice | null;
1120
- consolePort?: number;
1121
- appSlot?: number;
1122
- createdAt: string;
1123
- parked?: {
1124
- at: string;
1125
- };
1126
- notice?: string;
1127
- appAttempt?: string;
1128
- agent?: HostedAgentGrant;
1129
- metroPort?: number;
1130
- clientMetroPort?: number;
1184
+ /** The read-only `stim macos --plan --json` payload; SwiftPM work and worker availability remain unknown. */
1185
+ interface MacosBuildPlanPayload {
1186
+ platform: "macos";
1187
+ product: string;
1188
+ buildMachine: string;
1189
+ fingerprint: string | null;
1190
+ cacheKey: string | null;
1191
+ cacheHit: boolean;
1192
+ provider: null;
1193
+ cacheSkipped: boolean;
1194
+ prebuild: null;
1195
+ outcome: null;
1196
+ expectedMs: null;
1197
+ basis: number;
1131
1198
  }
1132
- declare function deviceHostRoot(): string;
1133
- declare function deviceHostArea(id: string): string;
1134
- declare function parseHostedChoice(value: unknown): HostedIosChoice | null;
1135
- declare function parseHostedDevice(value: unknown): HostedIosDevice | null;
1136
- declare function parseHostedAndroidDevice(value: unknown): HostedAndroidDevice | null;
1137
- /** Android Emulator -help-port defines the supported even console ports as 5554 through 5584. */
1138
- declare function hostedConsolePort(value: unknown): value is number;
1139
- declare function parseHostedPlatformDevice(value: unknown, platform: HostedDevicePlatform): HostedDevice | null;
1140
- declare function hostedDeviceId(device: HostedDevice): string;
1141
- declare function parseHostedRequest(value: unknown): HostedDeviceRequest | null;
1142
- declare function parseHostedOfferRequest(value: unknown): HostedDeviceOfferRequest | null;
1143
- declare function parseHostedLocalDeviceCount(value: unknown): number | {
1144
- unknown: string;
1145
- } | null;
1146
- declare function parseHostedNativeOffer(value: unknown): HostedNativeOffer | null;
1147
- /** A missing established journal or malformed record is a refusal, never an empty reservation set. */
1148
- declare function readHostedSessions(): HostedDeviceSession[];
1149
- /** The private worker's exact device record; an absent record is unresolved after creation started. */
1150
- declare function readHostedDevice(home: string): HostedIosDevice;
1151
- declare function readHostedDevice(home: string, platform: "android"): HostedAndroidDevice;
1152
- declare function readHostedDevice(home: string, platform: "macos"): HostedMacosDevice;
1153
- declare function readHostedDevice(home: string, platform: HostedDevicePlatform): HostedDevice;
1154
- declare function readHostedDeviceLedger(home: string, options?: {
1155
- required?: boolean;
1156
- }): {
1157
- ios: string[];
1158
- android: string[];
1159
- web: string[];
1160
- } | null;
1161
- /** Hosted sessions use isolated homes: only one exact device of their platform may appear in this ledger. */
1162
- declare function assertHostedDeviceLedger(home: string, id: string, platform?: HostedDevicePlatform, options?: {
1163
- allowEmpty?: boolean;
1164
- }): "listed" | "empty";
1165
- //#endregion
1166
- //#region state/workspace-state.d.ts
1167
- interface WorkspaceState {
1168
- supervisor?: Record<string, unknown>;
1169
- collectors?: Record<string, unknown>;
1170
- lastBuild?: Record<string, unknown>;
1171
- launches?: Record<string, unknown>;
1172
- remoteDevice?: Record<string, unknown>;
1173
- metroTunnel?: Record<string, unknown>;
1174
- [key: string]: unknown;
1199
+ type ActivityState = "driven" | "active" | "idle" | "unknown";
1200
+ interface ActivityDriver {
1201
+ tool: string;
1202
+ pid: number | null;
1203
+ since: string | null;
1175
1204
  }
1176
- declare const IDLE_STOP_KEY = "devServerStop";
1177
- /** Why the supervisor last stopped the dev server on its own: `metro.idleStopMinutes` with no use. */
1178
- interface IdleStopRecord {
1179
- reason: "idle";
1180
- at: string;
1181
- idleMinutes: number;
1205
+ /** The kinds of evidence that date a device's last activity, in the order `recent` lists them. */
1206
+ declare const ACTIVITY_RECENCY_BASES: readonly ["agent-action", "device-log", "metro-bundle", "workspace-use", "supervisor-start", "page-log", "viewer"];
1207
+ type ActivityRecencyBasis = (typeof ACTIVITY_RECENCY_BASES)[number];
1208
+ interface DeviceActivity {
1209
+ state: ActivityState;
1210
+ driver?: ActivityDriver;
1211
+ lastActivityAt?: string;
1212
+ /** The newest time of each kind of evidence behind `lastActivityAt`, so a reader can leave out app log chatter. */
1213
+ recent?: Partial<Record<ActivityRecencyBasis, string>>;
1214
+ basis: string[];
1182
1215
  }
1183
- declare function readIdleStop(state: WorkspaceState | null | undefined): IdleStopRecord | null;
1184
- declare const DEVICE_RECLAIM_REASON = "reclaimed for a waiting run";
1185
- declare const DEVICE_IDLE_SHUTDOWN_KEY = "deviceIdleShutdowns";
1186
- /** An owned simulator or emulator shut down after being idle. */
1187
- interface DeviceIdleShutdownRecord {
1188
- at: string;
1189
- idleMinutes: number;
1190
- reason?: string;
1216
+ /** Every state a device's app process can report. */
1217
+ declare const APP_PROCESS_STATES: readonly ["running", "stopped", "unknown"];
1218
+ /**
1219
+ * Whether the workspace's app process is alive on a device now. This is current process state, not launch evidence:
1220
+ * `launched` in an `ios` or `android` result stays the record of one launch. `id` is the bundle identifier or
1221
+ * package that was checked; `state` is "unknown" when the process listing could not be read.
1222
+ */
1223
+ interface DeviceAppProcess {
1224
+ id: string;
1225
+ state: (typeof APP_PROCESS_STATES)[number];
1191
1226
  }
1192
- /** The recorded idle shutdowns by device slot key (`ios`, `android`, `ios:<slot>`). */
1193
- declare function readDeviceIdleShutdowns(state: WorkspaceState | null | undefined): Record<string, DeviceIdleShutdownRecord>;
1194
- declare const DEV_SERVER_STOP_REQUEST_KEY = "devServerStopRequest";
1195
- /** A Stim component's intent to stop the supervisor with `processToken`, written before it signals. */
1196
- interface DevServerStopRequest {
1197
- processToken: string;
1198
- by: string;
1199
- pid: number;
1200
- at: string;
1201
- workspace?: string;
1227
+ /**
1228
+ * A linked worktree's `git status`. `changed` counts tracked paths with staged or unstaged changes, including
1229
+ * conflicts; `untracked` counts untracked entries as `git status` lists them, so an untracked directory counts once.
1230
+ * `ahead` and `behind` compare HEAD with `upstream`, and are null when there is no upstream or it no longer exists.
1231
+ * `mergedInto` names the default branch (`origin/main`) when `gc` would consider the branch merged into it, judged
1232
+ * from local refs without fetching.
1233
+ */
1234
+ interface WorktreeGit {
1235
+ changed: number;
1236
+ untracked: number;
1237
+ upstream: string | null;
1238
+ ahead: number | null;
1239
+ behind: number | null;
1240
+ mergedInto: string | null;
1202
1241
  }
1203
- declare function readDevServerStopRequest(state: WorkspaceState | null | undefined): DevServerStopRequest | null;
1204
1242
  /**
1205
- * Why the dev server last stopped, stored under `IDLE_STOP_KEY`. `requested` names the Stim component that
1206
- * asked; `signal` is a SIGTERM or SIGINT no Stim component asked for; `server-exited` is the dev server
1207
- * process exiting on its own.
1243
+ * The GitHub pull request of a worktree's branch and HEAD, as `status --watch` last looked it up through `gh`.
1244
+ * `state` is `draft` for an open draft. `checks` counts the head commit's check runs and commit statuses, null when it
1245
+ * has none. `checkedAt` is when Stim last asked GitHub.
1208
1246
  */
1209
- type DevServerStopRecord = IdleStopRecord | {
1210
- reason: "requested";
1211
- at: string;
1212
- by: string;
1213
- byPid: number;
1214
- byWorkspace?: string;
1215
- } | {
1216
- reason: "signal";
1217
- at: string;
1218
- signal: string;
1219
- } | {
1220
- reason: "server-exited";
1221
- at: string;
1222
- mode: string;
1223
- code: number | null;
1224
- signal: string | null;
1225
- };
1226
- /** A stopped dev server's last cause in status; `vanished` is a supervisor proven gone that recorded none. */
1227
- type MetroLastStop = DevServerStopRecord | {
1228
- reason: "vanished";
1229
- pid: number;
1230
- startedAt: string | null;
1231
- };
1232
- declare function readDevServerStop(state: WorkspaceState | null | undefined): DevServerStopRecord | null;
1233
- /** Each platform's latest run; `lastBuild` holds whichever platform ran last. */
1234
- declare const LAST_BUILD_KEYS: Readonly<Record<StatsPlatform, string>>;
1235
- declare const BUILD_HISTORY_KEY = "buildHistory";
1236
- declare const BUILD_HISTORY_LIMIT = 10;
1237
- /** A recorded miss reason in the shape status reports, without `baseline.cacheKey`; null when malformed. */
1238
- declare function parseMissReason(value: unknown): BuildMissReason | null;
1247
+ interface WorktreePullRequest {
1248
+ number: number;
1249
+ url: string;
1250
+ title: string;
1251
+ state: "open" | "draft" | "merged" | "closed";
1252
+ checks: {
1253
+ passing: number;
1254
+ failing: number;
1255
+ pending: number;
1256
+ } | null;
1257
+ reviewDecision: "approved" | "changes-requested" | "review-required" | null;
1258
+ checkedAt: string;
1259
+ }
1260
+ interface WorktreeFacts {
1261
+ path: string;
1262
+ branch?: string;
1263
+ repository?: string;
1264
+ /** Null when git could not be read in time, the worktree is in a folder status does not open, or one-shot status skipped an idle environment or an unprovisioned worktree. */
1265
+ git?: WorktreeGit | null;
1266
+ /** Null when GitHub has no pull request for the branch; absent when unknown, such as without `gh`. */
1267
+ pullRequest?: WorktreePullRequest | null;
1268
+ /** Present with `git`: what the worktree's git chip shows, from `gitChip`. */
1269
+ gitChip?: GitChip;
1270
+ }
1271
+ /** Every coding-agent tool whose sessions status can attribute to an environment. */
1272
+ declare const AGENT_TOOLS: readonly ["claude-code", "codex"];
1273
+ type AgentTool = (typeof AGENT_TOOLS)[number];
1239
1274
  /**
1240
- * The first diagnostics of a failed build in the shape a last-build record stores and `status` reports, the
1241
- * ones with a source position first.
1275
+ * A coding-agent session working in an environment: one whose working directory `cwd` is the environment's path,
1276
+ * inside it, or its git worktree root, or one that ran a Stim command in it. `title` is the short name the tool keeps
1277
+ * for the session, never its conversation. `lastActiveAt` is the tool's own last update, or the Stim command's time
1278
+ * when that is newer. `openUrl` opens the session in the tool's desktop app when that app is installed on this machine.
1279
+ * `webUrl` opens a Claude Code session with Remote Control connected on claude.ai/code or in the Claude mobile app.
1242
1280
  */
1243
- declare function buildDiagnostics(value: unknown): BuildDiagnostic[];
1244
- declare function readDevicePlacement(state: WorkspaceState | null, platform: StatsPlatform, slot?: string): DevicePlacement | null;
1245
- declare function readLastBuilds(state: WorkspaceState | null | undefined): Partial<Record<StatsPlatform, LastBuildReport>>;
1246
- /** Each platform's recorded runs, newest first, at most `BUILD_HISTORY_LIMIT` each. */
1247
- declare function readBuildHistory(state: WorkspaceState | null | undefined): Partial<Record<BuildPlatform, BuildHistoryEntry[]>>;
1248
- declare function readWorkspaceState(root: string): WorkspaceState | null;
1249
- declare function lastUseFrom(state: WorkspaceState | null, logMtimes: readonly number[]): number;
1250
- declare const MAINTENANCE_LOG_NAME = "maintenance.ndjson";
1281
+ interface AgentSession {
1282
+ tool: AgentTool;
1283
+ sessionId: string;
1284
+ title?: string;
1285
+ cwd: string;
1286
+ startedAt?: string;
1287
+ lastActiveAt?: string;
1288
+ pid?: number;
1289
+ openUrl?: string;
1290
+ webUrl?: string;
1291
+ }
1251
1292
  /**
1252
- * When the workspace was last used, in epoch milliseconds. A workspace that recorded no use falls back to the mtime
1253
- * of its workspace.json, which is written once when the workspace is created, so it is a lower bound on the last
1254
- * use. NaN when its state.json exists but does not parse, or when workspace.json cannot be read either.
1293
+ * An agent session that stopped running in an environment, with the details Stim last found while it ran. `endedAt`
1294
+ * is the last time a status watcher found it running.
1255
1295
  */
1256
- declare function workspaceLastUsed(root: string): number;
1257
- declare const WARM_KEY = "warm";
1258
- /** How long a successful warm keeps a workspace `ready` when nothing runs in it. */
1259
- declare const READY_PHASE_MS: number;
1296
+ interface EndedAgentSession extends Omit<AgentSession, "pid"> {
1297
+ endedAt: string;
1298
+ }
1299
+ interface AndroidRuntimeFacts {
1300
+ serial: string | null;
1301
+ state: "detected" | "not-detected" | "missing" | "unknown";
1302
+ error?: string;
1303
+ }
1304
+ /** Every connection state a physical device can report. */
1305
+ declare const PHYSICAL_DEVICE_CONNECTIONS: readonly ["connected", "disconnected", "unknown"];
1306
+ type PhysicalDeviceConnection = (typeof PHYSICAL_DEVICE_CONNECTIONS)[number];
1260
1307
  /**
1261
- * What `stim worktree warm` last recorded in a workspace: a warm in progress, held by the ownership claim
1262
- * `claim` names, or a successful warm that finished at `at`.
1308
+ * A physical iPhone, iPad or Android phone the workspace holds an unexpired lease on, from `ios --device`,
1309
+ * `android --device` or `device lock`. Stim uses it and never owns it, so `owned` is always false. `id` is the
1310
+ * UDID or adb serial. `name` is the device's own name, falling back to the name the lease recorded; `model` is the
1311
+ * marketing name devicectl reports, null when it could not be read, or the Android model the lease recorded.
1312
+ * `connection` is `connected` when devicectl can reach the phone or adb lists it as `device`, `disconnected` when
1313
+ * the tool answered without it, and `unknown` when the tool could not be read in time. `lease.holder` is the
1314
+ * workspace path that holds it.
1263
1315
  */
1264
- type WarmRecord = {
1265
- phase: "warming";
1266
- step: WarmStep;
1267
- startedAt: string;
1268
- claim: {
1269
- root: string;
1270
- claimId: string;
1316
+ interface PhysicalDeviceState {
1317
+ platform: StatsPlatform;
1318
+ slot: string;
1319
+ id: string;
1320
+ name: string | null;
1321
+ model: string | null;
1322
+ owned: false;
1323
+ physical: true;
1324
+ connection: PhysicalDeviceConnection;
1325
+ lease: {
1326
+ holder: string;
1327
+ kind: "declared" | "run";
1328
+ grantedAt: string | null;
1329
+ expiresAt: string;
1271
1330
  };
1272
- } | {
1273
- phase: "ready";
1274
- at: string;
1275
- };
1276
- declare function readWarmRecord(state: WorkspaceState | null | undefined): WarmRecord | null;
1277
- declare const WORKSPACE_AGENT_KEY = "agentSession";
1278
- /**
1279
- * The coding-agent session whose shell ran the Stim command that last recorded `lastUsedAt`, with that command's
1280
- * working directory as `cwd` and its time as `lastActiveAt`.
1281
- */
1282
- declare function readWorkspaceAgent(state: WorkspaceState | null | undefined): AgentSession | null;
1283
- //#endregion
1284
- //#region state/hosted-native.d.ts
1285
- interface HostedNativePlacement<D> {
1286
- machine: string;
1287
- session: string;
1288
- appAttempt: string;
1289
- device: D | null;
1290
- selected: string;
1291
- reason?: string;
1292
- agent: HostedAgentAccess;
1293
1331
  }
1294
- declare function parseHostedNativePlacement(value: unknown, platform: "ios"): HostedNativePlacement<HostedIosDevice> | null;
1295
- declare function parseHostedNativePlacement(value: unknown, platform: "android"): HostedNativePlacement<HostedAndroidDevice> | null;
1296
- declare function parseHostedNativePlacement(value: unknown, platform: "ios" | "android"): HostedNativePlacement<HostedIosDevice | HostedAndroidDevice> | null;
1297
- declare function hostedNativeRecords(state: WorkspaceState | null, platform: "ios" | "android"): Record<string, unknown>;
1298
- declare function unreadableHostedNative(slot: string, platform: "ios" | "android"): string;
1299
- //#endregion
1300
- //#region state/hosted-android.d.ts
1301
- /** A workspace slot's placement; null device means its reservation has not reached ready yet. */
1302
- interface HostedAndroidPlacement extends HostedNativePlacement<HostedAndroidDevice> {}
1303
- /** Public hosting facts; the host's serial, AVD name and private Metro gateway are excluded. */
1304
- type HostedAndroidStatus = {
1305
- machine: string;
1306
- session: string;
1307
- selected: string;
1308
- reason?: string;
1309
- agent: HostedAgentAccess;
1310
- device: {
1311
- name: string;
1312
- systemImage: string;
1313
- api: number;
1314
- } | null;
1315
- /** The latest session probe in status, independent of a conflicting local emulator's state. */
1316
- state?: string;
1317
- };
1318
- declare function parseHostedAndroidPlacement(value: unknown): HostedAndroidPlacement | null;
1319
- declare function hostedAndroidStatus(placement: HostedAndroidPlacement): HostedAndroidStatus;
1320
- declare function hostedAndroidRecords(state: WorkspaceState | null): Record<string, unknown>;
1321
- declare function unreadableHostedAndroid(slot: string): string;
1322
- declare function hostedAndroidPlacements(state: WorkspaceState | null): Record<string, HostedAndroidPlacement>;
1323
- declare function hostedAndroidDeviceName(device: HostedAndroidDevice): string;
1324
- //#endregion
1325
- //#region state/hosted-ios.d.ts
1326
- /** A workspace slot's placement; null device means its reservation has not reached ready yet. */
1327
- interface HostedIosPlacement extends HostedNativePlacement<HostedIosDevice> {}
1328
- /** Public hosting facts; the host's UDID and private Metro gateway are excluded. */
1329
- type HostedIosStatus = {
1330
- machine: string;
1331
- session: string;
1332
- selected: string;
1333
- reason?: string;
1334
- agent: HostedAgentAccess;
1335
- device: {
1336
- name: string;
1337
- runtime: string;
1338
- } | null;
1339
- /** The latest session probe in status, independent of a conflicting local simulator's state. */
1340
- state?: string;
1341
- };
1342
- declare function parseHostedIosPlacement(value: unknown): HostedIosPlacement | null;
1343
- declare function hostedIosStatus(placement: HostedIosPlacement): HostedIosStatus;
1344
- declare function hostedIosRecords(state: WorkspaceState | null): Record<string, unknown>;
1345
- declare function unreadableHostedIos(slot: string): string;
1346
- declare function hostedIosPlacements(state: WorkspaceState | null): Record<string, HostedIosPlacement>;
1347
- //#endregion
1348
- //#region state/maintenance.d.ts
1349
- type MaintenanceMode = "off" | "report" | "on";
1350
- type MaintenanceCheck = "pressure" | "size" | "worktree" | "sweep" | "idle";
1351
- type MaintenanceActionKind = "would-clear-outputs" | "would-trim-cache" | "would-empty-cache" | "would-shutdown-device" | "would-stop-workspace" | "would-remove-worktree" | "would-remove-orphan" | "would-unregister-cache" | "would-delete-parked-device" | "would-delete-devices" | "would-clear-build-dirs" | "would-delete-dependencies" | "would-stop-gradle-daemons" | "would-delete-gradle-version" | "would-delete-temp-leftovers";
1352
- /** Disk pressure: 0 above every threshold, 1 under the budget floor, 2 under the urgent threshold, 3 under the critical threshold or the hard floor. */
1353
- type DiskPressureLevel = 0 | 1 | 2 | 3;
1354
- interface MaintenanceAction {
1355
- kind: MaintenanceActionKind;
1356
- target: string;
1357
- bytes: number;
1358
- reason: string;
1359
- workspace?: string;
1360
- dir?: string;
1361
- olderThanDays?: number;
1362
- check?: "worktree" | "sweep" | "disk";
1363
- /** The disk pressure level that planned the action; it runs only while free disk stays under that level's floor. */
1364
- level?: 2 | 3;
1332
+ interface RemoteDeviceState {
1333
+ platform: "ios" | "android" | null;
1334
+ backend: "eas";
1335
+ sessionId: string;
1336
+ state: "claimed" | "unclaimed" | "unknown";
1337
+ startedAt: string | null;
1338
+ webPreviewUrl: string | null;
1365
1339
  }
1366
- interface MaintenanceSize {
1367
- name: string;
1368
- dir: string;
1369
- bytes: number;
1370
- measuredAt: number;
1371
- category: "workspace-outputs" | "build-cache" | "metro-cache" | "compilation-cache" | "ccache" | "owned-devices" | "other";
1372
- workspace?: string;
1373
- idleDays?: number | null;
1374
- blocked?: string;
1340
+ /**
1341
+ * One part of a worktree's git chip, in display order: commits ahead of and behind the upstream, uncommitted files
1342
+ * (changed plus untracked), the base branch the branch is merged into (left out when its pull request is merged,
1343
+ * whose own mark says so), and a branch with no upstream that is not merged.
1344
+ */
1345
+ type GitChipPart = {
1346
+ kind: "arrows";
1347
+ ahead: number;
1348
+ behind: number;
1349
+ } | {
1350
+ kind: "changed";
1351
+ count: number;
1352
+ } | {
1353
+ kind: "merged";
1354
+ into: string;
1355
+ } | {
1356
+ kind: "no-upstream";
1357
+ };
1358
+ /** A pull request's checks at a glance: any failing, else any pending, else any passing; null without checks. */
1359
+ type ChecksState = "passing" | "failing" | "pending" | null;
1360
+ interface GitChip {
1361
+ parts: GitChipPart[];
1362
+ ci: ChecksState;
1375
1363
  }
1376
1364
  /**
1377
- * A process whose physical footprint, as `top` reports it, is abnormally large. `command` is the one command that
1378
- * safely restarts or stops it, null when Stim knows none; `note` says what that command does.
1365
+ * Whether a running owned simulator or emulator lacks the workspace's app: `none` when its platform never built
1366
+ * successfully here and the latest build failed, `closed` when status saw no app process, else null.
1379
1367
  */
1380
- interface MemoryCulprit {
1381
- pid: number;
1382
- name: string;
1383
- bytes: number;
1384
- command: string | null;
1385
- note: string | null;
1386
- }
1387
- interface MaintenancePressure {
1388
- disk: {
1389
- volume: string;
1390
- freeMb: number;
1368
+ type AppPresence = "none" | "closed" | null;
1369
+ declare const WORKSPACE_STAGE_KINDS: readonly ["building", "warming", "ready", "build-failed", "running", "stopped"];
1370
+ /**
1371
+ * Where a workspace is, first match wins: `building` while a build runs, `warming` and `ready` from `phase` when
1372
+ * nothing is live, `build-failed` when the newest run of either platform failed, `running` when it is live, its
1373
+ * macOS app is running or orphaned, or it holds a remote device, else `stopped`. `since` is when that began: the
1374
+ * build's start, the warm phase's time, the failed run's end (else start), the supervisor's start (else the running
1375
+ * macOS app's build end, else its start), or Metro's last stop. `platform` names the build for `building`
1376
+ * and `build-failed`. `closedApps` lists, for `running`, the devices whose `appPresence` is `closed`.
1377
+ */
1378
+ interface WorkspaceStage {
1379
+ kind: (typeof WORKSPACE_STAGE_KINDS)[number];
1380
+ since: string | null;
1381
+ platform: StatsPlatform | "macos" | null;
1382
+ closedApps: {
1383
+ platform: StatsPlatform;
1384
+ slot: string;
1391
1385
  }[];
1392
- memory: {
1393
- level: "normal" | "warning" | "critical" | null;
1394
- availableBytes: number | null;
1395
- pressured: boolean;
1396
- /** Read only while the level is warning or critical; absent otherwise. */
1397
- culprits?: MemoryCulprit[];
1398
- };
1399
- warningSince: number | null;
1400
- diskLevel?: DiskPressureLevel;
1401
- }
1402
- interface MaintenancePass {
1403
- startedAt: number;
1404
- durationMs: number;
1405
- trigger: string;
1406
- mode: "report" | "on";
1407
- freedBytes: number;
1408
- actions: number;
1409
- stopped: 0;
1410
- blocked: string[];
1411
1386
  }
1412
- interface MaintenanceRecord extends NdjsonRecord {
1413
- ts: number;
1414
- src: "maintenance";
1415
- level: "debug" | "info" | "warn" | "error";
1416
- msg: string;
1417
- event: "maintenance_pass" | "maintenance_action" | "maintenance_skip" | "maintenance_failure" | "maintenance_check";
1418
- pass: string;
1419
- trigger: string;
1420
- mode: "report" | "on";
1387
+ /** Every code a status issue can carry. */
1388
+ declare const STATUS_ISSUE_CODES: readonly ["port-not-ours", "sim-missing", "sim-without-metro", "avd-serial-changed", "avd-missing", "avd-not-detected", "avd-unchecked", "android-reverse-missing", "supervisor-unverified", "browser-unverified", "browser-orphaned"];
1389
+ type StatusIssueCode = (typeof STATUS_ISSUE_CODES)[number];
1390
+ /**
1391
+ * One thing in a workspace that needs the user, or with severity `info` a note that needs nothing. `remedy` is a
1392
+ * command to run from `workspace`; `slot` is absent for the default device slot. `warnings` carries the `error` and
1393
+ * `warning` issues as text.
1394
+ *
1395
+ * Severity:
1396
+ * - `error`: Stim cannot verify or safely act on something; a person resolves it, following the teardown guide.
1397
+ * - `warning`: something is broken now and needs someone to act, such as an app that cannot reach Metro, a held
1398
+ * port or a device that vanished while expected.
1399
+ * - `info`: a fact the next normal Stim command handles by itself, so it needs no action.
1400
+ *
1401
+ * The phone app and Stim Desktop show `error` and `warning` and hide `info`; plain `stim status` prints `info` as a
1402
+ * dim note with no remedy.
1403
+ */
1404
+ interface StatusIssue {
1405
+ code: StatusIssueCode;
1406
+ severity: "error" | "warning" | "info";
1407
+ message: string;
1408
+ remedy: string;
1409
+ workspace: string;
1410
+ slot?: string;
1421
1411
  }
1422
- interface MaintenanceState {
1423
- version: 1;
1424
- lastAt: Partial<Record<MaintenanceCheck, number>>;
1425
- deferredAt?: Partial<Record<MaintenanceCheck, number>>;
1426
- pressure: MaintenancePressure | null;
1427
- sizes: MaintenanceSize[];
1428
- lastPass: MaintenancePass | null;
1429
- recent: MaintenanceRecord[];
1430
- plan: MaintenanceAction[];
1431
- skipKeys?: string[];
1412
+ /** Every state the owned page's latest load can report. */
1413
+ declare const WEB_PAGE_STATES: readonly ["loading", "loaded", "failed"];
1414
+ /**
1415
+ * The owned page's latest load, from the page-load marker in the workspace's web log: `url` is the document it
1416
+ * loaded, `state` is `failed` when that document did not load or the page crashed, with the log message as
1417
+ * `error`. `route`, present only when an in-app route change (history API or fragment) moved the page off `url`
1418
+ * since the load, is the URL it shows now.
1419
+ */
1420
+ interface WebPageState {
1421
+ url: string;
1422
+ state: (typeof WEB_PAGE_STATES)[number];
1423
+ error?: string;
1424
+ route?: string;
1432
1425
  }
1433
- interface MaintenanceStatus {
1434
- mode: MaintenanceMode;
1435
- invalid?: string;
1436
- claim?: {
1437
- unresolved: string;
1438
- removeCommand: string;
1439
- };
1440
- lastChecks: {
1441
- pressure: number | null;
1442
- size: number | null;
1443
- worktree: number | null;
1444
- sweep: number | null;
1445
- };
1446
- pressure: MaintenancePressure | null;
1447
- sizes: MaintenanceSize[];
1448
- lastPass: MaintenancePass | null;
1449
- running: {
1450
- startedAt: string;
1451
- trigger: string;
1452
- } | null;
1453
- recent: MaintenanceRecord[];
1454
- plan: MaintenanceAction[];
1426
+ /**
1427
+ * The workspace's Stim-owned Chrome. `pid` is Chrome's process and `supervisorPid` the Stim process that holds
1428
+ * its DevTools session. `cdpEndpoint` is the loopback DevTools HTTP endpoint agents can attach to, and `targetId`
1429
+ * the DevTools target of the owned page; both are null when the browser is not running. `profile` is the
1430
+ * Stim-owned user data directory. `page` is null before the page's first load. `activity` names DevTools clients
1431
+ * other than Stim's as drivers.
1432
+ */
1433
+ interface WebBrowserState {
1434
+ browser: "chrome";
1435
+ version: string | null;
1436
+ running: boolean;
1437
+ pid: number | null;
1438
+ supervisorPid: number | null;
1439
+ url: string;
1440
+ headless: boolean;
1441
+ viewport: WebViewport;
1442
+ profile: string;
1443
+ cdpEndpoint: string | null;
1444
+ targetId: string | null;
1445
+ page?: WebPageState | null;
1446
+ activity?: DeviceActivity;
1455
1447
  }
1456
- /** Rejects missing, corrupt or unsupported payloads without throwing. */
1457
- declare function parseMaintenanceState(value: unknown): MaintenanceState | null;
1458
- declare function readMaintenanceState(): MaintenanceState | null;
1459
- declare function readMaintenanceAttempt(): number | undefined;
1460
- //#endregion
1461
- //#region state/archive.d.ts
1462
- interface ArchivedBytes {
1463
- logs: number;
1464
- recordings: number;
1465
- agentActions: number;
1466
- record: number;
1467
- total: number;
1448
+ /** The steps of `stim worktree warm`: `refresh` fast-forwards and installs in the source checkout, `copy` carries ignored entries. */
1449
+ type WarmStep = "refresh" | "copy";
1450
+ /**
1451
+ * Where a workspace is in its lifecycle: `warming` while `stim worktree warm` runs in it, `ready` after a warm
1452
+ * succeeded and before any `start`, `ios`, `android`, `web` or `reload` there, for at most two hours; `live` when
1453
+ * anything it owns runs, else `idle`.
1454
+ */
1455
+ declare const WORKSPACE_PHASES: readonly ["warming", "ready", "live", "idle"];
1456
+ type WorkspacePhase = (typeof WORKSPACE_PHASES)[number];
1457
+ /** A folder's size on disk as `status --watch` last measured it. */
1458
+ interface DiskMeasure {
1459
+ bytes: number;
1460
+ measuredAt: string;
1468
1461
  }
1469
- interface ArchivedWorkspace {
1470
- id: string;
1471
- projectRoot: string;
1472
- project: string;
1473
- workspace: string;
1474
- worktree: {
1475
- repository: string | null;
1476
- branch: string | null;
1477
- head: string | null;
1478
- subject: string | null;
1479
- merged: boolean | null;
1480
- pullRequest: {
1481
- number: number;
1482
- state: string;
1483
- title: string;
1484
- url: string;
1485
- } | null;
1486
- };
1487
- removedAt: string;
1488
- removedBy: string;
1489
- lastUsedAt: string | null;
1490
- builds: {
1491
- count: number;
1492
- last: LastBuildReport | null;
1493
- lastErrorCount: number;
1494
- };
1495
- agents: EndedAgentSession[];
1496
- bytes: ArchivedBytes;
1497
- expires: {
1498
- logs: string | null;
1499
- recordings: string | null;
1500
- agentActions: string | null;
1501
- record: string | null;
1502
- };
1503
- version: number;
1504
- replacedBy?: string;
1462
+ /**
1463
+ * An environment's disk use as `status --watch` last measured it. `worktreeBytes` is the git worktree folder, or the
1464
+ * workspace folder outside one, node_modules included. `nodeModulesBytes` is node_modules at the worktree root and,
1465
+ * when different, at the workspace path, and is part of `worktreeBytes`. `buildBytes` is Stim's own folder for the
1466
+ * workspace: Xcode derived data, Gradle outputs and logs. A figure is null until it was measured; `measuredAt` is the
1467
+ * oldest measurement.
1468
+ */
1469
+ interface EnvironmentDisk {
1470
+ worktreeBytes: number | null;
1471
+ nodeModulesBytes: number | null;
1472
+ buildBytes: number | null;
1473
+ measuredAt: string;
1505
1474
  }
1506
- interface ArchivedUsage {
1507
- count: number;
1508
- bytes: number;
1509
- byKind: {
1510
- logs: number;
1511
- recordings: number;
1512
- agentActions: number;
1513
- record: number;
1475
+ /**
1476
+ * A Metro bundle request: `bundling` while one is in flight on the workspace's Metro, with its `platform`,
1477
+ * `startedAt` and, when Metro reported progress for it, `percent` (0-100). `last` is the newest finished request,
1478
+ * `durationMs` from request to response end.
1479
+ */
1480
+ interface MetroBundleState {
1481
+ bundling: boolean;
1482
+ platform?: StatsPlatform;
1483
+ startedAt?: string;
1484
+ percent?: number;
1485
+ last?: {
1486
+ platform: StatsPlatform;
1487
+ status: "ok" | "failed";
1488
+ durationMs: number;
1489
+ finishedAt: string;
1514
1490
  };
1515
1491
  }
1516
- declare function readArchives(): ArchivedWorkspace[];
1517
- /** Reads current archive files asynchronously, outside the synchronous state-read cache; cancellation propagates. */
1518
- declare function readArchivesAsync(signal?: AbortSignal): Promise<ArchivedWorkspace[]>;
1519
- declare function readArchive(id: string): ArchivedWorkspace | null;
1520
- /** Reads a current archive without the synchronous state-read cache; invalid or missing records return null. */
1521
- declare function readArchiveAsync(id: string, signal?: AbortSignal): Promise<ArchivedWorkspace | null>;
1522
- declare function readArchiveState(id: string): WorkspaceState | null;
1523
- declare function archivedUsage(archives: readonly ArchivedWorkspace[]): ArchivedUsage;
1524
- declare function linkReplacedArchives(archives: readonly ArchivedWorkspace[], paths: readonly string[]): ArchivedWorkspace[];
1525
- declare function archiveEnabled(env: NodeJS.ProcessEnv, layers: readonly unknown[]): boolean;
1526
- //#endregion
1527
- //#region state/macos.d.ts
1528
- interface MacosProcess {
1529
- pid: number;
1530
- processToken: string;
1531
- startedAtMicros: number;
1492
+ interface SimulatorState {
1493
+ devicePlacement?: DevicePlacement;
1494
+ host?: HostedIosStatus;
1495
+ name: string | null;
1496
+ udid: string;
1497
+ owned: boolean;
1498
+ state: string;
1499
+ activity?: DeviceActivity;
1500
+ app?: DeviceAppProcess;
1501
+ appPresence?: AppPresence;
1502
+ /** The simulator's data folder, for an owned simulator once measured. */
1503
+ disk?: DiskMeasure;
1504
+ /** Present while the device is not booted after idle shutdown or queue reclaim. */
1505
+ idleShutdown?: DeviceIdleShutdownRecord;
1532
1506
  }
1533
- interface MacosBuild {
1534
- state: "running" | "ok" | "failed";
1535
- startedAt: string;
1536
- finishedAt?: string;
1537
- durationMs?: number;
1538
- fingerprint?: string;
1539
- cacheKey?: string;
1540
- cacheHit?: boolean;
1541
- cacheSource?: "local" | "provider" | "peer";
1542
- error?: string;
1543
- errorCode?: string;
1544
- buildMachine?: string;
1545
- builtOn?: string;
1546
- offloadedTo?: string;
1547
- offloadFallback?: string;
1507
+ interface AndroidDeviceState {
1508
+ devicePlacement?: DevicePlacement;
1509
+ host?: HostedAndroidStatus;
1510
+ name: string | undefined;
1511
+ owned: boolean;
1512
+ physical: boolean;
1513
+ serial?: string | null;
1514
+ state?: AndroidRuntimeFacts["state"] | "ready" | "stopped" | "unverified";
1515
+ deviceProfile?: string | null;
1516
+ activity?: DeviceActivity;
1517
+ app?: DeviceAppProcess;
1518
+ appPresence?: AppPresence;
1519
+ /** The AVD's folder, for an owned emulator once measured. */
1520
+ disk?: DiskMeasure;
1521
+ /** Present while the emulator is not running after idle shutdown or queue reclaim. */
1522
+ idleShutdown?: DeviceIdleShutdownRecord;
1548
1523
  }
1549
- interface MacosAppRecord {
1550
- launchId: string;
1551
- arguments: string[];
1552
- product: string;
1553
- /** The app's visible name: the product and the workspace label. Absent in older records. */
1554
- displayName?: string;
1555
- bundle: string;
1556
- bundleId: string;
1557
- executable: string;
1558
- build: MacosBuild;
1559
- supervisor?: MacosProcess;
1560
- app?: MacosProcess;
1561
- /** Set when `stim macos --remote` reserved a session on another Mac; the app then has no local process. */
1562
- host?: HostedMacosPlacement;
1563
- /** Host launch evidence: true for a live app; status can override it in memory after probing the session. */
1564
- hostLaunched?: boolean | "unverified";
1524
+ /** The tutorial format version the installed Stim writes into the tutorial app. */
1525
+ declare const TUTORIAL_VERSION = 2;
1526
+ interface EnvironmentState {
1527
+ slots?: {
1528
+ slot: string;
1529
+ ios: SimulatorState | null | undefined;
1530
+ android: AndroidDeviceState | null | undefined;
1531
+ }[];
1532
+ path: string;
1533
+ /** The 16-hex identity of the registered canonical project path, used by shared workspace links. */
1534
+ workspaceId?: string;
1535
+ /** Statically detected app platforms; always set by status, empty when none are detected. */
1536
+ platforms?: string[];
1537
+ /** Present when the app's app.json sets expo.extra.stimTutorial to a positive integer: that version. */
1538
+ tutorial?: {
1539
+ version: number;
1540
+ };
1541
+ /** When `stim doctor` last ran in this workspace, per platform; absent until it has run. */
1542
+ doctorRuns?: Partial<Record<"ios" | "android", {
1543
+ at: string;
1544
+ }>>;
1545
+ live: boolean;
1546
+ phase?: WorkspacePhase;
1547
+ /** When the warm started (`warming`) or finished (`ready`); null for `live` and `idle`. */
1548
+ phaseSince?: string | null;
1549
+ /** Whether stim-server may record this workspace's device screens, from `recording.enabled`. */
1550
+ recording?: {
1551
+ enabled: boolean;
1552
+ };
1553
+ /** Present when `workspace.hidden` is true: clients list the workspace under Hidden. */
1554
+ hidden?: true;
1555
+ /** Where the workspace is, from `workspaceStage`; `stim status --json` always sets it. */
1556
+ stage?: WorkspaceStage;
1557
+ /** The step a `warming` workspace's warm is in; absent in every other phase. */
1558
+ warmStep?: WarmStep;
1559
+ /**
1560
+ * The memory this workspace's processes use, as `memorySource` says: the sum of its `machine` owners' `memoryMb`
1561
+ * when status read their footprints, or else a fixed estimate per booted simulator, detected emulator, running
1562
+ * Metro and running Chrome. `capacity.committedMb` sums it.
1563
+ */
1564
+ memoryMb: number;
1565
+ /** How `memoryMb` was obtained; absent from payloads written before it existed, which carry the estimate. */
1566
+ memorySource?: Exclude<MemorySource, "rss">;
1567
+ warnings: string[];
1568
+ issues: StatusIssue[];
1569
+ ios?: SimulatorState | null;
1570
+ android?: AndroidDeviceState | null;
1571
+ metro?: {
1572
+ port: number;
1573
+ running: boolean;
1574
+ pid: number | null;
1575
+ tunnel?: {
1576
+ provider: Exclude<TunnelMode, "auto" | "off" | "expo">;
1577
+ url: string;
1578
+ };
1579
+ idleStop?: IdleStopRecord;
1580
+ lastStop?: MetroLastStop;
1581
+ /** The other process that answers Metro on `port`; `cwd` is null when its directory could not be read. */
1582
+ heldBy?: {
1583
+ pid: number;
1584
+ cwd: string | null;
1585
+ };
1586
+ /** Absent when the Metro log holds no bundle request. */
1587
+ bundle?: MetroBundleState;
1588
+ } | null;
1589
+ web?: WebBrowserState | null;
1590
+ macos?: MacosAppState | null;
1591
+ supervisor?: {
1592
+ pid: number | null;
1593
+ mode: string | null;
1594
+ startedAt: string | null;
1595
+ healthy: boolean;
1596
+ } | null;
1597
+ logs?: {
1598
+ dir: string;
1599
+ errorsSinceMarker: number;
1600
+ } | null;
1601
+ /** `installed` is whether the agent-device executable is on the PATH of the process that ran status. */
1602
+ agentDevice?: {
1603
+ stateDir: string;
1604
+ installed?: boolean;
1605
+ };
1606
+ worktree?: WorktreeFacts | null;
1607
+ remoteDevices?: RemoteDeviceState[];
1608
+ /** The physical devices this workspace leases, in every slot; absent when it leases none. */
1609
+ physicalDevices?: PhysicalDeviceState[];
1610
+ build?: BuildReport | null;
1611
+ lastBuilds?: Partial<Record<StatsPlatform, LastBuildReport>>;
1612
+ /** Each platform's recent runs, newest first, at most `BUILD_HISTORY_LIMIT` each. */
1613
+ builds?: Partial<Record<BuildPlatform, BuildHistoryEntry[]>>;
1614
+ disk?: EnvironmentDisk;
1615
+ /** The coding-agent sessions working in the environment, most recently active first; absent when none. */
1616
+ agents?: AgentSession[];
1617
+ /** The agent sessions that stopped running here in the last 3 days, most recently ended first; absent when none. */
1618
+ endedAgents?: EndedAgentSession[];
1565
1619
  }
1566
- interface MacosAppState extends MacosAppRecord {
1567
- state: "running" | "orphaned" | "stopped" | "unverified";
1620
+ /** `committedMb` sums the environments' `memoryMb`; `overCapacity` is that sum over 60% of `totalMemoryMb`. */
1621
+ interface StatusCapacity {
1622
+ liveCount: number;
1623
+ committedMb: number;
1624
+ totalMemoryMb: number;
1625
+ overCapacity: boolean;
1626
+ /** `concurrency.maxBuilds` usage; present only while that cap is set. */
1627
+ builds?: StatusBuildSlots;
1628
+ /** `concurrency.maxDevices` usage; present only while that cap is set. */
1629
+ devices?: StatusDeviceSlots;
1630
+ /** This machine's load. Optional only so payloads from releases that predate it still decode. */
1631
+ load?: StatusCapacityLoad;
1568
1632
  }
1569
- declare function parseMacosRecord(value: unknown): MacosAppRecord | null;
1570
- declare function readMacosRecord(root: string): MacosAppRecord | null;
1571
- declare function readHostedMacosApp(home: string): MacosAppRecord | null;
1572
- declare function macosAppState(record: MacosAppRecord | null): MacosAppState | null;
1573
- //#endregion
1574
- //#region state/status.d.ts
1575
- type StatsPlatform = "ios" | "android";
1576
- /** A platform whose build reports phases: the stats platforms and `macos`. */
1577
- type BuildPlatform = StatsPlatform | "macos";
1578
- type RunOutcomeKind = "hit" | "cold";
1579
- declare const BUILD_PHASES: readonly ["prepare", "cache-lookup", "wait", "prebuild", "pods", "compile", "device", "install", "launch"];
1580
- type BuildPhase = (typeof BUILD_PHASES)[number];
1581
- type ActiveBuildState = "running" | "stale" | "unknown";
1582
1633
  /**
1583
- * Where a running build compiles: `local`, or the remote machine it was offloaded to, with the phase it is in there
1584
- * (`sync`, `deps`, `prebuild`, `pods`, `build` or `fetch`) and when the offload and that phase started.
1634
+ * `free` is under `busyAt` (`server.maxLoadPerCore`), where placement keeps work on this machine; `busy` is at or over
1635
+ * it, where placement prefers another machine; `holding` is at or over `limit`, where new local native work waits.
1585
1636
  */
1586
- type BuildPlacement = "local" | {
1587
- host: string;
1588
- phase: string;
1589
- startedAt: string;
1590
- phaseStartedAt: string;
1591
- };
1592
- interface BuildWaitingFor {
1593
- kind: "build-slot" | "device-slot";
1594
- inUse: number;
1595
- max: number;
1596
- since: string;
1637
+ type LoadState = "free" | "busy" | "holding";
1638
+ /**
1639
+ * `loadPerCore` is the 5-minute load average divided by `cpus`, rounded to one decimal. `limit` is the load per core at
1640
+ * which new local native work waits, null while no limit is configured.
1641
+ */
1642
+ interface StatusCapacityLoad {
1643
+ cpus: number;
1644
+ loadPerCore: number;
1645
+ busyAt: number;
1646
+ limit: number | null;
1647
+ state: LoadState;
1597
1648
  }
1598
- interface BuildReport {
1599
- platform: BuildPlatform;
1600
- slot: string;
1601
- state: ActiveBuildState;
1602
- phase: BuildPhase;
1603
- startedAt: string;
1604
- phaseStartedAt: string;
1605
- outcome: RunOutcomeKind | null;
1606
- /** Whether `outcome` is this run's own; before its cache lookup resolves it is the project's latest outcome. */
1607
- outcomeKnown: boolean;
1608
- /** The resolved lookup result; absent before resolution and when the run skips cache lookup. */
1609
- cacheLookupOutcome?: "hit" | "miss";
1610
- expectedMs: number | null;
1611
- expectedPhaseMs: number | null;
1612
- /** Milliseconds spent in phases already left; sums repeat visits, excludes the current visit, and is omitted before any phase completes and by older Stim. */
1613
- completedPhaseMs?: Partial<Record<BuildPhase, number>>;
1614
- basis: number;
1615
- /**
1616
- * The phases a run like this one goes through, in order, with each one's median in milliseconds, from the same
1617
- * runs as `expectedMs`; null without comparable runs. The current phase can be one the plan does not list.
1618
- */
1619
- plannedPhases: PlannedPhase[] | null;
1620
- /** Why the run's cache lookup missed, once the run knows; `baseline` omits `cacheKey`. */
1621
- missReason?: BuildMissReason;
1622
- /**
1623
- * True while `missReason` is the miss of the key the run looked up first and the run will prebuild or install pods,
1624
- * then look the key up again. A hit on the second lookup removes `missReason` and sets `outcome` to `hit`.
1625
- */
1626
- missProvisional?: true;
1627
- /** What the native build tool is doing now, once it printed a line Stim recognizes. */
1628
- detail?: BuildDetail;
1629
- /** What the `device` or `launch` phase is waiting on, once Stim observed it; absent otherwise and from older Stim. */
1630
- activity?: BuildActivity;
1631
- placement: BuildPlacement;
1632
- /** While `phase` is `wait`: the workspace whose build of the same artifact this run waits on, when it is known. */
1633
- waitingOn?: {
1634
- path: string;
1635
- };
1636
- waitingFor?: BuildWaitingFor;
1649
+ /**
1650
+ * A held build slot. `workspace` is the root of the local build holding it, `client` the device id of the client
1651
+ * whose offloaded build this machine runs in it; both are null for a slot whose holder Stim cannot read.
1652
+ */
1653
+ interface StatusBuildSlotHolder {
1654
+ slot: number;
1655
+ workspace: string | null;
1656
+ client: string | null;
1657
+ since: string | null;
1658
+ unresolved?: true;
1659
+ }
1660
+ /** `inUse` counts the slots below `max` that a live or unresolved claim holds, which a new build cannot take. */
1661
+ interface StatusBuildSlots {
1662
+ max: number;
1663
+ inUse: number;
1664
+ holders: StatusBuildSlotHolder[];
1637
1665
  }
1638
1666
  /**
1639
- * What a run's `device` or `launch` phase is waiting on. `booting` lasts while the run waits for the owned simulator or
1640
- * emulator it started booting. `bundling` starts when the app's bundle request reaches this workspace's
1641
- * Metro and ends when Metro delivered it; `percent` is Metro's own progress for that request, present only once Metro
1642
- * reported one. `waiting-ready` lasts while the app reports its readiness pending. `startedAt` is when the evidence was
1643
- * recorded.
1667
+ * An owned device counted against `concurrency.maxDevices`. `label` is the label of the workspace that records it, or
1668
+ * the device's name when no workspace does; `workspace` and `slot` are null then.
1644
1669
  */
1645
- interface BuildActivity {
1646
- name: "booting" | "bundling" | "waiting-ready";
1647
- startedAt: string;
1648
- percent?: number;
1670
+ interface StatusDeviceSlotHolder {
1671
+ platform: "ios" | "android";
1672
+ label: string;
1673
+ workspace: string | null;
1674
+ slot: string | null;
1675
+ booting?: true;
1649
1676
  }
1650
- /** One phase a running build is expected to go through, and its median duration in comparable runs. */
1651
- interface PlannedPhase {
1652
- phase: BuildPhase;
1653
- expectedMs: number;
1677
+ /** `inUse` is null, with `unknown` saying why, when Stim cannot count the owned devices. */
1678
+ interface StatusDeviceSlots {
1679
+ max: number;
1680
+ inUse: number | null;
1681
+ unknown?: string;
1682
+ holders: StatusDeviceSlotHolder[];
1683
+ }
1684
+ interface DeviceLeaseState {
1685
+ slot?: string;
1686
+ path: string;
1687
+ platform: string;
1688
+ id: string | null;
1689
+ deviceName: string | null;
1690
+ holder: string | null;
1691
+ grantedAt: string | null;
1692
+ expiresAt: string | null;
1693
+ mine: boolean;
1694
+ expired: boolean;
1695
+ parsed: boolean;
1654
1696
  }
1655
- /** The native build tool's step inside a build's `compile` phase. */
1656
- declare const NATIVE_BUILD_STEPS: readonly ["configure", "compile", "link", "resources", "script", "dex", "package", "sign"];
1657
- type NativeBuildStep = (typeof NATIVE_BUILD_STEPS)[number];
1658
1697
  /**
1659
- * A running build's progress as its tool reports it. `unit` is `targets` for xcodebuild, `tasks` for Gradle and
1660
- * `steps` for SwiftPM. xcodebuild's `done` counts targets it finished and `total` the targets in its dependency graph,
1661
- * which includes targets with nothing to do; Gradle's `done` counts the tasks it reported, with a null `total`;
1662
- * SwiftPM's `done` and `total` are the `[done/total]` of its latest progress line, and its total can grow while it
1663
- * builds. They are counts, not a completion fraction. `status` reports the detail only during the `compile` phase. `line` is
1664
- * the latest compile, link or task line with paths shortened to file names.
1698
+ * Where a memory figure comes from. `footprint` is each process's physical footprint, which Activity Monitor's Memory
1699
+ * column shows. `rss` sums resident set sizes, which count pages shared between processes once per process, so a
1700
+ * simulator reports well above its footprint; the machine owners fall back to it when the footprint helper cannot be
1701
+ * built. `estimate` is a fixed amount per running thing, which an environment reports whenever it has no footprint.
1665
1702
  */
1666
- interface BuildDetail {
1667
- step: NativeBuildStep | null;
1668
- unit: "targets" | "tasks" | "steps" | null;
1669
- done: number | null;
1670
- total: number | null;
1671
- line: string | null;
1672
- updatedAt: string;
1703
+ declare const MEMORY_SOURCES: readonly ["footprint", "rss", "estimate"];
1704
+ type MemorySource = (typeof MEMORY_SOURCES)[number];
1705
+ /** Every kind of process owner the status machine section reports. */
1706
+ declare const MACHINE_OWNER_KINDS: readonly ["simulator", "emulator", "metro", "build", "browser", "macos", "server", "shared"];
1707
+ type MachineOwnerKind = (typeof MACHINE_OWNER_KINDS)[number];
1708
+ /**
1709
+ * One thing using this machine's CPU and memory now. Each process is counted in exactly one owner: the one whose root
1710
+ * process is its nearest ancestor. `workspace` and `slot` (absent for the default slot) name the workspace a
1711
+ * simulator, emulator, Metro, build or Chrome belongs to; a device no workspace records has a null workspace, and
1712
+ * machine-wide processes are `shared`. `id` is the simulator's UDID, the emulator's AVD name, Metro's port as text,
1713
+ * the build's platform, or null. `owned` is true only for what Stim started and stops: a workspace's owned device,
1714
+ * Metro, build or Chrome. `cpuPercent` is `ps` %CPU summed over the owner's processes, where 100 is one core.
1715
+ * `residentMb` sums their resident set sizes; pages shared between processes count once per process, so a
1716
+ * simulator, whose processes all map the runtime's shared libraries, reports well above its physical footprint.
1717
+ * `memoryMb` sums their physical footprints when `MachineUsageState.memorySource` is `footprint`, taking the resident
1718
+ * size of a process the footprint helper could not read, and equals `residentMb` when it is `rss`.
1719
+ */
1720
+ interface MachineOwner {
1721
+ kind: MachineOwnerKind;
1722
+ name: string;
1723
+ workspace: string | null;
1724
+ slot?: string;
1725
+ id: string | null;
1726
+ owned: boolean;
1727
+ cpuPercent: number;
1728
+ residentMb: number;
1729
+ memoryMb: number;
1730
+ processes: number;
1673
1731
  }
1674
- /** Where a build's app came from: a cache tier, or `false` when it compiled or failed before one was found. */
1675
- type BuildCacheHit = "local" | "remote" | false;
1676
- /** A platform's most recent `ios` or `android` run in one workspace. */
1677
- interface DevicePlacement {
1678
- decision: "local" | "hosted" | "waited-locally" | "eas";
1679
- reason: string;
1680
- machine?: string;
1732
+ /** Where this machine's CPU and memory go, from one pass over the host process table. */
1733
+ interface MachineUsageState {
1734
+ memorySource: Exclude<MemorySource, "estimate">;
1735
+ owners: MachineOwner[];
1681
1736
  }
1682
- interface LastBuildReport {
1683
- devicePlacement?: DevicePlacement;
1684
- platform: BuildPlatform;
1685
- status: "ok" | "failed";
1686
- cacheHit: BuildCacheHit;
1687
- cacheSkipped: boolean;
1688
- durationMs: number | null;
1689
- fingerprint: string | null;
1690
- startedAt: string;
1691
- finishedAt: string | null;
1692
- errorCode?: string;
1693
- missReason?: BuildMissReason;
1694
- /** The selected auto, local, or configured machine entry; present on new build records, including cache hits. */
1695
- buildMachine?: string;
1696
- /** Where compilation ran: here or a machine name; absent when no build ran. */
1697
- builtOn?: string;
1698
- /** The remote machine that compiled the app when the build was offloaded. */
1699
- offloadedTo?: string;
1700
- /** Why the run built here after it considered offloading; absent when it offloaded or never considered it. */
1701
- offloadFallback?: string;
1702
- /** The first compiler diagnostics of a failed build, when the build tool reported any. */
1703
- diagnostics?: BuildDiagnostic[];
1704
- /** Present on a failed run: what failed, from `buildCause`. */
1705
- cause?: BuildCause;
1737
+ /** The payload `stim status --json` prints, and `status --watch --json` prints on each change. */
1738
+ interface StatusPayload {
1739
+ maintenance?: MaintenanceStatus;
1740
+ archived?: ArchivedWorkspace[];
1741
+ archivedUsage?: ArchivedUsage;
1742
+ environments: (EnvironmentState & {
1743
+ labelOnly?: true;
1744
+ })[];
1745
+ capacity: StatusCapacity;
1746
+ deviceLeases: DeviceLeaseState[];
1747
+ unprovisionedWorktrees: WorktreeFacts[];
1748
+ simctlAvailable: boolean;
1749
+ /** Null when nothing runs that status attributes, so it read no process table, or when the table was unreadable. */
1750
+ machine: MachineUsageState | null;
1706
1751
  }
1752
+ //#endregion
1753
+ //#region state/build-capacity.d.ts
1754
+ declare function buildSlotsDir(): string;
1755
+ declare function buildSlotPath(index: number): string;
1707
1756
  /**
1708
- * A failed run's cause: the first diagnostic with a file and a line, keyed `file:line`, else the run's error code
1709
- * (or `failed`), with null `file` and `line`. Consecutive failures with the same `key` failed the same way.
1757
+ * Takes the first free one of `max` `concurrency.maxBuilds` slots, recording `details` and the slot `index`. Returns
1758
+ * null while every slot is held; throws the claim refusal when no slot is busy but one cannot be resolved.
1710
1759
  */
1711
- interface BuildCause {
1712
- key: string;
1713
- file: string | null;
1714
- line: number | null;
1760
+ declare function tryAcquireBuildSlotClaim({ max, details }: {
1761
+ max: number;
1762
+ details: Record<string, unknown>;
1763
+ }): {
1764
+ claim: ClaimHandle;
1765
+ index: number;
1766
+ path: string;
1767
+ } | null;
1768
+ /**
1769
+ * How busy this machine is for native builds. `loadPerCore` is the 5-minute load average divided by the CPU count,
1770
+ * rounded to one decimal. `builds` counts this Stim home's runs that hold a live native-run claim and are in
1771
+ * prebuild, pods or compile here, not on a remote machine, plus the build slots this machine holds for other machines'
1772
+ * offloaded builds. `maxBuilds` is `concurrency.maxBuilds`, 0 when unlimited.
1773
+ */
1774
+ interface MachineCapacity {
1775
+ cpus: number;
1776
+ loadPerCore: number;
1777
+ builds: number;
1778
+ maxBuilds: number;
1779
+ maxLoadPerCore: number;
1715
1780
  }
1716
- /** How a recorded build ended. `interrupted` is a run whose process ended without recording a result. */
1717
- declare const BUILD_RESULTS: readonly ["succeeded", "failed", "cancelled", "interrupted"];
1718
- type BuildResult = (typeof BUILD_RESULTS)[number];
1781
+ declare function maxLoadPerCore(): number;
1782
+ /** The 5-minute load average per CPU, rounded to one decimal, and the CPU count it divides by. */
1783
+ declare function loadPerCore(): {
1784
+ cpus: number;
1785
+ loadPerCore: number;
1786
+ };
1787
+ declare function loadState(load: number, busyAt: number, limit: number | null): LoadState;
1788
+ declare function machineCapacity(): MachineCapacity;
1789
+ /** Why a machine with this capacity should not take another native build; null when it can. */
1790
+ declare function saturation(capacity: MachineCapacity): string | null;
1791
+ //#endregion
1792
+ //#region state/build-machines.d.ts
1719
1793
  /**
1720
- * One run in a workspace's recent build history. `configuration` is the iOS configuration or the Android
1721
- * variant the run built, `Debug` or `debug` by default, and null when the run ended before resolving it.
1722
- * `phases` holds the milliseconds spent in each phase the run entered. An interrupted run has null
1723
- * `durationMs` and `finishedAt`, no cache facts, and 0 for the phase it stopped in.
1794
+ * What this machine keeps about a remote machine it asked for access. `machine` is the `remote.machines` entry and
1795
+ * `address` the name it resolved to. Once approved, `serverKey` is the worker's pinned stim-server key: every later
1796
+ * connection must prove it holds that key. While pending, `ticket` is the setup ticket this machine generated or was
1797
+ * given, and `expiresAt` its expiry when known. Records of protocol 1, which pinned a tailnet node, are not read.
1724
1798
  */
1725
- interface BuildHistoryEntry extends LastBuildReport {
1726
- result: BuildResult;
1727
- slot: string;
1728
- configuration: string | null;
1729
- cacheKey: string | null;
1730
- phases: Partial<Record<BuildPhase, number>>;
1731
- /** A `stim macos` run's SwiftPM step total; absent for other runs and when the build reported none. */
1732
- compileSteps?: number;
1799
+ interface MachineCredential {
1800
+ machine: string;
1801
+ transport: "tailscale";
1802
+ address: string;
1803
+ state: "pending" | "approved";
1804
+ requestedAt: string;
1805
+ serverKey?: string;
1806
+ deviceId?: string;
1807
+ ticket?: string;
1808
+ expiresAt?: string;
1733
1809
  }
1734
- /** One compiler error from a failed build: where it is, when the tool said, and its message. */
1735
- interface BuildDiagnostic {
1736
- file: string | null;
1737
- line: number | null;
1738
- column: number | null;
1739
- message: string;
1810
+ type BuildMachineCredential = MachineCredential;
1811
+ declare const MACHINE_CREDENTIALS_VERSION = 2;
1812
+ /** A stored credential, or null when it is malformed or from an older version. */
1813
+ declare function parseMachineCredential(value: unknown): MachineCredential | null;
1814
+ declare function readBuildMachines(): BuildMachineCredential[];
1815
+ //#endregion
1816
+ //#region state/client-identity.d.ts
1817
+ /** This machine's long-term X25519 key as a client of other machines, in `$STIM_HOME/client-identity.key`. */
1818
+ declare function clientIdentity(): NoiseKeyPair;
1819
+ //#endregion
1820
+ //#region state/config-types.d.ts
1821
+ type SettingsObject = Record<string, unknown>;
1822
+ interface SupervisorRecord {
1823
+ processToken?: string;
1824
+ pid?: number;
1825
+ port?: number;
1826
+ startedAt?: string;
1827
+ serverPid?: number;
1828
+ mode?: string;
1829
+ [key: string]: unknown;
1740
1830
  }
1741
- /** What kind of native input a changed fingerprint source is. */
1742
- type BuildMissCategory = "native-dependency" | "config-plugin" | "app-config" | "app-asset" | "package" | "native-dir" | "autolinking" | "package-scripts" | "file" | "other";
1743
- interface BuildMissChange {
1744
- source: string;
1745
- change: "added" | "removed" | "changed";
1746
- category: BuildMissCategory;
1831
+ interface IosDeviceRecord {
1832
+ deviceUdid?: string;
1833
+ deviceName?: string | null;
1834
+ owned?: boolean;
1835
+ serial?: string;
1836
+ simslimManaged?: boolean;
1837
+ simslimApplied?: {
1838
+ profile: string;
1839
+ springBoardPid: number;
1840
+ };
1841
+ schemeApprovals?: string[];
1842
+ [key: string]: unknown;
1843
+ }
1844
+ interface AndroidDeviceRecord {
1845
+ avdName?: string;
1846
+ consolePort?: number;
1847
+ serial?: string;
1848
+ kind?: string;
1849
+ deviceName?: string | null;
1850
+ owned?: boolean;
1851
+ setupIncomplete?: boolean;
1852
+ bootPending?: boolean;
1853
+ [key: string]: unknown;
1747
1854
  }
1748
- /**
1749
- * Why a run compiled instead of installing a cached app. `changes` holds at most 20 entries,
1750
- * ordered by importance; `changeCount` is the full number of changed fingerprint sources.
1751
- * Only a plan reports `prebuild-pending`: the run would prebuild before compiling, so the changes
1752
- * compare the fingerprint before that prebuild.
1753
- */
1754
- interface BuildMissReason {
1755
- kind: "changed" | "no-baseline" | "same-sources" | "cache-skipped" | "fingerprint-error" | "prebuild-pending";
1756
- summary: string;
1757
- changes: BuildMissChange[];
1758
- changeCount: number;
1759
- /** `cacheKey` is kept in workspace state so a later miss can find this baseline; status omits it. */
1760
- baseline: {
1761
- fingerprint: string;
1762
- cacheKey?: string;
1763
- from: "workspace" | "project";
1764
- } | null;
1765
- rekeyedBy: string[];
1855
+ type DeviceRecord = IosDeviceRecord | AndroidDeviceRecord;
1856
+ interface PlatformRecords {
1857
+ ios?: IosDeviceRecord;
1858
+ android?: AndroidDeviceRecord;
1859
+ [platform: string]: DeviceRecord | undefined;
1766
1860
  }
1767
- /** The payload `stim ios --plan --json` and `stim android --plan --json` print. */
1768
- interface BuildPlanPayload {
1769
- platform: StatsPlatform;
1770
- slot?: string;
1771
- fingerprint: string;
1772
- cacheKey: string | null;
1773
- cacheHit: BuildCacheHit;
1774
- provider: string | null;
1775
- cacheSkipped: boolean;
1776
- prebuild: "none" | "generate" | "regenerate" | "refuse" | null;
1777
- outcome: RunOutcomeKind | null;
1778
- expectedMs: number | null;
1779
- basis: number;
1780
- /** On a predicted miss with cache reads on, why the cache has no app; `baseline` omits `cacheKey`. */
1781
- missReason?: BuildMissReason;
1782
- refusal?: {
1783
- code: string;
1784
- message: string;
1785
- remedy: string;
1786
- };
1787
- /** With ios.remote or android.remote set to auto or a Mac, where the plan assumes the device runs, such as `this machine; auto may use janics-mac-mini`. */
1788
- placement?: string;
1861
+ interface ProjectRecord {
1862
+ ports?: Record<string, number>;
1863
+ metroPort?: number | null;
1864
+ platforms?: PlatformRecords;
1865
+ deviceSlots?: Record<string, PlatformRecords>;
1866
+ supervisor?: SupervisorRecord;
1867
+ settings?: SettingsObject;
1868
+ worktreeRoot?: boolean;
1869
+ worktreeBranch?: string;
1870
+ worktreeBranchOwned?: boolean;
1871
+ worktreeMainRoot?: string;
1872
+ worktreeRemovalComplete?: boolean;
1873
+ worktreePendingBranchSha?: string;
1874
+ label?: string;
1875
+ bundleId?: string;
1876
+ androidPackage?: string;
1877
+ isExpo?: boolean;
1878
+ lastBuild?: Record<string, unknown>;
1879
+ doctorRuns?: Partial<Record<"ios" | "android", DoctorRunRecord>>;
1880
+ [key: string]: unknown;
1789
1881
  }
1790
- /** The read-only `stim macos --plan --json` payload; SwiftPM work and worker availability remain unknown. */
1791
- interface MacosBuildPlanPayload {
1792
- platform: "macos";
1793
- product: string;
1794
- buildMachine: string;
1795
- fingerprint: string | null;
1796
- cacheKey: string | null;
1797
- cacheHit: boolean;
1798
- provider: null;
1799
- cacheSkipped: boolean;
1800
- prebuild: null;
1801
- outcome: null;
1802
- expectedMs: null;
1803
- basis: number;
1882
+ interface DoctorRunRecord {
1883
+ at: string;
1884
+ version: string;
1804
1885
  }
1805
- type ActivityState = "driven" | "active" | "idle" | "unknown";
1806
- interface ActivityDriver {
1807
- tool: string;
1808
- pid: number | null;
1809
- since: string | null;
1886
+ interface RepoRecord {
1887
+ settings?: SettingsObject;
1888
+ [key: string]: unknown;
1810
1889
  }
1811
- /** The kinds of evidence that date a device's last activity, in the order `recent` lists them. */
1812
- declare const ACTIVITY_RECENCY_BASES: readonly ["agent-action", "device-log", "metro-bundle", "workspace-use", "supervisor-start", "page-log", "viewer"];
1813
- type ActivityRecencyBasis = (typeof ACTIVITY_RECENCY_BASES)[number];
1814
- interface DeviceActivity {
1815
- state: ActivityState;
1816
- driver?: ActivityDriver;
1817
- lastActivityAt?: string;
1818
- /** The newest time of each kind of evidence behind `lastActivityAt`, so a reader can leave out app log chatter. */
1819
- recent?: Partial<Record<ActivityRecencyBasis, string>>;
1820
- basis: string[];
1890
+ interface ConcurrencyLimits {
1891
+ maxBuilds: number;
1892
+ maxDevices: number;
1821
1893
  }
1822
- /** Every state a device's app process can report. */
1823
- declare const APP_PROCESS_STATES: readonly ["running", "stopped", "unknown"];
1824
- /**
1825
- * Whether the workspace's app process is alive on a device now. This is current process state, not launch evidence:
1826
- * `launched` in an `ios` or `android` result stays the record of one launch. `id` is the bundle identifier or
1827
- * package that was checked; `state` is "unknown" when the process listing could not be read.
1828
- */
1829
- interface DeviceAppProcess {
1830
- id: string;
1831
- state: (typeof APP_PROCESS_STATES)[number];
1894
+ interface StimConfig {
1895
+ version?: number;
1896
+ homeId?: string;
1897
+ projects: Record<string, ProjectRecord>;
1898
+ repos: Record<string, RepoRecord>;
1899
+ tempDir?: unknown;
1900
+ iosSimulatorApp?: unknown;
1901
+ androidEmulatorApp?: unknown;
1902
+ optimizations?: unknown;
1903
+ concurrency?: {
1904
+ maxBuilds?: unknown;
1905
+ maxDevices?: unknown;
1906
+ };
1907
+ pool?: {
1908
+ iosParkedMax?: unknown;
1909
+ androidParkedMax?: unknown;
1910
+ };
1911
+ parked?: {
1912
+ ios?: unknown;
1913
+ android?: unknown;
1914
+ };
1915
+ caches?: {
1916
+ buildCache?: unknown;
1917
+ metroCache?: unknown;
1918
+ };
1919
+ hosting?: {
1920
+ agentDriver?: unknown;
1921
+ };
1922
+ debug?: {
1923
+ logs?: unknown;
1924
+ };
1925
+ server?: {
1926
+ buildsPaused?: unknown;
1927
+ devicesPaused?: unknown;
1928
+ acceptClientBuilds?: unknown;
1929
+ maxLoadPerCore?: unknown;
1930
+ workerRoot?: unknown;
1931
+ gradleDaemonIdleMinutes?: unknown;
1932
+ };
1933
+ remote?: {
1934
+ machines?: unknown;
1935
+ easMaxDurationMinutes?: unknown;
1936
+ build?: unknown;
1937
+ buildPoolDisabled?: unknown;
1938
+ devicePoolDisabled?: unknown;
1939
+ };
1940
+ [key: string]: unknown;
1832
1941
  }
1942
+ type Config = StimConfig;
1943
+ //#endregion
1944
+ //#region state/automatic-pools.d.ts
1945
+ type AutomaticPoolRole = "build" | "device";
1946
+ declare function automaticMachineEnabled(role: AutomaticPoolRole, machine: string, config?: StimConfig | null): boolean;
1947
+ declare function requireAutomaticMachine(role: AutomaticPoolRole, machine: string): void;
1833
1948
  /**
1834
- * A linked worktree's `git status`. `changed` counts tracked paths with staged or unstaged changes, including
1835
- * conflicts; `untracked` counts untracked entries as `git status` lists them, so an untracked directory counts once.
1836
- * `ahead` and `behind` compare HEAD with `upstream`, and are null when there is no upstream or it no longer exists.
1837
- * `mergedInto` names the default branch (`origin/main`) when `gc` would consider the branch merged into it, judged
1838
- * from local refs without fetching.
1949
+ * Refuses a pool with no enabled member: local, or a configured remote approved for the role. `canHost` excludes
1950
+ * device-pool remotes that can never host, such as a Linux machine.
1839
1951
  */
1840
- interface WorktreeGit {
1841
- changed: number;
1842
- untracked: number;
1843
- upstream: string | null;
1844
- ahead: number | null;
1845
- behind: number | null;
1846
- mergedInto: string | null;
1847
- }
1952
+ declare function validateAutomaticPool(role: AutomaticPoolRole, config: StimConfig, canHost?: (machine: string) => boolean): void;
1953
+ //#endregion
1954
+ //#region state/config.d.ts
1955
+ declare function withConfigLock<T>(fn: () => T): T;
1956
+ /** Waits for the config lock without blocking the event loop. The signal cancels acquisition; `fn` runs synchronously. */
1957
+ declare function withConfigLockAsync<T>(fn: () => T, signal?: AbortSignal): Promise<T>;
1958
+ declare function configCorruptRepair(path?: string): string;
1959
+ /** The build worker root: `server.workerRoot` when it is absolute, else `$STIM_HOME/build-worker`. */
1960
+ declare function buildWorkerRoot(config?: Config | null): string;
1848
1961
  /**
1849
- * The GitHub pull request of a worktree's branch and HEAD, as `status --watch` last looked it up through `gh`.
1850
- * `state` is `draft` for an open draft. `checks` counts the head commit's check runs and commit statuses, null when it
1851
- * has none. `checkedAt` is when Stim last asked GitHub.
1962
+ * A short directory at the drive root that stands in for the build worker directory `path` on Windows. The NDK's
1963
+ * ninja is not long-path aware (STIM_PATH_TOO_LONG), and it opens paths under the checkout and under the Gradle user
1964
+ * home's transforms cache, both of which are too long under the worker root. A subst drive does not help: Node's
1965
+ * native realpath, which expo-modules-autolinking uses, resolves it back to the long path.
1852
1966
  */
1853
- interface WorktreePullRequest {
1854
- number: number;
1855
- url: string;
1856
- title: string;
1857
- state: "open" | "draft" | "merged" | "closed";
1858
- checks: {
1859
- passing: number;
1860
- failing: number;
1861
- pending: number;
1862
- } | null;
1863
- reviewDecision: "approved" | "changes-requested" | "review-required" | null;
1864
- checkedAt: string;
1865
- }
1866
- interface WorktreeFacts {
1867
- path: string;
1868
- branch?: string;
1869
- repository?: string;
1870
- /** Null when git could not be read in time, the worktree is in a folder status does not open, or one-shot status skipped an idle environment or an unprovisioned worktree. */
1871
- git?: WorktreeGit | null;
1872
- /** Null when GitHub has no pull request for the branch; absent when unknown, such as without `gh`. */
1873
- pullRequest?: WorktreePullRequest | null;
1874
- /** Present with `git`: what the worktree's git chip shows, from `gitChip`. */
1875
- gitChip?: GitChip;
1967
+ declare function windowsShortDir(path: string, systemDrive?: string): string;
1968
+ /** The ASCII key a Windows build worker records beside a `windowsShortDir` to tell which `kind` and `path` it serves. */
1969
+ declare function windowsShortDirKey(kind: "checkout" | "gradle", path: string): string;
1970
+ declare function loadConfig(): Config | null;
1971
+ declare function getProject(projectPath: string): ProjectRecord | null;
1972
+ declare function getConcurrencyLimits({ env }?: {
1973
+ env?: NodeJS.ProcessEnv;
1974
+ }): ConcurrencyLimits;
1975
+ interface ParkedMax {
1976
+ max: number;
1977
+ error: string | null;
1876
1978
  }
1877
- /** Every coding-agent tool whose sessions status can attribute to an environment. */
1878
- declare const AGENT_TOOLS: readonly ["claude-code", "codex"];
1879
- type AgentTool = (typeof AGENT_TOOLS)[number];
1880
- /**
1881
- * A coding-agent session working in an environment: one whose working directory `cwd` is the environment's path,
1882
- * inside it, or its git worktree root, or one that ran a Stim command in it. `title` is the short name the tool keeps
1883
- * for the session, never its conversation. `lastActiveAt` is the tool's own last update, or the Stim command's time
1884
- * when that is newer. `openUrl` opens the session in the tool's desktop app when that app is installed on this machine.
1885
- * `webUrl` opens a Claude Code session with Remote Control connected on claude.ai/code or in the Claude mobile app.
1886
- */
1887
- interface AgentSession {
1888
- tool: AgentTool;
1889
- sessionId: string;
1890
- title?: string;
1891
- cwd: string;
1892
- startedAt?: string;
1893
- lastActiveAt?: string;
1894
- pid?: number;
1895
- openUrl?: string;
1896
- webUrl?: string;
1979
+ declare function getParkedMax(platform: "ios" | "android", { config, env }?: {
1980
+ config?: Config | null;
1981
+ env?: NodeJS.ProcessEnv;
1982
+ }): ParkedMax;
1983
+ declare function getProjectSettings(projectPath: string): Record<string, unknown>;
1984
+ declare function getRepoSettings(gitCommonDir: string): Record<string, unknown>;
1985
+ declare function isPathPrefix(prefix: string, path: string): boolean;
1986
+ declare function findEnclosingWorktreeRoot(projectPath: string): string | null;
1987
+ declare function allMetroPorts(): number[];
1988
+ //#endregion
1989
+ //#region state/debug-log.d.ts
1990
+ declare const DEBUG_ENV = "STIM_DEBUG";
1991
+ declare function debugLogDir(): string;
1992
+ /** The `STIM_DEBUG` override (1/true on, 0/false off, anything else off), else the machine setting `debug.logs`. Never throws. */
1993
+ declare function debugLoggingEnabled(env?: NodeJS.ProcessEnv): boolean;
1994
+ interface DebugLog {
1995
+ /** Whether debug logging is on right now; re-read every few seconds so a long-running process follows the setting. */
1996
+ enabled(): boolean;
1997
+ /** Appends one record to `$STIM_HOME/logs/debug/<component>.ndjson` when enabled. Never throws; keys that look like secrets are redacted. */
1998
+ log(event: string, fields?: Record<string, unknown>): void;
1897
1999
  }
1898
2000
  /**
1899
- * An agent session that stopped running in an environment, with the details Stim last found while it ran. `endedAt`
1900
- * is the last time a status watcher found it running.
2001
+ * Debug-level records for one component (`cli` or `server`). Off by default; `STIM_DEBUG=1` or `debug.logs` turns it
2002
+ * on. Callers pass names, durations and codes, never arguments, environment values, tokens or tickets.
1901
2003
  */
1902
- interface EndedAgentSession extends Omit<AgentSession, "pid"> {
1903
- endedAt: string;
1904
- }
1905
- interface AndroidRuntimeFacts {
1906
- serial: string | null;
1907
- state: "detected" | "not-detected" | "missing" | "unknown";
1908
- error?: string;
1909
- }
1910
- /** Every connection state a physical device can report. */
1911
- declare const PHYSICAL_DEVICE_CONNECTIONS: readonly ["connected", "disconnected", "unknown"];
1912
- type PhysicalDeviceConnection = (typeof PHYSICAL_DEVICE_CONNECTIONS)[number];
2004
+ declare function createDebugLog(component: "cli" | "server", { env, now, base }?: {
2005
+ env?: NodeJS.ProcessEnv;
2006
+ now?: () => number;
2007
+ base?: () => Record<string, unknown>;
2008
+ }): DebugLog;
2009
+ //#endregion
2010
+ //#region state/trace.d.ts
2011
+ declare const TRACE_ENV = "STIM_TRACE";
2012
+ /**
2013
+ * `args` with the value of any flag or assignment that looks like a secret, credentials in URLs, token shapes and
2014
+ * the `exact` values replaced. `program` selects the flags that carry a credential without a secret-looking name,
2015
+ * such as `curl -u`.
2016
+ */
2017
+ declare function redactArgv(args: readonly string[], exact?: readonly string[], program?: string): string[];
2018
+ /** A shell command line with the same redactions as `redactArgv`, clipped to a fixed length. */
2019
+ declare function redactCommandLine(command: string, exact?: readonly string[]): string;
2020
+ type TraceArgs = Record<string, unknown>;
2021
+ type EndSpan = (args?: TraceArgs) => void;
2022
+ type Args = TraceArgs;
2023
+ interface TracePhases {
2024
+ /** Ends the phase in progress and starts `name`; entering the phase already in progress does nothing. */
2025
+ enter(name: string, args?: Args): void;
2026
+ end(args?: Args): void;
2027
+ }
2028
+ interface Trace {
2029
+ enabled(): boolean;
2030
+ /** Starts a span; the returned function ends it, with optional extra args. */
2031
+ begin(name: string, args?: TraceArgs): EndSpan;
2032
+ /** `begin` for the outermost span of a process: it ends at exit with the exit code. */
2033
+ command(name: string, args?: TraceArgs): void;
2034
+ /** `begin` for a child process: same event with the `exec` category. */
2035
+ beginExec(name: string, args?: TraceArgs): EndSpan;
2036
+ /** Runs `fn` inside a span and ends it when `fn` returns or throws. */
2037
+ span<T>(name: string, fn: () => T, args?: TraceArgs): T;
2038
+ /** `span` for an async `fn`: ends when its promise settles. */
2039
+ spanAsync<T>(name: string, fn: () => Promise<T>, args?: TraceArgs): Promise<T>;
2040
+ mark(name: string, args?: TraceArgs): void;
2041
+ /** A strip of consecutive, non-overlapping phases on its own track. */
2042
+ phases(track: string): TracePhases;
2043
+ }
2044
+ /**
2045
+ * Timing spans for one stim process tree, written as Chrome trace events (open the file in Perfetto or
2046
+ * chrome://tracing) when `STIM_TRACE=<path>` is set. Unset, every call is one environment check. A stim command
2047
+ * (`trace.command`) truncates the file and writes `[`; every other process that inherits the variable appends one
2048
+ * event per line, creating the file if it is missing, so the file has no closing bracket. Child process arguments are written through `redactArgv`.
2049
+ */
2050
+ declare const trace: Trace;
2051
+ //#endregion
2052
+ //#region state/home-identity.d.ts
2053
+ /** The persistent, nonsecret identity of this Stim home; null until the CLI initializes it. */
2054
+ declare function readHomeIdentity(config?: Config | null): string | null;
2055
+ //#endregion
2056
+ //#region state/json-file.d.ts
1913
2057
  /**
1914
- * A physical iPhone, iPad or Android phone the workspace holds an unexpired lease on, from `ios --device`,
1915
- * `android --device` or `device lock`. Stim uses it and never owns it, so `owned` is always false. `id` is the
1916
- * UDID or adb serial. `name` is the device's own name, falling back to the name the lease recorded; `model` is the
1917
- * marketing name devicectl reports, null when it could not be read, or the Android model the lease recorded.
1918
- * `connection` is `connected` when devicectl can reach the phone or adb lists it as `device`, `disconnected` when
1919
- * the tool answered without it, and `unknown` when the tool could not be read in time. `lease.holder` is the
1920
- * workspace path that holds it.
2058
+ * Runs `fn` with each state file read from disk at most once: inside it, including after an `await`, `readStateFile`
2059
+ * 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
2060
+ * share a mutable object. Only for computations that write none of the files they read.
1921
2061
  */
1922
- interface PhysicalDeviceState {
1923
- platform: StatsPlatform;
1924
- slot: string;
1925
- id: string;
1926
- name: string | null;
1927
- model: string | null;
1928
- owned: false;
1929
- physical: true;
1930
- connection: PhysicalDeviceConnection;
1931
- lease: {
1932
- holder: string;
1933
- kind: "declared" | "run";
1934
- grantedAt: string | null;
1935
- expiresAt: string;
1936
- };
2062
+ declare function withStateReadCache<T>(fn: () => T): T;
2063
+ declare function readStateFile(path: string): string;
2064
+ declare function readJsonFile(path: string): unknown;
2065
+ declare function isJsonObject(value: unknown): value is Record<string, unknown>;
2066
+ declare function readJsonObject(path: string): Record<string, unknown> | null;
2067
+ //#endregion
2068
+ //#region state/ledgers.d.ts
2069
+ type CreatedDevicePlatform = "ios" | "android" | "web";
2070
+ /** `web` lists the absolute paths of browser profile directories Stim created. */
2071
+ interface CreatedDevices {
2072
+ ios: ReadonlySet<string>;
2073
+ android: ReadonlySet<string>;
2074
+ web: ReadonlySet<string>;
1937
2075
  }
1938
- interface RemoteDeviceState {
1939
- platform: "ios" | "android" | null;
1940
- backend: "eas";
2076
+ declare function readCreatedDevices(): CreatedDevices;
2077
+ interface EasSessionClaim {
1941
2078
  sessionId: string;
1942
- state: "claimed" | "unclaimed" | "unknown";
1943
- startedAt: string | null;
1944
- webPreviewUrl: string | null;
2079
+ name: string;
2080
+ platform: "ios" | "android";
2081
+ workspaceRoot: string;
2082
+ workspaceHome: string;
2083
+ stateFile: string;
1945
2084
  }
1946
- /**
1947
- * One part of a worktree's git chip, in display order: commits ahead of and behind the upstream, uncommitted files
1948
- * (changed plus untracked), the base branch the branch is merged into (left out when its pull request is merged,
1949
- * whose own mark says so), and a branch with no upstream that is not merged.
1950
- */
1951
- type GitChipPart = {
1952
- kind: "arrows";
1953
- ahead: number;
1954
- behind: number;
1955
- } | {
1956
- kind: "changed";
1957
- count: number;
1958
- } | {
1959
- kind: "merged";
1960
- into: string;
1961
- } | {
1962
- kind: "no-upstream";
1963
- };
1964
- /** A pull request's checks at a glance: any failing, else any pending, else any passing; null without checks. */
1965
- type ChecksState = "passing" | "failing" | "pending" | null;
1966
- interface GitChip {
1967
- parts: GitChipPart[];
1968
- ci: ChecksState;
2085
+ interface EasSessionLedgerRead {
2086
+ claims: Map<string, EasSessionClaim>;
2087
+ notice: string | null;
2088
+ safe: boolean;
1969
2089
  }
2090
+ /** Returns the claim normalized to canonical paths, or null when it is not a valid claim for `id`. */
2091
+ declare function validEasSessionClaim(id: string, value: unknown): EasSessionClaim | null;
2092
+ declare function readEasSessionLedger(root?: string): EasSessionLedgerRead;
2093
+ //#endregion
2094
+ //#region state/error-entries.d.ts
1970
2095
  /**
1971
- * Whether a running owned simulator or emulator lacks the workspace's app: `none` when its platform never built
1972
- * successfully here and the latest build failed, `closed` when status saw no app process, else null.
1973
- */
1974
- type AppPresence = "none" | "closed" | null;
1975
- declare const WORKSPACE_STAGE_KINDS: readonly ["building", "warming", "ready", "build-failed", "running", "stopped"];
1976
- /**
1977
- * Where a workspace is, first match wins: `building` while a build runs, `warming` and `ready` from `phase` when
1978
- * nothing is live, `build-failed` when the newest run of either platform failed, `running` when it is live, its
1979
- * macOS app is running or orphaned, or it holds a remote device, else `stopped`. `since` is when that began: the
1980
- * build's start, the warm phase's time, the failed run's end (else start), the supervisor's start (else the running
1981
- * macOS app's build end, else its start), or Metro's last stop. `platform` names the build for `building`
1982
- * and `build-failed`. `closedApps` lists, for `running`, the devices whose `appPresence` is `closed`.
2096
+ * The number of rows a log list shows for `records`, an error query's result in log order. Stim Desktop's
2097
+ * `LogEntryList` and the phone's `groupRecords` group the same way and replay the same vectors: in Expo's dev
2098
+ * server one failed bundle is a `Bundling failed` marker line, the error line and a failed bundle response,
2099
+ * which the apps list as one row, and every other record is its own row.
1983
2100
  */
1984
- interface WorkspaceStage {
1985
- kind: (typeof WORKSPACE_STAGE_KINDS)[number];
1986
- since: string | null;
1987
- platform: StatsPlatform | "macos" | null;
1988
- closedApps: {
1989
- platform: StatsPlatform;
1990
- slot: string;
1991
- }[];
2101
+ declare function countErrorEntries(records: readonly NdjsonRecord[]): number;
2102
+ //#endregion
2103
+ //#region state/fingerprint-memo.d.ts
2104
+ declare const FINGERPRINT_MEMO_SCHEMA = 1;
2105
+ /** Full native fingerprints shared by every workspace of this Stim home, one file per platform and static digest. */
2106
+ declare function fingerprintMemoDir(platform?: string): string;
2107
+ declare function fingerprintMemoFile(platform: string, digest: string): string;
2108
+ declare function fingerprintMemoLock(): string;
2109
+ /** The full fingerprint a tree with this static digest produced, written by the CLI. */
2110
+ interface FingerprintMemoRecord {
2111
+ schema: typeof FINGERPRINT_MEMO_SCHEMA;
2112
+ platform: string;
2113
+ digest: string;
2114
+ recordedAt: number;
2115
+ hash: string;
2116
+ sources: unknown[];
2117
+ /** The packages the static check counted as native, to name the ones a disagreeing check found it missed. */
2118
+ nativePackages: string[];
1992
2119
  }
1993
- /** Every code a status issue can carry. */
1994
- declare const STATUS_ISSUE_CODES: readonly ["port-not-ours", "sim-missing", "sim-without-metro", "avd-serial-changed", "avd-missing", "avd-not-detected", "avd-unchecked", "android-reverse-missing", "supervisor-unverified", "browser-unverified", "browser-orphaned"];
1995
- type StatusIssueCode = (typeof STATUS_ISSUE_CODES)[number];
1996
- /**
1997
- * One thing in a workspace that needs the user, or with severity `info` a note that needs nothing. `remedy` is a
1998
- * command to run from `workspace`; `slot` is absent for the default device slot. `warnings` carries the `error` and
1999
- * `warning` issues as text.
2000
- *
2001
- * Severity:
2002
- * - `error`: Stim cannot verify or safely act on something; a person resolves it, following the teardown guide.
2003
- * - `warning`: something is broken now and needs someone to act, such as an app that cannot reach Metro, a held
2004
- * port or a device that vanished while expected.
2005
- * - `info`: a fact the next normal Stim command handles by itself, so it needs no action.
2006
- *
2007
- * The phone app and Stim Desktop show `error` and `warning` and hide `info`; plain `stim status` prints `info` as a
2008
- * dim note with no remedy.
2009
- */
2010
- interface StatusIssue {
2011
- code: StatusIssueCode;
2012
- severity: "error" | "warning" | "info";
2013
- message: string;
2014
- remedy: string;
2015
- workspace: string;
2016
- slot?: string;
2120
+ declare function readFingerprintMemo(platform: string, digest: string): FingerprintMemoRecord | null;
2121
+ //#endregion
2122
+ //#region state/logs-query.d.ts
2123
+ interface SinceResult {
2124
+ ms?: number;
2125
+ error?: string;
2017
2126
  }
2018
- /** Every state the owned page's latest load can report. */
2019
- declare const WEB_PAGE_STATES: readonly ["loading", "loaded", "failed"];
2020
- /**
2021
- * The owned page's latest load, from the page-load marker in the workspace's web log: `url` is the document it
2022
- * loaded, `state` is `failed` when that document did not load or the page crashed, with the log message as
2023
- * `error`. `route`, present only when an in-app route change (history API or fragment) moved the page off `url`
2024
- * since the load, is the URL it shows now.
2025
- */
2026
- interface WebPageState {
2027
- url: string;
2028
- state: (typeof WEB_PAGE_STATES)[number];
2127
+ interface GrepResult {
2128
+ re?: RegExp;
2029
2129
  error?: string;
2030
- route?: string;
2031
2130
  }
2032
- /**
2033
- * The workspace's Stim-owned Chrome. `pid` is Chrome's process and `supervisorPid` the Stim process that holds
2034
- * its DevTools session. `cdpEndpoint` is the loopback DevTools HTTP endpoint agents can attach to, and `targetId`
2035
- * the DevTools target of the owned page; both are null when the browser is not running. `profile` is the
2036
- * Stim-owned user data directory. `page` is null before the page's first load. `activity` names DevTools clients
2037
- * other than Stim's as drivers.
2038
- */
2039
- interface WebBrowserState {
2040
- browser: "chrome";
2041
- version: string | null;
2042
- running: boolean;
2043
- pid: number | null;
2044
- supervisorPid: number | null;
2045
- url: string;
2046
- headless: boolean;
2047
- viewport: WebViewport;
2048
- profile: string;
2049
- cdpEndpoint: string | null;
2050
- targetId: string | null;
2051
- page?: WebPageState | null;
2052
- activity?: DeviceActivity;
2131
+ interface MarkerWindow {
2132
+ launchTs: number | null;
2133
+ bundleTs: number | null;
2134
+ pageLoadTs: number | null;
2053
2135
  }
2054
- /** The steps of `stim worktree warm`: `refresh` fast-forwards and installs in the source checkout, `copy` carries ignored entries. */
2055
- type WarmStep = "refresh" | "copy";
2056
- /**
2057
- * Where a workspace is in its lifecycle: `warming` while `stim worktree warm` runs in it, `ready` after a warm
2058
- * succeeded and before any `start`, `ios`, `android`, `web` or `reload` there, for at most two hours; `live` when
2059
- * anything it owns runs, else `idle`.
2060
- */
2061
- declare const WORKSPACE_PHASES: readonly ["warming", "ready", "live", "idle"];
2062
- type WorkspacePhase = (typeof WORKSPACE_PHASES)[number];
2063
- /** A folder's size on disk as `status --watch` last measured it. */
2064
- interface DiskMeasure {
2065
- bytes: number;
2066
- measuredAt: string;
2136
+ interface QueryCriteria {
2137
+ slot?: string;
2138
+ includeAppDeviceErrors?: boolean;
2139
+ sources?: string[];
2140
+ minLevel?: string;
2141
+ grep?: RegExp;
2142
+ sinceTs?: number;
2143
+ errorsOnly?: boolean;
2144
+ markerTs?: number;
2145
+ bundleMarkerTs?: number;
2146
+ }
2147
+ interface TailState {
2148
+ offset: number;
2149
+ partial: string;
2067
2150
  }
2151
+ declare function parseSince(text: unknown): SinceResult;
2152
+ declare function compileGrep(pattern: unknown): GrepResult;
2153
+ declare const ERROR_SOURCES: string[];
2154
+ declare function markerWindow(records: NdjsonRecord[]): MarkerWindow;
2068
2155
  /**
2069
- * An environment's disk use as `status --watch` last measured it. `worktreeBytes` is the git worktree folder, or the
2070
- * workspace folder outside one, node_modules included. `nodeModulesBytes` is node_modules at the worktree root and,
2071
- * when different, at the workspace path, and is part of `worktreeBytes`. `buildBytes` is Stim's own folder for the
2072
- * workspace: Xcode derived data, Gradle outputs and logs. A figure is null until it was measured; `measuredAt` is the
2073
- * oldest measurement.
2156
+ * The platform a bundle marker speaks for, lowercased: its `platform` field, or the tag @expo/cli prints before
2157
+ * "Bundled" ("iOS", "Android", "Web", "RSC(iOS)" as ios, or an environment tag such as "DOM"). Null when unknown.
2074
2158
  */
2075
- interface EnvironmentDisk {
2076
- worktreeBytes: number | null;
2077
- nodeModulesBytes: number | null;
2078
- buildBytes: number | null;
2079
- measuredAt: string;
2080
- }
2159
+ declare function bundleMarkerPlatform(record: NdjsonRecord): string | null;
2160
+ declare function recordMatches(record: NdjsonRecord | null | undefined, criteria?: QueryCriteria): boolean;
2161
+ declare function buildCriteria({ slot, sources, minLevel, since, grep, errorsOnly, markerTs, bundleMarkerTs, now }?: {
2162
+ slot?: string;
2163
+ sources?: string[];
2164
+ minLevel?: string;
2165
+ since?: string | null;
2166
+ grep?: string | RegExp | null;
2167
+ errorsOnly?: boolean;
2168
+ markerTs?: number;
2169
+ bundleMarkerTs?: number;
2170
+ now?: number;
2171
+ }): QueryCriteria;
2172
+ declare function logFiles(dir: string): string[];
2173
+ declare function fileSizes(dir: string): Record<string, number>;
2174
+ declare function readLogRecords(dir: string, include?: (name: string) => boolean): NdjsonRecord[];
2175
+ declare const NATIVE_CRASH_LOG_PREFIX = "native-crash-";
2176
+ /** Reads the CLI timeline with retained native crash records after other records at the same timestamp. */
2177
+ declare function readLogTimeline(dir: string, records?: NdjsonRecord[]): NdjsonRecord[];
2178
+ declare function isExpoErrorContext(record: NdjsonRecord, event: unknown): boolean;
2179
+ type ExpoContextTarget = "msg" | "field";
2081
2180
  /**
2082
- * A Metro bundle request: `bundling` while one is in flight on the workspace's Metro, with its `platform`,
2083
- * `startedAt` and, when Metro reported progress for it, `percent` (0-100). `last` is the newest finished request,
2084
- * `durationMs` from request to response end.
2181
+ * Adds the code frame and stack lines Expo printed after each Expo error record, either joined into
2182
+ * `msg` or as a `context` string array.
2085
2183
  */
2086
- interface MetroBundleState {
2087
- bundling: boolean;
2088
- platform?: StatsPlatform;
2089
- startedAt?: string;
2090
- percent?: number;
2091
- last?: {
2092
- platform: StatsPlatform;
2093
- status: "ok" | "failed";
2094
- durationMs: number;
2095
- finishedAt: string;
2096
- };
2097
- }
2098
- interface SimulatorState {
2099
- devicePlacement?: DevicePlacement;
2100
- host?: HostedIosStatus;
2101
- name: string | null;
2102
- udid: string;
2103
- owned: boolean;
2104
- state: string;
2105
- activity?: DeviceActivity;
2106
- app?: DeviceAppProcess;
2107
- appPresence?: AppPresence;
2108
- /** The simulator's data folder, for an owned simulator once measured. */
2109
- disk?: DiskMeasure;
2110
- /** Present while the device is not booted after idle shutdown or queue reclaim. */
2111
- idleShutdown?: DeviceIdleShutdownRecord;
2112
- }
2113
- interface AndroidDeviceState {
2114
- devicePlacement?: DevicePlacement;
2115
- host?: HostedAndroidStatus;
2116
- name: string | undefined;
2117
- owned: boolean;
2118
- physical: boolean;
2119
- serial?: string | null;
2120
- state?: AndroidRuntimeFacts["state"] | "ready" | "stopped" | "unverified";
2121
- deviceProfile?: string | null;
2122
- activity?: DeviceActivity;
2123
- app?: DeviceAppProcess;
2124
- appPresence?: AppPresence;
2125
- /** The AVD's folder, for an owned emulator once measured. */
2126
- disk?: DiskMeasure;
2127
- /** Present while the emulator is not running after idle shutdown or queue reclaim. */
2128
- idleShutdown?: DeviceIdleShutdownRecord;
2184
+ declare function attachExpoErrorContext(all: NdjsonRecord[], matched: NdjsonRecord[], into?: ExpoContextTarget): NdjsonRecord[];
2185
+ interface LogQueryOptions {
2186
+ slot?: string;
2187
+ sources?: string[];
2188
+ minLevel?: string;
2189
+ since?: string;
2190
+ grep?: string | RegExp;
2191
+ errorsOnly?: boolean;
2192
+ now?: number;
2129
2193
  }
2130
- /** The tutorial format version the installed Stim writes into the tutorial app. */
2131
- declare const TUTORIAL_VERSION = 2;
2132
- interface EnvironmentState {
2133
- slots?: {
2134
- slot: string;
2135
- ios: SimulatorState | null | undefined;
2136
- android: AndroidDeviceState | null | undefined;
2137
- }[];
2138
- path: string;
2139
- /** The 16-hex identity of the registered canonical project path, used by shared workspace links. */
2140
- workspaceId?: string;
2141
- /** Statically detected app platforms; always set by status, empty when none are detected. */
2142
- platforms?: string[];
2143
- /** Present when the app's app.json sets expo.extra.stimTutorial to a positive integer: that version. */
2144
- tutorial?: {
2145
- version: number;
2146
- };
2147
- /** When `stim doctor` last ran in this workspace, per platform; absent until it has run. */
2148
- doctorRuns?: Partial<Record<"ios" | "android", {
2149
- at: string;
2150
- }>>;
2151
- live: boolean;
2152
- phase?: WorkspacePhase;
2153
- /** When the warm started (`warming`) or finished (`ready`); null for `live` and `idle`. */
2154
- phaseSince?: string | null;
2155
- /** Whether stim-server may record this workspace's device screens, from `recording.enabled`. */
2156
- recording?: {
2157
- enabled: boolean;
2158
- };
2159
- /** Present when `workspace.hidden` is true: clients list the workspace under Hidden. */
2160
- hidden?: true;
2161
- /** Where the workspace is, from `workspaceStage`; `stim status --json` always sets it. */
2162
- stage?: WorkspaceStage;
2163
- /** The step a `warming` workspace's warm is in; absent in every other phase. */
2164
- warmStep?: WarmStep;
2194
+ interface LogQueryPlan {
2195
+ /** Whether a record belongs to the queried slot's timeline, before any other filter. */
2196
+ inTimeline: (record: NdjsonRecord) => boolean;
2197
+ matches: (record: NdjsonRecord) => boolean;
2198
+ launchTs: number | null;
2199
+ sinceTs: number | undefined;
2165
2200
  /**
2166
- * The memory this workspace's processes use, as `memorySource` says: the sum of its `machine` owners' `memoryMb`
2167
- * when status read their footprints, or else a fixed estimate per booted simulator, detected emulator, running
2168
- * Metro and running Chrome. `capacity.committedMb` sums it.
2201
+ * Whether no record with a timestamp at most `maxTs`, or without one when `maxTs` is Infinity, can match.
2202
+ * `slots` lists every `slot ?? 'default'` value the records can carry; without it, a query that depends on
2203
+ * per-slot launch markers cannot rule out any timestamp.
2169
2204
  */
2170
- memoryMb: number;
2171
- /** How `memoryMb` was obtained; absent from payloads written before it existed, which carry the estimate. */
2172
- memorySource?: Exclude<MemorySource, "rss">;
2173
- warnings: string[];
2174
- issues: StatusIssue[];
2175
- ios?: SimulatorState | null;
2176
- android?: AndroidDeviceState | null;
2177
- metro?: {
2178
- port: number;
2179
- running: boolean;
2180
- pid: number | null;
2181
- tunnel?: {
2182
- provider: Exclude<TunnelMode, "auto" | "off" | "expo">;
2183
- url: string;
2184
- };
2185
- idleStop?: IdleStopRecord;
2186
- lastStop?: MetroLastStop;
2187
- /** The other process that answers Metro on `port`; `cwd` is null when its directory could not be read. */
2188
- heldBy?: {
2189
- pid: number;
2190
- cwd: string | null;
2191
- };
2192
- /** Absent when the Metro log holds no bundle request. */
2193
- bundle?: MetroBundleState;
2194
- } | null;
2195
- web?: WebBrowserState | null;
2196
- macos?: MacosAppState | null;
2197
- supervisor?: {
2198
- pid: number | null;
2199
- mode: string | null;
2200
- startedAt: string | null;
2201
- healthy: boolean;
2202
- } | null;
2203
- logs?: {
2204
- dir: string;
2205
- errorsSinceMarker: number;
2206
- } | null;
2207
- /** `installed` is whether the agent-device executable is on the PATH of the process that ran status. */
2208
- agentDevice?: {
2209
- stateDir: string;
2210
- installed?: boolean;
2211
- };
2212
- worktree?: WorktreeFacts | null;
2213
- remoteDevices?: RemoteDeviceState[];
2214
- /** The physical devices this workspace leases, in every slot; absent when it leases none. */
2215
- physicalDevices?: PhysicalDeviceState[];
2216
- build?: BuildReport | null;
2217
- lastBuilds?: Partial<Record<StatsPlatform, LastBuildReport>>;
2218
- /** Each platform's recent runs, newest first, at most `BUILD_HISTORY_LIMIT` each. */
2219
- builds?: Partial<Record<BuildPlatform, BuildHistoryEntry[]>>;
2220
- disk?: EnvironmentDisk;
2221
- /** The coding-agent sessions working in the environment, most recently active first; absent when none. */
2222
- agents?: AgentSession[];
2223
- /** The agent sessions that stopped running here in the last 3 days, most recently ended first; absent when none. */
2224
- endedAgents?: EndedAgentSession[];
2225
- }
2226
- /** `committedMb` sums the environments' `memoryMb`; `overCapacity` is that sum over 60% of `totalMemoryMb`. */
2227
- interface StatusCapacity {
2228
- liveCount: number;
2229
- committedMb: number;
2230
- totalMemoryMb: number;
2231
- overCapacity: boolean;
2205
+ excludesUpTo: (maxTs: number, slots?: ReadonlySet<unknown>) => boolean;
2232
2206
  }
2233
- interface DeviceLeaseState {
2234
- slot?: string;
2235
- path: string;
2236
- platform: string;
2237
- id: string | null;
2238
- deviceName: string | null;
2239
- holder: string | null;
2240
- grantedAt: string | null;
2241
- expiresAt: string | null;
2242
- mine: boolean;
2243
- expired: boolean;
2244
- parsed: boolean;
2207
+ /** Decides which records a query matches from the timeline's marker records alone. */
2208
+ declare function planLogQuery(markers: readonly NdjsonRecord[], { slot, sources, minLevel, since, grep, errorsOnly, now }?: LogQueryOptions): LogQueryPlan;
2209
+ declare function queryLogs({ slot, dir, records, sources, minLevel, since, grep, tail, errorsOnly, errorContext, now }?: LogQueryOptions & {
2210
+ dir?: string;
2211
+ records?: NdjsonRecord[];
2212
+ tail?: number;
2213
+ errorContext?: boolean;
2214
+ }): NdjsonRecord[];
2215
+ /** Queries the JSON timeline, including Expo context fields on errors as `stim logs --json` does. */
2216
+ declare function queryJsonLogs(options?: Parameters<typeof queryLogs>[0]): NdjsonRecord[];
2217
+ declare function tailRead(prev: TailState | null | undefined, size: number): {
2218
+ start: number;
2219
+ prev: TailState;
2220
+ };
2221
+ declare function advanceTail(prev: TailState | null | undefined, chunk: string | null | undefined, size: number): {
2222
+ state: TailState;
2223
+ records: NdjsonRecord[];
2224
+ };
2225
+ declare function followLogs({ dir, onRecord, criteria, intervalMs, offsets, identities: seededIdentities, errorContext }: {
2226
+ dir: string;
2227
+ onRecord: (record: NdjsonRecord) => void;
2228
+ criteria?: QueryCriteria;
2229
+ /** An explicit polling interval. Omit for filesystem hints with a ten-second repair scan. */
2230
+ intervalMs?: number;
2231
+ offsets?: Record<string, number> | null;
2232
+ /** `fileIdentity` of each file `offsets` was read from, so a replacement made since is recognized. */
2233
+ identities?: Record<string, string> | null;
2234
+ /** Holds each Expo error until its code frame and stack stop growing, then attaches them. */
2235
+ errorContext?: ExpoContextTarget;
2236
+ }): () => void;
2237
+ declare function fileIdentity(stat: BigIntStats): string | undefined;
2238
+ declare function sortByTs(records: NdjsonRecord[]): NdjsonRecord[];
2239
+ //#endregion
2240
+ //#region state/log-reader.d.ts
2241
+ interface LogDirQuery extends LogQueryOptions {
2242
+ tail?: number;
2243
+ /** Records from outside the directory, such as agent-device actions; they follow its records at equal timestamps. */
2244
+ extra?: readonly NdjsonRecord[];
2245
2245
  }
2246
2246
  /**
2247
- * Where a memory figure comes from. `footprint` is each process's physical footprint, which Activity Monitor's Memory
2248
- * column shows. `rss` sums resident set sizes, which count pages shared between processes once per process, so a
2249
- * simulator reports well above its footprint; the machine owners fall back to it when the footprint helper cannot be
2250
- * built. `estimate` is a fixed amount per running thing, which an environment reports whenever it has no footprint.
2247
+ * An indexed view of a workspace log directory, read in timestamp order without loading whole files. Each file
2248
+ * generation is indexed once per process (block timestamp bounds, markers, slots and launch attempts) and later
2249
+ * views read only what was appended since. Close it to release the open files.
2251
2250
  */
2252
- declare const MEMORY_SOURCES: readonly ["footprint", "rss", "estimate"];
2253
- type MemorySource = (typeof MEMORY_SOURCES)[number];
2254
- /** Every kind of process owner the status machine section reports. */
2255
- declare const MACHINE_OWNER_KINDS: readonly ["simulator", "emulator", "metro", "build", "browser", "macos", "server", "shared"];
2256
- type MachineOwnerKind = (typeof MACHINE_OWNER_KINDS)[number];
2251
+ interface LogDir {
2252
+ /** Bytes read from each current `.ndjson` file, through its last complete line. */
2253
+ readonly sizes: Record<string, number>;
2254
+ /** `fileIdentity` of each current `.ndjson` file that `sizes` was read from. */
2255
+ readonly identities: Record<string, string>;
2256
+ /** The oldest timestamp in the directory. */
2257
+ readonly firstTs: number | undefined;
2258
+ /** Launch attempt records outside native crash files, in timeline order. */
2259
+ launchAttempts(): NdjsonRecord[];
2260
+ /** The records `queryJsonLogs` returns for this directory's timeline followed by `extra`. */
2261
+ query(query?: LogDirQuery): Promise<NdjsonRecord[]>;
2262
+ /** Every matching record in timestamp order, in batches of at most 500, with the same filters and context as query. */
2263
+ batches(query?: Omit<LogDirQuery, "tail">): AsyncIterable<NdjsonRecord[]>;
2264
+ /** Prepares the directory marker predicate for records without markers, such as attributed agent actions. */
2265
+ filter(query?: LogQueryOptions): (record: NdjsonRecord) => boolean;
2266
+ close(): Promise<void>;
2267
+ }
2257
2268
  /**
2258
- * One thing using this machine's CPU and memory now. Each process is counted in exactly one owner: the one whose root
2259
- * process is its nearest ancestor. `workspace` and `slot` (absent for the default slot) name the workspace a
2260
- * simulator, emulator, Metro, build or Chrome belongs to; a device no workspace records has a null workspace, and
2261
- * machine-wide processes are `shared`. `id` is the simulator's UDID, the emulator's AVD name, Metro's port as text,
2262
- * the build's platform, or null. `owned` is true only for what Stim started and stops: a workspace's owned device,
2263
- * Metro, build or Chrome. `cpuPercent` is `ps` %CPU summed over the owner's processes, where 100 is one core.
2264
- * `residentMb` sums their resident set sizes; pages shared between processes count once per process, so a
2265
- * simulator, whose processes all map the runtime's shared libraries, reports well above its physical footprint.
2266
- * `memoryMb` sums their physical footprints when `MachineUsageState.memorySource` is `footprint`, taking the resident
2267
- * size of a process the footprint helper could not read, and equals `residentMb` when it is `rss`.
2269
+ * Opens `dir` for reading. With `order: 'timeline'`, native crash files follow every other file at equal
2270
+ * timestamps, as `readLogTimeline` orders them; with `'name'`, every file is ranked by name, as `readLogRecords`.
2268
2271
  */
2269
- interface MachineOwner {
2270
- kind: MachineOwnerKind;
2271
- name: string;
2272
- workspace: string | null;
2273
- slot?: string;
2274
- id: string | null;
2275
- owned: boolean;
2276
- cpuPercent: number;
2277
- residentMb: number;
2278
- memoryMb: number;
2279
- processes: number;
2280
- }
2281
- /** Where this machine's CPU and memory go, from one pass over the host process table. */
2282
- interface MachineUsageState {
2283
- memorySource: Exclude<MemorySource, "estimate">;
2284
- owners: MachineOwner[];
2272
+ declare function openLogDir(dir: string, { order, signal }?: {
2273
+ order?: "timeline" | "name";
2274
+ signal?: AbortSignal;
2275
+ }): Promise<LogDir>;
2276
+ //#endregion
2277
+ //#region state/ndjson-tail.d.ts
2278
+ /**
2279
+ * Returns a reader of `file` and its rotated generation that yields, on every call, the records a full
2280
+ * `readNdjsonGenerations(file)` would, while reading only the bytes appended since the previous call. A file renamed
2281
+ * to its rotated generation between two calls is finished from there; any other replacement or a shrunk file is
2282
+ * read again from its start. A file rewritten in place to at least its previous length is not detected.
2283
+ */
2284
+ declare function createNdjsonTail(file: string): () => NdjsonRecord[];
2285
+ //#endregion
2286
+ //#region state/paths.d.ts
2287
+ declare function getConfigPath(): string;
2288
+ declare function configLockPath(): string;
2289
+ declare function workspaceMetadataFile(projectRoot: string): string;
2290
+ declare function workspaceAgentDeviceDir(projectRoot: string): string;
2291
+ declare function workspaceLogsDir(projectRoot: string): string;
2292
+ /** Device screen footage stim-server records for the workspace, one directory per platform and slot. */
2293
+ declare function workspaceRecordingsDir(projectRoot: string): string;
2294
+ declare function workspaceLogErrorIndex(projectRoot: string): string;
2295
+ declare function workspaceDerivedData(projectRoot: string): string;
2296
+ declare function workspaceGradleBuild(projectRoot: string): string;
2297
+ declare function workspaceBuildDetailFile(projectRoot: string): string;
2298
+ /** The agent sessions that stopped running in the workspace in the last `ENDED_AGENT_RETENTION_MS`. */
2299
+ declare function workspaceEndedAgentsFile(projectRoot: string): string;
2300
+ declare function workspaceEndedAgentsLock(projectRoot: string): string;
2301
+ declare function supervisorPidFile(projectRoot: string): string;
2302
+ declare function workspaceStateFile(projectRoot: string): string;
2303
+ /** The dependency directories `gc --delete` deleted from the workspace's worktree, apart from state.json so writing it is not workspace activity. */
2304
+ declare function workspaceLightenedFile(projectRoot: string): string;
2305
+ declare function workspaceStateLock(projectRoot: string): string;
2306
+ declare function supervisorLogFile(projectRoot: string): string;
2307
+ declare function emulatorLogFile(projectRoot: string): string;
2308
+ declare function sharedCompilationCache(): string;
2309
+ declare function sharedCcache(): string;
2310
+ declare function sharedGradle(): string;
2311
+ declare function sharedPods(): string;
2312
+ declare function createdDevicesFile(): string;
2313
+ declare function gitMergeCacheDir(): string;
2314
+ declare function pullRequestCacheDir(): string;
2315
+ declare function agentSessionsCacheFile(): string;
2316
+ declare function diskUsageCacheDir(): string;
2317
+ /** The ownership claim root that admits one disk-usage walk at a time on this machine. */
2318
+ declare function diskUsageWalkClaims(): string;
2319
+ /** The remote machines this machine asked for build access, each with its pinned stim-server key once approved. */
2320
+ declare function buildMachinesFile(): string;
2321
+ declare function buildMachinesLock(): string;
2322
+ /** The remote machines this machine asked for access, separate from build credentials. */
2323
+ declare function deviceHostMachinesFile(): string;
2324
+ declare function deviceHostMachinesLock(): string;
2325
+ declare function deviceHostMachinesClaims(): string;
2326
+ declare function createdDevicesLock(): string;
2327
+ /** The EAS session ledger lives under the real home directory, never under STIM_HOME. */
2328
+ declare function easMachineStateRoot(): string;
2329
+ declare function easSessionLedgerFile(root?: string): string;
2330
+ declare function easSessionLedgerLock(root?: string): string;
2331
+ /** Where stim-server records, one file per server process, the devices whose frames a client subscribes to. */
2332
+ declare function deviceViewersDir(): string;
2333
+ declare function budgetSweepFile(): string;
2334
+ declare function budgetSweepLock(): string;
2335
+ declare function statsFile(): string;
2336
+ declare function maintenanceDir(): string;
2337
+ declare function maintenanceStateFile(): string;
2338
+ declare function maintenanceAttemptFile(): string;
2339
+ declare function maintenanceNdjsonFile(): string;
2340
+ declare function gcLogDir(): string;
2341
+ declare function gcLogFile(): string;
2342
+ declare function buildLedgerDir(): string;
2343
+ declare function buildLedgerFile(): string;
2344
+ declare function buildLedgerLock(): string;
2345
+ declare function maintenanceChildLogFile(): string;
2346
+ declare function maintenanceRunClaims(): string;
2347
+ /** Dependency trees `worktree remove` moved out of a worktree before git removed it; gc deletes what is left. */
2348
+ declare function trashRoot(): string;
2349
+ declare function archiveRoot(): string;
2350
+ declare function archiveDir(id: string): string;
2351
+ declare function archiveLock(): string;
2352
+ /** Uncommitted changes of removed worktrees: `<repository>/<branch-or-dir>-<timestamp>/` holding `manifest.json`. */
2353
+ declare function worktreeArchiveRoot(): string;
2354
+ /** This machine's own long-term X25519 key as a client of other machines' stim-servers. */
2355
+ declare function clientIdentityKeyFile(): string;
2356
+ /**
2357
+ * The local Unix socket. sun_path permits 103 UTF-8 bytes on macOS and 107 on Linux. Longer paths use
2358
+ * /tmp/stim-sockets-<uid>/<SHA-256 of the normalized absolute socket path>.sock.
2359
+ */
2360
+ declare function serverLocalSocket(): string;
2361
+ declare function serverSetupDir(): string;
2362
+ declare function setupJournalFile(hash: string): string | null;
2363
+ //#endregion
2364
+ //#region state/placement.d.ts
2365
+ /**
2366
+ * The placement words every workload shares (`remote.build`, `ios.remote`, `android.remote`, `macos.remote` and their
2367
+ * flags). Anything else a setting holds is a machine name, or for devices `eas` or `proxy`.
2368
+ *
2369
+ * - `local`: this machine only.
2370
+ * - `auto`: this machine first, a remote machine when this one is full or busy.
2371
+ * - `remote`: remote machines first, in `remote.machines` order; this machine only when none takes the run.
2372
+ * - `remote-only`: remote machines in `remote.machines` order, never this machine.
2373
+ */
2374
+ declare const PLACEMENT_WORDS: readonly ["local", "auto", "remote", "remote-only"];
2375
+ type PlacementWord = (typeof PLACEMENT_WORDS)[number];
2376
+ type AutomaticPlacement = Exclude<PlacementWord, "local">;
2377
+ declare function placementWord(value: string): PlacementWord | null;
2378
+ declare function prefersRemote(word: PlacementWord): boolean;
2379
+ declare function mayRunHere(word: PlacementWord): boolean;
2380
+ //#endregion
2381
+ //#region state/recordings.d.ts
2382
+ /** The footage stim-server keeps per device: the last 15 minutes recorded, however long ago. */
2383
+ declare const RECORDING_FOOTAGE_MS: number;
2384
+ /** The recordings of every workspace of one Stim home together; past it the oldest footage goes first. */
2385
+ declare const RECORDING_CAP_BYTES: number;
2386
+ /** The platforms stim-server records: owned simulators and emulators, and the Stim-owned Chrome page. */
2387
+ declare const RECORDING_PLATFORMS: readonly ["ios", "android", "web"];
2388
+ type RecordingPlatform = (typeof RECORDING_PLATFORMS)[number];
2389
+ /**
2390
+ * One file of H.264 footage. A closed segment is named `<start>-<end>.seg`, in epoch milliseconds of its first and
2391
+ * last access unit; the segment being written is `<start>.part`, and its end is its modification time.
2392
+ */
2393
+ interface RecordedSegment {
2394
+ file: string;
2395
+ start: number;
2396
+ end: number;
2397
+ bytes: number;
2398
+ open: boolean;
2285
2399
  }
2286
- /** The payload `stim status --json` prints, and `status --watch --json` prints on each change. */
2287
- interface StatusPayload {
2288
- maintenance?: MaintenanceStatus;
2289
- archived?: ArchivedWorkspace[];
2290
- archivedUsage?: ArchivedUsage;
2291
- environments: (EnvironmentState & {
2292
- labelOnly?: true;
2293
- })[];
2294
- capacity: StatusCapacity;
2295
- deviceLeases: DeviceLeaseState[];
2296
- unprovisionedWorktrees: WorktreeFacts[];
2297
- simctlAvailable: boolean;
2298
- /** Null when nothing runs that status attributes, so it read no process table, or when the table was unreadable. */
2299
- machine: MachineUsageState | null;
2400
+ interface RecordedDevice {
2401
+ platform: RecordingPlatform;
2402
+ slot: string;
2403
+ dir: string;
2404
+ segments: RecordedSegment[];
2300
2405
  }
2406
+ /** The directory under a workspace's recordings that holds one device slot's footage. */
2407
+ declare function recordingDeviceName(platform: RecordingPlatform, slot: string): string;
2408
+ /** Segment names hold whole milliseconds: the start rounded down and the end rounded up. */
2409
+ declare function closedSegmentName(start: number, end: number): string;
2410
+ declare function openSegmentName(start: number): string;
2411
+ /** The segments in one device directory, oldest first. Files that are not segments are left out; `closedOnly` excludes files still being written. */
2412
+ declare function listSegments(dir: string, closedOnly?: boolean): RecordedSegment[];
2413
+ /** Reads current segment files asynchronously, oldest first; cancellation propagates. */
2414
+ declare function listSegmentsAsync(dir: string, closedOnly?: boolean, signal?: AbortSignal): Promise<RecordedSegment[]>;
2415
+ /** Every device slot recorded under a workspace's recordings directory. */
2416
+ declare function listRecordedDevices(recordingsDir: string, closedOnly?: boolean): RecordedDevice[];
2417
+ /** Reads current device slots and their segment files asynchronously; cancellation propagates. */
2418
+ declare function listRecordedDevicesAsync(recordingsDir: string, closedOnly?: boolean, signal?: AbortSignal): Promise<RecordedDevice[]>;
2419
+ declare function recordedBytes(devices: readonly RecordedDevice[]): number;
2420
+ /**
2421
+ * The oldest closed segments to delete so that one device keeps at most `footageMs` of footage. Time between
2422
+ * segments, while nothing was recorded, does not count. The open segment is never chosen.
2423
+ */
2424
+ declare function footageDrops(segments: readonly RecordedSegment[], footageMs: number): RecordedSegment[];
2425
+ /** The oldest closed segments across all devices to delete so that together they hold at most `capBytes`. */
2426
+ declare function capDrops(devices: readonly RecordedDevice[], capBytes: number): RecordedSegment[];
2427
+ /**
2428
+ * Whether stim-server records a workspace's devices: `STIM_RECORDING`, then `recording.enabled` in the workspace,
2429
+ * repo and machine layers, in that order, and true by default.
2430
+ */
2431
+ declare function recordingEnabled(env: NodeJS.ProcessEnv, layers: readonly unknown[]): boolean;
2432
+ //#endregion
2433
+ //#region state/run-id.d.ts
2434
+ declare const RUN_ID_ENV = "STIM_RUN_ID";
2435
+ /** A run id as the CLI and stim-server accept it: letters, digits, `.`, `_` and `-`, at most 64. Null otherwise. */
2436
+ declare function validRunId(value: unknown): string | null;
2437
+ /**
2438
+ * The run id of the ambient operation context, else of this CLI invocation: `STIM_RUN_ID` when it holds a valid id
2439
+ * (Stim Desktop passes one), else a random one. The CLI entry exports it back to `STIM_RUN_ID` so processes the run
2440
+ * starts inherit it; this function does not.
2441
+ */
2442
+ declare function runId(env?: NodeJS.ProcessEnv): string;
2443
+ //#endregion
2444
+ //#region state/settings-schema.d.ts
2445
+ declare const SETTINGS_SCHEMA_FILE = "settings.schema.json";
2446
+ declare const SETTINGS_SCHEMA_URL: string;
2447
+ type JsonSchema = Record<string, unknown>;
2448
+ /**
2449
+ * The published settings schema. The root describes a committed `.stim.json`;
2450
+ * `$defs.machine` describes the settings keys of `$STIM_HOME/config.json`.
2451
+ * Every leaf carries `x-stim` with its dotted key, kind, writable scopes,
2452
+ * environment override, and sensitivity.
2453
+ */
2454
+ declare function settingsJsonSchema(): JsonSchema;
2301
2455
  //#endregion
2302
2456
  //#region state/status-derived.d.ts
2303
2457
  declare function withGitChip(worktree: WorktreeFacts): WorktreeFacts;
@@ -2558,23 +2712,21 @@ declare function readDeviceHostMachines(): DeviceHostMachineCredential[];
2558
2712
  //#endregion
2559
2713
  //#region state/hosted-metro.d.ts
2560
2714
  declare const HOSTED_METRO_REQUESTS_KEY = "hostedMetroRequests";
2561
- declare const HOSTED_METRO_GATEWAYS_KEY = "hostedMetroGateways";
2715
+ declare const HOSTED_METRO_LINKS_KEY = "hostedMetroLinks";
2562
2716
  /** Private supervisor request, keyed by hosted session; never part of a public payload. */
2563
2717
  interface HostedMetroRequest {
2564
2718
  id: string;
2565
2719
  machine: string;
2566
- address: string;
2567
- peer: string;
2568
- secret: string;
2569
2720
  }
2570
- interface HostedMetroGateway {
2721
+ /** The supervisor's answer to a request: `ready` while the host holds one of its links, `error` when it cannot link. */
2722
+ interface HostedMetroLinks {
2571
2723
  id: string;
2572
2724
  processToken: string;
2573
- port?: number;
2725
+ ready?: true;
2574
2726
  error?: string;
2575
2727
  }
2576
2728
  declare function hostedMetroRequests(state: WorkspaceState | null): Record<string, HostedMetroRequest>;
2577
- declare function hostedMetroGateways(state: WorkspaceState | null): Record<string, HostedMetroGateway>;
2729
+ declare function hostedMetroLinks(state: WorkspaceState | null): Record<string, HostedMetroLinks>;
2578
2730
  //#endregion
2579
2731
  //#region state/tailnet.d.ts
2580
2732
  declare const TAILNET_MACHINE_PATTERN: string;
@@ -2684,6 +2836,81 @@ interface GcLogRecord extends NdjsonRecord {
2684
2836
  declare function isGcLogRecord(record: NdjsonRecord): record is GcLogRecord;
2685
2837
  declare function readGcLog(file?: string): GcLogRecord[];
2686
2838
  //#endregion
2839
+ //#region state/build-ledger.d.ts
2840
+ declare const BUILD_LEDGER_CAP = 500;
2841
+ type BuildLedgerPlatform = "ios" | "android" | "macos";
2842
+ type BuildLedgerOutcome = BuildResult;
2843
+ type BuildLedgerCacheResult = "hit" | "miss" | "bypassed";
2844
+ interface BuildLedgerPlacement {
2845
+ where: "local" | "offloaded";
2846
+ /** The build machine that compiled the app, for an offloaded build. */
2847
+ machine?: string;
2848
+ /** The run considered offloading, then built here; `reason` says why. */
2849
+ fellBack?: true;
2850
+ reason?: string;
2851
+ }
2852
+ interface BuildLedgerCache {
2853
+ result: BuildLedgerCacheResult;
2854
+ /** Where a hit came from. */
2855
+ source?: "local" | "remote";
2856
+ key: string | null;
2857
+ fingerprint: string | null;
2858
+ missReason?: string;
2859
+ }
2860
+ interface BuildLedgerFailure {
2861
+ code: string | null;
2862
+ message: string | null;
2863
+ remedy: string | null;
2864
+ /** The phase the run was in when it failed. */
2865
+ phase: string | null;
2866
+ }
2867
+ /** The simulator, emulator or device the run targeted. Never a serial or UDID. */
2868
+ interface BuildLedgerDevice {
2869
+ name: string;
2870
+ runtime?: string;
2871
+ }
2872
+ /** One native build run, as `stim logs --source builds --json` prints it. */
2873
+ interface BuildLedgerRecord extends NdjsonRecord {
2874
+ /** Epoch milliseconds when the run finished. */
2875
+ ts: number;
2876
+ src: "builds";
2877
+ level: "info" | "warn" | "error";
2878
+ msg: string;
2879
+ event: "build";
2880
+ id: string;
2881
+ /** Epoch milliseconds when the run started. */
2882
+ startedAt: number;
2883
+ project: string;
2884
+ workspace: string;
2885
+ branch: string | null;
2886
+ platform: BuildLedgerPlatform;
2887
+ scheme?: string;
2888
+ variant?: string;
2889
+ configuration: string | null;
2890
+ placement: BuildLedgerPlacement;
2891
+ cache: BuildLedgerCache;
2892
+ durationMs: number;
2893
+ /** Milliseconds in each local phase of the run. */
2894
+ phases: Record<string, number>;
2895
+ /** Milliseconds in each phase on the build machine (`sync`, `deps`, `prebuild`, `pods`, `build`, `fetch`). */
2896
+ offloadPhases?: Record<string, number>;
2897
+ outcome: BuildLedgerOutcome;
2898
+ failure?: BuildLedgerFailure;
2899
+ device?: BuildLedgerDevice;
2900
+ /** This machine's 5-minute load per core when the run started. Absent in older records. */
2901
+ loadPerCore?: number;
2902
+ /** The run's first owned simulator or emulator boot: when it started, in epoch milliseconds, and the load per core then. */
2903
+ boot?: BuildLedgerBoot;
2904
+ stimVersion: string;
2905
+ }
2906
+ interface BuildLedgerBoot {
2907
+ startedAt: number;
2908
+ loadPerCore: number;
2909
+ }
2910
+ declare function isBuildLedgerRecord(record: NdjsonRecord): record is BuildLedgerRecord;
2911
+ /** The ledger's records, oldest first. A missing or unreadable ledger is empty. */
2912
+ declare function readBuildLedger(file?: string): BuildLedgerRecord[];
2913
+ //#endregion
2687
2914
  //#region state/agent-device.d.ts
2688
2915
  declare function agentDeviceStateDirs(home?: string, env?: NodeJS.ProcessEnv): string[];
2689
2916
  declare function agentDeviceStateDirsAsync(home?: string, env?: NodeJS.ProcessEnv): Promise<string[]>;
@@ -2798,4 +3025,4 @@ declare class KeyedEntities<T> {
2798
3025
  /** Applies `delta` to `entities` keyed by `key`, keeping the order of `entities` and appending new keys. */
2799
3026
  declare function applyKeyedDelta<T>(entities: readonly T[], delta: KeyedDelta<T>, key: (entity: T) => string): T[];
2800
3027
  //#endregion
2801
- export { BuildMachineTotals as $, hostedAppArea as $a, readHomeIdentity as $c, HostedAndroidChoice as $i, swiftpmCacheUsageFile as $l, RunOutcomeKind as $n, listRecordedDevicesAsync as $o, HostedIosPlacement as $r, workspaceGradleBuild as $s, APP_PROCESS_STATES as $t, HostedLogsCursor as A, HOSTED_MACOS_APP_SLOTS as Aa, readLogTimeline as Ac, MetroLastStop as Ai, ProjectRecord as Al, DevicePlacement as An, TunnelMode as Ao, archiveEnabled as Ar, maintenanceAttemptFile as As, ViewedDevice as At, cannotHost as B, hostedAgentDriverName as Ba, countErrorEntries as Bc, readDevServerStop as Bi, readBuildMachines as Bl, MachineOwner as Bn, RUN_ID_ENV as Bo, MaintenanceActionKind as Br, sharedCcache as Bs, endedAgentSessionOf as Bt, GcLogRecord as C, parseHostedOfferRequest as Ca, logFiles as Cc, DevServerStopRecord as Ci, requireAutomaticMachine as Cl, BuildReport as Cn, SettingDefinition as Co, macosAppState as Cr, easSessionLedgerFile as Cs, readStatsReport as Ct, readGcLog as D, readHostedDeviceLedger as Da, queryJsonLogs as Dc, IdleStopRecord as Di, DeviceRecord as Dl, DeviceActivity as Dn, SettingWriteResult as Do, ArchivedBytes as Dr, gcLogFile as Ds, trimSamples as Dt, isGcLogRecord as E, readHostedDevice as Ea, planLogQuery as Ec, IDLE_STOP_KEY as Ei, Config as El, ChecksState as En, SettingType as Eo, readMacosRecord as Er, gcLogDir as Es, trimCapacityWaits as Et, readHostedNativeLogsCheckpoint as F, HostedAgentLease as Fa, FingerprintMemoRecord as Fc, WorkspaceState as Fi, clientIdentity as Fl, GitChip as Fn, expectedShape as Fo, readArchiveState as Fr, maintenanceStateFile as Fs, PullRequestCacheEntry as Ft, HOSTED_METRO_GATEWAYS_KEY as G, parseHostedMacosChoice as Ga, readCreatedDevices as Gc, readLastBuilds as Gi, saturation as Gl, MetroBundleState as Gn, RECORDING_PLATFORMS as Go, MaintenanceRecord as Gr, supervisorLogFile as Gs, readDiskUsage as Gt, findPeer as H, hostedMacosBundleId as Ha, CreatedDevices as Hc, readDeviceIdleShutdowns as Hi, buildSlotPath as Hl, MachineUsageState as Hn, validRunId as Ho, MaintenanceMode as Hr, sharedGradle as Hs, pullRequestCacheFile as Ht, readLogsSince as I, HostedAppLaunch as Ia, fingerprintMemoDir as Ic, buildDiagnostics as Ii, BuildMachineCredential as Il, GitChipPart as In, isLayeredSetting as Io, readArchives as Ir, pullRequestCacheDir as Is, StatusCacheEntry as It, HostedMetroRequest as J, HOSTED_APP_CHUNK_BYTES as Ja, isJsonObject as Jc, readWorkspaceState as Ji, SimRuntimeUsage as Jl, PHYSICAL_DEVICE_CONNECTIONS as Jn, RecordingPlatform as Jo, MaintenanceStatus as Jr, workspaceAgentDeviceDir as Js, readPullRequestCache as Jt, HOSTED_METRO_REQUESTS_KEY as K, parseHostedMacosDevice as Ka, readEasSessionLedger as Kc, readWarmRecord as Ki, tryAcquireBuildSlotClaim as Kl, NATIVE_BUILD_STEPS as Kn, RecordedDevice as Ko, MaintenanceSize as Kr, supervisorPidFile as Ks, readDiskUsageFailure as Kt, Endpoint as L, HostedMacosChoice as La, fingerprintMemoFile as Lc, lastUseFrom as Li, MACHINE_CREDENTIALS_VERSION as Ll, LastBuildReport as Ln, isSensitiveReference as Lo, readArchivesAsync as Lr, serverLocalSocket as Ls, agentSessionOf as Lt, hostedMacosLogsDir as M, HostedAgentDriverName as Ma, sortByTs as Mc, WARM_KEY as Mi, SettingsObject as Ml, EndedAgentSession as Mn, WebViewport as Mo, linkReplacedArchives as Mr, maintenanceDir as Ms, stimBuildDigest as Mt, hostedNativeLogsDir as N, HostedAgentGrant as Na, tailRead as Nc, WORKSPACE_AGENT_KEY as Ni, StimConfig as Nl, EnvironmentDisk as Nn, acceptsShape as No, readArchive as Nr, maintenanceNdjsonFile as Ns, AgentSessionsCache as Nt, HOSTED_LOGS_FIRST_BYTES as O, readHostedSessions as Oa, queryLogs as Oc, LAST_BUILD_KEYS as Oi, DoctorRunRecord as Ol, DeviceAppProcess as On, SettingsPayload as Oo, ArchivedUsage as Or, getConfigPath as Os, wholePhases as Ot, parseHostedLogsCursor as P, HostedAgentIssuedGrant as Pa, FINGERPRINT_MEMO_SCHEMA as Pc, WarmRecord as Pi, SupervisorRecord as Pl, EnvironmentState as Pn, coerceSettingText as Po, readArchiveAsync as Pr, maintenanceRunClaims as Ps, ENDED_AGENT_RETENTION_MS as Pt, readDeviceHostMachines as Q, HostedAppRecord as Qa, withStateReadCache as Qc, HOSTED_PARKED_CANDIDATES as Qi, readSwiftpmCacheUsage as Ql, RemoteDeviceState as Qn, listRecordedDevices as Qo, readMaintenanceState as Qr, workspaceEndedAgentsLock as Qs, AGENT_TOOLS as Qt, TAILNET_MACHINE_PATTERN as R, HostedMacosDevice as Ra, fingerprintMemoLock as Rc, parseMissReason as Ri, MachineCredential as Rl, MACHINE_OWNER_KINDS as Rn, settingDefinition as Ro, DiskPressureLevel as Rr, serverSetupDir as Rs, diskUsageCacheFile as Rt, GcLogOptions as S, parseHostedNativeOffer as Sa, isExpoErrorContext as Sc, DEV_SERVER_STOP_REQUEST_KEY as Si, automaticMachineEnabled as Sl, BuildPlatform as Sn, SETTING_SCOPES as So, MacosProcess as Sr, easMachineStateRoot as Ss, readStats as St, GcLogTrigger as T, parseHostedRequest as Ta, parseSince as Tc, DeviceIdleShutdownRecord as Ti, ConcurrencyLimits as Tl, BuildWaitingFor as Tn, SettingScope as To, readHostedMacosApp as Tr, emulatorLogFile as Ts, trimCapacityRefusals as Tt, machineEndpoint as U, parseHostedAgentAccess as Ua, EasSessionClaim as Uc, readDevicePlacement as Ui, buildSlotsDir as Ul, MacosBuildPlanPayload as Un, RECORDING_CAP_BYTES as Uo, MaintenancePass as Ur, sharedPods as Us, readAgentSessionsCache as Ut, endpoint as V, hostedMacosAppSlot as Va, CreatedDevicePlatform as Vc, readDevServerStopRequest as Vi, MachineCapacity as Vl, MachineOwnerKind as Vn, runId as Vo, MaintenanceCheck as Vr, sharedCompilationCache as Vs, listStatusCacheEntries as Vt, parseMachine as W, parseHostedAgentGrant as Wa, EasSessionLedgerRead as Wc, readIdleStop as Wi, machineCapacity as Wl, MemorySource as Wn, RECORDING_FOOTAGE_MS as Wo, MaintenancePressure as Wr, statsFile as Ws, readBuildDetail as Wt, hostedMetroRequests as X, HostedAppFile as Xa, readJsonObject as Xc, DEVICE_HOST_LIMITS as Xi, readMachineCacheUsage as Xl, PhysicalDeviceState as Xn, closedSegmentName as Xo, parseMaintenanceState as Xr, workspaceDerivedData as Xs, withGitChip as Xt, hostedMetroGateways as Y, HostedAppDelivery as Ya, readJsonFile as Yc, workspaceLastUsed as Yi, machineCacheUsageFile as Yl, PhysicalDeviceConnection as Yn, capDrops as Yo, MemoryCulprit as Yr, workspaceBuildDetailFile as Ys, withDerivedFacts as Yt, DeviceHostMachineCredential as Z, HostedAppOffer as Za, readStateFile as Zc, DeviceHostLimits as Zi, SwiftpmCacheUsage as Zl, PlannedPhase as Zn, footageDrops as Zo, readMaintenanceAttempt as Zr, workspaceEndedAgentsFile as Zs, ACTIVITY_RECENCY_BASES as Zt, isSetupJournalPrunable as _, hostedWorkerSettleMs as _a, bundleMarkerPlatform as _c, unreadableHostedNative as _i, windowsShortDir as _l, BuildMissChange as _n, OffloadMode as _o, WorktreeGit as _r, deviceHostMachinesFile as _s, decodeStats as _t, MachineView as a, HostedDevicePlatform as aa, workspaceStateLock as ac, unreadableHostedIos as ai, ParkedMax as al, AndroidDeviceState as an, readHostedAppMetadata as ao, StatusIssueCode as ar, recordingEnabled as as, ReadStatsResult as at, AgentActionReaderOptions as au, agentDeviceStateDirs as b, parseHostedDevice as ba, fileSizes as bc, DEVICE_IDLE_SHUTDOWN_KEY as bi, withConfigLockAsync as bl, BuildPlacement as bn, SETTINGS as bo, MacosAppState as br, diskUsageCacheDir as bs, projectRootDirectories as bt, SummaryBuild as c, HostedDeviceSession as ca, openLogDir as cc, hostedAndroidDeviceName as ci, configCorruptRepair as cl, BUILD_PHASES as cn, validHostedAppBlob as co, WEB_PAGE_STATES as cr, archiveLock as cs, RunSample as ct, createAgentActionReader as cu, WorktreeRow as d, HostedNativeOffer as da, LogQueryPlan as dc, hostedAndroidStatus as di, getParkedMax as dl, BuildCacheHit as dn, settingsJsonSchema as do, WarmStep as dr, buildMachinesLock as ds, StatsCapacityRefusal as dt, NdjsonRecord as du, HostedAndroidDevice as ea, workspaceLogErrorIndex as ec, HostedIosStatus as ei, DEBUG_ENV as el, ActiveBuildState as en, hostedAppAttempt as eo, STATUS_ISSUE_CODES as er, listSegments as es, CAPACITY_REFUSAL_LIMIT as et, AgentDeviceUsage as eu, statusViews as f, assertHostedDeviceLedger as fa, NATIVE_CRASH_LOG_PREFIX as fc, parseHostedAndroidPlacement as fi, getProject as fl, BuildCause as fn, ANDROID_COMPILER_CACHE_CHOICES as fo, WebBrowserState as fr, clientIdentityKeyFile as fs, StatsCapacityWait as ft, SOURCES as fu, isJournalExpired as g, hostedDeviceId as ga, buildCriteria as gc, parseHostedNativePlacement as gi, loadConfig as gl, BuildMissCategory as gn, OFFLOAD_MODES as go, WorktreeFacts as gr, deviceHostMachinesClaims as gs, StatsScope as gt, readNdjsonGenerations as gu, SetupJournal as h, hostedConsolePort as ha, attachExpoErrorContext as hc, hostedNativeRecords as hi, isPathPrefix as hl, BuildHistoryEntry as hn, IOS_SIMULATOR_APPS as ho, WorkspaceStage as hr, createdDevicesLock as hs, StatsReport as ht, parseNdjsonText as hu, ArchivedSummary as i, HostedDevicePhase as ia, workspaceStateFile as ic, parseHostedIosPlacement as ii, debugLoggingEnabled as il, AgentTool as in, readHostedApp as io, StatusIssue as ir, recordingDeviceName as is, PLACEMENT_DECISIONS as it, readAgentDeviceUsageCache as iu, HostedLogsPage as j, HostedAgentAccess as ja, recordMatches as jc, READY_PHASE_MS as ji, RepoRecord as jl, DiskMeasure as jn, WEB_VIEWPORTS as jo, archivedUsage as jr, maintenanceChildLogFile as js, readViewedDevices as jt, HOSTED_LOGS_PAGE_BYTES as k, HOSTED_AGENT_DRIVERS as ka, readLogRecords as kc, MAINTENANCE_LOG_NAME as ki, PlatformRecords as kl, DeviceLeaseState as kn, TUNNEL_MODES as ko, ArchivedWorkspace as kr, gitMergeCacheDir as ks, DeviceViewersRecord as kt, SummaryHistoryEntry as l, HostedIosChoice as la, ERROR_SOURCES as lc, hostedAndroidPlacements as li, findEnclosingWorktreeRoot as ll, BUILD_RESULTS as ln, SETTINGS_SCHEMA_FILE as lo, WORKSPACE_PHASES as lr, archiveRoot as ls, STATS_VERSION as lt, createAsyncAgentActionReader as lu, SetupCapability as m, deviceHostRoot as ma, advanceTail as mc, HostedNativePlacement as mi, getRepoSettings as ml, BuildDiagnostic as mn, ANDROID_PCH_CHOICES as mo, WorkspacePhase as mr, createdDevicesFile as ms, StatsRecord as mt, parseNdjsonLine as mu, KeyedEntities as n, HostedDeviceOffer as na, workspaceMetadataFile as nc, hostedIosRecords as ni, createDebugLog as nl, ActivityRecencyBasis as nn, parseHostedAppManifest as no, StatsPlatform as nr, openSegmentName as ns, HISTORY_LIMIT as nt, agentDeviceUsageFile as nu, SUMMARY_ARCHIVES as o, HostedDeviceRequest as oa, LogDir as oc, HostedAndroidPlacement as oi, allMetroPorts as ol, AndroidRuntimeFacts as on, rememberHostedAppBlobRename as oo, StatusPayload as or, agentSessionsCacheFile as os, RunEstimates as ot, AgentRecordSelection as ou, workspaceSummary as p, deviceHostArea as pa, QueryCriteria as pc, unreadableHostedAndroid as pi, getProjectSettings as pl, BuildDetail as pn, ANDROID_EMULATOR_APPS as po, WebPageState as pr, configLockPath as ps, StatsPlacement as pt, levelRank as pu, HostedMetroGateway as q, parseHostedMacosPlacement as qa, validEasSessionClaim as qc, readWorkspaceAgent as qi, MachineCacheUsage as ql, NativeBuildStep as qn, RecordedSegment as qo, MaintenanceState as qr, trashRoot as qs, readEndedAgentSessions as qt, applyKeyedDelta as r, HostedDeviceOfferRequest as ra, workspaceRecordingsDir as rc, hostedIosStatus as ri, debugLogDir as rl, AgentSession as rn, parseHostedAppOffer as ro, StatusCapacity as rr, recordedBytes as rs, OffloadSummary as rt, readAgentDeviceUsage as ru, StatusViews as s, HostedDeviceSelectors as sa, LogDirQuery as sc, HostedAndroidStatus as si, buildWorkerRoot as sl, AppPresence as sn, validHostedAppArguments as so, TUTORIAL_VERSION as sr, archiveDir as ss, RunHistory as st, AgentTarget as su, KeyedDelta as t, HostedDevice as ta, workspaceLogsDir as tc, hostedIosPlacements as ti, DebugLog as tl, ActivityDriver as tn, hostedAppBlobs as to, SimulatorState as tr, listSegmentsAsync as ts, CAPACITY_REFUSAL_MAX_AGE_MS as tt, AgentDeviceUsageRoots as tu, WorkspaceSummary as u, HostedIosDevice as ua, LogQueryOptions as uc, hostedAndroidRecords as ui, getConcurrencyLimits as ul, BuildActivity as un, SETTINGS_SCHEMA_URL as uo, WORKSPACE_STAGE_KINDS as ur, buildMachinesFile as us, StatsBucket as ut, LEVELS as uu, parseSetupJournal as v, parseHostedAndroidDevice as va, compileGrep as vc, BUILD_HISTORY_KEY as vi, windowsShortDirKey as vl, BuildMissReason as vn, REMOTE_DEVICE_BACKENDS as vo, WorktreePullRequest as vr, deviceHostMachinesLock as vs, findProjectRoot as vt, GcLogStatus as w, parseHostedPlatformDevice as wa, markerWindow as wc, DevServerStopRequest as wi, validateAutomaticPool as wl, BuildResult as wn, SettingEntry as wo, parseMacosRecord as wr, easSessionLedgerLock as ws, statsProjectKey as wt, agentDeviceStateDirsAsync as x, parseHostedLocalDeviceCount as xa, followLogs as xc, DEVICE_RECLAIM_REASON as xi, AutomaticPoolRole as xl, BuildPlanPayload as xn, SETTING_GROUPS as xo, MacosBuild as xr, diskUsageWalkClaims as xs, readRunEstimates as xt, readSetupJournal as y, parseHostedChoice as ya, fileIdentity as yc, BUILD_HISTORY_LIMIT as yi, withConfigLock as yl, BuildPhase as yn, RemoteDeviceBackend as yo, MacosAppRecord as yr, deviceViewersDir as ys, offloadSummary as yt, TailnetPeer as z, HostedMacosPlacement as za, readFingerprintMemo as zc, readBuildHistory as zi, parseMachineCredential as zl, MEMORY_SOURCES as zn, settingValueError as zo, MaintenanceAction as zr, setupJournalFile as zs, diskUsageFailureFile as zt };
3028
+ export { endpoint as $, AndroidRuntimeFacts as $a, IDLE_STOP_KEY as $c, ParkedMax as $i, parseHostedRequest as $l, deviceHostMachinesClaims as $n, StatusCapacity as $o, QueryCriteria as $r, readMacosRecord as $s, listStatusCacheEntries as $t, createAsyncAgentActionReader as $u, BuildLedgerPlatform as A, BuildMachineCredential as Aa, hostedIosStatus as Ac, EasSessionLedgerRead as Ai, HostedDeviceOffer as Al, recordingDeviceName as An, LastBuildReport as Ao, trashRoot as Ar, SettingScope as As, findProjectRoot as At, parseHostedAppManifest as Au, HOSTED_LOGS_FIRST_BYTES as B, machineCapacity as Ba, unreadableHostedAndroid as Bc, EndSpan as Bi, assertHostedDeviceLedger as Bl, archiveLock as Bn, NATIVE_BUILD_STEPS as Bo, workspaceMetadataFile as Br, expectedShape as Bs, wholePhases as Bt, readMachineCacheUsage as Bu, BuildLedgerBoot as C, PlatformRecords as Ca, parseMaintenanceState as Cc, fingerprintMemoFile as Ci, workspaceLastUsed as Cl, footageDrops as Cn, DevicePlacement as Co, sharedCcache as Cr, REPLACED_SETTINGS as Cs, StatsCapacityRefusal as Ct, HostedAppDelivery as Cu, BuildLedgerFailure as D, StimConfig as Da, HostedIosStatus as Dc, CreatedDevicePlatform as Di, HostedAndroidChoice as Dl, listSegmentsAsync as Dn, EnvironmentState as Do, statsFile as Dr, SETTING_SCOPES as Ds, StatsReport as Dt, hostedAppArea as Du, BuildLedgerDevice as E, SettingsObject as Ea, HostedIosPlacement as Ec, countErrorEntries as Ei, HOSTED_PARKED_CANDIDATES as El, listSegments as En, EnvironmentDisk as Eo, sharedPods as Er, SETTING_GROUPS as Es, StatsRecord as Et, HostedAppRecord as Eu, GcLogRecord as F, MachineCapacity as Fa, hostedAndroidDeviceName as Fc, readJsonFile as Fi, HostedDeviceSelectors as Fl, mayRunHere as Fn, MachineOwnerKind as Fo, workspaceEndedAgentsLock as Fr, TunnelMode as Fs, readStatsReport as Ft, validHostedAppArguments as Fu, hostedNativeLogsDir as G, AGENT_TOOLS as Ga, BUILD_HISTORY_KEY as Gc, redactArgv as Gi, hostedWorkerSettleMs as Gl, buildLedgerFile as Gn, PlannedPhase as Go, createNdjsonTail as Gr, settingValueError as Gs, AgentSessionsCache as Gt, AgentDeviceUsageRoots as Gu, HostedLogsCursor as H, saturation as Ha, hostedNativeRecords as Hc, Trace as Hi, deviceHostRoot as Hl, budgetSweepFile as Hn, PHYSICAL_DEVICE_CONNECTIONS as Ho, workspaceStateFile as Hr, isSensitiveReference as Hs, ViewedDevice as Ht, readSwiftpmCacheUsage as Hu, GcLogStatus as I, buildSlotPath as Ia, hostedAndroidPlacements as Ic, readJsonObject as Ii, HostedDeviceSession as Il, placementWord as In, MachineUsageState as Io, workspaceGradleBuild as Ir, WEB_VIEWPORTS as Is, statsProjectKey as It, validHostedAppBlob as Iu, readLogsSince as J, ActivityDriver as Ja, DEVICE_RECLAIM_REASON as Jc, DEBUG_ENV as Ji, parseHostedDevice as Jl, buildMachinesLock as Jn, STATUS_ISSUE_CODES as Jo, openLogDir as Jr, MacosBuild as Js, StatusCacheEntry as Jt, readAgentDeviceUsageCache as Ju, parseHostedLogsCursor as K, APP_PROCESS_STATES as Ka, BUILD_HISTORY_LIMIT as Kc, redactCommandLine as Ki, parseHostedAndroidDevice as Kl, buildLedgerLock as Kn, RemoteDeviceState as Ko, LogDir as Kr, MacosAppRecord as Ks, ENDED_AGENT_RETENTION_MS as Kt, agentDeviceUsageFile as Ku, GcLogTrigger as L, buildSlotsDir as La, hostedAndroidRecords as Lc, readStateFile as Li, HostedIosChoice as Ll, prefersRemote as Ln, MacosBuildPlanPayload as Lo, workspaceLightenedFile as Lr, WebViewport as Ls, trimCapacityRefusals as Lt, MachineCacheUsage as Lu, isBuildLedgerRecord as M, MachineCredential as Ma, unreadableHostedIos as Mc, readEasSessionLedger as Mi, HostedDevicePhase as Ml, AutomaticPlacement as Mn, MACHINE_OWNER_KINDS as Mo, workspaceBuildDetailFile as Mr, SettingWriteResult as Ms, projectRootDirectories as Mt, readHostedApp as Mu, readBuildLedger as N, parseMachineCredential as Na, HostedAndroidPlacement as Nc, validEasSessionClaim as Ni, HostedDevicePlatform as Nl, PLACEMENT_WORDS as Nn, MEMORY_SOURCES as No, workspaceDerivedData as Nr, SettingsPayload as Ns, readRunEstimates as Nt, readHostedAppMetadata as Nu, BuildLedgerOutcome as O, SupervisorRecord as Oa, hostedIosPlacements as Oc, CreatedDevices as Oi, HostedAndroidDevice as Ol, openSegmentName as On, GitChip as Oo, supervisorLogFile as Or, SettingDefinition as Os, StatsScope as Ot, hostedAppAttempt as Ou, GcLogOptions as P, readBuildMachines as Pa, HostedAndroidStatus as Pc, isJsonObject as Pi, HostedDeviceRequest as Pl, PlacementWord as Pn, MachineOwner as Po, workspaceEndedAgentsFile as Pr, TUNNEL_MODES as Ps, readStats as Pt, rememberHostedAppBlobRename as Pu, cannotHost as Q, AndroidDeviceState as Qa, DeviceIdleShutdownRecord as Qc, debugLoggingEnabled as Qi, parseHostedPlatformDevice as Ql, createdDevicesLock as Qn, StatusBuildSlots as Qo, NATIVE_CRASH_LOG_PREFIX as Qr, readHostedMacosApp as Qs, endedAgentSessionOf as Qt, createAgentActionReader as Qu, isGcLogRecord as R, loadPerCore as Ra, hostedAndroidStatus as Rc, withStateReadCache as Ri, HostedIosDevice as Rl, agentSessionsCacheFile as Rn, MemorySource as Ro, workspaceLogErrorIndex as Rr, acceptsShape as Rs, trimCapacityWaits as Rt, SimRuntimeUsage as Ru, BUILD_LEDGER_CAP as S, DoctorRunRecord as Sa, MemoryCulprit as Sc, fingerprintMemoDir as Si, readWorkspaceState as Sl, closedSegmentName as Sn, DeviceLeaseState as So, setupJournalFile as Sr, REMOTE_DEVICE_BACKENDS as Ss, StatsBucket as St, HOSTED_APP_CHUNK_BYTES as Su, BuildLedgerCacheResult as T, RepoRecord as Ta, readMaintenanceState as Tc, readFingerprintMemo as Ti, DeviceHostLimits as Tl, listRecordedDevicesAsync as Tn, EndedAgentSession as To, sharedGradle as Tr, SETTINGS as Ts, StatsPlacement as Tt, HostedAppOffer as Tu, HostedLogsPage as U, tryAcquireBuildSlotClaim as Ua, parseHostedNativePlacement as Uc, TraceArgs as Ui, hostedConsolePort as Ul, budgetSweepLock as Un, PhysicalDeviceConnection as Uo, workspaceStateLock as Ur, replacementAdvice as Us, readViewedDevices as Ut, swiftpmCacheUsageFile as Uu, HOSTED_LOGS_PAGE_BYTES as V, maxLoadPerCore as Va, HostedNativePlacement as Vc, TRACE_ENV as Vi, deviceHostArea as Vl, archiveRoot as Vn, NativeBuildStep as Vo, workspaceRecordingsDir as Vr, isLayeredSetting as Vs, DeviceViewersRecord as Vt, SwiftpmCacheUsage as Vu, hostedMacosLogsDir as W, ACTIVITY_RECENCY_BASES as Wa, unreadableHostedNative as Wc, TracePhases as Wi, hostedDeviceId as Wl, buildLedgerDir as Wn, PhysicalDeviceState as Wo, worktreeArchiveRoot as Wr, settingDefinition as Ws, stimBuildDigest as Wt, AgentDeviceUsage as Wu, TAILNET_MACHINE_PATTERN as X, AgentSession as Xa, DevServerStopRecord as Xc, createDebugLog as Xi, parseHostedNativeOffer as Xl, configLockPath as Xn, StatsPlatform as Xo, LogQueryOptions as Xr, macosAppState as Xs, diskUsageCacheFile as Xt, AgentRecordSelection as Xu, Endpoint as Y, ActivityRecencyBasis as Ya, DEV_SERVER_STOP_REQUEST_KEY as Yc, DebugLog as Yi, parseHostedLocalDeviceCount as Yl, clientIdentityKeyFile as Yn, SimulatorState as Yo, ERROR_SOURCES as Yr, MacosProcess as Ys, agentSessionOf as Yt, AgentActionReaderOptions as Yu, TailnetPeer as Z, AgentTool as Za, DevServerStopRequest as Zc, debugLogDir as Zi, parseHostedOfferRequest as Zl, createdDevicesFile as Zn, StatusBuildSlotHolder as Zo, LogQueryPlan as Zr, parseMacosRecord as Zs, diskUsageFailureFile as Zt, AgentTarget as Zu, isSetupJournalPrunable as _, requireAutomaticMachine as _a, MaintenancePressure as _c, recordMatches as _i, readDevicePlacement as _l, RECORDING_PLATFORMS as _n, BuildResult as _o, maintenanceRunClaims as _r, WorktreePullRequest as _s, ReadStatsResult as _t, parseHostedAgentAccess as _u, MachineView as a, getParkedMax as aa, linkReplacedArchives as ac, parseNdjsonText as ad, fileIdentity as ai, WARM_KEY as al, readEndedAgentSessions as an, BuildCause as ao, easMachineStateRoot as ar, StatusPayload as as, HostedMetroLinks as at, HostedAgentAccess as au, agentDeviceStateDirs as b, Config as ba, MaintenanceState as bc, FINGERPRINT_MEMO_SCHEMA as bi, readWarmRecord as bl, RecordingPlatform as bn, DeviceActivity as bo, serverLocalSocket as br, ANDROID_PCH_CHOICES as bs, RunSample as bt, parseHostedMacosDevice as bu, SummaryBuild as c, getRepoSettings as ca, readArchiveState as cc, isExpoErrorContext as ci, WorkspaceState as cl, withGitChip as cn, BuildHistoryEntry as co, emulatorLogFile as cr, WORKSPACE_PHASES as cs, hostedMetroRequests as ct, HostedAgentIssuedGrant as cu, WorktreeRow as d, windowsShortDir as da, DiskPressureLevel as dc, parseSince as di, lastUseFrom as dl, settingsJsonSchema as dn, BuildMissReason as do, getConfigPath as dr, WebBrowserState as ds, BuildMachineTotals as dt, HostedMacosChoice as du, allMetroPorts as ea, ArchivedBytes as ec, LEVELS as ed, advanceTail as ei, IdleStopRecord as el, pullRequestCacheFile as en, AppPresence as eo, deviceHostMachinesFile as er, StatusCapacityLoad as es, findPeer as et, readHostedDevice as eu, statusViews as f, windowsShortDirKey as fa, MaintenanceAction as fc, planLogQuery as fi, parseMissReason as fl, RUN_ID_ENV as fn, BuildPhase as fo, gitMergeCacheDir as fr, WebPageState as fs, CAPACITY_REFUSAL_LIMIT as ft, HostedMacosDevice as fu, isJournalExpired as g, automaticMachineEnabled as ga, MaintenancePass as gc, readLogTimeline as gi, readDeviceIdleShutdowns as gl, RECORDING_FOOTAGE_MS as gn, BuildReport as go, maintenanceNdjsonFile as gr, WorktreeGit as gs, PLACEMENT_DECISIONS as gt, hostedMacosBundleId as gu, SetupJournal as h, AutomaticPoolRole as ha, MaintenanceMode as hc, readLogRecords as hi, readDevServerStopRequest as hl, RECORDING_CAP_BYTES as hn, BuildPlatform as ho, maintenanceDir as hr, WorktreeFacts as hs, OffloadSummary as ht, hostedMacosAppSlot as hu, ArchivedSummary as i, getConcurrencyLimits as ia, archivedUsage as ic, parseNdjsonLine as id, compileGrep as ii, READY_PHASE_MS as il, readDiskUsageFailure as in, BuildCacheHit as io, diskUsageWalkClaims as ir, StatusIssueCode as is, HOSTED_METRO_REQUESTS_KEY as it, HOSTED_MACOS_APP_SLOTS as iu, BuildLedgerRecord as j, MACHINE_CREDENTIALS_VERSION as ja, parseHostedIosPlacement as jc, readCreatedDevices as ji, HostedDeviceOfferRequest as jl, recordingEnabled as jn, LoadState as jo, workspaceAgentDeviceDir as jr, SettingType as js, offloadSummary as jt, parseHostedAppOffer as ju, BuildLedgerPlacement as k, clientIdentity as ka, hostedIosRecords as kc, EasSessionClaim as ki, HostedDevice as kl, recordedBytes as kn, GitChipPart as ko, supervisorPidFile as kr, SettingEntry as ks, decodeStats as kt, hostedAppBlobs as ku, SummaryHistoryEntry as l, isPathPrefix as la, readArchives as lc, logFiles as li, buildDiagnostics as ll, SETTINGS_SCHEMA_FILE as ln, BuildMissCategory as lo, gcLogDir as lr, WORKSPACE_STAGE_KINDS as ls, DeviceHostMachineCredential as lt, HostedAgentLease as lu, SetupCapability as m, withConfigLockAsync as ma, MaintenanceCheck as mc, queryLogs as mi, readDevServerStop as ml, validRunId as mn, BuildPlanPayload as mo, maintenanceChildLogFile as mr, WorkspaceStage as ms, HISTORY_LIMIT as mt, hostedAgentDriverName as mu, KeyedEntities as n, configCorruptRepair as na, ArchivedWorkspace as nc, SOURCES as nd, buildCriteria as ni, MAINTENANCE_LOG_NAME as nl, readBuildDetail as nn, BUILD_RESULTS as no, deviceViewersDir as nr, StatusDeviceSlots as ns, parseMachine as nt, readHostedSessions as nu, SUMMARY_ARCHIVES as o, getProject as oa, readArchive as oc, readNdjsonGenerations as od, fileSizes as oi, WORKSPACE_AGENT_KEY as ol, readPullRequestCache as on, BuildDetail as oo, easSessionLedgerFile as or, TUTORIAL_VERSION as os, HostedMetroRequest as ot, HostedAgentDriverName as ou, workspaceSummary as p, withConfigLock as pa, MaintenanceActionKind as pc, queryJsonLogs as pi, readBuildHistory as pl, runId as pn, BuildPlacement as po, maintenanceAttemptFile as pr, WorkspacePhase as ps, CAPACITY_REFUSAL_MAX_AGE_MS as pt, HostedMacosPlacement as pu, readHostedNativeLogsCheckpoint as q, ActiveBuildState as qa, DEVICE_IDLE_SHUTDOWN_KEY as qc, trace as qi, parseHostedChoice as ql, buildMachinesFile as qn, RunOutcomeKind as qo, LogDirQuery as qr, MacosAppState as qs, PullRequestCacheEntry as qt, readAgentDeviceUsage as qu, applyKeyedDelta as r, findEnclosingWorktreeRoot as ra, archiveEnabled as rc, levelRank as rd, bundleMarkerPlatform as ri, MetroLastStop as rl, readDiskUsage as rn, BuildActivity as ro, diskUsageCacheDir as rr, StatusIssue as rs, HOSTED_METRO_LINKS_KEY as rt, HOSTED_AGENT_DRIVERS as ru, StatusViews as s, getProjectSettings as sa, readArchiveAsync as sc, followLogs as si, WarmRecord as sl, withDerivedFacts as sn, BuildDiagnostic as so, easSessionLedgerLock as sr, WEB_PAGE_STATES as ss, hostedMetroLinks as st, HostedAgentGrant as su, KeyedDelta as t, buildWorkerRoot as ta, ArchivedUsage as tc, NdjsonRecord as td, attachExpoErrorContext as ti, LAST_BUILD_KEYS as tl, readAgentSessionsCache as tn, BUILD_PHASES as to, deviceHostMachinesLock as tr, StatusDeviceSlotHolder as ts, machineEndpoint as tt, readHostedDeviceLedger as tu, WorkspaceSummary as u, loadConfig as ua, readArchivesAsync as uc, markerWindow as ui, lastNativeUseFrom as ul, SETTINGS_SCHEMA_URL as un, BuildMissChange as uo, gcLogFile as ur, WarmStep as us, readDeviceHostMachines as ut, HostedAppLaunch as uu, parseSetupJournal as v, validateAutomaticPool as va, MaintenanceRecord as vc, sortByTs as vi, readIdleStop as vl, RecordedDevice as vn, BuildWaitingFor as vo, maintenanceStateFile as vr, ANDROID_COMPILER_CACHE_CHOICES as vs, RunEstimates as vt, parseHostedAgentGrant as vu, BuildLedgerCache as w, ProjectRecord as wa, readMaintenanceAttempt as wc, fingerprintMemoLock as wi, DEVICE_HOST_LIMITS as wl, listRecordedDevices as wn, DiskMeasure as wo, sharedCompilationCache as wr, RemoteDeviceBackend as ws, StatsCapacityWait as wt, HostedAppFile as wu, agentDeviceStateDirsAsync as x, DeviceRecord as xa, MaintenanceStatus as xc, FingerprintMemoRecord as xi, readWorkspaceAgent as xl, capDrops as xn, DeviceAppProcess as xo, serverSetupDir as xr, IOS_SIMULATOR_APPS as xs, STATS_VERSION as xt, parseHostedMacosPlacement as xu, readSetupJournal as y, ConcurrencyLimits as ya, MaintenanceSize as yc, tailRead as yi, readLastBuilds as yl, RecordedSegment as yn, ChecksState as yo, pullRequestCacheDir as yr, ANDROID_EMULATOR_APPS as ys, RunHistory as yt, parseHostedMacosChoice as yu, readGcLog as z, loadState as za, parseHostedAndroidPlacement as zc, readHomeIdentity as zi, HostedNativeOffer as zl, archiveDir as zn, MetroBundleState as zo, workspaceLogsDir as zr, coerceSettingText as zs, trimSamples as zt, machineCacheUsageFile as zu };