stim 1.0.0 → 1.2.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.
Files changed (66) hide show
  1. package/README.md +29 -10
  2. package/dist/android-BW8i_YxU.mjs +204 -0
  3. package/dist/android-Bcmev2s2.mjs +2334 -0
  4. package/dist/android-K63_0UfF.mjs +727 -0
  5. package/dist/android-cas-D6HPZ6UQ.mjs +1078 -0
  6. package/dist/android-cas-compiler.mjs +2 -2
  7. package/dist/app-install-NFxUahnH.mjs +1149 -0
  8. package/dist/build-lock-BsVoLDaq.mjs +645 -0
  9. package/dist/build-slots-D0b6sJyo.mjs +152 -0
  10. package/dist/{cache-manifest-4tH64LQ9.mjs → cache-manifest-Cu4_Znw9.mjs} +2 -2
  11. package/dist/cache-manifest.mjs +1 -1
  12. package/dist/cli.mjs +24 -27166
  13. package/dist/collector-run.d.mts +1 -0
  14. package/dist/collector-run.mjs +7 -5
  15. package/dist/command-output-8wHMEde0.mjs +289 -0
  16. package/dist/{config-7kmtuhO2.mjs → config-CMtIaTk9.mjs} +44 -13
  17. package/dist/deps-BLBsTNDS.mjs +435 -0
  18. package/dist/dev-client-RpvXxCXV.mjs +620 -0
  19. package/dist/device-CoCPmazS.mjs +250 -0
  20. package/dist/device-lease-Dpik41RY.mjs +335 -0
  21. package/dist/device-pool-B5pEVa3t.mjs +408 -0
  22. package/dist/device-remote-E81KAdXf.mjs +1209 -0
  23. package/dist/doctor-CqPeMsSm.mjs +1130 -0
  24. package/dist/doctor-D_CX7ib5.mjs +530 -0
  25. package/dist/error-diagnostics-Dw8Gn3yw.mjs +636 -0
  26. package/dist/{exec-bsN9MJXb.mjs → exec-CyylIdq9.mjs} +4 -2
  27. package/dist/gc-B7KkDinF.mjs +1665 -0
  28. package/dist/guide-BS2Xc24o.mjs +4503 -0
  29. package/dist/ios-B7KLgIp5.mjs +2733 -0
  30. package/dist/ios-D1h1Di39.mjs +451 -0
  31. package/dist/ios-device-D3pzTKQE.mjs +81 -0
  32. package/dist/ios-device-xNt0Lg6v.mjs +413 -0
  33. package/dist/logs-DcX9AvRF.mjs +176 -0
  34. package/dist/logs-query-oqn47Ffx.mjs +273 -0
  35. package/dist/metro-COslRK_F.mjs +184 -0
  36. package/dist/metro-store-CDDZHtPl.mjs +92 -0
  37. package/dist/ownership-CGPart6T.mjs +60 -0
  38. package/dist/ownership-CYOyqxUo.mjs +475 -0
  39. package/dist/ownership-claim-7zRxxTfZ.mjs +569 -0
  40. package/dist/{project-Dit1CckW.mjs → project-BBTVABUz.mjs} +12 -3
  41. package/dist/reclaim-C5Jmuahx.mjs +348 -0
  42. package/dist/reload-Z8nKifAk.mjs +332 -0
  43. package/dist/remote-cache-DDmJ1Roq.mjs +994 -0
  44. package/dist/{server-bare-BmTVVmBB.mjs → server-bare-DEk37Mz2.mjs} +8 -2
  45. package/dist/{server-expo-CHJe1r6j.mjs → server-expo-C3ktAwUG.mjs} +6 -5
  46. package/dist/server-expo-Drd7ksHu.mjs +2 -0
  47. package/dist/settings-DwU1_U_q.mjs +708 -0
  48. package/dist/spawn-entry-nCE6m770.mjs +14 -0
  49. package/dist/start-BrY4EuIg.mjs +822 -0
  50. package/dist/{state-2nush3MK.mjs → state-CZ-ER-8d.mjs} +21 -22
  51. package/dist/stats-BCWEVLrM.mjs +307 -0
  52. package/dist/stats-BsF15Bti.mjs +62 -0
  53. package/dist/status-DFI1Hfpg.mjs +393 -0
  54. package/dist/stop-B7DR4awK.mjs +3 -0
  55. package/dist/stop-Btg770vV.mjs +591 -0
  56. package/dist/supervisor-run.d.mts +0 -1
  57. package/dist/supervisor-run.mjs +4 -4
  58. package/dist/workspace-process-lock-BKfdys1q.mjs +47 -0
  59. package/dist/worktree-BPTbI-LN.mjs +1322 -0
  60. package/dist/worktree-C79xx_kM.mjs +543 -0
  61. package/dist/xcode-DeKCribl.mjs +1832 -0
  62. package/package.json +5 -5
  63. package/shim/bundle-response.cjs +5 -0
  64. package/dist/android-jc8MnUyL.mjs +0 -514
  65. package/dist/metro-store-COLl1pOk.mjs +0 -1249
  66. package/dist/server-expo-BZJm--wA.mjs +0 -2
