stim 0.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/android-CC5bUer7.mjs +204 -0
- package/dist/android-DnZlT3aU.mjs +2279 -0
- package/dist/android-cas-DGlTStWu.mjs +1078 -0
- package/dist/android-cas-compiler.d.mts +1 -0
- package/dist/android-cas-compiler.mjs +71 -0
- package/dist/android-xmyGBNy5.mjs +665 -0
- package/dist/app-install-oZIQRbdD.mjs +1141 -0
- package/dist/build-lock-vE45ZzJZ.mjs +645 -0
- package/dist/build-slots-CgacA9zQ.mjs +152 -0
- package/dist/cache-manifest-oeH18ERr.mjs +66 -0
- package/dist/cache-manifest.d.mts +27 -0
- package/dist/cache-manifest.mjs +2 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +40 -0
- package/dist/collector-run.d.mts +119 -0
- package/dist/collector-run.mjs +541 -0
- package/dist/command-output-8wHMEde0.mjs +289 -0
- package/dist/config-D7uu8Gbq.mjs +381 -0
- package/dist/deps-64wVnpZc.mjs +435 -0
- package/dist/dev-client-Bvky1hya.mjs +557 -0
- package/dist/device-DJKv5Qej.mjs +250 -0
- package/dist/device-lease-D-G3SgVe.mjs +335 -0
- package/dist/device-pool-BlHXnYYs.mjs +408 -0
- package/dist/device-remote-CCgkG82J.mjs +1209 -0
- package/dist/doctor-BRF9aAJ3.mjs +530 -0
- package/dist/doctor-DlVxTtMq.mjs +1137 -0
- package/dist/error-diagnostics-B5IJwv3-.mjs +636 -0
- package/dist/errors-B6W7FkxQ.mjs +15 -0
- package/dist/exec-bsN9MJXb.mjs +63 -0
- package/dist/gc-DhXdgSdt.mjs +1651 -0
- package/dist/guide-DrhrDBo5.mjs +4319 -0
- package/dist/ios-BZxKPuqP.mjs +382 -0
- package/dist/ios-CK1Vrk6Q.mjs +2721 -0
- package/dist/ios-device-CYbuRNXR.mjs +81 -0
- package/dist/ios-device-CdSm0GDw.mjs +413 -0
- package/dist/logs-Dxoy16Qv.mjs +176 -0
- package/dist/logs-query-oqn47Ffx.mjs +273 -0
- package/dist/metro-B01H3EuD.mjs +184 -0
- package/dist/metro-store-CDDZHtPl.mjs +92 -0
- package/dist/ndjson-DcAtEx_K.mjs +131 -0
- package/dist/ndjson-DvHSsNU9.d.mts +16 -0
- package/dist/ownership-B9QIdQOw.mjs +475 -0
- package/dist/ownership-D8HmSv2E.mjs +60 -0
- package/dist/ownership-claim-CeJLEpjD.mjs +569 -0
- package/dist/process-output-C7IlIzd7.mjs +40 -0
- package/dist/project-COj6nzzh.mjs +243 -0
- package/dist/reclaim-BPvN2HlP.mjs +347 -0
- package/dist/reload-DYZEBbZy.mjs +332 -0
- package/dist/remote-cache-DOi5-zLj.mjs +934 -0
- package/dist/server-bare-BYHqEeyw.mjs +352 -0
- package/dist/server-expo-BEMr_m6p.mjs +312 -0
- package/dist/server-expo-rb0k-0w7.mjs +2 -0
- package/dist/settings-BSwrY4FZ.mjs +687 -0
- package/dist/spawn-entry-nCE6m770.mjs +14 -0
- package/dist/start-ByCylYtB.mjs +822 -0
- package/dist/state-IYEY-zi8.mjs +268 -0
- package/dist/stats-DZ4Q5J-7.mjs +62 -0
- package/dist/stats-wqxPm7Tv.mjs +307 -0
- package/dist/status-Dia0XTqG.mjs +363 -0
- package/dist/stop-BApyaF21.mjs +591 -0
- package/dist/stop-D6o5zAdm.mjs +3 -0
- package/dist/supervisor-run.d.mts +84 -0
- package/dist/supervisor-run.mjs +210 -0
- package/dist/workspace-process-lock-CxOO9-pf.mjs +47 -0
- package/dist/worktree-Dx3ZC5lS.mjs +539 -0
- package/dist/worktree-DxEmUI_n.mjs +1322 -0
- package/dist/xcode-CDB6fytw.mjs +1705 -0
- package/package.json +61 -8
- package/shim/android-cas-pch.cmake +35 -0
- package/shim/android-cas.gradle +29 -0
- package/shim/android-cas.toolchain.cmake +12 -0
- package/shim/android-optimizations.gradle +30 -0
- package/shim/bundle-response.cjs +46 -0
- package/shim/bundle-response.d.cts +5 -0
- package/shim/expo-metro-config.cjs +188 -0
- package/shim/metro-cache-generation.cjs +20 -0
- package/shim/metro-cache-generation.d.cts +5 -0
- package/skill/SKILL.md +14 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { t as getExecutor } from "./exec-bsN9MJXb.mjs";
|
|
2
|
+
import { P as volumeRootFor, g as loadConfig, u as getConfigDir } from "./config-D7uu8Gbq.mjs";
|
|
3
|
+
import { D as workspaceLogsDir } from "./state-IYEY-zi8.mjs";
|
|
4
|
+
import { f as listWorktrees } from "./worktree-Dx3ZC5lS.mjs";
|
|
5
|
+
import { a as findProjectRoot, c as projectShortcut } from "./project-COj6nzzh.mjs";
|
|
6
|
+
import { a as isMetroRunning, i as resolveProjectMetro } from "./metro-B01H3EuD.mjs";
|
|
7
|
+
import { S as readParked, v as POOL_SETTING_REMEDY, x as parkedMaxSetting } from "./remote-cache-DOi5-zLj.mjs";
|
|
8
|
+
import { a as formatElapsed, r as clockTime, u as plural } from "./command-output-8wHMEde0.mjs";
|
|
9
|
+
import { l as listAllIosSims } from "./ios-BZxKPuqP.mjs";
|
|
10
|
+
import { i as listLeaseFiles } from "./device-lease-D-G3SgVe.mjs";
|
|
11
|
+
import { s as queryLogs } from "./logs-query-oqn47Ffx.mjs";
|
|
12
|
+
import { t as resolveSupervisorTarget } from "./ownership-B9QIdQOw.mjs";
|
|
13
|
+
import { i as readSupervisorState } from "./stop-BApyaF21.mjs";
|
|
14
|
+
import { existsSync } from "fs";
|
|
15
|
+
import { totalmem } from "os";
|
|
16
|
+
import chalk from "chalk";
|
|
17
|
+
//#region src/status.ts
|
|
18
|
+
const IOS_SIM_MB = 1500;
|
|
19
|
+
const ANDROID_EMULATOR_MB = 2500;
|
|
20
|
+
const METRO_MB = 700;
|
|
21
|
+
function poolLine({ platform, parked, max }) {
|
|
22
|
+
if (parked <= 0) return null;
|
|
23
|
+
const what = plural(parked, `parked ${platform === "ios" ? "iOS simulator" : "Android emulator"}`);
|
|
24
|
+
return max > 0 ? `pool: ${what} (max ${max})` : `pool: ${what} (parking off; gc --delete removes them)`;
|
|
25
|
+
}
|
|
26
|
+
function environmentState(project, { simsByUdid = {}, metro = null, worktrees = [], simsAvailable = true, supervisor = null, logs = null } = {}) {
|
|
27
|
+
const ios = project.platforms?.ios;
|
|
28
|
+
const android = project.platforms?.android;
|
|
29
|
+
const sim = ios ? simsByUdid[ios.deviceUdid] : null;
|
|
30
|
+
const simBooted = Boolean(sim && sim.state === "Booted");
|
|
31
|
+
const metroRunning = Boolean(metro?.metro);
|
|
32
|
+
const live = simBooted || metroRunning || Boolean(android?.serial);
|
|
33
|
+
let memoryMb = 0;
|
|
34
|
+
if (simBooted) memoryMb += IOS_SIM_MB;
|
|
35
|
+
if (android?.serial) memoryMb += ANDROID_EMULATOR_MB;
|
|
36
|
+
if (metroRunning) memoryMb += METRO_MB;
|
|
37
|
+
const warnings = [];
|
|
38
|
+
if (metro?.notOurs) warnings.push(`port ${project.metroPort}: ${metro.notOurs}`);
|
|
39
|
+
if (ios && !sim && simsAvailable) warnings.push(`recorded sim ${ios.deviceUdid} no longer exists`);
|
|
40
|
+
if (simBooted && project.metroPort && !metroRunning) warnings.push("simulator is booted with no Metro serving it");
|
|
41
|
+
if (supervisor && supervisor.alive === false) warnings.push(`stale supervisor record for ${project.__path}`);
|
|
42
|
+
return {
|
|
43
|
+
path: project.__path,
|
|
44
|
+
live,
|
|
45
|
+
memoryMb,
|
|
46
|
+
warnings,
|
|
47
|
+
ios: ios ? {
|
|
48
|
+
name: sim?.name ?? null,
|
|
49
|
+
udid: ios.deviceUdid,
|
|
50
|
+
owned: Boolean(ios.owned),
|
|
51
|
+
state: sim?.state ?? (simsAvailable ? "missing" : "unknown")
|
|
52
|
+
} : null,
|
|
53
|
+
android: android ? {
|
|
54
|
+
name: android.avdName ?? android.serial,
|
|
55
|
+
owned: Boolean(android.owned),
|
|
56
|
+
physical: Boolean(android.serial && !android.avdName)
|
|
57
|
+
} : null,
|
|
58
|
+
metro: project.metroPort ? {
|
|
59
|
+
port: project.metroPort,
|
|
60
|
+
running: metroRunning,
|
|
61
|
+
pid: metro?.metro?.pid ?? null
|
|
62
|
+
} : null,
|
|
63
|
+
supervisor: supervisor ? {
|
|
64
|
+
pid: supervisor.pid ?? null,
|
|
65
|
+
mode: supervisor.mode ?? null,
|
|
66
|
+
startedAt: supervisor.startedAt ?? null,
|
|
67
|
+
healthy: Boolean(supervisor.healthy)
|
|
68
|
+
} : null,
|
|
69
|
+
logs: logs ? {
|
|
70
|
+
dir: logs.dir,
|
|
71
|
+
errorsSinceMarker: logs.errorsSinceMarker ?? 0
|
|
72
|
+
} : null,
|
|
73
|
+
worktree: worktrees.find((w) => w.path === project.__path) ?? null
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function capacity(states, totalMemoryMb) {
|
|
77
|
+
const committedMb = states.reduce((n, s) => n + s.memoryMb, 0);
|
|
78
|
+
return {
|
|
79
|
+
liveCount: states.filter((s) => s.live).length,
|
|
80
|
+
committedMb,
|
|
81
|
+
totalMemoryMb,
|
|
82
|
+
overCapacity: Boolean(totalMemoryMb && committedMb > totalMemoryMb * .6)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function parseDfFree(output) {
|
|
86
|
+
const lines = String(output || "").trim().split("\n");
|
|
87
|
+
if (lines.length < 2) return null;
|
|
88
|
+
const lastLine = lines[lines.length - 1];
|
|
89
|
+
if (lastLine === void 0) return null;
|
|
90
|
+
const m = /\s(\d+)\s+(\d+)\s+(\d+)\s+(\d+)%/.exec(lastLine);
|
|
91
|
+
if (!m) return null;
|
|
92
|
+
const totalKb = Number(m[1]);
|
|
93
|
+
const availableKb = Number(m[3]);
|
|
94
|
+
if (!Number.isFinite(totalKb) || !Number.isFinite(availableKb) || totalKb <= 0) return null;
|
|
95
|
+
return {
|
|
96
|
+
availableMb: Math.round(availableKb / 1024),
|
|
97
|
+
totalMb: Math.round(totalKb / 1024)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function diskIsTight(disk) {
|
|
101
|
+
return Boolean(disk && disk.availableMb < 25600);
|
|
102
|
+
}
|
|
103
|
+
function formatSpace(mb) {
|
|
104
|
+
if (!Number.isFinite(mb)) return "?";
|
|
105
|
+
if (mb >= 1048576) return `${(mb / 1048576).toFixed(1)} TB`;
|
|
106
|
+
if (mb >= 1024) return `${Math.round(mb / 1024)} GB`;
|
|
107
|
+
return `${Math.round(mb)} MB`;
|
|
108
|
+
}
|
|
109
|
+
function diskLine(volumes) {
|
|
110
|
+
const usable = (volumes || []).filter((v) => Boolean(v && v.disk));
|
|
111
|
+
if (usable.length === 0) return null;
|
|
112
|
+
if (usable.length === 1) {
|
|
113
|
+
const first = usable[0];
|
|
114
|
+
if (!first) return null;
|
|
115
|
+
const { disk } = first;
|
|
116
|
+
return `${formatSpace(disk.availableMb)} free of ${formatSpace(disk.totalMb)} on disk.`;
|
|
117
|
+
}
|
|
118
|
+
return `${usable.map((v) => `${formatSpace(v.disk.availableMb)} free on ${v.volume}`).join(", ")}.`;
|
|
119
|
+
}
|
|
120
|
+
function tightVolumes(volumes) {
|
|
121
|
+
return (volumes || []).filter((v) => v && diskIsTight(v.disk));
|
|
122
|
+
}
|
|
123
|
+
function unprovisionedWorktrees(worktrees, projectPaths) {
|
|
124
|
+
const known = new Set(projectPaths);
|
|
125
|
+
return worktrees.filter((w) => !known.has(w.path));
|
|
126
|
+
}
|
|
127
|
+
function deviceLeaseStates(entries, { root, now }) {
|
|
128
|
+
return entries.map((entry) => {
|
|
129
|
+
const lease = entry.lease;
|
|
130
|
+
return {
|
|
131
|
+
path: entry.path,
|
|
132
|
+
platform: entry.platform,
|
|
133
|
+
id: entry.id,
|
|
134
|
+
deviceName: lease?.deviceName ?? null,
|
|
135
|
+
holder: lease?.holder ?? null,
|
|
136
|
+
grantedAt: lease?.grantedAt ?? null,
|
|
137
|
+
expiresAt: lease?.expiresAt ?? null,
|
|
138
|
+
mine: Boolean(lease && root && lease.holder === root),
|
|
139
|
+
expired: Boolean(lease && Date.parse(lease.expiresAt) <= now),
|
|
140
|
+
parsed: Boolean(lease)
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
function deviceLeaseLines(states, now) {
|
|
145
|
+
if (states.length === 0) return [];
|
|
146
|
+
const lines = [`Device leases (${states.length}):`];
|
|
147
|
+
for (const state of states) {
|
|
148
|
+
const device = `${state.platform} ${state.id ?? state.path}${state.deviceName ? ` (${state.deviceName})` : ""}`;
|
|
149
|
+
if (!state.parsed || state.expiresAt === null) {
|
|
150
|
+
lines.push(` ${device} -- unreadable lease file, so nothing may take the device: ${state.path}`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const when = clockTime(state.expiresAt);
|
|
154
|
+
const remaining = Date.parse(state.expiresAt) - now;
|
|
155
|
+
const expiry = state.expired ? `expired at ${when}` : `until ${when} (${formatElapsed(remaining)} left)`;
|
|
156
|
+
lines.push(` ${device} -- ${state.holder} ${expiry}${state.mine ? " [this workspace]" : ""}`);
|
|
157
|
+
}
|
|
158
|
+
return lines;
|
|
159
|
+
}
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/commands/status.ts
|
|
162
|
+
function formatGb(mb) {
|
|
163
|
+
return `${(mb / 1024).toFixed(1)} GB`;
|
|
164
|
+
}
|
|
165
|
+
function statusCommand(program) {
|
|
166
|
+
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) => {
|
|
167
|
+
const cfg = loadConfig();
|
|
168
|
+
const projects = Object.entries(cfg?.projects || {});
|
|
169
|
+
const cwdRoot = findProjectRoot(process.cwd());
|
|
170
|
+
const simsByUdid = {};
|
|
171
|
+
let simsAvailable = true;
|
|
172
|
+
let simctlError = null;
|
|
173
|
+
try {
|
|
174
|
+
for (const sim of listAllIosSims()) simsByUdid[sim.udid] = sim;
|
|
175
|
+
} catch (e) {
|
|
176
|
+
simsAvailable = false;
|
|
177
|
+
simctlError = String(e?.message || e).split("\n")[0] ?? "";
|
|
178
|
+
}
|
|
179
|
+
const worktrees = listWorktrees(process.cwd()).slice(1);
|
|
180
|
+
const states = [];
|
|
181
|
+
const labelOnlyRoots = [];
|
|
182
|
+
for (const [path, proj] of projects) {
|
|
183
|
+
let metro = null;
|
|
184
|
+
if (proj.metroPort) metro = await resolveOnPort(proj.metroPort, path);
|
|
185
|
+
const supervisor = await supervisorFacts(path, proj, metro);
|
|
186
|
+
states.push(environmentState({
|
|
187
|
+
...proj,
|
|
188
|
+
__path: path
|
|
189
|
+
}, {
|
|
190
|
+
simsByUdid,
|
|
191
|
+
metro,
|
|
192
|
+
worktrees,
|
|
193
|
+
simsAvailable,
|
|
194
|
+
supervisor,
|
|
195
|
+
logs: logFacts(path)
|
|
196
|
+
}));
|
|
197
|
+
const state = states[states.length - 1];
|
|
198
|
+
labelOnlyRoots.push(Boolean(proj.worktreeRoot && !proj.bundleId && !state?.metro && !state?.ios && !state?.android));
|
|
199
|
+
}
|
|
200
|
+
const leaseNow = Date.now();
|
|
201
|
+
const leases = deviceLeaseStates(listLeaseFiles(), {
|
|
202
|
+
root: cwdRoot,
|
|
203
|
+
now: leaseNow
|
|
204
|
+
});
|
|
205
|
+
const cap = capacity(states, Math.round(totalmem() / 1048576));
|
|
206
|
+
const orphanWorktrees = unprovisionedWorktrees(worktrees, projects.map(([p]) => p));
|
|
207
|
+
const pools = ["ios", "android"].map((platform) => {
|
|
208
|
+
const { max, error } = parkedMaxSetting(platform);
|
|
209
|
+
return {
|
|
210
|
+
error,
|
|
211
|
+
line: poolLine({
|
|
212
|
+
platform,
|
|
213
|
+
parked: readParked(platform).length,
|
|
214
|
+
max
|
|
215
|
+
})
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
if (opts.json) {
|
|
219
|
+
console.log(JSON.stringify({
|
|
220
|
+
environments: states.map((state, i) => labelOnlyRoots[i] ? {
|
|
221
|
+
...state,
|
|
222
|
+
labelOnly: true
|
|
223
|
+
} : state),
|
|
224
|
+
capacity: cap,
|
|
225
|
+
deviceLeases: leases,
|
|
226
|
+
unprovisionedWorktrees: orphanWorktrees,
|
|
227
|
+
simctlAvailable: simsAvailable
|
|
228
|
+
}));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (projects.length === 0 && orphanWorktrees.length === 0) {
|
|
232
|
+
console.log(chalk.dim("No projects registered."));
|
|
233
|
+
for (const pool of pools) {
|
|
234
|
+
if (pool.error) console.log(chalk.yellow(`${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
235
|
+
if (pool.line) console.log(chalk.dim(pool.line));
|
|
236
|
+
}
|
|
237
|
+
for (const line of deviceLeaseLines(leases, leaseNow)) console.log(line);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (!simsAvailable) console.log(chalk.yellow(`simctl could not be read (${simctlError}), so no iOS sim below could be checked.`));
|
|
241
|
+
for (const [i, [path, proj]] of projects.entries()) {
|
|
242
|
+
const state = states[i];
|
|
243
|
+
if (!state) continue;
|
|
244
|
+
const shortcut = projectShortcut(path, proj);
|
|
245
|
+
const marker = path === cwdRoot ? chalk.bold.cyan(`* ${shortcut}`) : shortcut;
|
|
246
|
+
const idle = state.live ? "" : chalk.dim(" [idle]");
|
|
247
|
+
console.log(`\n${marker}${idle} ${chalk.dim(`(${path})`)}`);
|
|
248
|
+
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"})`));
|
|
249
|
+
if (state.metro) {
|
|
250
|
+
const label = state.metro.running ? chalk.green(`running (pid ${state.metro.pid})`) : chalk.dim("not running");
|
|
251
|
+
console.log(` metro: port ${state.metro.port} ${label}`);
|
|
252
|
+
}
|
|
253
|
+
if (state.supervisor) {
|
|
254
|
+
const health = state.supervisor.healthy ? chalk.green("healthy") : chalk.yellow("not answering");
|
|
255
|
+
const mode = state.supervisor.mode ? chalk.dim(` (${state.supervisor.mode})`) : "";
|
|
256
|
+
console.log(` supervisor: pid ${state.supervisor.pid}${mode} ${health}`);
|
|
257
|
+
}
|
|
258
|
+
if (state.logs) {
|
|
259
|
+
const n = state.logs.errorsSinceMarker;
|
|
260
|
+
const errs = n > 0 ? chalk.yellow(` (${n} error${n === 1 ? "" : "s"} since the last marker)`) : "";
|
|
261
|
+
console.log(chalk.dim(` logs: ${state.logs.dir}`) + errs);
|
|
262
|
+
}
|
|
263
|
+
if (state.ios) {
|
|
264
|
+
const booted = state.ios.state === "Booted" ? chalk.green("booted") : chalk.dim(state.ios.state.toLowerCase());
|
|
265
|
+
const owned = state.ios.owned ? chalk.dim(" (owned)") : "";
|
|
266
|
+
console.log(` ios: ${chalk.cyan(state.ios.name ?? state.ios.udid)} ${booted}${owned}`);
|
|
267
|
+
}
|
|
268
|
+
if (state.android) {
|
|
269
|
+
const kind = state.android.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
|
|
270
|
+
console.log(` android: ${chalk.cyan(state.android.name)} ${kind}${state.android.owned ? chalk.dim(" (owned)") : ""}`);
|
|
271
|
+
}
|
|
272
|
+
for (const w of state.warnings) console.log(chalk.yellow(` ! ${w}`));
|
|
273
|
+
}
|
|
274
|
+
for (const pool of pools) {
|
|
275
|
+
if (pool.error) console.log(chalk.yellow(`\n${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
276
|
+
if (pool.line) console.log(chalk.dim(`\n${pool.line}`));
|
|
277
|
+
}
|
|
278
|
+
const leaseLines = deviceLeaseLines(leases, leaseNow);
|
|
279
|
+
if (leaseLines.length) {
|
|
280
|
+
console.log("");
|
|
281
|
+
for (const line of leaseLines) console.log(line);
|
|
282
|
+
}
|
|
283
|
+
if (orphanWorktrees.length) {
|
|
284
|
+
console.log(chalk.dim(`\nWorktrees with no environment (${orphanWorktrees.length}):`));
|
|
285
|
+
for (const w of orphanWorktrees) console.log(chalk.dim(` ${w.path}${w.branch ? ` [${w.branch}]` : ""}`));
|
|
286
|
+
}
|
|
287
|
+
console.log(chalk.dim(`\n${cap.liveCount} live environment(s), roughly ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)} committed.`));
|
|
288
|
+
const volumes = readVolumes(cwdRoot || process.cwd());
|
|
289
|
+
const line = diskLine(volumes);
|
|
290
|
+
if (line) {
|
|
291
|
+
const tight = tightVolumes(volumes);
|
|
292
|
+
if (tight.length) {
|
|
293
|
+
const which = tight.map((v) => v.volume).join(" and ");
|
|
294
|
+
console.log(chalk.yellow(`${line} A single iOS build can exhaust ${which} -- run \`stim gc\` before starting another environment.`));
|
|
295
|
+
} else console.log(chalk.dim(line));
|
|
296
|
+
}
|
|
297
|
+
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."));
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
function readVolumes(projectPath) {
|
|
301
|
+
const roots = [.../* @__PURE__ */ new Set([
|
|
302
|
+
"/",
|
|
303
|
+
volumeRootFor(getConfigDir()),
|
|
304
|
+
volumeRootFor(projectPath)
|
|
305
|
+
])];
|
|
306
|
+
const volumes = [];
|
|
307
|
+
for (const volume of roots) {
|
|
308
|
+
const quoted = `'${volume.replace(/'/g, "'\\''")}'`;
|
|
309
|
+
const disk = parseDfFree(getExecutor().runQuiet(`df -k ${quoted}`, { timeoutMs: 5e3 }));
|
|
310
|
+
if (disk) volumes.push({
|
|
311
|
+
volume,
|
|
312
|
+
disk
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
return volumes;
|
|
316
|
+
}
|
|
317
|
+
async function resolveOnPort(port, path) {
|
|
318
|
+
return await isMetroRunning(port) ? resolveProjectMetro(port, path) : { missing: true };
|
|
319
|
+
}
|
|
320
|
+
async function supervisorFacts(path, proj, metroResolution) {
|
|
321
|
+
const state = readSupervisorState(path);
|
|
322
|
+
const record = proj?.supervisor ?? null;
|
|
323
|
+
const pid = state?.pid ?? record?.pid ?? null;
|
|
324
|
+
if (!pid) return null;
|
|
325
|
+
const port = state?.port ?? record?.port ?? null;
|
|
326
|
+
const alive = resolveSupervisorTarget({
|
|
327
|
+
state,
|
|
328
|
+
record,
|
|
329
|
+
reservedPort: proj?.metroPort
|
|
330
|
+
}).status === "ours";
|
|
331
|
+
let healthy = false;
|
|
332
|
+
if (alive && port) {
|
|
333
|
+
const resolution = port === proj?.metroPort && metroResolution ? metroResolution : await resolveOnPort(port, path);
|
|
334
|
+
healthy = Boolean(resolution?.metro);
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
pid,
|
|
338
|
+
mode: state?.mode ?? record?.mode ?? null,
|
|
339
|
+
startedAt: state?.startedAt ?? record?.startedAt ?? null,
|
|
340
|
+
alive,
|
|
341
|
+
healthy
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function logFacts(path) {
|
|
345
|
+
const dir = workspaceLogsDir(path);
|
|
346
|
+
if (!existsSync(dir)) return null;
|
|
347
|
+
try {
|
|
348
|
+
return {
|
|
349
|
+
dir,
|
|
350
|
+
errorsSinceMarker: queryLogs({
|
|
351
|
+
dir,
|
|
352
|
+
errorsOnly: true
|
|
353
|
+
}).length
|
|
354
|
+
};
|
|
355
|
+
} catch {
|
|
356
|
+
return {
|
|
357
|
+
dir,
|
|
358
|
+
errorsSinceMarker: 0
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
//#endregion
|
|
363
|
+
export { statusCommand as default, readVolumes };
|