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