@stim-cli/core 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/{core-CmZJEFj_.mjs → core-BwaxUjLX.mjs} +133 -5
- package/dist/index-DgLuTAvh.d.mts +1826 -0
- package/dist/index.d.mts +41 -1
- package/dist/index.mjs +2 -2
- package/dist/oversight.d.mts +308 -0
- package/dist/oversight.mjs +666 -0
- package/dist/ownership-claim-Xxxr9MPp.d.mts +152 -0
- package/dist/ownership-claim.d.mts +1 -151
- package/dist/phone-protocol.d.mts +434 -0
- package/dist/phone-protocol.mjs +2 -0
- package/dist/process-identity-BTyww2Xj.d.mts +37 -0
- package/dist/process-identity.d.mts +2 -30
- package/dist/process-identity.mjs +10 -2
- package/dist/protocol-BjnE921M.d.mts +1442 -0
- package/dist/protocol.d.mts +2 -0
- package/dist/protocol.mjs +372 -0
- package/dist/receive-protocol.d.mts +12 -0
- package/dist/receive-protocol.mjs +16563 -0
- package/dist/state.d.mts +2 -737
- package/dist/state.mjs +2738 -680
- package/package.json +21 -1
|
@@ -0,0 +1,1826 @@
|
|
|
1
|
+
import { o as ClaimHandle } from "./ownership-claim-Xxxr9MPp.mjs";
|
|
2
|
+
//#region state/build-capacity.d.ts
|
|
3
|
+
declare function buildSlotsDir(): string;
|
|
4
|
+
declare function buildSlotPath(index: number): string;
|
|
5
|
+
/**
|
|
6
|
+
* Takes the first free one of `max` `concurrency.maxBuilds` slots, recording `details` and the slot `index`. Returns
|
|
7
|
+
* null while every slot is held; throws the claim refusal when no slot is busy but one cannot be resolved.
|
|
8
|
+
*/
|
|
9
|
+
declare function tryAcquireBuildSlotClaim({ max, details }: {
|
|
10
|
+
max: number;
|
|
11
|
+
details: Record<string, unknown>;
|
|
12
|
+
}): {
|
|
13
|
+
claim: ClaimHandle;
|
|
14
|
+
index: number;
|
|
15
|
+
path: string;
|
|
16
|
+
} | null;
|
|
17
|
+
/**
|
|
18
|
+
* How busy this Mac is for native builds. `loadPerCore` is the 5-minute load average divided by the CPU count,
|
|
19
|
+
* rounded to one decimal. `builds` counts this Stim home's runs that hold a live native-run claim and are in
|
|
20
|
+
* prebuild, pods or compile here, not on a build machine, plus the build slots this Mac holds for other Macs'
|
|
21
|
+
* offloaded builds. `maxBuilds` is `concurrency.maxBuilds`, 0 when unlimited.
|
|
22
|
+
*/
|
|
23
|
+
interface MachineCapacity {
|
|
24
|
+
cpus: number;
|
|
25
|
+
loadPerCore: number;
|
|
26
|
+
builds: number;
|
|
27
|
+
maxBuilds: number;
|
|
28
|
+
maxLoadPerCore: number;
|
|
29
|
+
}
|
|
30
|
+
declare function machineCapacity(): MachineCapacity;
|
|
31
|
+
/** Why a Mac with this capacity should not take another native build; null when it can. */
|
|
32
|
+
declare function saturation(capacity: MachineCapacity): string | null;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region state/build-machines.d.ts
|
|
35
|
+
/**
|
|
36
|
+
* A build machine this Mac asked to build on. `machine` is the `offload.machines` entry; `nodeId` is the
|
|
37
|
+
* worker's tailnet StableID pinned when the request was sent, which every later connection must match.
|
|
38
|
+
*/
|
|
39
|
+
interface BuildMachineCredential {
|
|
40
|
+
machine: string;
|
|
41
|
+
nodeId: string;
|
|
42
|
+
dnsName: string;
|
|
43
|
+
deviceId: string;
|
|
44
|
+
deviceToken: string;
|
|
45
|
+
state: "pending" | "approved";
|
|
46
|
+
requestedAt: string;
|
|
47
|
+
}
|
|
48
|
+
declare function readBuildMachines(): BuildMachineCredential[];
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region state/config-types.d.ts
|
|
51
|
+
type SettingsObject = Record<string, unknown>;
|
|
52
|
+
interface SupervisorRecord {
|
|
53
|
+
processToken?: string;
|
|
54
|
+
pid?: number;
|
|
55
|
+
port?: number;
|
|
56
|
+
startedAt?: string;
|
|
57
|
+
serverPid?: number;
|
|
58
|
+
mode?: string;
|
|
59
|
+
[key: string]: unknown;
|
|
60
|
+
}
|
|
61
|
+
interface IosDeviceRecord {
|
|
62
|
+
deviceUdid?: string;
|
|
63
|
+
deviceName?: string | null;
|
|
64
|
+
owned?: boolean;
|
|
65
|
+
serial?: string;
|
|
66
|
+
simslimManaged?: boolean;
|
|
67
|
+
schemeApprovals?: string[];
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
interface AndroidDeviceRecord {
|
|
71
|
+
avdName?: string;
|
|
72
|
+
consolePort?: number;
|
|
73
|
+
serial?: string;
|
|
74
|
+
kind?: string;
|
|
75
|
+
deviceName?: string | null;
|
|
76
|
+
owned?: boolean;
|
|
77
|
+
setupIncomplete?: boolean;
|
|
78
|
+
bootPending?: boolean;
|
|
79
|
+
[key: string]: unknown;
|
|
80
|
+
}
|
|
81
|
+
type DeviceRecord = IosDeviceRecord | AndroidDeviceRecord;
|
|
82
|
+
interface PlatformRecords {
|
|
83
|
+
ios?: IosDeviceRecord;
|
|
84
|
+
android?: AndroidDeviceRecord;
|
|
85
|
+
[platform: string]: DeviceRecord | undefined;
|
|
86
|
+
}
|
|
87
|
+
interface ProjectRecord {
|
|
88
|
+
ports?: Record<string, number>;
|
|
89
|
+
metroPort?: number | null;
|
|
90
|
+
platforms?: PlatformRecords;
|
|
91
|
+
deviceSlots?: Record<string, PlatformRecords>;
|
|
92
|
+
supervisor?: SupervisorRecord;
|
|
93
|
+
settings?: SettingsObject;
|
|
94
|
+
worktreeRoot?: boolean;
|
|
95
|
+
worktreeBranch?: string;
|
|
96
|
+
worktreeBranchOwned?: boolean;
|
|
97
|
+
worktreeMainRoot?: string;
|
|
98
|
+
worktreeRemovalComplete?: boolean;
|
|
99
|
+
worktreePendingBranchSha?: string;
|
|
100
|
+
label?: string;
|
|
101
|
+
bundleId?: string;
|
|
102
|
+
androidPackage?: string;
|
|
103
|
+
isExpo?: boolean;
|
|
104
|
+
lastBuild?: Record<string, unknown>;
|
|
105
|
+
doctorRuns?: Partial<Record<"ios" | "android", DoctorRunRecord>>;
|
|
106
|
+
[key: string]: unknown;
|
|
107
|
+
}
|
|
108
|
+
interface DoctorRunRecord {
|
|
109
|
+
at: string;
|
|
110
|
+
version: string;
|
|
111
|
+
}
|
|
112
|
+
interface RepoRecord {
|
|
113
|
+
settings?: SettingsObject;
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
}
|
|
116
|
+
interface ConcurrencyLimits {
|
|
117
|
+
maxBuilds: number;
|
|
118
|
+
maxDevices: number;
|
|
119
|
+
}
|
|
120
|
+
interface StimConfig {
|
|
121
|
+
version?: number;
|
|
122
|
+
projects: Record<string, ProjectRecord>;
|
|
123
|
+
repos: Record<string, RepoRecord>;
|
|
124
|
+
tempDir?: unknown;
|
|
125
|
+
iosSimulatorApp?: unknown;
|
|
126
|
+
androidEmulatorApp?: unknown;
|
|
127
|
+
optimizations?: unknown;
|
|
128
|
+
concurrency?: {
|
|
129
|
+
maxBuilds?: unknown;
|
|
130
|
+
maxDevices?: unknown;
|
|
131
|
+
};
|
|
132
|
+
pool?: {
|
|
133
|
+
iosParkedMax?: unknown;
|
|
134
|
+
androidParkedMax?: unknown;
|
|
135
|
+
};
|
|
136
|
+
parked?: {
|
|
137
|
+
ios?: unknown;
|
|
138
|
+
android?: unknown;
|
|
139
|
+
};
|
|
140
|
+
caches?: {
|
|
141
|
+
buildCache?: unknown;
|
|
142
|
+
metroCache?: unknown;
|
|
143
|
+
};
|
|
144
|
+
hosting?: {
|
|
145
|
+
machines?: unknown;
|
|
146
|
+
agentDriver?: unknown;
|
|
147
|
+
};
|
|
148
|
+
server?: {
|
|
149
|
+
acceptClientBuilds?: unknown;
|
|
150
|
+
};
|
|
151
|
+
offload?: {
|
|
152
|
+
machine?: unknown;
|
|
153
|
+
machines?: unknown;
|
|
154
|
+
mode?: unknown;
|
|
155
|
+
workerRoot?: unknown;
|
|
156
|
+
maxLoadPerCore?: unknown;
|
|
157
|
+
gradleDaemonIdleMinutes?: unknown;
|
|
158
|
+
};
|
|
159
|
+
[key: string]: unknown;
|
|
160
|
+
}
|
|
161
|
+
type Config = StimConfig;
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region state/config.d.ts
|
|
164
|
+
declare function withConfigLock<T>(fn: () => T): T;
|
|
165
|
+
declare function configCorruptRepair(path?: string): string;
|
|
166
|
+
/** The build worker root: `offload.workerRoot` when it is absolute, else `$STIM_HOME/build-worker`. */
|
|
167
|
+
declare function buildWorkerRoot(config?: Config | null): string;
|
|
168
|
+
declare function loadConfig(): Config | null;
|
|
169
|
+
declare function getProject(projectPath: string): ProjectRecord | null;
|
|
170
|
+
declare function getConcurrencyLimits({ env }?: {
|
|
171
|
+
env?: NodeJS.ProcessEnv;
|
|
172
|
+
}): ConcurrencyLimits;
|
|
173
|
+
declare function getProjectSettings(projectPath: string): Record<string, unknown>;
|
|
174
|
+
declare function getProjectSetting(projectPath: string, dottedKey: string): unknown;
|
|
175
|
+
declare function getRepoSettings(gitCommonDir: string): Record<string, unknown>;
|
|
176
|
+
declare function isPathPrefix(prefix: string, path: string): boolean;
|
|
177
|
+
declare function findEnclosingWorktreeRoot(projectPath: string): string | null;
|
|
178
|
+
declare function allMetroPorts(): number[];
|
|
179
|
+
declare function findProjectByMetroPort(port: number): string | null;
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region state/json-file.d.ts
|
|
182
|
+
/**
|
|
183
|
+
* Runs `fn` with each state file read from disk at most once: inside it, including after an `await`, `readStateFile`
|
|
184
|
+
* 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
|
|
185
|
+
* share a mutable object. Only for computations that write none of the files they read.
|
|
186
|
+
*/
|
|
187
|
+
declare function withStateReadCache<T>(fn: () => T): T;
|
|
188
|
+
declare function readStateFile(path: string): string;
|
|
189
|
+
declare function readJsonFile(path: string): unknown;
|
|
190
|
+
declare function isJsonObject(value: unknown): value is Record<string, unknown>;
|
|
191
|
+
declare function readJsonObject(path: string): Record<string, unknown> | null;
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region state/ledgers.d.ts
|
|
194
|
+
type CreatedDevicePlatform = "ios" | "android" | "web";
|
|
195
|
+
/** `web` lists the absolute paths of browser profile directories Stim created. */
|
|
196
|
+
interface CreatedDevices {
|
|
197
|
+
ios: ReadonlySet<string>;
|
|
198
|
+
android: ReadonlySet<string>;
|
|
199
|
+
web: ReadonlySet<string>;
|
|
200
|
+
}
|
|
201
|
+
declare function readCreatedDevices(): CreatedDevices;
|
|
202
|
+
interface EasSessionClaim {
|
|
203
|
+
sessionId: string;
|
|
204
|
+
name: string;
|
|
205
|
+
platform: "ios" | "android";
|
|
206
|
+
workspaceRoot: string;
|
|
207
|
+
workspaceHome: string;
|
|
208
|
+
stateFile: string;
|
|
209
|
+
}
|
|
210
|
+
interface EasSessionLedgerRead {
|
|
211
|
+
claims: Map<string, EasSessionClaim>;
|
|
212
|
+
notice: string | null;
|
|
213
|
+
safe: boolean;
|
|
214
|
+
}
|
|
215
|
+
/** Returns the claim normalized to canonical paths, or null when it is not a valid claim for `id`. */
|
|
216
|
+
declare function validEasSessionClaim(id: string, value: unknown): EasSessionClaim | null;
|
|
217
|
+
declare function readEasSessionLedger(root?: string): EasSessionLedgerRead;
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region state/ndjson.d.ts
|
|
220
|
+
interface NdjsonRecord {
|
|
221
|
+
ts?: number;
|
|
222
|
+
src?: string;
|
|
223
|
+
level?: string;
|
|
224
|
+
msg?: string;
|
|
225
|
+
/** With `logs --errors --json`: the code frame and stack lines Expo printed after this error. */
|
|
226
|
+
context?: string[];
|
|
227
|
+
[key: string]: unknown;
|
|
228
|
+
}
|
|
229
|
+
declare const LEVELS: string[];
|
|
230
|
+
declare const SOURCES: string[];
|
|
231
|
+
declare function levelRank(level?: string): number;
|
|
232
|
+
declare function parseNdjsonLine(line: unknown): NdjsonRecord | null;
|
|
233
|
+
declare function parseNdjsonText(text: unknown): NdjsonRecord[];
|
|
234
|
+
declare function readNdjsonGenerations(file: string): NdjsonRecord[];
|
|
235
|
+
//#endregion
|
|
236
|
+
//#region state/error-entries.d.ts
|
|
237
|
+
/**
|
|
238
|
+
* The number of rows a log list shows for `records`, an error query's result in log order. Stim Desktop's
|
|
239
|
+
* `LogEntryList` and the phone's `groupRecords` group the same way and replay the same vectors: in Expo's dev
|
|
240
|
+
* server one failed bundle is a `Bundling failed` marker line, the error line and a failed bundle response,
|
|
241
|
+
* which the apps list as one row, and every other record is its own row.
|
|
242
|
+
*/
|
|
243
|
+
declare function countErrorEntries(records: readonly NdjsonRecord[]): number;
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region state/logs-query.d.ts
|
|
246
|
+
interface SinceResult {
|
|
247
|
+
ms?: number;
|
|
248
|
+
error?: string;
|
|
249
|
+
}
|
|
250
|
+
interface GrepResult {
|
|
251
|
+
re?: RegExp;
|
|
252
|
+
error?: string;
|
|
253
|
+
}
|
|
254
|
+
interface MarkerWindow {
|
|
255
|
+
launchTs: number | null;
|
|
256
|
+
bundleTs: number | null;
|
|
257
|
+
pageLoadTs: number | null;
|
|
258
|
+
}
|
|
259
|
+
interface QueryCriteria {
|
|
260
|
+
slot?: string;
|
|
261
|
+
includeAppDeviceErrors?: boolean;
|
|
262
|
+
sources?: string[];
|
|
263
|
+
minLevel?: string;
|
|
264
|
+
grep?: RegExp;
|
|
265
|
+
sinceTs?: number;
|
|
266
|
+
errorsOnly?: boolean;
|
|
267
|
+
markerTs?: number;
|
|
268
|
+
bundleMarkerTs?: number;
|
|
269
|
+
}
|
|
270
|
+
interface TailState {
|
|
271
|
+
offset: number;
|
|
272
|
+
partial: string;
|
|
273
|
+
}
|
|
274
|
+
declare function parseSince(text: unknown): SinceResult;
|
|
275
|
+
declare function compileGrep(pattern: unknown): GrepResult;
|
|
276
|
+
declare const ERROR_SOURCES: string[];
|
|
277
|
+
declare function markerWindow(records: NdjsonRecord[]): MarkerWindow;
|
|
278
|
+
/**
|
|
279
|
+
* The platform a bundle marker speaks for, lowercased: its `platform` field, or the tag @expo/cli prints before
|
|
280
|
+
* "Bundled" ("iOS", "Android", "Web", "RSC(iOS)" as ios, or an environment tag such as "DOM"). Null when unknown.
|
|
281
|
+
*/
|
|
282
|
+
declare function bundleMarkerPlatform(record: NdjsonRecord): string | null;
|
|
283
|
+
declare function recordMatches(record: NdjsonRecord | null | undefined, criteria?: QueryCriteria): boolean;
|
|
284
|
+
declare function buildCriteria({ slot, sources, minLevel, since, grep, errorsOnly, markerTs, bundleMarkerTs, now }?: {
|
|
285
|
+
slot?: string;
|
|
286
|
+
sources?: string[];
|
|
287
|
+
minLevel?: string;
|
|
288
|
+
since?: string | null;
|
|
289
|
+
grep?: string | RegExp | null;
|
|
290
|
+
errorsOnly?: boolean;
|
|
291
|
+
markerTs?: number;
|
|
292
|
+
bundleMarkerTs?: number;
|
|
293
|
+
now?: number;
|
|
294
|
+
}): QueryCriteria;
|
|
295
|
+
declare function logFiles(dir: string): string[];
|
|
296
|
+
declare function fileSizes(dir: string): Record<string, number>;
|
|
297
|
+
declare function readLogRecords(dir: string, include?: (name: string) => boolean): NdjsonRecord[];
|
|
298
|
+
type ExpoContextTarget = "msg" | "field";
|
|
299
|
+
/**
|
|
300
|
+
* Adds the code frame and stack lines Expo printed after each Expo error record, either joined into
|
|
301
|
+
* `msg` or as a `context` string array.
|
|
302
|
+
*/
|
|
303
|
+
declare function attachExpoErrorContext(all: NdjsonRecord[], matched: NdjsonRecord[], into?: ExpoContextTarget): NdjsonRecord[];
|
|
304
|
+
declare function queryLogs({ slot, dir, records, sources, minLevel, since, grep, tail, errorsOnly, errorContext, now }?: {
|
|
305
|
+
slot?: string;
|
|
306
|
+
dir?: string;
|
|
307
|
+
records?: NdjsonRecord[];
|
|
308
|
+
sources?: string[];
|
|
309
|
+
minLevel?: string;
|
|
310
|
+
since?: string;
|
|
311
|
+
grep?: string | RegExp;
|
|
312
|
+
tail?: number;
|
|
313
|
+
errorsOnly?: boolean;
|
|
314
|
+
errorContext?: boolean;
|
|
315
|
+
now?: number;
|
|
316
|
+
}): NdjsonRecord[];
|
|
317
|
+
declare function tailRead(prev: TailState | null | undefined, size: number): {
|
|
318
|
+
start: number;
|
|
319
|
+
prev: TailState;
|
|
320
|
+
};
|
|
321
|
+
declare function advanceTail(prev: TailState | null | undefined, chunk: string | null | undefined, size: number): {
|
|
322
|
+
state: TailState;
|
|
323
|
+
records: NdjsonRecord[];
|
|
324
|
+
};
|
|
325
|
+
declare function followLogs({ dir, onRecord, criteria, intervalMs, offsets, errorContext }: {
|
|
326
|
+
dir: string;
|
|
327
|
+
onRecord: (record: NdjsonRecord) => void;
|
|
328
|
+
criteria?: QueryCriteria;
|
|
329
|
+
intervalMs?: number;
|
|
330
|
+
offsets?: Record<string, number> | null;
|
|
331
|
+
/** Holds each Expo error until a poll adds no more of its code frame or stack lines, then attaches them. */
|
|
332
|
+
errorContext?: ExpoContextTarget;
|
|
333
|
+
}): () => void;
|
|
334
|
+
declare function sortByTs(records: NdjsonRecord[]): NdjsonRecord[];
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region state/paths.d.ts
|
|
337
|
+
declare function getConfigPath(): string;
|
|
338
|
+
declare function configLockPath(): string;
|
|
339
|
+
declare function workspaceMetadataFile(projectRoot: string): string;
|
|
340
|
+
declare function workspaceLogsDir(projectRoot: string): string;
|
|
341
|
+
/** Device screen footage stim-server records for the workspace, one directory per platform and slot. */
|
|
342
|
+
declare function workspaceRecordingsDir(projectRoot: string): string;
|
|
343
|
+
declare function workspaceLogErrorIndex(projectRoot: string): string;
|
|
344
|
+
declare function workspaceDerivedData(projectRoot: string): string;
|
|
345
|
+
declare function workspaceGradleBuild(projectRoot: string): string;
|
|
346
|
+
declare function workspaceBuildDetailFile(projectRoot: string): string;
|
|
347
|
+
/** The agent sessions that stopped running in the workspace in the last `ENDED_AGENT_RETENTION_MS`. */
|
|
348
|
+
declare function workspaceEndedAgentsFile(projectRoot: string): string;
|
|
349
|
+
declare function workspaceEndedAgentsLock(projectRoot: string): string;
|
|
350
|
+
declare function supervisorPidFile(projectRoot: string): string;
|
|
351
|
+
declare function workspaceStateFile(projectRoot: string): string;
|
|
352
|
+
declare function workspaceStateLock(projectRoot: string): string;
|
|
353
|
+
declare function supervisorLogFile(projectRoot: string): string;
|
|
354
|
+
declare function emulatorLogFile(projectRoot: string): string;
|
|
355
|
+
declare function sharedCompilationCache(): string;
|
|
356
|
+
declare function sharedCcache(): string;
|
|
357
|
+
declare function sharedGradle(): string;
|
|
358
|
+
declare function sharedPods(): string;
|
|
359
|
+
declare function createdDevicesFile(): string;
|
|
360
|
+
declare function gitMergeCacheDir(): string;
|
|
361
|
+
declare function pullRequestCacheDir(): string;
|
|
362
|
+
declare function agentSessionsCacheFile(): string;
|
|
363
|
+
declare function diskUsageCacheDir(): string;
|
|
364
|
+
/** The build machines this Mac paired with, each with its pinned tailnet node and device token. */
|
|
365
|
+
declare function buildMachinesFile(): string;
|
|
366
|
+
declare function buildMachinesLock(): string;
|
|
367
|
+
/** The hosting machines this Mac asked for access, separate from build credentials. */
|
|
368
|
+
declare function deviceHostMachinesFile(): string;
|
|
369
|
+
declare function deviceHostMachinesLock(): string;
|
|
370
|
+
declare function deviceHostMachinesClaims(): string;
|
|
371
|
+
declare function createdDevicesLock(): string;
|
|
372
|
+
/** The EAS session ledger lives under the real home directory, never under STIM_HOME. */
|
|
373
|
+
declare function easMachineStateRoot(): string;
|
|
374
|
+
declare function easSessionLedgerFile(root?: string): string;
|
|
375
|
+
declare function easSessionLedgerLock(root?: string): string;
|
|
376
|
+
/** Where stim-server records, one file per server process, the devices whose frames a client subscribes to. */
|
|
377
|
+
declare function deviceViewersDir(): string;
|
|
378
|
+
declare function statsFile(): string;
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region state/recordings.d.ts
|
|
381
|
+
/** The footage stim-server keeps per device: the last 15 minutes recorded, however long ago. */
|
|
382
|
+
declare const RECORDING_FOOTAGE_MS: number;
|
|
383
|
+
/** The recordings of every workspace of one Stim home together; past it the oldest footage goes first. */
|
|
384
|
+
declare const RECORDING_CAP_BYTES: number;
|
|
385
|
+
/** The platforms stim-server records: owned simulators and emulators, and the Stim-owned Chrome page. */
|
|
386
|
+
declare const RECORDING_PLATFORMS: readonly ["ios", "android", "web"];
|
|
387
|
+
type RecordingPlatform = (typeof RECORDING_PLATFORMS)[number];
|
|
388
|
+
/**
|
|
389
|
+
* One file of H.264 footage. A closed segment is named `<start>-<end>.seg`, in epoch milliseconds of its first and
|
|
390
|
+
* last access unit; the segment being written is `<start>.part`, and its end is its modification time.
|
|
391
|
+
*/
|
|
392
|
+
interface RecordedSegment {
|
|
393
|
+
file: string;
|
|
394
|
+
start: number;
|
|
395
|
+
end: number;
|
|
396
|
+
bytes: number;
|
|
397
|
+
open: boolean;
|
|
398
|
+
}
|
|
399
|
+
interface RecordedDevice {
|
|
400
|
+
platform: RecordingPlatform;
|
|
401
|
+
slot: string;
|
|
402
|
+
dir: string;
|
|
403
|
+
segments: RecordedSegment[];
|
|
404
|
+
}
|
|
405
|
+
/** The directory under a workspace's recordings that holds one device slot's footage. */
|
|
406
|
+
declare function recordingDeviceName(platform: RecordingPlatform, slot: string): string;
|
|
407
|
+
/** Segment names hold whole milliseconds: the start rounded down and the end rounded up. */
|
|
408
|
+
declare function closedSegmentName(start: number, end: number): string;
|
|
409
|
+
declare function openSegmentName(start: number): string;
|
|
410
|
+
/** The segments in one device directory, oldest first. Files that are not segments are left out. */
|
|
411
|
+
declare function listSegments(dir: string): RecordedSegment[];
|
|
412
|
+
/** Every device slot recorded under a workspace's recordings directory. */
|
|
413
|
+
declare function listRecordedDevices(recordingsDir: string): RecordedDevice[];
|
|
414
|
+
declare function recordedBytes(devices: readonly RecordedDevice[]): number;
|
|
415
|
+
/**
|
|
416
|
+
* The oldest closed segments to delete so that one device keeps at most `footageMs` of footage. Time between
|
|
417
|
+
* segments, while nothing was recorded, does not count. The open segment is never chosen.
|
|
418
|
+
*/
|
|
419
|
+
declare function footageDrops(segments: readonly RecordedSegment[], footageMs: number): RecordedSegment[];
|
|
420
|
+
/** The oldest closed segments across all devices to delete so that together they hold at most `capBytes`. */
|
|
421
|
+
declare function capDrops(devices: readonly RecordedDevice[], capBytes: number): RecordedSegment[];
|
|
422
|
+
/**
|
|
423
|
+
* Whether stim-server records a workspace's devices: `STIM_RECORDING`, then `recording.enabled` in the workspace,
|
|
424
|
+
* repo and machine layers, in that order, and true by default.
|
|
425
|
+
*/
|
|
426
|
+
declare function recordingEnabled(env: NodeJS.ProcessEnv, layers: readonly unknown[]): boolean;
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region state/settings-registry.d.ts
|
|
429
|
+
declare const ANDROID_COMPILER_CACHE_CHOICES: readonly ["auto", "ccache", "cas", "none"];
|
|
430
|
+
declare const ANDROID_PCH_CHOICES: readonly ["auto", "on", "off"];
|
|
431
|
+
type TunnelMode = "auto" | "off" | "expo" | "cloudflared" | "ngrok" | "tailscale";
|
|
432
|
+
declare const TUNNEL_MODES: readonly TunnelMode[];
|
|
433
|
+
type RemoteDeviceBackend = "proxy" | "eas";
|
|
434
|
+
type SettingScope = "machine" | "workspace" | "repo" | "committed";
|
|
435
|
+
declare const SETTING_SCOPES: readonly SettingScope[];
|
|
436
|
+
type SettingType = {
|
|
437
|
+
kind: "string";
|
|
438
|
+
pattern?: string;
|
|
439
|
+
patternHelp?: string;
|
|
440
|
+
} | {
|
|
441
|
+
kind: "path";
|
|
442
|
+
absolute?: boolean;
|
|
443
|
+
relative?: boolean;
|
|
444
|
+
} | {
|
|
445
|
+
kind: "strings";
|
|
446
|
+
} | {
|
|
447
|
+
kind: "number";
|
|
448
|
+
integer?: boolean;
|
|
449
|
+
minimum?: number;
|
|
450
|
+
maximum?: number;
|
|
451
|
+
} | {
|
|
452
|
+
kind: "boolean";
|
|
453
|
+
} | {
|
|
454
|
+
kind: "choice";
|
|
455
|
+
choices: readonly string[];
|
|
456
|
+
} | {
|
|
457
|
+
kind: "object";
|
|
458
|
+
} | {
|
|
459
|
+
kind: "bundle-url";
|
|
460
|
+
};
|
|
461
|
+
/**
|
|
462
|
+
* One setting Stim reads. `scopes` are the layers the setting may be written to;
|
|
463
|
+
* `committedAt: 'repository'` reads the committed layer from the repository root's
|
|
464
|
+
* `.stim.json` instead of the app's. A `sensitive` value is never printed and is
|
|
465
|
+
* written to `.stim.json` only as an `env:` or `file:` reference. `scopedHomeValue`
|
|
466
|
+
* replaces every layer and the default while STIM_HOME is set and `env` is not.
|
|
467
|
+
* `desktopDefault` replaces `default` on macOS while Stim Desktop is installed.
|
|
468
|
+
*/
|
|
469
|
+
interface SettingDefinition {
|
|
470
|
+
key: string;
|
|
471
|
+
type: SettingType;
|
|
472
|
+
scopes: readonly SettingScope[];
|
|
473
|
+
description: string;
|
|
474
|
+
default?: string | number | boolean;
|
|
475
|
+
env?: string;
|
|
476
|
+
sensitive?: boolean;
|
|
477
|
+
committedAt?: "repository";
|
|
478
|
+
scopedHomeValue?: number;
|
|
479
|
+
desktopDefault?: string;
|
|
480
|
+
}
|
|
481
|
+
interface SettingEntry {
|
|
482
|
+
key: string;
|
|
483
|
+
value: unknown;
|
|
484
|
+
origin: SettingScope | "env" | "default" | null;
|
|
485
|
+
layers: Partial<Record<SettingScope, unknown>>;
|
|
486
|
+
env?: {
|
|
487
|
+
name: string;
|
|
488
|
+
value: string;
|
|
489
|
+
};
|
|
490
|
+
sensitive?: true;
|
|
491
|
+
defaultReason?: string;
|
|
492
|
+
}
|
|
493
|
+
/** The payload `stim settings --json` prints. */
|
|
494
|
+
interface SettingsPayload {
|
|
495
|
+
project: string | null;
|
|
496
|
+
files: Partial<Record<SettingScope, string>>;
|
|
497
|
+
settings: SettingEntry[];
|
|
498
|
+
unknown: Array<{
|
|
499
|
+
key: string;
|
|
500
|
+
scope: SettingScope;
|
|
501
|
+
file: string;
|
|
502
|
+
value: unknown;
|
|
503
|
+
}>;
|
|
504
|
+
}
|
|
505
|
+
declare const REMOTE_DEVICE_BACKENDS: readonly RemoteDeviceBackend[];
|
|
506
|
+
declare const IOS_SIMULATOR_APPS: readonly ["xcode", "siniulator", "stim-desktop"];
|
|
507
|
+
declare const ANDROID_EMULATOR_APPS: readonly ["emulator", "stim-desktop"];
|
|
508
|
+
declare const OFFLOAD_MODES: readonly ["auto", "force", "off"];
|
|
509
|
+
type OffloadMode = (typeof OFFLOAD_MODES)[number];
|
|
510
|
+
declare const WEB_VIEWPORTS: readonly ["desktop", "phone"];
|
|
511
|
+
type WebViewport = (typeof WEB_VIEWPORTS)[number];
|
|
512
|
+
declare const SETTINGS: readonly SettingDefinition[];
|
|
513
|
+
declare function settingDefinition(key: string): SettingDefinition | null;
|
|
514
|
+
declare function isLayeredSetting(setting: SettingDefinition): boolean;
|
|
515
|
+
declare const SETTING_GROUPS: readonly string[];
|
|
516
|
+
declare function expectedShape(type: SettingType): string;
|
|
517
|
+
declare function acceptsShape(setting: SettingDefinition, value: unknown): boolean;
|
|
518
|
+
declare function settingValueError(setting: SettingDefinition, value: unknown): string | null;
|
|
519
|
+
declare function isSensitiveReference(value: unknown): boolean;
|
|
520
|
+
/**
|
|
521
|
+
* Coerces raw text (a CLI argument or an environment variable) through a setting's
|
|
522
|
+
* registry type, the same way for both sources. Types whose values are not written
|
|
523
|
+
* as bare text (boolean, number, strings, object) are read as JSON; a value that
|
|
524
|
+
* fails to parse is left as the original string so `settingValueError` reports it. A boolean also reads `1` and `0`.
|
|
525
|
+
*/
|
|
526
|
+
declare function coerceSettingText(setting: SettingDefinition, raw: string): unknown;
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region state/settings-schema.d.ts
|
|
529
|
+
declare const SETTINGS_SCHEMA_FILE = "settings.schema.json";
|
|
530
|
+
declare const SETTINGS_SCHEMA_URL: string;
|
|
531
|
+
type JsonSchema = Record<string, unknown>;
|
|
532
|
+
/**
|
|
533
|
+
* The published settings schema. The root describes a committed `.stim.json`;
|
|
534
|
+
* `$defs.machine` describes the settings keys of `$STIM_HOME/config.json`.
|
|
535
|
+
* Every leaf carries `x-stim` with its dotted key, kind, writable scopes,
|
|
536
|
+
* environment override, and sensitivity.
|
|
537
|
+
*/
|
|
538
|
+
declare function settingsJsonSchema(): JsonSchema;
|
|
539
|
+
//#endregion
|
|
540
|
+
//#region state/hosted-app.d.ts
|
|
541
|
+
interface HostedAppFile {
|
|
542
|
+
path: string;
|
|
543
|
+
kind: "file" | "exec" | "link";
|
|
544
|
+
size: number;
|
|
545
|
+
sha256: string;
|
|
546
|
+
}
|
|
547
|
+
interface HostedAppOffer {
|
|
548
|
+
session: string;
|
|
549
|
+
attempt: string;
|
|
550
|
+
bundleId: string;
|
|
551
|
+
mode: "development" | "release";
|
|
552
|
+
devClientScheme?: string;
|
|
553
|
+
arguments?: string[];
|
|
554
|
+
manifest: {
|
|
555
|
+
sha256: string;
|
|
556
|
+
size: number;
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
interface HostedAppDelivery extends Omit<HostedAppOffer, "manifest"> {
|
|
560
|
+
state: "receiving" | "installing" | "installed" | "unknown";
|
|
561
|
+
launched: true | "unverified" | null;
|
|
562
|
+
notice?: string;
|
|
563
|
+
}
|
|
564
|
+
interface HostedAppRecord extends HostedAppDelivery {
|
|
565
|
+
manifest: HostedAppOffer["manifest"];
|
|
566
|
+
files: HostedAppFile[];
|
|
567
|
+
}
|
|
568
|
+
declare const HOSTED_APP_CHUNK_BYTES: number;
|
|
569
|
+
declare function hostedAppAttempt(value: unknown): value is string;
|
|
570
|
+
declare function hostedAppArea(session: string, attempt: string, workerHome?: string): string;
|
|
571
|
+
/** At most 32 plain arguments of 1024 characters (8192 in total), with no NUL, CR or LF. */
|
|
572
|
+
declare function validHostedAppArguments(value: unknown): value is string[];
|
|
573
|
+
declare function parseHostedAppOffer(value: unknown): HostedAppOffer | null;
|
|
574
|
+
/** Relative normalized paths, with no file or link as another entry's ancestor. */
|
|
575
|
+
declare function parseHostedAppManifest(value: unknown): HostedAppFile[] | null;
|
|
576
|
+
/** Reads a server-written receipt; malformed or missing established state remains unresolved. */
|
|
577
|
+
declare function readHostedAppMetadata(session: string, attempt: string, workerHome?: string): Omit<HostedAppRecord, "files">;
|
|
578
|
+
declare function readHostedApp(session: string, attempt: string, workerHome?: string): HostedAppRecord;
|
|
579
|
+
//#endregion
|
|
580
|
+
//#region state/hosted-macos.d.ts
|
|
581
|
+
/** App slots one host offers; a slot names the host-assigned bundle id `<bundleId>.hosted<slot>`. */
|
|
582
|
+
declare const HOSTED_MACOS_APP_SLOTS = 64;
|
|
583
|
+
declare const HOSTED_AGENT_DRIVERS: readonly ["none", "agent-device"];
|
|
584
|
+
type HostedAgentDriverName = (typeof HOSTED_AGENT_DRIVERS)[number];
|
|
585
|
+
/** What a host reports in a macOS offer: no simulator is created, so the choice is the host itself. */
|
|
586
|
+
interface HostedMacosChoice {
|
|
587
|
+
architecture: "arm64" | "x86_64";
|
|
588
|
+
macosVersion: string;
|
|
589
|
+
}
|
|
590
|
+
/** A ready hosted macOS session's identity: the host it runs on and the app slot reserved for it. */
|
|
591
|
+
interface HostedMacosDevice extends HostedMacosChoice {
|
|
592
|
+
appSlot: number;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* The rest of an agent-device `macos-app` lease's owner scope, which a client names on every request:
|
|
596
|
+
* `deviceKey` is `<bundleId>@<pid>` of the hosted app.
|
|
597
|
+
*/
|
|
598
|
+
interface HostedAgentLease {
|
|
599
|
+
tenant: string;
|
|
600
|
+
runId: string;
|
|
601
|
+
clientId: string;
|
|
602
|
+
deviceKey: string;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Agent control the host grants a client for one installed hosted app, sent only over that client's approved
|
|
606
|
+
* device-host connection and never journaled. `none` means the host's `hosting.agentDriver` starts no driver.
|
|
607
|
+
* `path` is the session's base route on the host, `scope` the driver's handle that limits it to this one app,
|
|
608
|
+
* and `lease` the scope the driver's lease was allocated with.
|
|
609
|
+
*/
|
|
610
|
+
type HostedAgentGrant = {
|
|
611
|
+
driver: "none";
|
|
612
|
+
} | {
|
|
613
|
+
driver: Exclude<HostedAgentDriverName, "none">;
|
|
614
|
+
path: string;
|
|
615
|
+
token: string;
|
|
616
|
+
scope: string;
|
|
617
|
+
lease: HostedAgentLease;
|
|
618
|
+
};
|
|
619
|
+
/** `app.launch` and `app.attach` results; a host includes `agent` once the app is installed. */
|
|
620
|
+
type HostedAppLaunch = HostedAppDelivery & {
|
|
621
|
+
agent?: HostedAgentGrant;
|
|
622
|
+
};
|
|
623
|
+
/**
|
|
624
|
+
* Agent control as the client hands it to a coding agent: secrets stay in files Stim writes with mode
|
|
625
|
+
* 0600, and `command` shows how to address the hosted app. Never carries a token inline. `setting` names
|
|
626
|
+
* the hosting Mac's setting that turns a driver on.
|
|
627
|
+
*/
|
|
628
|
+
type HostedAgentAccess = {
|
|
629
|
+
driver: "none";
|
|
630
|
+
setting: "hosting.agentDriver";
|
|
631
|
+
} | {
|
|
632
|
+
driver: "agent-device";
|
|
633
|
+
remoteConfig: string;
|
|
634
|
+
command: string;
|
|
635
|
+
};
|
|
636
|
+
/** Where a workspace's macOS app runs when `stim macos --remote` placed it on another Mac. */
|
|
637
|
+
interface HostedMacosPlacement {
|
|
638
|
+
machine: string;
|
|
639
|
+
session: string;
|
|
640
|
+
appSlot: number;
|
|
641
|
+
appAttempt: string;
|
|
642
|
+
/** The host-assigned id the running app uses, `hostedMacosBundleId(<offered id>, appSlot)`. */
|
|
643
|
+
bundleId: string;
|
|
644
|
+
agent: HostedAgentAccess;
|
|
645
|
+
}
|
|
646
|
+
declare function hostedMacosAppSlot(value: unknown): value is number;
|
|
647
|
+
declare function hostedMacosBundleId(bundleId: string, appSlot: number): string;
|
|
648
|
+
declare function parseHostedMacosChoice(value: unknown): HostedMacosChoice | null;
|
|
649
|
+
declare function parseHostedMacosDevice(value: unknown): HostedMacosDevice | null;
|
|
650
|
+
/** A grant naming a driver this client does not know is not usable; it parses as null. */
|
|
651
|
+
declare function parseHostedAgentGrant(value: unknown): HostedAgentGrant | null;
|
|
652
|
+
declare function parseHostedMacosPlacement(value: unknown): HostedMacosPlacement | null;
|
|
653
|
+
//#endregion
|
|
654
|
+
//#region state/macos.d.ts
|
|
655
|
+
interface MacosProcess {
|
|
656
|
+
pid: number;
|
|
657
|
+
processToken: string;
|
|
658
|
+
startedAtMicros: number;
|
|
659
|
+
}
|
|
660
|
+
interface MacosBuild {
|
|
661
|
+
state: "running" | "ok" | "failed";
|
|
662
|
+
startedAt: string;
|
|
663
|
+
finishedAt?: string;
|
|
664
|
+
durationMs?: number;
|
|
665
|
+
error?: string;
|
|
666
|
+
errorCode?: string;
|
|
667
|
+
buildMachine?: string;
|
|
668
|
+
builtOn?: string;
|
|
669
|
+
offloadedTo?: string;
|
|
670
|
+
offloadFallback?: string;
|
|
671
|
+
}
|
|
672
|
+
interface MacosAppRecord {
|
|
673
|
+
launchId: string;
|
|
674
|
+
arguments: string[];
|
|
675
|
+
product: string;
|
|
676
|
+
bundle: string;
|
|
677
|
+
bundleId: string;
|
|
678
|
+
executable: string;
|
|
679
|
+
build: MacosBuild;
|
|
680
|
+
supervisor?: MacosProcess;
|
|
681
|
+
app?: MacosProcess;
|
|
682
|
+
/** Set when `stim macos --remote` reserved a session on another Mac; the app then has no local process. */
|
|
683
|
+
host?: HostedMacosPlacement;
|
|
684
|
+
/** Host launch evidence: true for a live app; status can override it in memory after probing the session. */
|
|
685
|
+
hostLaunched?: boolean | "unverified";
|
|
686
|
+
}
|
|
687
|
+
interface MacosAppState extends MacosAppRecord {
|
|
688
|
+
state: "running" | "orphaned" | "stopped" | "unverified";
|
|
689
|
+
}
|
|
690
|
+
declare function parseMacosRecord(value: unknown): MacosAppRecord | null;
|
|
691
|
+
declare function readMacosRecord(root: string): MacosAppRecord | null;
|
|
692
|
+
declare function readHostedMacosApp(home: string): MacosAppRecord | null;
|
|
693
|
+
declare function macosAppState(record: MacosAppRecord | null): MacosAppState | null;
|
|
694
|
+
//#endregion
|
|
695
|
+
//#region state/workspace-state.d.ts
|
|
696
|
+
interface WorkspaceState {
|
|
697
|
+
supervisor?: Record<string, unknown>;
|
|
698
|
+
collectors?: Record<string, unknown>;
|
|
699
|
+
lastBuild?: Record<string, unknown>;
|
|
700
|
+
launches?: Record<string, unknown>;
|
|
701
|
+
remoteDevice?: Record<string, unknown>;
|
|
702
|
+
metroTunnel?: Record<string, unknown>;
|
|
703
|
+
[key: string]: unknown;
|
|
704
|
+
}
|
|
705
|
+
declare const IDLE_STOP_KEY = "devServerStop";
|
|
706
|
+
/** Why the supervisor last stopped the dev server on its own: `metro.idleStopMinutes` with no use. */
|
|
707
|
+
interface IdleStopRecord {
|
|
708
|
+
reason: "idle";
|
|
709
|
+
at: string;
|
|
710
|
+
idleMinutes: number;
|
|
711
|
+
}
|
|
712
|
+
declare function readIdleStop(state: WorkspaceState | null | undefined): IdleStopRecord | null;
|
|
713
|
+
declare const DEVICE_IDLE_SHUTDOWN_KEY = "deviceIdleShutdowns";
|
|
714
|
+
/** An owned simulator or emulator the supervisor shut down after `devices.idleShutdownMinutes` with no use. */
|
|
715
|
+
interface DeviceIdleShutdownRecord {
|
|
716
|
+
at: string;
|
|
717
|
+
idleMinutes: number;
|
|
718
|
+
}
|
|
719
|
+
/** The recorded idle shutdowns by device slot key (`ios`, `android`, `ios:<slot>`). */
|
|
720
|
+
declare function readDeviceIdleShutdowns(state: WorkspaceState | null | undefined): Record<string, DeviceIdleShutdownRecord>;
|
|
721
|
+
declare const DEV_SERVER_STOP_REQUEST_KEY = "devServerStopRequest";
|
|
722
|
+
/** A Stim component's intent to stop the supervisor with `processToken`, written before it signals. */
|
|
723
|
+
interface DevServerStopRequest {
|
|
724
|
+
processToken: string;
|
|
725
|
+
by: string;
|
|
726
|
+
pid: number;
|
|
727
|
+
at: string;
|
|
728
|
+
workspace?: string;
|
|
729
|
+
}
|
|
730
|
+
declare function readDevServerStopRequest(state: WorkspaceState | null | undefined): DevServerStopRequest | null;
|
|
731
|
+
/**
|
|
732
|
+
* Why the dev server last stopped, stored under `IDLE_STOP_KEY`. `requested` names the Stim component that
|
|
733
|
+
* asked; `signal` is a SIGTERM or SIGINT no Stim component asked for; `server-exited` is the dev server
|
|
734
|
+
* process exiting on its own.
|
|
735
|
+
*/
|
|
736
|
+
type DevServerStopRecord = IdleStopRecord | {
|
|
737
|
+
reason: "requested";
|
|
738
|
+
at: string;
|
|
739
|
+
by: string;
|
|
740
|
+
byPid: number;
|
|
741
|
+
byWorkspace?: string;
|
|
742
|
+
} | {
|
|
743
|
+
reason: "signal";
|
|
744
|
+
at: string;
|
|
745
|
+
signal: string;
|
|
746
|
+
} | {
|
|
747
|
+
reason: "server-exited";
|
|
748
|
+
at: string;
|
|
749
|
+
mode: string;
|
|
750
|
+
code: number | null;
|
|
751
|
+
signal: string | null;
|
|
752
|
+
};
|
|
753
|
+
/** A stopped dev server's last cause in status; `vanished` is a supervisor proven gone that recorded none. */
|
|
754
|
+
type MetroLastStop = DevServerStopRecord | {
|
|
755
|
+
reason: "vanished";
|
|
756
|
+
pid: number;
|
|
757
|
+
startedAt: string | null;
|
|
758
|
+
};
|
|
759
|
+
declare function readDevServerStop(state: WorkspaceState | null | undefined): DevServerStopRecord | null;
|
|
760
|
+
/** Each platform's latest run; `lastBuild` holds whichever platform ran last. */
|
|
761
|
+
declare const LAST_BUILD_KEYS: Readonly<Record<StatsPlatform, string>>;
|
|
762
|
+
declare const BUILD_HISTORY_KEY = "buildHistory";
|
|
763
|
+
declare const BUILD_HISTORY_LIMIT = 10;
|
|
764
|
+
/** A recorded miss reason in the shape status reports, without `baseline.cacheKey`; null when malformed. */
|
|
765
|
+
declare function parseMissReason(value: unknown): BuildMissReason | null;
|
|
766
|
+
/**
|
|
767
|
+
* The first diagnostics of a failed build in the shape a last-build record stores and `status` reports, the
|
|
768
|
+
* ones with a source position first.
|
|
769
|
+
*/
|
|
770
|
+
declare function buildDiagnostics(value: unknown): BuildDiagnostic[];
|
|
771
|
+
declare function readLastBuilds(state: WorkspaceState | null | undefined): Partial<Record<StatsPlatform, LastBuildReport>>;
|
|
772
|
+
/** Each platform's recorded runs, newest first, at most `BUILD_HISTORY_LIMIT` each. */
|
|
773
|
+
declare function readBuildHistory(state: WorkspaceState | null | undefined): Partial<Record<StatsPlatform, BuildHistoryEntry[]>>;
|
|
774
|
+
declare function readWorkspaceState(root: string): WorkspaceState | null;
|
|
775
|
+
declare function lastUseFrom(state: WorkspaceState | null, logMtimes: readonly number[]): number;
|
|
776
|
+
declare function workspaceLastUsed(root: string): number;
|
|
777
|
+
declare const WARM_KEY = "warm";
|
|
778
|
+
/** How long a successful warm keeps a workspace `ready` when nothing runs in it. */
|
|
779
|
+
declare const READY_PHASE_MS: number;
|
|
780
|
+
/**
|
|
781
|
+
* What `stim worktree warm` last recorded in a workspace: a warm in progress, held by the ownership claim
|
|
782
|
+
* `claim` names, or a successful warm that finished at `at`.
|
|
783
|
+
*/
|
|
784
|
+
type WarmRecord = {
|
|
785
|
+
phase: "warming";
|
|
786
|
+
step: WarmStep;
|
|
787
|
+
startedAt: string;
|
|
788
|
+
claim: {
|
|
789
|
+
root: string;
|
|
790
|
+
claimId: string;
|
|
791
|
+
};
|
|
792
|
+
} | {
|
|
793
|
+
phase: "ready";
|
|
794
|
+
at: string;
|
|
795
|
+
};
|
|
796
|
+
declare function readWarmRecord(state: WorkspaceState | null | undefined): WarmRecord | null;
|
|
797
|
+
declare const WORKSPACE_AGENT_KEY = "agentSession";
|
|
798
|
+
/**
|
|
799
|
+
* The coding-agent session whose shell ran the Stim command that last recorded `lastUsedAt`, with that command's
|
|
800
|
+
* working directory as `cwd` and its time as `lastActiveAt`.
|
|
801
|
+
*/
|
|
802
|
+
declare function readWorkspaceAgent(state: WorkspaceState | null | undefined): AgentSession | null;
|
|
803
|
+
//#endregion
|
|
804
|
+
//#region state/status.d.ts
|
|
805
|
+
type StatsPlatform = "ios" | "android";
|
|
806
|
+
type RunOutcomeKind = "hit" | "cold";
|
|
807
|
+
declare const BUILD_PHASES: readonly ["prepare", "cache-lookup", "wait", "prebuild", "pods", "compile", "device", "install", "launch"];
|
|
808
|
+
type BuildPhase = (typeof BUILD_PHASES)[number];
|
|
809
|
+
type ActiveBuildState = "running" | "stale" | "unknown";
|
|
810
|
+
/**
|
|
811
|
+
* Where a running build compiles: `local`, or the build machine it was offloaded to, with the phase it is in there
|
|
812
|
+
* (`sync`, `deps`, `prebuild`, `pods`, `build` or `fetch`) and when the offload and that phase started.
|
|
813
|
+
*/
|
|
814
|
+
type BuildPlacement = "local" | {
|
|
815
|
+
host: string;
|
|
816
|
+
phase: string;
|
|
817
|
+
startedAt: string;
|
|
818
|
+
phaseStartedAt: string;
|
|
819
|
+
};
|
|
820
|
+
interface BuildReport {
|
|
821
|
+
platform: StatsPlatform;
|
|
822
|
+
slot: string;
|
|
823
|
+
state: ActiveBuildState;
|
|
824
|
+
phase: BuildPhase;
|
|
825
|
+
startedAt: string;
|
|
826
|
+
phaseStartedAt: string;
|
|
827
|
+
outcome: RunOutcomeKind | null;
|
|
828
|
+
/** Whether `outcome` is this run's own; before its cache lookup resolves it is the project's latest outcome. */
|
|
829
|
+
outcomeKnown: boolean;
|
|
830
|
+
/** The resolved lookup result; absent before resolution and when the run skips cache lookup. */
|
|
831
|
+
cacheLookupOutcome?: "hit" | "miss";
|
|
832
|
+
expectedMs: number | null;
|
|
833
|
+
expectedPhaseMs: number | null;
|
|
834
|
+
basis: number;
|
|
835
|
+
/**
|
|
836
|
+
* The phases a run like this one goes through, in order, with each one's median in milliseconds, from the same
|
|
837
|
+
* runs as `expectedMs`; null without comparable runs. The current phase can be one the plan does not list.
|
|
838
|
+
*/
|
|
839
|
+
plannedPhases: PlannedPhase[] | null;
|
|
840
|
+
/** Why the run's cache lookup missed, once the run knows; `baseline` omits `cacheKey`. */
|
|
841
|
+
missReason?: BuildMissReason;
|
|
842
|
+
/**
|
|
843
|
+
* True while `missReason` is the miss of the key the run looked up first and the run will prebuild or install pods,
|
|
844
|
+
* then look the key up again. A hit on the second lookup removes `missReason` and sets `outcome` to `hit`.
|
|
845
|
+
*/
|
|
846
|
+
missProvisional?: true;
|
|
847
|
+
/** What the native build tool is doing now, once it printed a line Stim recognizes. */
|
|
848
|
+
detail?: BuildDetail;
|
|
849
|
+
placement: BuildPlacement;
|
|
850
|
+
/** While `phase` is `wait`: the workspace whose build of the same artifact this run waits on, when it is known. */
|
|
851
|
+
waitingOn?: {
|
|
852
|
+
path: string;
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
/** One phase a running build is expected to go through, and its median duration in comparable runs. */
|
|
856
|
+
interface PlannedPhase {
|
|
857
|
+
phase: BuildPhase;
|
|
858
|
+
expectedMs: number;
|
|
859
|
+
}
|
|
860
|
+
/** The native build tool's step inside a build's `compile` phase. */
|
|
861
|
+
declare const NATIVE_BUILD_STEPS: readonly ["configure", "compile", "link", "resources", "script", "dex", "package", "sign"];
|
|
862
|
+
type NativeBuildStep = (typeof NATIVE_BUILD_STEPS)[number];
|
|
863
|
+
/**
|
|
864
|
+
* A running build's progress as its tool reports it. `unit` is `targets` for xcodebuild and `tasks` for Gradle.
|
|
865
|
+
* xcodebuild's `done` counts targets it finished and `total` the targets in its dependency graph, which includes
|
|
866
|
+
* targets with nothing to do; Gradle's `done` counts the tasks it reported, with a null `total`. They are counts, not
|
|
867
|
+
* a completion fraction. `status` reports the detail only during the `compile` phase. `line` is
|
|
868
|
+
* the latest compile, link or task line with paths shortened to file names.
|
|
869
|
+
*/
|
|
870
|
+
interface BuildDetail {
|
|
871
|
+
step: NativeBuildStep | null;
|
|
872
|
+
unit: "targets" | "tasks" | null;
|
|
873
|
+
done: number | null;
|
|
874
|
+
total: number | null;
|
|
875
|
+
line: string | null;
|
|
876
|
+
updatedAt: string;
|
|
877
|
+
}
|
|
878
|
+
/** Where a build's app came from: a cache tier, or `false` when it compiled or failed before one was found. */
|
|
879
|
+
type BuildCacheHit = "local" | "remote" | false;
|
|
880
|
+
/** A platform's most recent `ios` or `android` run in one workspace. */
|
|
881
|
+
interface LastBuildReport {
|
|
882
|
+
platform: StatsPlatform;
|
|
883
|
+
status: "ok" | "failed";
|
|
884
|
+
cacheHit: BuildCacheHit;
|
|
885
|
+
cacheSkipped: boolean;
|
|
886
|
+
durationMs: number | null;
|
|
887
|
+
fingerprint: string | null;
|
|
888
|
+
startedAt: string;
|
|
889
|
+
finishedAt: string | null;
|
|
890
|
+
errorCode?: string;
|
|
891
|
+
missReason?: BuildMissReason;
|
|
892
|
+
/** The selected auto, local, or configured machine entry; present on new build records, including cache hits. */
|
|
893
|
+
buildMachine?: string;
|
|
894
|
+
/** Where compilation ran: here or a machine name; absent when no build ran. */
|
|
895
|
+
builtOn?: string;
|
|
896
|
+
/** The build machine that compiled the app when the build was offloaded. */
|
|
897
|
+
offloadedTo?: string;
|
|
898
|
+
/** Why the run built here after it considered offloading; absent when it offloaded or never considered it. */
|
|
899
|
+
offloadFallback?: string;
|
|
900
|
+
/** The first compiler diagnostics of a failed build, when the build tool reported any. */
|
|
901
|
+
diagnostics?: BuildDiagnostic[];
|
|
902
|
+
/** Present on a failed run: what failed, from `buildCause`. */
|
|
903
|
+
cause?: BuildCause;
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* A failed run's cause: the first diagnostic with a file and a line, keyed `file:line`, else the run's error code
|
|
907
|
+
* (or `failed`), with null `file` and `line`. Consecutive failures with the same `key` failed the same way.
|
|
908
|
+
*/
|
|
909
|
+
interface BuildCause {
|
|
910
|
+
key: string;
|
|
911
|
+
file: string | null;
|
|
912
|
+
line: number | null;
|
|
913
|
+
}
|
|
914
|
+
/** How a recorded build ended. `interrupted` is a run whose process ended without recording a result. */
|
|
915
|
+
declare const BUILD_RESULTS: readonly ["succeeded", "failed", "cancelled", "interrupted"];
|
|
916
|
+
type BuildResult = (typeof BUILD_RESULTS)[number];
|
|
917
|
+
/**
|
|
918
|
+
* One run in a workspace's recent build history. `configuration` is the iOS configuration or the Android
|
|
919
|
+
* variant the run built, `Debug` or `debug` by default, and null when the run ended before resolving it.
|
|
920
|
+
* `phases` holds the milliseconds spent in each phase the run entered. An interrupted run has null
|
|
921
|
+
* `durationMs` and `finishedAt`, no cache facts, and 0 for the phase it stopped in.
|
|
922
|
+
*/
|
|
923
|
+
interface BuildHistoryEntry extends LastBuildReport {
|
|
924
|
+
result: BuildResult;
|
|
925
|
+
slot: string;
|
|
926
|
+
configuration: string | null;
|
|
927
|
+
cacheKey: string | null;
|
|
928
|
+
phases: Partial<Record<BuildPhase, number>>;
|
|
929
|
+
}
|
|
930
|
+
/** One compiler error from a failed build: where it is, when the tool said, and its message. */
|
|
931
|
+
interface BuildDiagnostic {
|
|
932
|
+
file: string | null;
|
|
933
|
+
line: number | null;
|
|
934
|
+
column: number | null;
|
|
935
|
+
message: string;
|
|
936
|
+
}
|
|
937
|
+
/** What kind of native input a changed fingerprint source is. */
|
|
938
|
+
type BuildMissCategory = "native-dependency" | "config-plugin" | "app-config" | "app-asset" | "package" | "native-dir" | "autolinking" | "package-scripts" | "file" | "other";
|
|
939
|
+
interface BuildMissChange {
|
|
940
|
+
source: string;
|
|
941
|
+
change: "added" | "removed" | "changed";
|
|
942
|
+
category: BuildMissCategory;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Why a run compiled instead of installing a cached app. `changes` holds at most 20 entries,
|
|
946
|
+
* ordered by importance; `changeCount` is the full number of changed fingerprint sources.
|
|
947
|
+
* Only a plan reports `prebuild-pending`: the run would prebuild before compiling, so the changes
|
|
948
|
+
* compare the fingerprint before that prebuild.
|
|
949
|
+
*/
|
|
950
|
+
interface BuildMissReason {
|
|
951
|
+
kind: "changed" | "no-baseline" | "same-sources" | "cache-skipped" | "fingerprint-error" | "prebuild-pending";
|
|
952
|
+
summary: string;
|
|
953
|
+
changes: BuildMissChange[];
|
|
954
|
+
changeCount: number;
|
|
955
|
+
/** `cacheKey` is kept in workspace state so a later miss can find this baseline; status omits it. */
|
|
956
|
+
baseline: {
|
|
957
|
+
fingerprint: string;
|
|
958
|
+
cacheKey?: string;
|
|
959
|
+
from: "workspace" | "project";
|
|
960
|
+
} | null;
|
|
961
|
+
rekeyedBy: string[];
|
|
962
|
+
}
|
|
963
|
+
/** The payload `stim ios --plan --json` and `stim android --plan --json` print. */
|
|
964
|
+
interface BuildPlanPayload {
|
|
965
|
+
platform: StatsPlatform;
|
|
966
|
+
slot?: string;
|
|
967
|
+
fingerprint: string;
|
|
968
|
+
cacheKey: string | null;
|
|
969
|
+
cacheHit: BuildCacheHit;
|
|
970
|
+
provider: string | null;
|
|
971
|
+
cacheSkipped: boolean;
|
|
972
|
+
prebuild: "none" | "generate" | "regenerate" | "refuse" | null;
|
|
973
|
+
outcome: RunOutcomeKind | null;
|
|
974
|
+
expectedMs: number | null;
|
|
975
|
+
basis: number;
|
|
976
|
+
/** On a predicted miss with cache reads on, why the cache has no app; `baseline` omits `cacheKey`. */
|
|
977
|
+
missReason?: BuildMissReason;
|
|
978
|
+
refusal?: {
|
|
979
|
+
code: string;
|
|
980
|
+
message: string;
|
|
981
|
+
remedy: string;
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
type ActivityState = "driven" | "active" | "idle" | "unknown";
|
|
985
|
+
interface ActivityDriver {
|
|
986
|
+
tool: string;
|
|
987
|
+
pid: number | null;
|
|
988
|
+
since: string | null;
|
|
989
|
+
}
|
|
990
|
+
/** The kinds of evidence that date a device's last activity, in the order `recent` lists them. */
|
|
991
|
+
declare const ACTIVITY_RECENCY_BASES: readonly ["agent-action", "device-log", "metro-bundle", "workspace-use", "supervisor-start", "page-log", "viewer"];
|
|
992
|
+
type ActivityRecencyBasis = (typeof ACTIVITY_RECENCY_BASES)[number];
|
|
993
|
+
interface DeviceActivity {
|
|
994
|
+
state: ActivityState;
|
|
995
|
+
driver?: ActivityDriver;
|
|
996
|
+
lastActivityAt?: string;
|
|
997
|
+
/** The newest time of each kind of evidence behind `lastActivityAt`, so a reader can leave out app log chatter. */
|
|
998
|
+
recent?: Partial<Record<ActivityRecencyBasis, string>>;
|
|
999
|
+
basis: string[];
|
|
1000
|
+
}
|
|
1001
|
+
/** Every state a device's app process can report. */
|
|
1002
|
+
declare const APP_PROCESS_STATES: readonly ["running", "stopped", "unknown"];
|
|
1003
|
+
/**
|
|
1004
|
+
* Whether the workspace's app process is alive on a device now. This is current process state, not launch evidence:
|
|
1005
|
+
* `launched` in an `ios` or `android` result stays the record of one launch. `id` is the bundle identifier or
|
|
1006
|
+
* package that was checked; `state` is "unknown" when the process listing could not be read.
|
|
1007
|
+
*/
|
|
1008
|
+
interface DeviceAppProcess {
|
|
1009
|
+
id: string;
|
|
1010
|
+
state: (typeof APP_PROCESS_STATES)[number];
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* A linked worktree's `git status`. `changed` counts tracked paths with staged or unstaged changes, including
|
|
1014
|
+
* conflicts; `untracked` counts untracked entries as `git status` lists them, so an untracked directory counts once.
|
|
1015
|
+
* `ahead` and `behind` compare HEAD with `upstream`, and are null when there is no upstream or it no longer exists.
|
|
1016
|
+
* `mergedInto` names the default branch (`origin/main`) when `gc` would consider the branch merged into it, judged
|
|
1017
|
+
* from local refs without fetching.
|
|
1018
|
+
*/
|
|
1019
|
+
interface WorktreeGit {
|
|
1020
|
+
changed: number;
|
|
1021
|
+
untracked: number;
|
|
1022
|
+
upstream: string | null;
|
|
1023
|
+
ahead: number | null;
|
|
1024
|
+
behind: number | null;
|
|
1025
|
+
mergedInto: string | null;
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* The GitHub pull request of a worktree's branch and HEAD, as `status --watch` last looked it up through `gh`.
|
|
1029
|
+
* `state` is `draft` for an open draft. `checks` counts the head commit's check runs and commit statuses, null when it
|
|
1030
|
+
* has none. `checkedAt` is when Stim last asked GitHub.
|
|
1031
|
+
*/
|
|
1032
|
+
interface WorktreePullRequest {
|
|
1033
|
+
number: number;
|
|
1034
|
+
url: string;
|
|
1035
|
+
title: string;
|
|
1036
|
+
state: "open" | "draft" | "merged" | "closed";
|
|
1037
|
+
checks: {
|
|
1038
|
+
passing: number;
|
|
1039
|
+
failing: number;
|
|
1040
|
+
pending: number;
|
|
1041
|
+
} | null;
|
|
1042
|
+
reviewDecision: "approved" | "changes-requested" | "review-required" | null;
|
|
1043
|
+
checkedAt: string;
|
|
1044
|
+
}
|
|
1045
|
+
interface WorktreeFacts {
|
|
1046
|
+
path: string;
|
|
1047
|
+
branch?: string;
|
|
1048
|
+
repository?: string;
|
|
1049
|
+
/** Null when git could not be read in time, or the worktree is in a folder status does not open. */
|
|
1050
|
+
git?: WorktreeGit | null;
|
|
1051
|
+
/** Null when GitHub has no pull request for the branch; absent when unknown, such as without `gh`. */
|
|
1052
|
+
pullRequest?: WorktreePullRequest | null;
|
|
1053
|
+
/** Present with `git`: what the worktree's git chip shows, from `gitChip`. */
|
|
1054
|
+
gitChip?: GitChip;
|
|
1055
|
+
}
|
|
1056
|
+
/** Every coding-agent tool whose sessions status can attribute to an environment. */
|
|
1057
|
+
declare const AGENT_TOOLS: readonly ["claude-code", "codex"];
|
|
1058
|
+
type AgentTool = (typeof AGENT_TOOLS)[number];
|
|
1059
|
+
/**
|
|
1060
|
+
* A coding-agent session working in an environment: one whose working directory `cwd` is the environment's path,
|
|
1061
|
+
* inside it, or its git worktree root, or one that ran a Stim command in it. `title` is the short name the tool keeps
|
|
1062
|
+
* for the session, never its conversation. `lastActiveAt` is the tool's own last update, or the Stim command's time
|
|
1063
|
+
* when that is newer. `openUrl` opens the session in the tool's desktop app when that app is installed on this Mac.
|
|
1064
|
+
* `webUrl` opens a Claude Code session with Remote Control connected on claude.ai/code or in the Claude mobile app.
|
|
1065
|
+
*/
|
|
1066
|
+
interface AgentSession {
|
|
1067
|
+
tool: AgentTool;
|
|
1068
|
+
sessionId: string;
|
|
1069
|
+
title?: string;
|
|
1070
|
+
cwd: string;
|
|
1071
|
+
startedAt?: string;
|
|
1072
|
+
lastActiveAt?: string;
|
|
1073
|
+
pid?: number;
|
|
1074
|
+
openUrl?: string;
|
|
1075
|
+
webUrl?: string;
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* An agent session that stopped running in an environment, with the details Stim last found while it ran. `endedAt`
|
|
1079
|
+
* is the last time a status watcher found it running.
|
|
1080
|
+
*/
|
|
1081
|
+
interface EndedAgentSession extends Omit<AgentSession, "pid"> {
|
|
1082
|
+
endedAt: string;
|
|
1083
|
+
}
|
|
1084
|
+
interface AndroidRuntimeFacts {
|
|
1085
|
+
serial: string | null;
|
|
1086
|
+
state: "detected" | "not-detected" | "missing" | "unknown";
|
|
1087
|
+
error?: string;
|
|
1088
|
+
}
|
|
1089
|
+
/** Every connection state a physical device can report. */
|
|
1090
|
+
declare const PHYSICAL_DEVICE_CONNECTIONS: readonly ["connected", "disconnected", "unknown"];
|
|
1091
|
+
type PhysicalDeviceConnection = (typeof PHYSICAL_DEVICE_CONNECTIONS)[number];
|
|
1092
|
+
/**
|
|
1093
|
+
* A physical iPhone, iPad or Android phone the workspace holds an unexpired lease on, from `ios --device`,
|
|
1094
|
+
* `android --device` or `device lock`. Stim uses it and never owns it, so `owned` is always false. `id` is the
|
|
1095
|
+
* UDID or adb serial. `name` is the device's own name, falling back to the name the lease recorded; `model` is the
|
|
1096
|
+
* marketing name devicectl reports, null when it could not be read, or the Android model the lease recorded.
|
|
1097
|
+
* `connection` is `connected` when devicectl can reach the phone or adb lists it as `device`, `disconnected` when
|
|
1098
|
+
* the tool answered without it, and `unknown` when the tool could not be read in time. `lease.holder` is the
|
|
1099
|
+
* workspace path that holds it.
|
|
1100
|
+
*/
|
|
1101
|
+
interface PhysicalDeviceState {
|
|
1102
|
+
platform: StatsPlatform;
|
|
1103
|
+
slot: string;
|
|
1104
|
+
id: string;
|
|
1105
|
+
name: string | null;
|
|
1106
|
+
model: string | null;
|
|
1107
|
+
owned: false;
|
|
1108
|
+
physical: true;
|
|
1109
|
+
connection: PhysicalDeviceConnection;
|
|
1110
|
+
lease: {
|
|
1111
|
+
holder: string;
|
|
1112
|
+
kind: "declared" | "run";
|
|
1113
|
+
grantedAt: string | null;
|
|
1114
|
+
expiresAt: string;
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
interface RemoteDeviceState {
|
|
1118
|
+
platform: "ios" | "android" | null;
|
|
1119
|
+
backend: "eas";
|
|
1120
|
+
sessionId: string;
|
|
1121
|
+
state: "claimed" | "unclaimed" | "unknown";
|
|
1122
|
+
startedAt: string | null;
|
|
1123
|
+
webPreviewUrl: string | null;
|
|
1124
|
+
}
|
|
1125
|
+
/**
|
|
1126
|
+
* One part of a worktree's git chip, in display order: commits ahead of and behind the upstream, uncommitted files
|
|
1127
|
+
* (changed plus untracked), the base branch the branch is merged into (left out when its pull request is merged,
|
|
1128
|
+
* whose own mark says so), and a branch with no upstream that is not merged.
|
|
1129
|
+
*/
|
|
1130
|
+
type GitChipPart = {
|
|
1131
|
+
kind: "arrows";
|
|
1132
|
+
ahead: number;
|
|
1133
|
+
behind: number;
|
|
1134
|
+
} | {
|
|
1135
|
+
kind: "changed";
|
|
1136
|
+
count: number;
|
|
1137
|
+
} | {
|
|
1138
|
+
kind: "merged";
|
|
1139
|
+
into: string;
|
|
1140
|
+
} | {
|
|
1141
|
+
kind: "no-upstream";
|
|
1142
|
+
};
|
|
1143
|
+
/** A pull request's checks at a glance: any failing, else any pending, else any passing; null without checks. */
|
|
1144
|
+
type ChecksState = "passing" | "failing" | "pending" | null;
|
|
1145
|
+
interface GitChip {
|
|
1146
|
+
parts: GitChipPart[];
|
|
1147
|
+
ci: ChecksState;
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* Whether a running owned simulator or emulator lacks the workspace's app: `none` when its platform never built
|
|
1151
|
+
* successfully here and the latest build failed, `closed` when status saw no app process, else null.
|
|
1152
|
+
*/
|
|
1153
|
+
type AppPresence = "none" | "closed" | null;
|
|
1154
|
+
declare const WORKSPACE_STAGE_KINDS: readonly ["building", "warming", "ready", "build-failed", "running", "stopped"];
|
|
1155
|
+
/**
|
|
1156
|
+
* Where a workspace is, first match wins: `building` while a build runs, `warming` and `ready` from `phase` when
|
|
1157
|
+
* nothing is live, `build-failed` when the newest run of either platform failed, `running` when it is live or holds
|
|
1158
|
+
* a remote device, else `stopped`. `since` is when that began: the build's start, the warm phase's time, the failed
|
|
1159
|
+
* run's end (else start), the supervisor's start, or Metro's last stop. `platform` names the build for `building`
|
|
1160
|
+
* and `build-failed`. `closedApps` lists, for `running`, the devices whose `appPresence` is `closed`.
|
|
1161
|
+
*/
|
|
1162
|
+
interface WorkspaceStage {
|
|
1163
|
+
kind: (typeof WORKSPACE_STAGE_KINDS)[number];
|
|
1164
|
+
since: string | null;
|
|
1165
|
+
platform: StatsPlatform | "macos" | null;
|
|
1166
|
+
closedApps: {
|
|
1167
|
+
platform: StatsPlatform;
|
|
1168
|
+
slot: string;
|
|
1169
|
+
}[];
|
|
1170
|
+
}
|
|
1171
|
+
/** Every code a status issue can carry. */
|
|
1172
|
+
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"];
|
|
1173
|
+
type StatusIssueCode = (typeof STATUS_ISSUE_CODES)[number];
|
|
1174
|
+
/**
|
|
1175
|
+
* One thing in a workspace that needs the user, or with severity `info` a note that needs nothing. `remedy` is a
|
|
1176
|
+
* command to run from `workspace`; `slot` is absent for the default device slot. `warnings` carries the `error` and
|
|
1177
|
+
* `warning` issues as text.
|
|
1178
|
+
*
|
|
1179
|
+
* Severity:
|
|
1180
|
+
* - `error`: Stim cannot verify or safely act on something; a person resolves it, following the teardown guide.
|
|
1181
|
+
* - `warning`: something is broken now and needs someone to act, such as an app that cannot reach Metro, a held
|
|
1182
|
+
* port or a device that vanished while expected.
|
|
1183
|
+
* - `info`: a fact the next normal Stim command handles by itself, so it needs no action.
|
|
1184
|
+
*
|
|
1185
|
+
* The phone app and Stim Desktop show `error` and `warning` and hide `info`; plain `stim status` prints `info` as a
|
|
1186
|
+
* dim note with no remedy.
|
|
1187
|
+
*/
|
|
1188
|
+
interface StatusIssue {
|
|
1189
|
+
code: StatusIssueCode;
|
|
1190
|
+
severity: "error" | "warning" | "info";
|
|
1191
|
+
message: string;
|
|
1192
|
+
remedy: string;
|
|
1193
|
+
workspace: string;
|
|
1194
|
+
slot?: string;
|
|
1195
|
+
}
|
|
1196
|
+
/** Every state the owned page's latest load can report. */
|
|
1197
|
+
declare const WEB_PAGE_STATES: readonly ["loading", "loaded", "failed"];
|
|
1198
|
+
/**
|
|
1199
|
+
* The owned page's latest load, from the page-load marker in the workspace's web log: `url` is the document it
|
|
1200
|
+
* loaded, `state` is `failed` when that document did not load or the page crashed, with the log message as
|
|
1201
|
+
* `error`. `route`, present only when an in-app route change (history API or fragment) moved the page off `url`
|
|
1202
|
+
* since the load, is the URL it shows now.
|
|
1203
|
+
*/
|
|
1204
|
+
interface WebPageState {
|
|
1205
|
+
url: string;
|
|
1206
|
+
state: (typeof WEB_PAGE_STATES)[number];
|
|
1207
|
+
error?: string;
|
|
1208
|
+
route?: string;
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* The workspace's Stim-owned Chrome. `pid` is Chrome's process and `supervisorPid` the Stim process that holds
|
|
1212
|
+
* its DevTools session. `cdpEndpoint` is the loopback DevTools HTTP endpoint agents can attach to, and `targetId`
|
|
1213
|
+
* the DevTools target of the owned page; both are null when the browser is not running. `profile` is the
|
|
1214
|
+
* Stim-owned user data directory. `page` is null before the page's first load. `activity` names DevTools clients
|
|
1215
|
+
* other than Stim's as drivers.
|
|
1216
|
+
*/
|
|
1217
|
+
interface WebBrowserState {
|
|
1218
|
+
browser: "chrome";
|
|
1219
|
+
version: string | null;
|
|
1220
|
+
running: boolean;
|
|
1221
|
+
pid: number | null;
|
|
1222
|
+
supervisorPid: number | null;
|
|
1223
|
+
url: string;
|
|
1224
|
+
headless: boolean;
|
|
1225
|
+
viewport: WebViewport;
|
|
1226
|
+
profile: string;
|
|
1227
|
+
cdpEndpoint: string | null;
|
|
1228
|
+
targetId: string | null;
|
|
1229
|
+
page?: WebPageState | null;
|
|
1230
|
+
activity?: DeviceActivity;
|
|
1231
|
+
}
|
|
1232
|
+
/** The steps of `stim worktree warm`: `refresh` fast-forwards and installs in the source checkout, `copy` carries ignored entries. */
|
|
1233
|
+
type WarmStep = "refresh" | "copy";
|
|
1234
|
+
/**
|
|
1235
|
+
* Where a workspace is in its lifecycle: `warming` while `stim worktree warm` runs in it, `ready` after a warm
|
|
1236
|
+
* succeeded and before any `start`, `ios`, `android`, `web` or `reload` there, for at most two hours; `live` when
|
|
1237
|
+
* anything it owns runs, else `idle`.
|
|
1238
|
+
*/
|
|
1239
|
+
declare const WORKSPACE_PHASES: readonly ["warming", "ready", "live", "idle"];
|
|
1240
|
+
type WorkspacePhase = (typeof WORKSPACE_PHASES)[number];
|
|
1241
|
+
/** A folder's size on disk as `status --watch` last measured it. */
|
|
1242
|
+
interface DiskMeasure {
|
|
1243
|
+
bytes: number;
|
|
1244
|
+
measuredAt: string;
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* An environment's disk use as `status --watch` last measured it. `worktreeBytes` is the git worktree folder, or the
|
|
1248
|
+
* workspace folder outside one, node_modules included. `nodeModulesBytes` is node_modules at the worktree root and,
|
|
1249
|
+
* when different, at the workspace path, and is part of `worktreeBytes`. `buildBytes` is Stim's own folder for the
|
|
1250
|
+
* workspace: Xcode derived data, Gradle outputs and logs. A figure is null until it was measured; `measuredAt` is the
|
|
1251
|
+
* oldest measurement.
|
|
1252
|
+
*/
|
|
1253
|
+
interface EnvironmentDisk {
|
|
1254
|
+
worktreeBytes: number | null;
|
|
1255
|
+
nodeModulesBytes: number | null;
|
|
1256
|
+
buildBytes: number | null;
|
|
1257
|
+
measuredAt: string;
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* A Metro bundle request: `bundling` while one is in flight on the workspace's Metro, with its `platform`,
|
|
1261
|
+
* `startedAt` and, when Metro reported progress for it, `percent` (0-100). `last` is the newest finished request,
|
|
1262
|
+
* `durationMs` from request to response end.
|
|
1263
|
+
*/
|
|
1264
|
+
interface MetroBundleState {
|
|
1265
|
+
bundling: boolean;
|
|
1266
|
+
platform?: StatsPlatform;
|
|
1267
|
+
startedAt?: string;
|
|
1268
|
+
percent?: number;
|
|
1269
|
+
last?: {
|
|
1270
|
+
platform: StatsPlatform;
|
|
1271
|
+
status: "ok" | "failed";
|
|
1272
|
+
durationMs: number;
|
|
1273
|
+
finishedAt: string;
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
interface SimulatorState {
|
|
1277
|
+
name: string | null;
|
|
1278
|
+
udid: string;
|
|
1279
|
+
owned: boolean;
|
|
1280
|
+
state: string;
|
|
1281
|
+
activity?: DeviceActivity;
|
|
1282
|
+
app?: DeviceAppProcess;
|
|
1283
|
+
appPresence?: AppPresence;
|
|
1284
|
+
/** The simulator's data folder, for an owned simulator once measured. */
|
|
1285
|
+
disk?: DiskMeasure;
|
|
1286
|
+
/** Present while the device is not booted after the supervisor shut it down for `devices.idleShutdownMinutes`. */
|
|
1287
|
+
idleShutdown?: DeviceIdleShutdownRecord;
|
|
1288
|
+
}
|
|
1289
|
+
interface AndroidDeviceState {
|
|
1290
|
+
name: string | undefined;
|
|
1291
|
+
owned: boolean;
|
|
1292
|
+
physical: boolean;
|
|
1293
|
+
serial?: string | null;
|
|
1294
|
+
state?: AndroidRuntimeFacts["state"];
|
|
1295
|
+
deviceProfile?: string | null;
|
|
1296
|
+
activity?: DeviceActivity;
|
|
1297
|
+
app?: DeviceAppProcess;
|
|
1298
|
+
appPresence?: AppPresence;
|
|
1299
|
+
/** The AVD's folder, for an owned emulator once measured. */
|
|
1300
|
+
disk?: DiskMeasure;
|
|
1301
|
+
/** Present while the emulator is not running after the supervisor shut it down for `devices.idleShutdownMinutes`. */
|
|
1302
|
+
idleShutdown?: DeviceIdleShutdownRecord;
|
|
1303
|
+
}
|
|
1304
|
+
interface EnvironmentState {
|
|
1305
|
+
slots?: {
|
|
1306
|
+
slot: string;
|
|
1307
|
+
ios: SimulatorState | null | undefined;
|
|
1308
|
+
android: AndroidDeviceState | null | undefined;
|
|
1309
|
+
}[];
|
|
1310
|
+
path: string;
|
|
1311
|
+
live: boolean;
|
|
1312
|
+
phase?: WorkspacePhase;
|
|
1313
|
+
/** When the warm started (`warming`) or finished (`ready`); null for `live` and `idle`. */
|
|
1314
|
+
phaseSince?: string | null;
|
|
1315
|
+
/** Whether stim-server may record this workspace's device screens, from `recording.enabled`. */
|
|
1316
|
+
recording?: {
|
|
1317
|
+
enabled: boolean;
|
|
1318
|
+
};
|
|
1319
|
+
/** Where the workspace is, from `workspaceStage`; `stim status --json` always sets it. */
|
|
1320
|
+
stage?: WorkspaceStage;
|
|
1321
|
+
/** The step a `warming` workspace's warm is in; absent in every other phase. */
|
|
1322
|
+
warmStep?: WarmStep;
|
|
1323
|
+
/**
|
|
1324
|
+
* The memory this workspace's processes use, as `memorySource` says: the sum of its `machine` owners' `memoryMb`
|
|
1325
|
+
* when status read their footprints, or else a fixed estimate per booted simulator, detected emulator, running
|
|
1326
|
+
* Metro and running Chrome. `capacity.committedMb` sums it.
|
|
1327
|
+
*/
|
|
1328
|
+
memoryMb: number;
|
|
1329
|
+
/** How `memoryMb` was obtained; absent from payloads written before it existed, which carry the estimate. */
|
|
1330
|
+
memorySource?: Exclude<MemorySource, "rss">;
|
|
1331
|
+
warnings: string[];
|
|
1332
|
+
issues: StatusIssue[];
|
|
1333
|
+
ios?: SimulatorState | null;
|
|
1334
|
+
android?: AndroidDeviceState | null;
|
|
1335
|
+
metro?: {
|
|
1336
|
+
port: number;
|
|
1337
|
+
running: boolean;
|
|
1338
|
+
pid: number | null;
|
|
1339
|
+
tunnel?: {
|
|
1340
|
+
provider: Exclude<TunnelMode, "auto" | "off" | "expo">;
|
|
1341
|
+
url: string;
|
|
1342
|
+
};
|
|
1343
|
+
idleStop?: IdleStopRecord;
|
|
1344
|
+
lastStop?: MetroLastStop;
|
|
1345
|
+
/** The other process that answers Metro on `port`; `cwd` is null when its directory could not be read. */
|
|
1346
|
+
heldBy?: {
|
|
1347
|
+
pid: number;
|
|
1348
|
+
cwd: string | null;
|
|
1349
|
+
};
|
|
1350
|
+
/** Absent when the Metro log holds no bundle request. */
|
|
1351
|
+
bundle?: MetroBundleState;
|
|
1352
|
+
} | null;
|
|
1353
|
+
web?: WebBrowserState | null;
|
|
1354
|
+
macos?: MacosAppState | null;
|
|
1355
|
+
supervisor?: {
|
|
1356
|
+
pid: number | null;
|
|
1357
|
+
mode: string | null;
|
|
1358
|
+
startedAt: string | null;
|
|
1359
|
+
healthy: boolean;
|
|
1360
|
+
} | null;
|
|
1361
|
+
logs?: {
|
|
1362
|
+
dir: string;
|
|
1363
|
+
errorsSinceMarker: number;
|
|
1364
|
+
} | null;
|
|
1365
|
+
worktree?: WorktreeFacts | null;
|
|
1366
|
+
remoteDevices?: RemoteDeviceState[];
|
|
1367
|
+
/** The physical devices this workspace leases, in every slot; absent when it leases none. */
|
|
1368
|
+
physicalDevices?: PhysicalDeviceState[];
|
|
1369
|
+
build?: BuildReport | null;
|
|
1370
|
+
lastBuilds?: Partial<Record<StatsPlatform, LastBuildReport>>;
|
|
1371
|
+
/** Each platform's recent runs, newest first, at most `BUILD_HISTORY_LIMIT` each. */
|
|
1372
|
+
builds?: Partial<Record<StatsPlatform, BuildHistoryEntry[]>>;
|
|
1373
|
+
disk?: EnvironmentDisk;
|
|
1374
|
+
/** The coding-agent sessions working in the environment, most recently active first; absent when none. */
|
|
1375
|
+
agents?: AgentSession[];
|
|
1376
|
+
/** The agent sessions that stopped running here in the last 3 days, most recently ended first; absent when none. */
|
|
1377
|
+
endedAgents?: EndedAgentSession[];
|
|
1378
|
+
}
|
|
1379
|
+
/** `committedMb` sums the environments' `memoryMb`; `overCapacity` is that sum over 60% of `totalMemoryMb`. */
|
|
1380
|
+
interface StatusCapacity {
|
|
1381
|
+
liveCount: number;
|
|
1382
|
+
committedMb: number;
|
|
1383
|
+
totalMemoryMb: number;
|
|
1384
|
+
overCapacity: boolean;
|
|
1385
|
+
}
|
|
1386
|
+
interface DeviceLeaseState {
|
|
1387
|
+
slot?: string;
|
|
1388
|
+
path: string;
|
|
1389
|
+
platform: string;
|
|
1390
|
+
id: string | null;
|
|
1391
|
+
deviceName: string | null;
|
|
1392
|
+
holder: string | null;
|
|
1393
|
+
grantedAt: string | null;
|
|
1394
|
+
expiresAt: string | null;
|
|
1395
|
+
mine: boolean;
|
|
1396
|
+
expired: boolean;
|
|
1397
|
+
parsed: boolean;
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Where a memory figure comes from. `footprint` is each process's physical footprint, which Activity Monitor's Memory
|
|
1401
|
+
* column shows. `rss` sums resident set sizes, which count pages shared between processes once per process, so a
|
|
1402
|
+
* simulator reports well above its footprint; the machine owners fall back to it when the footprint helper cannot be
|
|
1403
|
+
* built. `estimate` is a fixed amount per running thing, which an environment reports whenever it has no footprint.
|
|
1404
|
+
*/
|
|
1405
|
+
declare const MEMORY_SOURCES: readonly ["footprint", "rss", "estimate"];
|
|
1406
|
+
type MemorySource = (typeof MEMORY_SOURCES)[number];
|
|
1407
|
+
/** Every kind of process owner the status machine section reports. */
|
|
1408
|
+
declare const MACHINE_OWNER_KINDS: readonly ["simulator", "emulator", "metro", "build", "browser", "macos", "server", "shared"];
|
|
1409
|
+
type MachineOwnerKind = (typeof MACHINE_OWNER_KINDS)[number];
|
|
1410
|
+
/**
|
|
1411
|
+
* One thing using this Mac's CPU and memory now. Each process is counted in exactly one owner: the one whose root
|
|
1412
|
+
* process is its nearest ancestor. `workspace` and `slot` (absent for the default slot) name the workspace a
|
|
1413
|
+
* simulator, emulator, Metro, build or Chrome belongs to; a device no workspace records has a null workspace, and
|
|
1414
|
+
* machine-wide processes are `shared`. `id` is the simulator's UDID, the emulator's AVD name, Metro's port as text,
|
|
1415
|
+
* the build's platform, or null. `owned` is true only for what Stim started and stops: a workspace's owned device,
|
|
1416
|
+
* Metro, build or Chrome. `cpuPercent` is `ps` %CPU summed over the owner's processes, where 100 is one core.
|
|
1417
|
+
* `residentMb` sums their resident set sizes; pages shared between processes count once per process, so a
|
|
1418
|
+
* simulator, whose processes all map the runtime's shared libraries, reports well above its physical footprint.
|
|
1419
|
+
* `memoryMb` sums their physical footprints when `MachineUsageState.memorySource` is `footprint`, taking the resident
|
|
1420
|
+
* size of a process the footprint helper could not read, and equals `residentMb` when it is `rss`.
|
|
1421
|
+
*/
|
|
1422
|
+
interface MachineOwner {
|
|
1423
|
+
kind: MachineOwnerKind;
|
|
1424
|
+
name: string;
|
|
1425
|
+
workspace: string | null;
|
|
1426
|
+
slot?: string;
|
|
1427
|
+
id: string | null;
|
|
1428
|
+
owned: boolean;
|
|
1429
|
+
cpuPercent: number;
|
|
1430
|
+
residentMb: number;
|
|
1431
|
+
memoryMb: number;
|
|
1432
|
+
processes: number;
|
|
1433
|
+
}
|
|
1434
|
+
/** Where this machine's CPU and memory go, from one pass over the host process table. */
|
|
1435
|
+
interface MachineUsageState {
|
|
1436
|
+
memorySource: Exclude<MemorySource, "estimate">;
|
|
1437
|
+
owners: MachineOwner[];
|
|
1438
|
+
}
|
|
1439
|
+
/** The payload `stim status --json` prints, and `status --watch --json` prints on each change. */
|
|
1440
|
+
interface StatusPayload {
|
|
1441
|
+
environments: (EnvironmentState & {
|
|
1442
|
+
labelOnly?: true;
|
|
1443
|
+
})[];
|
|
1444
|
+
capacity: StatusCapacity;
|
|
1445
|
+
deviceLeases: DeviceLeaseState[];
|
|
1446
|
+
unprovisionedWorktrees: WorktreeFacts[];
|
|
1447
|
+
simctlAvailable: boolean;
|
|
1448
|
+
/** Null when nothing runs that status attributes, so it read no process table, or when the table was unreadable. */
|
|
1449
|
+
machine: MachineUsageState | null;
|
|
1450
|
+
}
|
|
1451
|
+
//#endregion
|
|
1452
|
+
//#region state/status-derived.d.ts
|
|
1453
|
+
declare function withGitChip(worktree: WorktreeFacts): WorktreeFacts;
|
|
1454
|
+
/** The environment with the conclusions clients draw from it: `stage`, `appPresence`, `gitChip` and `cause`. */
|
|
1455
|
+
declare function withDerivedFacts<T extends EnvironmentState>(env: T): T;
|
|
1456
|
+
//#endregion
|
|
1457
|
+
//#region state/status-measures.d.ts
|
|
1458
|
+
/** The file that caches `path`'s measured size, one file per folder. */
|
|
1459
|
+
declare function diskUsageCacheFile(path: string): string;
|
|
1460
|
+
/** The file that caches the pull request of the worktree at `path`. */
|
|
1461
|
+
declare function pullRequestCacheFile(path: string): string;
|
|
1462
|
+
/** One file of the disk-usage or pull-request cache. */
|
|
1463
|
+
interface StatusCacheEntry {
|
|
1464
|
+
kind: "disk-usage" | "pull-request";
|
|
1465
|
+
file: string;
|
|
1466
|
+
/** The folder or worktree the file caches, or null when the file does not record one under its own name. */
|
|
1467
|
+
path: string | null;
|
|
1468
|
+
bytes: number;
|
|
1469
|
+
}
|
|
1470
|
+
/** Every finished file in the disk-usage and pull-request caches; a file being written is not listed. */
|
|
1471
|
+
declare function listStatusCacheEntries(): StatusCacheEntry[];
|
|
1472
|
+
/** A worktree's cached pull request lookup: the branch and HEAD it was looked up for, and when. */
|
|
1473
|
+
interface PullRequestCacheEntry {
|
|
1474
|
+
path: string;
|
|
1475
|
+
branch: string;
|
|
1476
|
+
head: string;
|
|
1477
|
+
checkedAt: string;
|
|
1478
|
+
pullRequest: WorktreePullRequest | null;
|
|
1479
|
+
}
|
|
1480
|
+
/** The cached pull request lookup of the worktree at `path`, or null before one succeeded. */
|
|
1481
|
+
declare function readPullRequestCache(path: string): PullRequestCacheEntry | null;
|
|
1482
|
+
/** The cached size of the folder at `path`, or null before it was measured. */
|
|
1483
|
+
declare function readDiskUsage(path: string): DiskMeasure | null;
|
|
1484
|
+
/** The running build's tool detail its process last wrote, when the file belongs to the build with `claimId`. */
|
|
1485
|
+
declare function readBuildDetail(root: string, claimId: string): BuildDetail | null;
|
|
1486
|
+
/** The coding-agent sessions `status --watch` last found running on this Mac, and when it looked. */
|
|
1487
|
+
interface AgentSessionsCache {
|
|
1488
|
+
discoveredAt: string;
|
|
1489
|
+
sessions: AgentSession[];
|
|
1490
|
+
}
|
|
1491
|
+
/** An agent session as Stim wrote it to its cache or workspace state, or null when it is not one. */
|
|
1492
|
+
declare function agentSessionOf(value: unknown): AgentSession | null;
|
|
1493
|
+
/** How long a workspace keeps an agent session after it stopped running. */
|
|
1494
|
+
declare const ENDED_AGENT_RETENTION_MS: number;
|
|
1495
|
+
/** An ended agent session as Stim wrote it, or null when it is not one. */
|
|
1496
|
+
declare function endedAgentSessionOf(value: unknown): EndedAgentSession | null;
|
|
1497
|
+
/** The workspace's agent sessions that ended within `ENDED_AGENT_RETENTION_MS` of `now`, most recently ended first. */
|
|
1498
|
+
declare function readEndedAgentSessions(root: string, now: number): EndedAgentSession[];
|
|
1499
|
+
/** The agent sessions `status --watch` last cached, or null before it cached any. */
|
|
1500
|
+
declare function readAgentSessionsCache(): AgentSessionsCache | null;
|
|
1501
|
+
//#endregion
|
|
1502
|
+
//#region state/stim-build.d.ts
|
|
1503
|
+
/**
|
|
1504
|
+
* A digest of Stim's built code: the first 16 hex characters of the sha256 over the sorted `*.mjs` names and
|
|
1505
|
+
* bytes of a `stim` `dist` directory. A client and a build machine offload only when both compute the same one.
|
|
1506
|
+
*/
|
|
1507
|
+
declare function stimBuildDigest(dir: string): string | null;
|
|
1508
|
+
//#endregion
|
|
1509
|
+
//#region state/viewers.d.ts
|
|
1510
|
+
interface ViewedDevice {
|
|
1511
|
+
platform: "ios" | "android";
|
|
1512
|
+
/** The simulator UDID or the emulator serial. */
|
|
1513
|
+
id: string;
|
|
1514
|
+
}
|
|
1515
|
+
/** A stim-server's viewer record: the devices it streams frames of, and the server's process identity. */
|
|
1516
|
+
interface DeviceViewersRecord {
|
|
1517
|
+
pid: number;
|
|
1518
|
+
processToken: string;
|
|
1519
|
+
devices: ViewedDevice[];
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* The devices a running stim-server streams frames of. A record whose server is not proven to be the same live
|
|
1523
|
+
* process counts for nothing.
|
|
1524
|
+
*/
|
|
1525
|
+
declare function readViewedDevices(dir?: string): ViewedDevice[];
|
|
1526
|
+
//#endregion
|
|
1527
|
+
//#region state/stats.d.ts
|
|
1528
|
+
declare const STATS_VERSION = 1;
|
|
1529
|
+
interface StatsBucket {
|
|
1530
|
+
runs: number;
|
|
1531
|
+
failed: number;
|
|
1532
|
+
hits: number;
|
|
1533
|
+
misses: number;
|
|
1534
|
+
coldRuns: number;
|
|
1535
|
+
coldRunMs: number;
|
|
1536
|
+
hitRuns: number;
|
|
1537
|
+
hitRunMs: number;
|
|
1538
|
+
timeSavedMs: number;
|
|
1539
|
+
firstRunAt: string;
|
|
1540
|
+
lastRunAt: string;
|
|
1541
|
+
lastColdBuildMs?: number;
|
|
1542
|
+
lastPodsMs?: number;
|
|
1543
|
+
offloadedRuns?: number;
|
|
1544
|
+
offloadedRunMs?: number;
|
|
1545
|
+
lastOffloadHost?: string;
|
|
1546
|
+
}
|
|
1547
|
+
type StatsScope = Partial<Record<StatsPlatform, StatsBucket>>;
|
|
1548
|
+
interface RunSample {
|
|
1549
|
+
at: string;
|
|
1550
|
+
durationMs: number;
|
|
1551
|
+
phases: Record<string, number>;
|
|
1552
|
+
/** Whether the run created, adopted or cold-booted its device; absent on samples recorded before the tag. */
|
|
1553
|
+
deviceSetup?: boolean;
|
|
1554
|
+
}
|
|
1555
|
+
type RunHistory = Partial<Record<StatsPlatform, Partial<Record<RunOutcomeKind, RunSample[]>>>>;
|
|
1556
|
+
/** Where a compiling build ran: here, on a build machine, or here after offloading it failed. */
|
|
1557
|
+
declare const PLACEMENT_DECISIONS: readonly ["here", "offloaded", "fell-back"];
|
|
1558
|
+
type PlacementDecision = (typeof PLACEMENT_DECISIONS)[number];
|
|
1559
|
+
interface StatsPlacement {
|
|
1560
|
+
at: string;
|
|
1561
|
+
project: string;
|
|
1562
|
+
platform: StatsPlatform;
|
|
1563
|
+
decision: PlacementDecision;
|
|
1564
|
+
reason: string;
|
|
1565
|
+
machine?: string;
|
|
1566
|
+
buildMs?: number;
|
|
1567
|
+
/** The project's last cold build here before this run. */
|
|
1568
|
+
localEstimateMs?: number;
|
|
1569
|
+
failed?: true;
|
|
1570
|
+
}
|
|
1571
|
+
interface BuildMachineTotals {
|
|
1572
|
+
offloaded: number;
|
|
1573
|
+
offloadedMs: number;
|
|
1574
|
+
/** Sum of local estimate minus offloaded build time, over offloaded builds that had an estimate; can be negative. */
|
|
1575
|
+
savedMs: number;
|
|
1576
|
+
fallbacks: number;
|
|
1577
|
+
lastOffloadAt?: string;
|
|
1578
|
+
lastFallbackAt?: string;
|
|
1579
|
+
}
|
|
1580
|
+
interface StatsRecord {
|
|
1581
|
+
version: number;
|
|
1582
|
+
machine: StatsScope;
|
|
1583
|
+
projects: Record<string, StatsScope>;
|
|
1584
|
+
history?: Record<string, RunHistory>;
|
|
1585
|
+
placements?: StatsPlacement[];
|
|
1586
|
+
buildMachines?: Record<string, BuildMachineTotals>;
|
|
1587
|
+
}
|
|
1588
|
+
/**
|
|
1589
|
+
* The two phase durations a run reads back to size its own heartbeat: the
|
|
1590
|
+
* project's last cold build and its last `pod install`, in milliseconds.
|
|
1591
|
+
*/
|
|
1592
|
+
interface RunEstimates {
|
|
1593
|
+
coldBuildMs: number | null;
|
|
1594
|
+
podsMs: number | null;
|
|
1595
|
+
}
|
|
1596
|
+
interface ReadStatsResult {
|
|
1597
|
+
record: StatsRecord | null;
|
|
1598
|
+
note: string | null;
|
|
1599
|
+
}
|
|
1600
|
+
declare const HISTORY_LIMIT = 10;
|
|
1601
|
+
declare function statsProjectKey({ root, commonDir, repoRoot }: {
|
|
1602
|
+
root: string;
|
|
1603
|
+
commonDir: string | null;
|
|
1604
|
+
repoRoot: string | null;
|
|
1605
|
+
}): string;
|
|
1606
|
+
interface BuildMachineDay {
|
|
1607
|
+
offloaded: number;
|
|
1608
|
+
offloadedMs: number;
|
|
1609
|
+
savedMs: number;
|
|
1610
|
+
fallbacks: number;
|
|
1611
|
+
}
|
|
1612
|
+
interface OffloadSummary {
|
|
1613
|
+
today: {
|
|
1614
|
+
here: number;
|
|
1615
|
+
offloaded: number;
|
|
1616
|
+
fellBack: number;
|
|
1617
|
+
};
|
|
1618
|
+
machines: Record<string, {
|
|
1619
|
+
today: BuildMachineDay;
|
|
1620
|
+
total: BuildMachineTotals;
|
|
1621
|
+
}>;
|
|
1622
|
+
/** Newest first. */
|
|
1623
|
+
placements: StatsPlacement[];
|
|
1624
|
+
}
|
|
1625
|
+
/** Placement counts for the local calendar day of `now`, per-machine totals, and the retained placements. */
|
|
1626
|
+
declare function offloadSummary(record: StatsRecord | null, now: number): OffloadSummary;
|
|
1627
|
+
declare function trimSamples(samples: RunSample[]): RunSample[];
|
|
1628
|
+
declare function readStats(): ReadStatsResult;
|
|
1629
|
+
declare function readRunEstimates({ projectKey, platform, read }: {
|
|
1630
|
+
projectKey: string | null;
|
|
1631
|
+
platform: StatsPlatform;
|
|
1632
|
+
read?: () => ReadStatsResult;
|
|
1633
|
+
}): RunEstimates;
|
|
1634
|
+
declare function wholePhases(phases: unknown): Record<string, number>;
|
|
1635
|
+
declare function decodeStats(text: string): {
|
|
1636
|
+
record: StatsRecord | null;
|
|
1637
|
+
newerVersion: number | null;
|
|
1638
|
+
};
|
|
1639
|
+
interface StatsReport {
|
|
1640
|
+
version: number;
|
|
1641
|
+
project: ({
|
|
1642
|
+
key: string;
|
|
1643
|
+
} & StatsReport["machine"]) | null;
|
|
1644
|
+
machine: {
|
|
1645
|
+
ios: StatsBucket | null;
|
|
1646
|
+
android: StatsBucket | null;
|
|
1647
|
+
};
|
|
1648
|
+
offload: OffloadSummary;
|
|
1649
|
+
}
|
|
1650
|
+
declare function readStatsReport(key: string | null, now: number): {
|
|
1651
|
+
report: StatsReport;
|
|
1652
|
+
note: string | null;
|
|
1653
|
+
};
|
|
1654
|
+
declare function findProjectRoot(startDir: string): string | null;
|
|
1655
|
+
//#endregion
|
|
1656
|
+
//#region state/device-host.d.ts
|
|
1657
|
+
type HostedDevicePlatform = "ios" | "android" | "macos";
|
|
1658
|
+
interface HostedIosChoice {
|
|
1659
|
+
deviceTypeId: string;
|
|
1660
|
+
runtimeId: string;
|
|
1661
|
+
deviceType: string;
|
|
1662
|
+
runtime: string;
|
|
1663
|
+
architecture: "arm64" | "x86_64";
|
|
1664
|
+
}
|
|
1665
|
+
interface HostedIosDevice extends HostedIosChoice {
|
|
1666
|
+
udid: string;
|
|
1667
|
+
name: string;
|
|
1668
|
+
}
|
|
1669
|
+
interface HostedAndroidChoice {
|
|
1670
|
+
systemImage: string;
|
|
1671
|
+
deviceProfile: string;
|
|
1672
|
+
architecture: "arm64-v8a" | "x86_64";
|
|
1673
|
+
}
|
|
1674
|
+
interface HostedAndroidDevice extends HostedAndroidChoice {
|
|
1675
|
+
avdName: string;
|
|
1676
|
+
serial: string;
|
|
1677
|
+
consolePort: number;
|
|
1678
|
+
}
|
|
1679
|
+
type HostedDevice = HostedIosDevice | HostedAndroidDevice | HostedMacosDevice;
|
|
1680
|
+
interface HostedDeviceSelectors {
|
|
1681
|
+
deviceType?: string;
|
|
1682
|
+
runtime?: string;
|
|
1683
|
+
systemImage?: string;
|
|
1684
|
+
deviceProfile?: string;
|
|
1685
|
+
}
|
|
1686
|
+
interface HostedDeviceOfferRequest extends HostedDeviceSelectors {
|
|
1687
|
+
platform: HostedDevicePlatform;
|
|
1688
|
+
}
|
|
1689
|
+
type HostedNativeOffer = {
|
|
1690
|
+
resources: {
|
|
1691
|
+
cpus: number;
|
|
1692
|
+
/** Five-minute system load divided by available CPU count. */
|
|
1693
|
+
loadPerCore: number;
|
|
1694
|
+
memoryFreeBytes: number;
|
|
1695
|
+
memoryPressure: "normal" | "warning" | "critical" | null;
|
|
1696
|
+
/** Available bytes on the Stim home volume, not necessarily the Android AVD volume. */
|
|
1697
|
+
workerDiskFreeBytes: number | null;
|
|
1698
|
+
};
|
|
1699
|
+
declined: string | null;
|
|
1700
|
+
} & ({
|
|
1701
|
+
platform: "ios";
|
|
1702
|
+
choice: HostedIosChoice | null;
|
|
1703
|
+
} | {
|
|
1704
|
+
platform: "android";
|
|
1705
|
+
choice: HostedAndroidChoice | null;
|
|
1706
|
+
} | {
|
|
1707
|
+
platform: "macos";
|
|
1708
|
+
choice: HostedMacosChoice | null;
|
|
1709
|
+
});
|
|
1710
|
+
type HostedDeviceOffer = HostedNativeOffer & {
|
|
1711
|
+
capacity: {
|
|
1712
|
+
running: number;
|
|
1713
|
+
max: number;
|
|
1714
|
+
available: number | null;
|
|
1715
|
+
};
|
|
1716
|
+
};
|
|
1717
|
+
interface HostedDeviceRequest extends HostedDeviceOfferRequest {
|
|
1718
|
+
workspace: string;
|
|
1719
|
+
slot: string;
|
|
1720
|
+
attempt: string;
|
|
1721
|
+
}
|
|
1722
|
+
type HostedDevicePhase = "preparing" | "ready" | "stopping" | "stopped" | "unknown";
|
|
1723
|
+
interface HostedDeviceSession extends HostedDeviceRequest {
|
|
1724
|
+
id: string;
|
|
1725
|
+
client: string;
|
|
1726
|
+
state: HostedDevicePhase;
|
|
1727
|
+
device: HostedDevice | null;
|
|
1728
|
+
consolePort?: number;
|
|
1729
|
+
appSlot?: number;
|
|
1730
|
+
createdAt: string;
|
|
1731
|
+
notice?: string;
|
|
1732
|
+
appAttempt?: string;
|
|
1733
|
+
metroPort?: number;
|
|
1734
|
+
}
|
|
1735
|
+
declare function deviceHostRoot(): string;
|
|
1736
|
+
declare function deviceHostArea(id: string): string;
|
|
1737
|
+
declare function parseHostedChoice(value: unknown): HostedIosChoice | null;
|
|
1738
|
+
declare function parseHostedDevice(value: unknown): HostedIosDevice | null;
|
|
1739
|
+
declare function parseHostedAndroidDevice(value: unknown): HostedAndroidDevice | null;
|
|
1740
|
+
/** Android Emulator -help-port defines the supported even console ports as 5554 through 5584. */
|
|
1741
|
+
declare function hostedConsolePort(value: unknown): value is number;
|
|
1742
|
+
declare function parseHostedPlatformDevice(value: unknown, platform: HostedDevicePlatform): HostedDevice | null;
|
|
1743
|
+
declare function hostedDeviceId(device: HostedDevice): string;
|
|
1744
|
+
declare function parseHostedRequest(value: unknown): HostedDeviceRequest | null;
|
|
1745
|
+
declare function parseHostedOfferRequest(value: unknown): HostedDeviceOfferRequest | null;
|
|
1746
|
+
declare function parseHostedNativeOffer(value: unknown): HostedNativeOffer | null;
|
|
1747
|
+
/** A missing established journal or malformed record is a refusal, never an empty reservation set. */
|
|
1748
|
+
declare function readHostedSessions(): HostedDeviceSession[];
|
|
1749
|
+
/** The private worker's exact device record; an absent record is unresolved after creation started. */
|
|
1750
|
+
declare function readHostedDevice(home: string): HostedIosDevice;
|
|
1751
|
+
declare function readHostedDevice(home: string, platform: "android"): HostedAndroidDevice;
|
|
1752
|
+
declare function readHostedDevice(home: string, platform: "macos"): HostedMacosDevice;
|
|
1753
|
+
declare function readHostedDevice(home: string, platform: HostedDevicePlatform): HostedDevice;
|
|
1754
|
+
/** Hosted sessions use isolated homes: only one exact device of their platform may appear in this ledger. */
|
|
1755
|
+
declare function assertHostedDeviceLedger(home: string, id: string, platform?: HostedDevicePlatform): void;
|
|
1756
|
+
//#endregion
|
|
1757
|
+
//#region state/device-host-machines.d.ts
|
|
1758
|
+
/** A separately approved hosting machine, pinned before sending its device token. */
|
|
1759
|
+
interface DeviceHostMachineCredential {
|
|
1760
|
+
machine: string;
|
|
1761
|
+
nodeId: string;
|
|
1762
|
+
dnsName: string;
|
|
1763
|
+
deviceId: string;
|
|
1764
|
+
deviceToken: string;
|
|
1765
|
+
state: "pending" | "approved";
|
|
1766
|
+
requestedAt: string;
|
|
1767
|
+
}
|
|
1768
|
+
/** An absent store is empty; unreadable or malformed credentials refuse access without discarding pins. */
|
|
1769
|
+
declare function readDeviceHostMachines(): DeviceHostMachineCredential[];
|
|
1770
|
+
//#endregion
|
|
1771
|
+
//#region state/tailnet.d.ts
|
|
1772
|
+
interface TailnetPeer {
|
|
1773
|
+
nodeId: string;
|
|
1774
|
+
dnsName: string;
|
|
1775
|
+
/** A tailnet address of the node; WireGuard delivers packets to it only from that node. */
|
|
1776
|
+
address: string;
|
|
1777
|
+
}
|
|
1778
|
+
declare function parseMachine(entry: string): {
|
|
1779
|
+
name: string;
|
|
1780
|
+
port: number;
|
|
1781
|
+
} | null;
|
|
1782
|
+
/**
|
|
1783
|
+
* The one peer in `tailscale status --json` whose MagicDNS name is `name` or starts with `name.`. `ID` there is
|
|
1784
|
+
* the node's StableID, the same value `tailscale whois` reports as `Node.StableID`.
|
|
1785
|
+
*/
|
|
1786
|
+
declare function findPeer(status: unknown, name: string): TailnetPeer | "missing" | "ambiguous";
|
|
1787
|
+
interface Endpoint {
|
|
1788
|
+
url: string;
|
|
1789
|
+
servername: string;
|
|
1790
|
+
host: string;
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* Connects to the pinned node's own tailnet address rather than resolving its name, so the socket reaches the
|
|
1794
|
+
* node whose ID was just checked. `tailscale serve` still needs the MagicDNS name for TLS (SNI and certificate)
|
|
1795
|
+
* and for its Host routing.
|
|
1796
|
+
*/
|
|
1797
|
+
declare function endpoint(peer: TailnetPeer, port: number): Endpoint;
|
|
1798
|
+
/**
|
|
1799
|
+
* The endpoint of a paired machine's pinned node, or why Stim does not connect to it. The name must still
|
|
1800
|
+
* resolve to exactly the pinned node; the token is never sent anywhere else.
|
|
1801
|
+
*/
|
|
1802
|
+
declare function pinnedEndpoint(credential: {
|
|
1803
|
+
machine: string;
|
|
1804
|
+
nodeId: string;
|
|
1805
|
+
}, current: unknown): Endpoint | string;
|
|
1806
|
+
//#endregion
|
|
1807
|
+
//#region state/hosted-logs.d.ts
|
|
1808
|
+
type HostedLogsCursor = Record<string, number>;
|
|
1809
|
+
interface HostedLogsPage {
|
|
1810
|
+
records: NdjsonRecord[];
|
|
1811
|
+
cursor: HostedLogsCursor;
|
|
1812
|
+
/** True when the budget ended this page before the end of the logs; ask again with `cursor`. */
|
|
1813
|
+
more: boolean;
|
|
1814
|
+
}
|
|
1815
|
+
declare const HOSTED_LOGS_PAGE_BYTES: number;
|
|
1816
|
+
declare const HOSTED_LOGS_FIRST_BYTES: number;
|
|
1817
|
+
declare function parseHostedLogsCursor(value: unknown): HostedLogsCursor | null;
|
|
1818
|
+
declare function hostedMacosLogsDir(home: string): string | null;
|
|
1819
|
+
/**
|
|
1820
|
+
* The records in `dir` after `cursor`, in file order. A file without a cursor entry starts at most
|
|
1821
|
+
* {@link HOSTED_LOGS_FIRST_BYTES} before its end. A file that shrank since the cursor was taken was rotated: the end of
|
|
1822
|
+
* its previous generation is read first, and only as much of it as the page budget allows.
|
|
1823
|
+
*/
|
|
1824
|
+
declare function readLogsSince(dir: string, cursor: HostedLogsCursor): HostedLogsPage;
|
|
1825
|
+
//#endregion
|
|
1826
|
+
export { StatsPlacement as $, levelRank as $a, configLockPath as $i, DevServerStopRequest as $n, hostedAppAttempt as $r, BuildPhase as $t, deviceHostArea as A, workspaceStateFile as Aa, expectedShape as Ai, STATUS_ISSUE_CODES as An, DeviceRecord as Ao, readMacosRecord as Ar, withDerivedFacts as At, parseHostedRequest as B, followLogs as Ba, RecordingPlatform as Bi, WarmStep as Bn, MachineCapacity as Bo, HostedMacosPlacement as Br, AndroidDeviceState as Bt, HostedDeviceRequest as C, workspaceEndedAgentsFile as Ca, SettingsPayload as Ci, NativeBuildStep as Cn, getProjectSettings as Co, MacosAppRecord as Cr, listStatusCacheEntries as Ct, HostedIosDevice as D, workspaceLogsDir as Da, WebViewport as Di, PlannedPhase as Dn, withConfigLock as Do, macosAppState as Dr, readDiskUsage as Dt, HostedIosChoice as E, workspaceLogErrorIndex as Ea, WEB_VIEWPORTS as Ei, PhysicalDeviceState as En, loadConfig as Eo, MacosProcess as Er, readBuildDetail as Et, parseHostedChoice as F, attachExpoErrorContext as Fa, RECORDING_CAP_BYTES as Fi, StatusIssueCode as Fn, SettingsObject as Fo, HostedAgentGrant as Fr, ActiveBuildState as Ft, OffloadSummary as G, readLogRecords as Ga, listSegments as Gi, WorktreeFacts as Gn, tryAcquireBuildSlotClaim as Go, parseHostedMacosDevice as Gr, BuildCacheHit as Gt, readHostedSessions as H, markerWindow as Ha, closedSegmentName as Hi, WebPageState as Hn, buildSlotsDir as Ho, hostedMacosBundleId as Hr, AppPresence as Ht, parseHostedDevice as I, buildCriteria as Ia, RECORDING_FOOTAGE_MS as Ii, StatusPayload as In, StimConfig as Io, HostedAgentLease as Ir, ActivityDriver as It, RunEstimates as J, tailRead as Ja, recordingDeviceName as Ji, BUILD_HISTORY_KEY as Jn, HostedAppDelivery as Jr, BuildDiagnostic as Jt, PLACEMENT_DECISIONS as K, recordMatches as Ka, openSegmentName as Ki, WorktreeGit as Kn, parseHostedMacosPlacement as Kr, BuildCause as Kt, parseHostedNativeOffer as L, bundleMarkerPlatform as La, RECORDING_PLATFORMS as Li, WEB_PAGE_STATES as Ln, SupervisorRecord as Lo, HostedAppLaunch as Lr, ActivityRecencyBasis as Lt, hostedConsolePort as M, ERROR_SOURCES as Ma, isSensitiveReference as Mi, StatsPlatform as Mn, PlatformRecords as Mo, HOSTED_MACOS_APP_SLOTS as Mr, ACTIVITY_RECENCY_BASES as Mt, hostedDeviceId as N, QueryCriteria as Na, settingDefinition as Ni, StatusCapacity as Nn, ProjectRecord as No, HostedAgentAccess as Nr, AGENT_TOOLS as Nt, HostedNativeOffer as O, workspaceMetadataFile as Oa, acceptsShape as Oi, RemoteDeviceState as On, ConcurrencyLimits as Oo, parseMacosRecord as Or, readEndedAgentSessions as Ot, parseHostedAndroidDevice as P, advanceTail as Pa, settingValueError as Pi, StatusIssue as Pn, RepoRecord as Po, HostedAgentDriverName as Pr, APP_PROCESS_STATES as Pt, StatsBucket as Q, SOURCES as Qa, buildMachinesLock as Qi, DevServerStopRecord as Qn, hostedAppArea as Qr, BuildMissReason as Qt, parseHostedOfferRequest as R, compileGrep as Ra, RecordedDevice as Ri, WORKSPACE_PHASES as Rn, BuildMachineCredential as Ro, HostedMacosChoice as Rr, AgentSession as Rt, HostedDevicePlatform as S, workspaceDerivedData as Sa, SettingType as Si, NATIVE_BUILD_STEPS as Sn, getProjectSetting as So, workspaceLastUsed as Sr, endedAgentSessionOf as St, HostedDeviceSession as T, workspaceGradleBuild as Ta, TunnelMode as Ti, PhysicalDeviceConnection as Tn, isPathPrefix as To, MacosBuild as Tr, readAgentSessionsCache as Tt, BuildMachineTotals as U, parseSince as Ua, footageDrops as Ui, WorkspacePhase as Un, machineCapacity as Uo, parseHostedAgentGrant as Ur, BUILD_PHASES as Ut, readHostedDevice as V, logFiles as Va, capDrops as Vi, WebBrowserState as Vn, buildSlotPath as Vo, hostedMacosAppSlot as Vr, AndroidRuntimeFacts as Vt, HISTORY_LIMIT as W, queryLogs as Wa, listRecordedDevices as Wi, WorkspaceStage as Wn, saturation as Wo, parseHostedMacosChoice as Wr, BUILD_RESULTS as Wt, RunSample as X, LEVELS as Xa, agentSessionsCacheFile as Xi, DEVICE_IDLE_SHUTDOWN_KEY as Xn, HostedAppOffer as Xr, BuildMissCategory as Xt, RunHistory as Y, countErrorEntries as Ya, recordingEnabled as Yi, BUILD_HISTORY_LIMIT as Yn, HostedAppFile as Yr, BuildHistoryEntry as Yt, STATS_VERSION as Z, NdjsonRecord as Za, buildMachinesFile as Zi, DEV_SERVER_STOP_REQUEST_KEY as Zn, HostedAppRecord as Zr, BuildMissChange as Zt, HostedAndroidDevice as _, sharedPods as _a, SETTING_GROUPS as _i, MachineOwner as _n, configCorruptRepair as _o, readIdleStop as _r, ENDED_AGENT_RETENTION_MS as _t, hostedMacosLogsDir as a, deviceViewersDir as aa, SETTINGS_SCHEMA_FILE as ai, DeviceActivity as an, EasSessionClaim as ao, READY_PHASE_MS as ar, offloadSummary as at, HostedDeviceOfferRequest as b, supervisorPidFile as ba, SettingEntry as bi, MemorySource as bn, getConcurrencyLimits as bo, readWorkspaceAgent as br, agentSessionOf as bt, Endpoint as c, easSessionLedgerFile as ca, ANDROID_COMPILER_CACHE_CHOICES as ci, DiskMeasure as cn, readEasSessionLedger as co, WarmRecord as cr, readStatsReport as ct, findPeer as d, getConfigPath as da, IOS_SIMULATOR_APPS as di, EnvironmentState as dn, readJsonFile as do, lastUseFrom as dr, wholePhases as dt, createdDevicesFile as ea, parseHostedAppManifest as ei, BuildPlacement as en, parseNdjsonLine as eo, DeviceIdleShutdownRecord as er, StatsRecord as et, parseMachine as f, gitMergeCacheDir as fa, OFFLOAD_MODES as fi, GitChip as fn, readJsonObject as fo, parseMissReason as fr, DeviceViewersRecord as ft, HostedAndroidChoice as g, sharedGradle as ga, SETTINGS as gi, MEMORY_SOURCES as gn, buildWorkerRoot as go, readDeviceIdleShutdowns as gr, AgentSessionsCache as gt, readDeviceHostMachines as h, sharedCompilationCache as ha, RemoteDeviceBackend as hi, MACHINE_OWNER_KINDS as hn, allMetroPorts as ho, readDevServerStopRequest as hr, stimBuildDigest as ht, HostedLogsPage as i, deviceHostMachinesLock as ia, validHostedAppArguments as ii, ChecksState as in, CreatedDevices as io, MetroLastStop as ir, findProjectRoot as it, deviceHostRoot as j, workspaceStateLock as ja, isLayeredSetting as ji, SimulatorState as jn, DoctorRunRecord as jo, HOSTED_AGENT_DRIVERS as jr, withGitChip as jt, assertHostedDeviceLedger as k, workspaceRecordingsDir as ka, coerceSettingText as ki, RunOutcomeKind as kn, Config as ko, readHostedMacosApp as kr, readPullRequestCache as kt, TailnetPeer as l, easSessionLedgerLock as la, ANDROID_EMULATOR_APPS as li, EndedAgentSession as ln, validEasSessionClaim as lo, WorkspaceState as lr, statsProjectKey as lt, DeviceHostMachineCredential as m, sharedCcache as ma, REMOTE_DEVICE_BACKENDS as mi, LastBuildReport as mn, withStateReadCache as mo, readDevServerStop as mr, readViewedDevices as mt, HOSTED_LOGS_PAGE_BYTES as n, deviceHostMachinesClaims as na, readHostedApp as ni, BuildReport as nn, readNdjsonGenerations as no, IdleStopRecord as nr, StatsScope as nt, parseHostedLogsCursor as o, diskUsageCacheDir as oa, SETTINGS_SCHEMA_URL as oi, DeviceAppProcess as on, EasSessionLedgerRead as oo, WARM_KEY as or, readRunEstimates as ot, pinnedEndpoint as p, pullRequestCacheDir as pa, OffloadMode as pi, GitChipPart as pn, readStateFile as po, readBuildHistory as pr, ViewedDevice as pt, ReadStatsResult as q, sortByTs as qa, recordedBytes as qi, WorktreePullRequest as qn, HOSTED_APP_CHUNK_BYTES as qr, BuildDetail as qt, HostedLogsCursor as r, deviceHostMachinesFile as ra, readHostedAppMetadata as ri, BuildResult as rn, CreatedDevicePlatform as ro, LAST_BUILD_KEYS as rr, decodeStats as rt, readLogsSince as s, easMachineStateRoot as sa, settingsJsonSchema as si, DeviceLeaseState as sn, readCreatedDevices as so, WORKSPACE_AGENT_KEY as sr, readStats as st, HOSTED_LOGS_FIRST_BYTES as t, createdDevicesLock as ta, parseHostedAppOffer as ti, BuildPlanPayload as tn, parseNdjsonText as to, IDLE_STOP_KEY as tr, StatsReport as tt, endpoint as u, emulatorLogFile as ua, ANDROID_PCH_CHOICES as ui, EnvironmentDisk as un, isJsonObject as uo, buildDiagnostics as ur, trimSamples as ut, HostedDevice as v, statsFile as va, SETTING_SCOPES as vi, MachineOwnerKind as vn, findEnclosingWorktreeRoot as vo, readLastBuilds as vr, PullRequestCacheEntry as vt, HostedDeviceSelectors as w, workspaceEndedAgentsLock as wa, TUNNEL_MODES as wi, PHYSICAL_DEVICE_CONNECTIONS as wn, getRepoSettings as wo, MacosAppState as wr, pullRequestCacheFile as wt, HostedDevicePhase as x, workspaceBuildDetailFile as xa, SettingScope as xi, MetroBundleState as xn, getProject as xo, readWorkspaceState as xr, diskUsageCacheFile as xt, HostedDeviceOffer as y, supervisorLogFile as ya, SettingDefinition as yi, MachineUsageState as yn, findProjectByMetroPort as yo, readWarmRecord as yr, StatusCacheEntry as yt, parseHostedPlatformDevice as z, fileSizes as za, RecordedSegment as zi, WORKSPACE_STAGE_KINDS as zn, readBuildMachines as zo, HostedMacosDevice as zr, AgentTool as zt };
|