@@ -0,0 +1,393 @@
1
+ import { t as getExecutor } from "./exec-CyylIdq9.mjs";
2
+ import { P as volumeRootFor, g as loadConfig, u as getConfigDir } from "./config-CMtIaTk9.mjs";
3
+ import { D as workspaceLogsDir } from "./state-CZ-ER-8d.mjs";
4
+ import { f as listWorktrees } from "./worktree-C79xx_kM.mjs";
5
+ import { a as findProjectRoot, c as projectShortcut } from "./project-BBTVABUz.mjs";
6
+ import { a as isMetroRunning, i as resolveProjectMetro } from "./metro-COslRK_F.mjs";
7
+ import { S as readParked, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DDmJ1Roq.mjs";
8
+ import { a as formatElapsed, r as clockTime, u as plural } from "./command-output-8wHMEde0.mjs";
9
+ import { u as listAllIosSims } from "./ios-D1h1Di39.mjs";
10
+ import { i as listLeaseFiles } from "./device-lease-Dpik41RY.mjs";
11
+ import { N as resolveOwnedAvdSerial } from "./android-K63_0UfF.mjs";
12
+ import { s as queryLogs } from "./logs-query-oqn47Ffx.mjs";
13
+ import { t as resolveSupervisorTarget } from "./ownership-CYOyqxUo.mjs";
14
+ import { i as readSupervisorState } from "./stop-Btg770vV.mjs";
15
+ import { existsSync } from "fs";
16
+ import { totalmem } from "os";
17
+ import chalk from "chalk";
18
+ //#region src/status.ts
19
+ const IOS_SIM_MB = 1500;
20
+ const ANDROID_EMULATOR_MB = 2500;
21
+ const METRO_MB = 700;
22
+ function poolLine({ platform, parked, max }) {
23
+ if (parked <= 0) return null;
24
+ const what = plural(parked, `parked ${platform === "ios" ? "iOS simulator" : "Android emulator"}`);
25
+ return max > 0 ? `pool: ${what} (max ${max})` : `pool: ${what} (parking off; gc --delete removes them)`;
26
+ }
27
+ function environmentState(project, { simsByUdid = {}, metro = null, worktrees = [], simsAvailable = true, androidRuntime = null, supervisor = null, logs = null } = {}) {
28
+ const ios = project.platforms?.ios;
29
+ const android = project.platforms?.android;
30
+ const sim = ios ? simsByUdid[ios.deviceUdid] : null;
31
+ const simBooted = Boolean(sim && sim.state === "Booted");
32
+ const metroRunning = Boolean(metro?.metro);
33
+ const androidDetected = androidRuntime ? Boolean(androidRuntime.serial) : Boolean(android?.serial);
34
+ const live = simBooted || metroRunning || androidDetected;
35
+ let memoryMb = 0;
36
+ if (simBooted) memoryMb += IOS_SIM_MB;
37
+ if (androidDetected) memoryMb += ANDROID_EMULATOR_MB;
38
+ if (metroRunning) memoryMb += METRO_MB;
39
+ const warnings = [];
40
+ if (metro?.notOurs) warnings.push(`port ${project.metroPort}: ${metro.notOurs}`);
41
+ if (ios && !sim && simsAvailable) warnings.push(`recorded sim ${ios.deviceUdid} no longer exists`);
42
+ if (simBooted && project.metroPort && !metroRunning) warnings.push("simulator is booted with no Metro serving it");
43
+ if (androidRuntime && android?.avdName) {
44
+ const recordedSerial = android.consolePort ? `emulator-${android.consolePort}` : android.serial;
45
+ if (androidRuntime.serial && recordedSerial && androidRuntime.serial !== recordedSerial) warnings.push(`owned AVD ${android.avdName} changed serial (${recordedSerial} -> ${androidRuntime.serial}); rerun your \`stim android\` command in this workspace to restore Metro forwarding, then reopen agent-device on ${androidRuntime.serial}`);
46
+ if (androidRuntime.state === "missing") warnings.push(`recorded AVD ${android.avdName} no longer exists`);
47
+ if (androidRuntime.state === "not-detected") warnings.push(`owned AVD ${android.avdName} is not detected by adb; rerun your \`stim android\` command in this workspace to reconnect`);
48
+ if (androidRuntime.error) warnings.push(`could not check owned AVD ${android.avdName}: ${androidRuntime.error}`);
49
+ }
50
+ if (supervisor && supervisor.alive === false) warnings.push(`stale supervisor record for ${project.__path}`);
51
+ return {
52
+ path: project.__path,
53
+ live,
54
+ memoryMb,
55
+ warnings,
56
+ ios: ios ? {
57
+ name: sim?.name ?? null,
58
+ udid: ios.deviceUdid,
59
+ owned: Boolean(ios.owned),
60
+ state: sim?.state ?? (simsAvailable ? "missing" : "unknown")
61
+ } : null,
62
+ android: android ? {
63
+ name: android.avdName ?? android.serial,
64
+ owned: Boolean(android.owned),
65
+ physical: Boolean(android.serial && !android.avdName),
66
+ ...androidRuntime ? {
67
+ serial: androidRuntime.serial,
68
+ state: androidRuntime.state
69
+ } : {}
70
+ } : null,
71
+ metro: project.metroPort ? {
72
+ port: project.metroPort,
73
+ running: metroRunning,
74
+ pid: metro?.metro?.pid ?? null
75
+ } : null,
76
+ supervisor: supervisor ? {
77
+ pid: supervisor.pid ?? null,
78
+ mode: supervisor.mode ?? null,
79
+ startedAt: supervisor.startedAt ?? null,
80
+ healthy: Boolean(supervisor.healthy)
81
+ } : null,
82
+ logs: logs ? {
83
+ dir: logs.dir,
84
+ errorsSinceMarker: logs.errorsSinceMarker ?? 0
85
+ } : null,
86
+ worktree: worktrees.find((w) => w.path === project.__path) ?? null
87
+ };
88
+ }
89
+ function capacity(states, totalMemoryMb) {
90
+ const committedMb = states.reduce((n, s) => n + s.memoryMb, 0);
91
+ return {
92
+ liveCount: states.filter((s) => s.live).length,
93
+ committedMb,
94
+ totalMemoryMb,
95
+ overCapacity: Boolean(totalMemoryMb && committedMb > totalMemoryMb * .6)
96
+ };
97
+ }
98
+ function parseDfFree(output) {
99
+ const lines = String(output || "").trim().split("\n");
100
+ if (lines.length < 2) return null;
101
+ const lastLine = lines[lines.length - 1];
102
+ if (lastLine === void 0) return null;
103
+ const m = /\s(\d+)\s+(\d+)\s+(\d+)\s+(\d+)%/.exec(lastLine);
104
+ if (!m) return null;
105
+ const totalKb = Number(m[1]);
106
+ const availableKb = Number(m[3]);
107
+ if (!Number.isFinite(totalKb) || !Number.isFinite(availableKb) || totalKb <= 0) return null;
108
+ return {
109
+ availableMb: Math.round(availableKb / 1024),
110
+ totalMb: Math.round(totalKb / 1024)
111
+ };
112
+ }
113
+ function diskIsTight(disk) {
114
+ return Boolean(disk && disk.availableMb < 25600);
115
+ }
116
+ function formatSpace(mb) {
117
+ if (!Number.isFinite(mb)) return "?";
118
+ if (mb >= 1048576) return `${(mb / 1048576).toFixed(1)} TB`;
119
+ if (mb >= 1024) return `${Math.round(mb / 1024)} GB`;
120
+ return `${Math.round(mb)} MB`;
121
+ }
122
+ function diskLine(volumes) {
123
+ const usable = (volumes || []).filter((v) => Boolean(v && v.disk));
124
+ if (usable.length === 0) return null;
125
+ if (usable.length === 1) {
126
+ const first = usable[0];
127
+ if (!first) return null;
128
+ const { disk } = first;
129
+ return `${formatSpace(disk.availableMb)} free of ${formatSpace(disk.totalMb)} on disk.`;
130
+ }
131
+ return `${usable.map((v) => `${formatSpace(v.disk.availableMb)} free on ${v.volume}`).join(", ")}.`;
132
+ }
133
+ function tightVolumes(volumes) {
134
+ return (volumes || []).filter((v) => v && diskIsTight(v.disk));
135
+ }
136
+ function unprovisionedWorktrees(worktrees, projectPaths) {
137
+ const known = new Set(projectPaths);
138
+ return worktrees.filter((w) => !known.has(w.path));
139
+ }
140
+ function deviceLeaseStates(entries, { root, now }) {
141
+ return entries.map((entry) => {
142
+ const lease = entry.lease;
143
+ return {
144
+ path: entry.path,
145
+ platform: entry.platform,
146
+ id: entry.id,
147
+ deviceName: lease?.deviceName ?? null,
148
+ holder: lease?.holder ?? null,
149
+ grantedAt: lease?.grantedAt ?? null,
150
+ expiresAt: lease?.expiresAt ?? null,
151
+ mine: Boolean(lease && root && lease.holder === root),
152
+ expired: Boolean(lease && Date.parse(lease.expiresAt) <= now),
153
+ parsed: Boolean(lease)
154
+ };
155
+ });
156
+ }
157
+ function deviceLeaseLines(states, now) {
158
+ if (states.length === 0) return [];
159
+ const lines = [`Device leases (${states.length}):`];
160
+ for (const state of states) {
161
+ const device = `${state.platform} ${state.id ?? state.path}${state.deviceName ? ` (${state.deviceName})` : ""}`;
162
+ if (!state.parsed || state.expiresAt === null) {
163
+ lines.push(` ${device} -- unreadable lease file, so nothing may take the device: ${state.path}`);
164
+ continue;
165
+ }
166
+ const when = clockTime(state.expiresAt);
167
+ const remaining = Date.parse(state.expiresAt) - now;
168
+ const expiry = state.expired ? `expired at ${when}` : `until ${when} (${formatElapsed(remaining)} left)`;
169
+ lines.push(` ${device} -- ${state.holder} ${expiry}${state.mine ? " [this workspace]" : ""}`);
170
+ }
171
+ return lines;
172
+ }
173
+ //#endregion
174
+ //#region src/commands/status.ts
175
+ function formatGb(mb) {
176
+ return `${(mb / 1024).toFixed(1)} GB`;
177
+ }
178
+ function statusCommand(program) {
179
+ program.command("status").description("Show every environment on this machine: devices, ports, what is actually running, and anything stuck.").option("--json", "print the state as JSON").action(async (opts) => {
180
+ const cfg = loadConfig();
181
+ const projects = Object.entries(cfg?.projects || {});
182
+ const cwdRoot = findProjectRoot(process.cwd());
183
+ const simsByUdid = {};
184
+ let simsAvailable = true;
185
+ let simctlError = null;
186
+ try {
187
+ for (const sim of listAllIosSims()) simsByUdid[sim.udid] = sim;
188
+ } catch (e) {
189
+ simsAvailable = false;
190
+ simctlError = String(e?.message || e).split("\n")[0] ?? "";
191
+ }
192
+ const worktrees = listWorktrees(process.cwd()).slice(1);
193
+ const states = [];
194
+ const labelOnlyRoots = [];
195
+ for (const [path, proj] of projects) {
196
+ let metro = null;
197
+ if (proj.metroPort) metro = await resolveOnPort(proj.metroPort, path);
198
+ const supervisor = await supervisorFacts(path, proj, metro);
199
+ states.push(environmentState({
200
+ ...proj,
201
+ __path: path
202
+ }, {
203
+ simsByUdid,
204
+ metro,
205
+ worktrees,
206
+ simsAvailable,
207
+ androidRuntime: proj.platforms?.android?.owned && proj.platforms.android.avdName ? readAndroidRuntime(proj.platforms.android.avdName) : null,
208
+ supervisor,
209
+ logs: logFacts(path)
210
+ }));
211
+ const state = states[states.length - 1];
212
+ labelOnlyRoots.push(Boolean(proj.worktreeRoot && !proj.bundleId && !state?.metro && !state?.ios && !state?.android));
213
+ }
214
+ const leaseNow = Date.now();
215
+ const leases = deviceLeaseStates(listLeaseFiles(), {
216
+ root: cwdRoot,
217
+ now: leaseNow
218
+ });
219
+ const cap = capacity(states, Math.round(totalmem() / 1048576));
220
+ const orphanWorktrees = unprovisionedWorktrees(worktrees, projects.map(([p]) => p));
221
+ const pools = ["ios", "android"].map((platform) => {
222
+ const { max, error } = parkedMaxSetting(platform);
223
+ return {
224
+ error,
225
+ line: poolLine({
226
+ platform,
227
+ parked: readParked(platform).length,
228
+ max
229
+ })
230
+ };
231
+ });
232
+ if (opts.json) {
233
+ console.log(JSON.stringify({
234
+ environments: states.map((state, i) => labelOnlyRoots[i] ? {
235
+ ...state,
236
+ labelOnly: true
237
+ } : state),
238
+ capacity: cap,
239
+ deviceLeases: leases,
240
+ unprovisionedWorktrees: orphanWorktrees,
241
+ simctlAvailable: simsAvailable
242
+ }));
243
+ return;
244
+ }
245
+ if (projects.length === 0 && orphanWorktrees.length === 0) {
246
+ console.log(chalk.dim("No projects registered."));
247
+ for (const pool of pools) {
248
+ if (pool.error) console.log(chalk.yellow(`${pool.error} ${POOL_SETTING_REMEDY}`));
249
+ if (pool.line) console.log(chalk.dim(pool.line));
250
+ }
251
+ for (const line of deviceLeaseLines(leases, leaseNow)) console.log(line);
252
+ return;
253
+ }
254
+ if (!simsAvailable) console.log(chalk.yellow(`simctl could not be read (${simctlError}), so no iOS sim below could be checked.`));
255
+ for (const [i, [path, proj]] of projects.entries()) {
256
+ const state = states[i];
257
+ if (!state) continue;
258
+ const shortcut = projectShortcut(path, proj);
259
+ const marker = path === cwdRoot ? chalk.bold.cyan(`* ${shortcut}`) : shortcut;
260
+ const idle = state.live ? "" : chalk.dim(" [idle]");
261
+ console.log(`\n${marker}${idle} ${chalk.dim(`(${path})`)}`);
262
+ console.log(labelOnlyRoots[i] ? chalk.dim(" worktree root (holds the label; the app registers its own entry)") : chalk.dim(` app: ${proj.bundleId ?? "?"} (${proj.isExpo ? "expo" : "bare"})`));
263
+ if (state.metro) {
264
+ const label = state.metro.running ? chalk.green(`running (pid ${state.metro.pid})`) : chalk.dim("not running");
265
+ console.log(` metro: port ${state.metro.port} ${label}`);
266
+ }
267
+ if (state.supervisor) {
268
+ const health = state.supervisor.healthy ? chalk.green("healthy") : chalk.yellow("not answering");
269
+ const mode = state.supervisor.mode ? chalk.dim(` (${state.supervisor.mode})`) : "";
270
+ console.log(` supervisor: pid ${state.supervisor.pid}${mode} ${health}`);
271
+ }
272
+ if (state.logs) {
273
+ const n = state.logs.errorsSinceMarker;
274
+ const errs = n > 0 ? chalk.yellow(` (${n} error${n === 1 ? "" : "s"} since the last marker)`) : "";
275
+ console.log(chalk.dim(` logs: ${state.logs.dir}`) + errs);
276
+ }
277
+ if (state.ios) {
278
+ const booted = state.ios.state === "Booted" ? chalk.green("booted") : chalk.dim(state.ios.state.toLowerCase());
279
+ const owned = state.ios.owned ? chalk.dim(" (owned)") : "";
280
+ console.log(` ios: ${chalk.cyan(state.ios.name ?? state.ios.udid)} ${booted}${owned}`);
281
+ }
282
+ if (state.android) {
283
+ const kind = state.android.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
284
+ const observed = state.android.state ? ` ${state.android.state}${state.android.serial ? ` (${state.android.serial})` : ""}` : "";
285
+ console.log(` android: ${chalk.cyan(state.android.name)} ${kind}${observed}${state.android.owned ? chalk.dim(" (owned)") : ""}`);
286
+ }
287
+ for (const w of state.warnings) console.log(chalk.yellow(` ! ${w}`));
288
+ }
289
+ for (const pool of pools) {
290
+ if (pool.error) console.log(chalk.yellow(`\n${pool.error} ${POOL_SETTING_REMEDY}`));
291
+ if (pool.line) console.log(chalk.dim(`\n${pool.line}`));
292
+ }
293
+ const leaseLines = deviceLeaseLines(leases, leaseNow);
294
+ if (leaseLines.length) {
295
+ console.log("");
296
+ for (const line of leaseLines) console.log(line);
297
+ }
298
+ if (orphanWorktrees.length) {
299
+ console.log(chalk.dim(`\nWorktrees with no environment (${orphanWorktrees.length}):`));
300
+ for (const w of orphanWorktrees) console.log(chalk.dim(` ${w.path}${w.branch ? ` [${w.branch}]` : ""}`));
301
+ }
302
+ console.log(chalk.dim(`\n${cap.liveCount} live environment(s), roughly ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)} committed.`));
303
+ const volumes = readVolumes(cwdRoot || process.cwd());
304
+ const line = diskLine(volumes);
305
+ if (line) {
306
+ const tight = tightVolumes(volumes);
307
+ if (tight.length) {
308
+ const which = tight.map((v) => v.volume).join(" and ");
309
+ console.log(chalk.yellow(`${line} A single iOS build can exhaust ${which} -- run \`stim gc\` before starting another environment.`));
310
+ } else console.log(chalk.dim(line));
311
+ }
312
+ if (cap.overCapacity) console.log(chalk.yellow("Over comfortable capacity. A machine that swaps is slower than one working in sequence -- release one before starting another."));
313
+ });
314
+ }
315
+ function readAndroidRuntime(avdName) {
316
+ try {
317
+ const resolved = resolveOwnedAvdSerial(avdName, { timeoutMs: 5e3 });
318
+ return {
319
+ serial: resolved.serial ?? null,
320
+ state: resolved.serial ? "detected" : resolved.missing ? "missing" : resolved.notRunning ? "not-detected" : "unknown"
321
+ };
322
+ } catch (error) {
323
+ return {
324
+ serial: null,
325
+ state: "unknown",
326
+ error: String(error?.message || error).split("\n")[0]
327
+ };
328
+ }
329
+ }
330
+ function readVolumes(projectPath) {
331
+ const roots = [.../* @__PURE__ */ new Set([
332
+ "/",
333
+ volumeRootFor(getConfigDir()),
334
+ volumeRootFor(projectPath)
335
+ ])];
336
+ const volumes = [];
337
+ for (const volume of roots) {
338
+ const quoted = `'${volume.replace(/'/g, "'\\''")}'`;
339
+ const disk = parseDfFree(getExecutor().runQuiet(`df -k ${quoted}`, { timeoutMs: 5e3 }));
340
+ if (disk) volumes.push({
341
+ volume,
342
+ disk
343
+ });
344
+ }
345
+ return volumes;
346
+ }
347
+ async function resolveOnPort(port, path) {
348
+ return await isMetroRunning(port) ? resolveProjectMetro(port, path) : { missing: true };
349
+ }
350
+ async function supervisorFacts(path, proj, metroResolution) {
351
+ const state = readSupervisorState(path);
352
+ const record = proj?.supervisor ?? null;
353
+ const pid = state?.pid ?? record?.pid ?? null;
354
+ if (!pid) return null;
355
+ const port = state?.port ?? record?.port ?? null;
356
+ const alive = resolveSupervisorTarget({
357
+ state,
358
+ record,
359
+ reservedPort: proj?.metroPort
360
+ }).status === "ours";
361
+ let healthy = false;
362
+ if (alive && port) {
363
+ const resolution = port === proj?.metroPort && metroResolution ? metroResolution : await resolveOnPort(port, path);
364
+ healthy = Boolean(resolution?.metro);
365
+ }
366
+ return {
367
+ pid,
368
+ mode: state?.mode ?? record?.mode ?? null,
369
+ startedAt: state?.startedAt ?? record?.startedAt ?? null,
370
+ alive,
371
+ healthy
372
+ };
373
+ }
374
+ function logFacts(path) {
375
+ const dir = workspaceLogsDir(path);
376
+ if (!existsSync(dir)) return null;
377
+ try {
378
+ return {
379
+ dir,
380
+ errorsSinceMarker: queryLogs({
381
+ dir,
382
+ errorsOnly: true
383
+ }).length
384
+ };
385
+ } catch {
386
+ return {
387
+ dir,
388
+ errorsSinceMarker: 0
389
+ };
390
+ }
391
+ }
392
+ //#endregion
393
+ export { statusCommand as default, readVolumes };
@@ -0,0 +1,3 @@
1
+ import { t as resolveSupervisorTarget } from "./ownership-CYOyqxUo.mjs";
2
+ import { a as resolveCollectorTargets, i as readSupervisorState, n as clearSupervisorState, o as runStop, r as readCollectorState, s as stopCommand, t as clearCollectorState } from "./stop-Btg770vV.mjs";
3
+ export { clearCollectorState, clearSupervisorState, stopCommand as default, readCollectorState, readSupervisorState, resolveCollectorTargets, resolveSupervisorTarget, runStop };