stim 1.8.0 → 1.10.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 +23 -155
- package/dist/{android-DWssqHQ8.mjs → android-787HhP5w.mjs} +168 -39
- package/dist/{android-BRgBYzU0.mjs → android-DBkeHwpm.mjs} +250 -200
- package/dist/{android-DeYdjjBP.mjs → android-DPov-fv2.mjs} +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-CITmIeWY.mjs} +22 -14
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/app-install-CrJ6t_bv.mjs +819 -0
- package/dist/budget-BP4jZZL4.mjs +620 -0
- package/dist/build-progress-BXx-ZBe4.mjs +512 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Pubfp8wV.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +7 -1
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-D5z2_bcF.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-BEq0Qw_a.mjs} +134 -121
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-r9UesA9a.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-DP4eWqea.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-DJHoca49.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-92U593KT.mjs} +1090 -660
- package/dist/{device-RdujjHLB.mjs → device-DhTZe7L4.mjs} +13 -20
- package/dist/{build-lock-CgtsB6TV.mjs → device-lease-CbEaIk7b.mjs} +481 -27
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-Di8Q-9Ro.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-Dy1jGj3U.mjs} +645 -119
- package/dist/{doctor-BMt156qe.mjs → doctor-B-inAJmt.mjs} +137 -113
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-xxWKNO3-.mjs} +22 -17
- package/dist/exec-DK8KaVHK.mjs +133 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-ChPFZMRC.mjs} +836 -813
- package/dist/{guide-BTAlD1_y.mjs → guide-DwmaD_Wa.mjs} +953 -209
- package/dist/guide-status-CWvti2Lg.mjs +125 -0
- package/dist/idle-DpRLp5lj.mjs +157 -0
- package/dist/{build-slots-C-oAHRT1.mjs → in-use-CjUluqIX.mjs} +102 -8
- package/dist/{ios-BcCiI4TS.mjs → ios-B2Fpqvlb.mjs} +60 -71
- package/dist/{ios-BP04pY5f.mjs → ios-Dd-hYJBh.mjs} +241 -234
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-BiOsSVzd.mjs} +3 -2
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-CtRdEVjx.mjs} +149 -52
- package/dist/launch-verify-CQS_Kg-C.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-MARIy6m9.mjs} +20 -15
- package/dist/metro-BWLOJ_Wr.mjs +409 -0
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-DiTfSz6p.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-CDY9IkVC.mjs} +23 -43
- package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D2xbLVoz.mjs} +2 -3
- package/dist/{teardown-BJqEzPo_.mjs → ownership-DZjdx8Gq.mjs} +664 -612
- package/dist/{ports-BIbJaKNW.mjs → ports-CLSSFOuz.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-BXZzOABt.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-DoETJ3rl.mjs} +11 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DVbb7kXH.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-BvOCeakp.mjs} +8 -7
- package/dist/server-expo-DBVTdult.mjs +2 -0
- package/dist/{settings-BXXorVM2.mjs → settings-DOugPlPz.mjs} +59 -159
- package/dist/settings-EWYNwe72.mjs +378 -0
- package/dist/settings.schema.json +1064 -0
- package/dist/simslim-Ca3487H6.mjs +436 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
- package/dist/spawn-claims-CUleC2cM.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-F9gv5dcC.mjs} +159 -114
- package/dist/start-VoFsPSes.mjs +2 -0
- package/dist/{state-DZobzxLW.mjs → state-WGdIbi_d.mjs} +5 -3
- package/dist/{stats-BYcZ6n1h.mjs → stats-BAgJaLA4.mjs} +66 -5
- package/dist/{stats-CLg5RuDS.mjs → stats-DBYJ5bxL.mjs} +4 -4
- package/dist/status-DLCD-o3s.mjs +764 -0
- package/dist/status-Dr4fRkym.mjs +216 -0
- package/dist/{guide-status-Craq9z0t.mjs → stim-installations-CINXy_su.mjs} +3 -122
- package/dist/{stop-C8JW6kKp.mjs → stop-Dj4pfmyv.mjs} +111 -31
- package/dist/{stop-B1kOpYei.mjs → stop-ZvOeTmKb.mjs} +2 -2
- package/dist/supervisor-run.d.mts +11 -2
- package/dist/supervisor-run.mjs +228 -42
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-BXA96myD.mjs} +14 -9
- package/dist/workspaces-BTUyFfkv.mjs +1003 -0
- package/dist/worktree-4aZg2NnI.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-BMS7GeqB.mjs} +523 -61
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-BlizKDpZ.mjs} +200 -54
- package/dist/{xcode-B6YaWeg0.mjs → xcode-B2tBkf0m.mjs} +66 -57
- package/package.json +6 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/device-lease-Ffz_M5t0.mjs +0 -359
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/logs-query-BGL-Pl12.mjs +0 -290
- package/dist/metro-C7bcJ0uo.mjs +0 -233
- package/dist/ownership-wolE-0Do.mjs +0 -470
- package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/spawn-entry-nCE6m770.mjs +0 -14
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/workspace-state-BT5E3SA2.mjs +0 -146
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
package/dist/status-DdkLki47.mjs
DELETED
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
import { t as getExecutor } from "./exec-B29XNuhP.mjs";
|
|
2
|
-
import { M as volumeRootFor, R as projectDeviceSlots, g as loadConfig, u as getConfigDir } from "./config-B7iyKWkL.mjs";
|
|
3
|
-
import { _ as workspaceLogsDir } from "./workspace-state-BT5E3SA2.mjs";
|
|
4
|
-
import { v as resolveSourceCheckout } from "./worktree-FG_ZKKdb.mjs";
|
|
5
|
-
import { a as findProjectRoot, c as projectShortcut } from "./project-DDZWf_16.mjs";
|
|
6
|
-
import { a as resolveProjectMetro, s as isMetroRunning } from "./metro-C7bcJ0uo.mjs";
|
|
7
|
-
import { I as resolveOwnedAvdSerial } from "./android-DWssqHQ8.mjs";
|
|
8
|
-
import { a as formatElapsed, r as clockTime, u as plural } from "./command-output-B3ycpsYv.mjs";
|
|
9
|
-
import { a as POOL_SETTING_REMEDY, l as parkedMaxSetting, u as readParked } from "./teardown-BJqEzPo_.mjs";
|
|
10
|
-
import { u as listAllIosSims } from "./ios-BcCiI4TS.mjs";
|
|
11
|
-
import { i as listLeaseFiles } from "./device-lease-Ffz_M5t0.mjs";
|
|
12
|
-
import { c as queryLogs } from "./logs-query-BGL-Pl12.mjs";
|
|
13
|
-
import { t as resolveSupervisorTarget } from "./ownership-wolE-0Do.mjs";
|
|
14
|
-
import { i as readSupervisorState } from "./stop-C8JW6kKp.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, androidRuntimes = {}, 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
|
-
let 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
|
-
const slots = [];
|
|
52
|
-
for (const { slot, platforms } of projectDeviceSlots(project).slice(1)) {
|
|
53
|
-
const deviceState = environmentState({
|
|
54
|
-
...project,
|
|
55
|
-
platforms,
|
|
56
|
-
deviceSlots: void 0
|
|
57
|
-
}, {
|
|
58
|
-
simsByUdid,
|
|
59
|
-
simsAvailable,
|
|
60
|
-
metro,
|
|
61
|
-
androidRuntime: androidRuntimes[slot]
|
|
62
|
-
});
|
|
63
|
-
slots.push({
|
|
64
|
-
slot,
|
|
65
|
-
ios: deviceState.ios,
|
|
66
|
-
android: deviceState.android
|
|
67
|
-
});
|
|
68
|
-
memoryMb += deviceState.memoryMb - (metroRunning ? METRO_MB : 0);
|
|
69
|
-
live ||= deviceState.live;
|
|
70
|
-
warnings.push(...deviceState.warnings.map((warning) => `${slot}: ${warning}`));
|
|
71
|
-
}
|
|
72
|
-
return {
|
|
73
|
-
path: project.__path,
|
|
74
|
-
...slots.length ? { slots } : {},
|
|
75
|
-
live,
|
|
76
|
-
memoryMb,
|
|
77
|
-
warnings,
|
|
78
|
-
ios: ios ? {
|
|
79
|
-
name: sim?.name ?? null,
|
|
80
|
-
udid: ios.deviceUdid,
|
|
81
|
-
owned: Boolean(ios.owned),
|
|
82
|
-
state: sim?.state ?? (simsAvailable ? "missing" : "unknown")
|
|
83
|
-
} : null,
|
|
84
|
-
android: android ? {
|
|
85
|
-
name: android.avdName ?? android.serial,
|
|
86
|
-
owned: Boolean(android.owned),
|
|
87
|
-
physical: Boolean(android.serial && !android.avdName),
|
|
88
|
-
...androidRuntime ? {
|
|
89
|
-
serial: androidRuntime.serial,
|
|
90
|
-
state: androidRuntime.state
|
|
91
|
-
} : {}
|
|
92
|
-
} : null,
|
|
93
|
-
metro: project.metroPort ? {
|
|
94
|
-
port: project.metroPort,
|
|
95
|
-
running: metroRunning,
|
|
96
|
-
pid: metro?.metro?.pid ?? null
|
|
97
|
-
} : null,
|
|
98
|
-
supervisor: supervisor ? {
|
|
99
|
-
pid: supervisor.pid ?? null,
|
|
100
|
-
mode: supervisor.mode ?? null,
|
|
101
|
-
startedAt: supervisor.startedAt ?? null,
|
|
102
|
-
healthy: Boolean(supervisor.healthy)
|
|
103
|
-
} : null,
|
|
104
|
-
logs: logs ? {
|
|
105
|
-
dir: logs.dir,
|
|
106
|
-
errorsSinceMarker: logs.errorsSinceMarker ?? 0
|
|
107
|
-
} : null,
|
|
108
|
-
worktree: worktrees.find((w) => w.path === project.__path) ?? null
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
function capacity(states, totalMemoryMb) {
|
|
112
|
-
const committedMb = states.reduce((n, s) => n + s.memoryMb, 0);
|
|
113
|
-
return {
|
|
114
|
-
liveCount: states.filter((s) => s.live).length,
|
|
115
|
-
committedMb,
|
|
116
|
-
totalMemoryMb,
|
|
117
|
-
overCapacity: Boolean(totalMemoryMb && committedMb > totalMemoryMb * .6)
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
function parseDfFree(output) {
|
|
121
|
-
const lines = String(output || "").trim().split("\n");
|
|
122
|
-
if (lines.length < 2) return null;
|
|
123
|
-
const lastLine = lines[lines.length - 1];
|
|
124
|
-
if (lastLine === void 0) return null;
|
|
125
|
-
const m = /\s(\d+)\s+(\d+)\s+(\d+)\s+(\d+)%/.exec(lastLine);
|
|
126
|
-
if (!m) return null;
|
|
127
|
-
const totalKb = Number(m[1]);
|
|
128
|
-
const availableKb = Number(m[3]);
|
|
129
|
-
if (!Number.isFinite(totalKb) || !Number.isFinite(availableKb) || totalKb <= 0) return null;
|
|
130
|
-
return {
|
|
131
|
-
availableMb: Math.round(availableKb / 1024),
|
|
132
|
-
totalMb: Math.round(totalKb / 1024)
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
function diskIsTight(disk) {
|
|
136
|
-
return Boolean(disk && disk.availableMb < 25600);
|
|
137
|
-
}
|
|
138
|
-
function formatSpace(mb) {
|
|
139
|
-
if (!Number.isFinite(mb)) return "?";
|
|
140
|
-
if (mb >= 1048576) return `${(mb / 1048576).toFixed(1)} TB`;
|
|
141
|
-
if (mb >= 1024) return `${Math.round(mb / 1024)} GB`;
|
|
142
|
-
return `${Math.round(mb)} MB`;
|
|
143
|
-
}
|
|
144
|
-
function diskLine(volumes) {
|
|
145
|
-
const usable = (volumes || []).filter((v) => Boolean(v && v.disk));
|
|
146
|
-
if (usable.length === 0) return null;
|
|
147
|
-
if (usable.length === 1) {
|
|
148
|
-
const first = usable[0];
|
|
149
|
-
if (!first) return null;
|
|
150
|
-
const { disk } = first;
|
|
151
|
-
return `${formatSpace(disk.availableMb)} free of ${formatSpace(disk.totalMb)} on disk.`;
|
|
152
|
-
}
|
|
153
|
-
return `${usable.map((v) => `${formatSpace(v.disk.availableMb)} free on ${v.volume}`).join(", ")}.`;
|
|
154
|
-
}
|
|
155
|
-
function tightVolumes(volumes) {
|
|
156
|
-
return (volumes || []).filter((v) => v && diskIsTight(v.disk));
|
|
157
|
-
}
|
|
158
|
-
function unprovisionedWorktrees(worktrees, projectPaths) {
|
|
159
|
-
const known = new Set(projectPaths);
|
|
160
|
-
return worktrees.filter((w) => !known.has(w.path));
|
|
161
|
-
}
|
|
162
|
-
function deviceLeaseStates(entries, { root, now }) {
|
|
163
|
-
return entries.map((entry) => {
|
|
164
|
-
const lease = entry.lease;
|
|
165
|
-
return {
|
|
166
|
-
path: entry.path,
|
|
167
|
-
platform: entry.platform,
|
|
168
|
-
...lease?.slot ? { slot: lease.slot } : {},
|
|
169
|
-
id: entry.id,
|
|
170
|
-
deviceName: lease?.deviceName ?? null,
|
|
171
|
-
holder: lease?.holder ?? null,
|
|
172
|
-
grantedAt: lease?.grantedAt ?? null,
|
|
173
|
-
expiresAt: lease?.expiresAt ?? null,
|
|
174
|
-
mine: Boolean(lease && root && lease.holder === root),
|
|
175
|
-
expired: Boolean(lease && Date.parse(lease.expiresAt) <= now),
|
|
176
|
-
parsed: Boolean(lease)
|
|
177
|
-
};
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
function deviceLeaseLines(states, now) {
|
|
181
|
-
if (states.length === 0) return [];
|
|
182
|
-
const lines = [`Device leases (${states.length}):`];
|
|
183
|
-
for (const state of states) {
|
|
184
|
-
const device = `${state.platform}${state.slot ? ` [${state.slot}]` : ""} ${state.id ?? state.path}${state.deviceName ? ` (${state.deviceName})` : ""}`;
|
|
185
|
-
if (!state.parsed || state.expiresAt === null) {
|
|
186
|
-
lines.push(` ${device} -- unreadable lease file, so nothing may take the device: ${state.path}`);
|
|
187
|
-
continue;
|
|
188
|
-
}
|
|
189
|
-
const when = clockTime(state.expiresAt);
|
|
190
|
-
const remaining = Date.parse(state.expiresAt) - now;
|
|
191
|
-
const expiry = state.expired ? `expired at ${when}` : `until ${when} (${formatElapsed(remaining)} left)`;
|
|
192
|
-
lines.push(` ${device} -- ${state.holder} ${expiry}${state.mine ? " [this workspace]" : ""}`);
|
|
193
|
-
}
|
|
194
|
-
return lines;
|
|
195
|
-
}
|
|
196
|
-
//#endregion
|
|
197
|
-
//#region src/commands/status.ts
|
|
198
|
-
function formatGb(mb) {
|
|
199
|
-
return `${(mb / 1024).toFixed(1)} GB`;
|
|
200
|
-
}
|
|
201
|
-
function statusCommand(program) {
|
|
202
|
-
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) => {
|
|
203
|
-
const cfg = loadConfig();
|
|
204
|
-
const projects = Object.entries(cfg?.projects || {});
|
|
205
|
-
const cwdRoot = findProjectRoot(process.cwd());
|
|
206
|
-
const simsByUdid = {};
|
|
207
|
-
let simsAvailable = true;
|
|
208
|
-
let simctlError = null;
|
|
209
|
-
try {
|
|
210
|
-
for (const sim of listAllIosSims()) simsByUdid[sim.udid] = sim;
|
|
211
|
-
} catch (e) {
|
|
212
|
-
simsAvailable = false;
|
|
213
|
-
simctlError = String(e?.message || e).split("\n")[0] ?? "";
|
|
214
|
-
}
|
|
215
|
-
const source = resolveSourceCheckout(process.cwd());
|
|
216
|
-
const sourcePath = "path" in source ? source.path : null;
|
|
217
|
-
const worktrees = source.entries.filter((entry) => !entry.bare && entry.path !== sourcePath);
|
|
218
|
-
const states = [];
|
|
219
|
-
const labelOnlyRoots = [];
|
|
220
|
-
for (const [path, proj] of projects) {
|
|
221
|
-
let metro = null;
|
|
222
|
-
if (proj.metroPort) metro = await resolveOnPort(proj.metroPort, path);
|
|
223
|
-
const supervisor = await supervisorFacts(path, proj, metro);
|
|
224
|
-
states.push(environmentState({
|
|
225
|
-
...proj,
|
|
226
|
-
__path: path
|
|
227
|
-
}, {
|
|
228
|
-
simsByUdid,
|
|
229
|
-
metro,
|
|
230
|
-
worktrees,
|
|
231
|
-
simsAvailable,
|
|
232
|
-
androidRuntimes: Object.fromEntries(projectDeviceSlots(proj).slice(1).map(({ slot, platforms }) => [slot, platforms.android?.owned && platforms.android.avdName ? readAndroidRuntime(platforms.android.avdName) : null])),
|
|
233
|
-
androidRuntime: proj.platforms?.android?.owned && proj.platforms.android.avdName ? readAndroidRuntime(proj.platforms.android.avdName) : null,
|
|
234
|
-
supervisor,
|
|
235
|
-
logs: logFacts(path)
|
|
236
|
-
}));
|
|
237
|
-
const state = states[states.length - 1];
|
|
238
|
-
labelOnlyRoots.push(Boolean(proj.worktreeRoot && !proj.bundleId && !state?.metro && !state?.ios && !state?.android));
|
|
239
|
-
}
|
|
240
|
-
const leaseNow = Date.now();
|
|
241
|
-
const leases = deviceLeaseStates(listLeaseFiles(), {
|
|
242
|
-
root: cwdRoot,
|
|
243
|
-
now: leaseNow
|
|
244
|
-
});
|
|
245
|
-
const cap = capacity(states, Math.round(totalmem() / 1048576));
|
|
246
|
-
const orphanWorktrees = unprovisionedWorktrees(worktrees, projects.map(([p]) => p));
|
|
247
|
-
const pools = ["ios", "android"].map((platform) => {
|
|
248
|
-
const { max, error } = parkedMaxSetting(platform);
|
|
249
|
-
return {
|
|
250
|
-
error,
|
|
251
|
-
line: poolLine({
|
|
252
|
-
platform,
|
|
253
|
-
parked: readParked(platform).length,
|
|
254
|
-
max
|
|
255
|
-
})
|
|
256
|
-
};
|
|
257
|
-
});
|
|
258
|
-
if (opts.json) {
|
|
259
|
-
console.log(JSON.stringify({
|
|
260
|
-
environments: states.map((state, i) => labelOnlyRoots[i] ? {
|
|
261
|
-
...state,
|
|
262
|
-
labelOnly: true
|
|
263
|
-
} : state),
|
|
264
|
-
capacity: cap,
|
|
265
|
-
deviceLeases: leases,
|
|
266
|
-
unprovisionedWorktrees: orphanWorktrees,
|
|
267
|
-
simctlAvailable: simsAvailable
|
|
268
|
-
}));
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (projects.length === 0 && orphanWorktrees.length === 0) {
|
|
272
|
-
console.log(chalk.dim("No projects registered."));
|
|
273
|
-
for (const pool of pools) {
|
|
274
|
-
if (pool.error) console.log(chalk.yellow(`${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
275
|
-
if (pool.line) console.log(chalk.dim(pool.line));
|
|
276
|
-
}
|
|
277
|
-
for (const line of deviceLeaseLines(leases, leaseNow)) console.log(line);
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
if (!simsAvailable) console.log(chalk.yellow(`simctl could not be read (${simctlError}), so no iOS sim below could be checked.`));
|
|
281
|
-
for (const [i, [path, proj]] of projects.entries()) {
|
|
282
|
-
const state = states[i];
|
|
283
|
-
if (!state) continue;
|
|
284
|
-
const shortcut = projectShortcut(path, proj);
|
|
285
|
-
const marker = path === cwdRoot ? chalk.bold.cyan(`* ${shortcut}`) : shortcut;
|
|
286
|
-
const idle = state.live ? "" : chalk.dim(" [idle]");
|
|
287
|
-
console.log(`\n${marker}${idle} ${chalk.dim(`(${path})`)}`);
|
|
288
|
-
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"})`));
|
|
289
|
-
if (state.metro) {
|
|
290
|
-
const label = state.metro.running ? chalk.green(`running (pid ${state.metro.pid})`) : chalk.dim("not running");
|
|
291
|
-
console.log(` metro: port ${state.metro.port} ${label}`);
|
|
292
|
-
}
|
|
293
|
-
if (state.supervisor) {
|
|
294
|
-
const health = state.supervisor.healthy ? chalk.green("healthy") : chalk.yellow("not answering");
|
|
295
|
-
const mode = state.supervisor.mode ? chalk.dim(` (${state.supervisor.mode})`) : "";
|
|
296
|
-
console.log(` supervisor: pid ${state.supervisor.pid}${mode} ${health}`);
|
|
297
|
-
}
|
|
298
|
-
if (state.logs) {
|
|
299
|
-
const n = state.logs.errorsSinceMarker;
|
|
300
|
-
const errs = n > 0 ? chalk.yellow(` (${n} error${n === 1 ? "" : "s"} since the last marker)`) : "";
|
|
301
|
-
console.log(chalk.dim(` logs: ${state.logs.dir}`) + errs);
|
|
302
|
-
}
|
|
303
|
-
for (const deviceState of [{
|
|
304
|
-
slot: "default",
|
|
305
|
-
ios: state.ios,
|
|
306
|
-
android: state.android
|
|
307
|
-
}, ...state.slots ?? []]) {
|
|
308
|
-
const slotLabel = deviceState.slot === "default" ? "" : ` [${deviceState.slot}]`;
|
|
309
|
-
if (deviceState.ios) {
|
|
310
|
-
const booted = deviceState.ios.state === "Booted" ? chalk.green("booted") : chalk.dim(deviceState.ios.state.toLowerCase());
|
|
311
|
-
const owned = deviceState.ios.owned ? chalk.dim(" (owned)") : "";
|
|
312
|
-
console.log(` ios${slotLabel}: ${chalk.cyan(deviceState.ios.name ?? deviceState.ios.udid)} ${booted}${owned}`);
|
|
313
|
-
}
|
|
314
|
-
if (deviceState.android) {
|
|
315
|
-
const kind = deviceState.android.physical ? chalk.dim("(physical)") : chalk.dim("(emulator)");
|
|
316
|
-
const observed = deviceState.android.state ? ` ${deviceState.android.state}${deviceState.android.serial ? ` (${deviceState.android.serial})` : ""}` : "";
|
|
317
|
-
console.log(` android${slotLabel}: ${chalk.cyan(deviceState.android.name)} ${kind}${observed}${deviceState.android.owned ? chalk.dim(" (owned)") : ""}`);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
for (const w of state.warnings) console.log(chalk.yellow(` ! ${w}`));
|
|
321
|
-
}
|
|
322
|
-
for (const pool of pools) {
|
|
323
|
-
if (pool.error) console.log(chalk.yellow(`\n${pool.error} ${POOL_SETTING_REMEDY}`));
|
|
324
|
-
if (pool.line) console.log(chalk.dim(`\n${pool.line}`));
|
|
325
|
-
}
|
|
326
|
-
const leaseLines = deviceLeaseLines(leases, leaseNow);
|
|
327
|
-
if (leaseLines.length) {
|
|
328
|
-
console.log("");
|
|
329
|
-
for (const line of leaseLines) console.log(line);
|
|
330
|
-
}
|
|
331
|
-
if (orphanWorktrees.length) {
|
|
332
|
-
console.log(chalk.dim(`\nWorktrees with no environment (${orphanWorktrees.length}):`));
|
|
333
|
-
for (const w of orphanWorktrees) console.log(chalk.dim(` ${w.path}${w.branch ? ` [${w.branch}]` : ""}`));
|
|
334
|
-
}
|
|
335
|
-
console.log(chalk.dim(`\n${cap.liveCount} live environment(s), roughly ${formatGb(cap.committedMb)} of ${formatGb(cap.totalMemoryMb)} committed.`));
|
|
336
|
-
const volumes = readVolumes(cwdRoot || process.cwd());
|
|
337
|
-
const line = diskLine(volumes);
|
|
338
|
-
if (line) {
|
|
339
|
-
const tight = tightVolumes(volumes);
|
|
340
|
-
if (tight.length) {
|
|
341
|
-
const which = tight.map((v) => v.volume).join(" and ");
|
|
342
|
-
console.log(chalk.yellow(`${line} A single iOS build can exhaust ${which} -- run \`stim gc\` before starting another environment.`));
|
|
343
|
-
} else console.log(chalk.dim(line));
|
|
344
|
-
}
|
|
345
|
-
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."));
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
function readAndroidRuntime(avdName) {
|
|
349
|
-
try {
|
|
350
|
-
const resolved = resolveOwnedAvdSerial(avdName, { timeoutMs: 5e3 });
|
|
351
|
-
return {
|
|
352
|
-
serial: resolved.serial ?? null,
|
|
353
|
-
state: resolved.serial ? "detected" : resolved.missing ? "missing" : resolved.notRunning ? "not-detected" : "unknown"
|
|
354
|
-
};
|
|
355
|
-
} catch (error) {
|
|
356
|
-
return {
|
|
357
|
-
serial: null,
|
|
358
|
-
state: "unknown",
|
|
359
|
-
error: String(error?.message || error).split("\n")[0]
|
|
360
|
-
};
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
function readVolumes(projectPath) {
|
|
364
|
-
const roots = [.../* @__PURE__ */ new Set([
|
|
365
|
-
"/",
|
|
366
|
-
volumeRootFor(getConfigDir()),
|
|
367
|
-
volumeRootFor(projectPath)
|
|
368
|
-
])];
|
|
369
|
-
const volumes = [];
|
|
370
|
-
for (const volume of roots) {
|
|
371
|
-
const quoted = `'${volume.replace(/'/g, "'\\''")}'`;
|
|
372
|
-
const disk = parseDfFree(getExecutor().runQuiet(`df -k ${quoted}`, { timeoutMs: 5e3 }));
|
|
373
|
-
if (disk) volumes.push({
|
|
374
|
-
volume,
|
|
375
|
-
disk
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
return volumes;
|
|
379
|
-
}
|
|
380
|
-
async function resolveOnPort(port, path) {
|
|
381
|
-
return await isMetroRunning(port) ? resolveProjectMetro(port, path) : { missing: true };
|
|
382
|
-
}
|
|
383
|
-
async function supervisorFacts(path, proj, metroResolution) {
|
|
384
|
-
const state = readSupervisorState(path);
|
|
385
|
-
const record = proj?.supervisor ?? null;
|
|
386
|
-
const pid = state?.pid ?? record?.pid ?? null;
|
|
387
|
-
if (!pid) return null;
|
|
388
|
-
const port = state?.port ?? record?.port ?? null;
|
|
389
|
-
const alive = resolveSupervisorTarget({
|
|
390
|
-
state,
|
|
391
|
-
record,
|
|
392
|
-
reservedPort: proj?.metroPort
|
|
393
|
-
}).status === "ours";
|
|
394
|
-
let healthy = false;
|
|
395
|
-
if (alive && port) {
|
|
396
|
-
const resolution = port === proj?.metroPort && metroResolution ? metroResolution : await resolveOnPort(port, path);
|
|
397
|
-
healthy = Boolean(resolution?.metro);
|
|
398
|
-
}
|
|
399
|
-
return {
|
|
400
|
-
pid,
|
|
401
|
-
mode: state?.mode ?? record?.mode ?? null,
|
|
402
|
-
startedAt: state?.startedAt ?? record?.startedAt ?? null,
|
|
403
|
-
alive,
|
|
404
|
-
healthy
|
|
405
|
-
};
|
|
406
|
-
}
|
|
407
|
-
function logFacts(path) {
|
|
408
|
-
const dir = workspaceLogsDir(path);
|
|
409
|
-
if (!existsSync(dir)) return null;
|
|
410
|
-
try {
|
|
411
|
-
return {
|
|
412
|
-
dir,
|
|
413
|
-
errorsSinceMarker: queryLogs({
|
|
414
|
-
dir,
|
|
415
|
-
errorsOnly: true
|
|
416
|
-
}).length
|
|
417
|
-
};
|
|
418
|
-
} catch {
|
|
419
|
-
return {
|
|
420
|
-
dir,
|
|
421
|
-
errorsSinceMarker: 0
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
//#endregion
|
|
426
|
-
export { statusCommand as default, readVolumes };
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { D as withDirLock, u as getConfigDir } from "./config-B7iyKWkL.mjs";
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname } from "node:path";
|
|
4
|
-
import { join as join$1, resolve as resolve$1 } from "path";
|
|
5
|
-
import { buildCacheRoot as sharedBuildCache, workspaceId, workspaceName as workspaceName$1, workspaceStateDir as workspaceDir } from "@stim-cli/core";
|
|
6
|
-
//#region src/workspace/paths.ts
|
|
7
|
-
const WORKSPACE_METADATA_FILE_NAME = "workspace.json";
|
|
8
|
-
function workspaceMetadataFile(projectRoot) {
|
|
9
|
-
return join$1(workspaceDir(projectRoot), WORKSPACE_METADATA_FILE_NAME);
|
|
10
|
-
}
|
|
11
|
-
function ensureWorkspaceStorage(projectRoot) {
|
|
12
|
-
const canonicalRoot = resolve$1(projectRoot);
|
|
13
|
-
const dir = workspaceDir(canonicalRoot);
|
|
14
|
-
const file = workspaceMetadataFile(canonicalRoot);
|
|
15
|
-
mkdirSync(dir, { recursive: true });
|
|
16
|
-
return withDirLock(join$1(dir, "metadata.lock"), () => {
|
|
17
|
-
if (!existsSync(file)) {
|
|
18
|
-
const metadata = {
|
|
19
|
-
projectRoot: canonicalRoot,
|
|
20
|
-
workspace: workspaceName$1(canonicalRoot),
|
|
21
|
-
version: 1
|
|
22
|
-
};
|
|
23
|
-
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
24
|
-
writeFileSync(tmp, `${JSON.stringify(metadata, null, 2)}\n`);
|
|
25
|
-
try {
|
|
26
|
-
renameSync(tmp, file);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
rmSync(tmp, { force: true });
|
|
29
|
-
throw error;
|
|
30
|
-
}
|
|
31
|
-
return dir;
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
if (JSON.parse(readFileSync(file, "utf-8")).projectRoot === canonicalRoot) return dir;
|
|
35
|
-
} catch {}
|
|
36
|
-
const error = /* @__PURE__ */ new Error(`Stim workspace collision at ${dir}: its workspace.json does not belong to ${canonicalRoot}.`);
|
|
37
|
-
error.code = "STIM_WORKSPACE_COLLISION";
|
|
38
|
-
throw error;
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function workspaceLogsDir(projectRoot) {
|
|
42
|
-
return join$1(workspaceDir(projectRoot), "logs");
|
|
43
|
-
}
|
|
44
|
-
function workspaceDerivedData(projectRoot) {
|
|
45
|
-
return join$1(workspaceDir(projectRoot), "derived-data");
|
|
46
|
-
}
|
|
47
|
-
function supervisorPidFile(projectRoot) {
|
|
48
|
-
return join$1(workspaceDir(projectRoot), "supervisor.pid");
|
|
49
|
-
}
|
|
50
|
-
function workspaceStateFile(projectRoot) {
|
|
51
|
-
return join$1(workspaceDir(projectRoot), "state.json");
|
|
52
|
-
}
|
|
53
|
-
function workspaceStateLock(projectRoot) {
|
|
54
|
-
return join$1(workspaceDir(projectRoot), "state.lock");
|
|
55
|
-
}
|
|
56
|
-
function supervisorLogFile(projectRoot) {
|
|
57
|
-
return join$1(workspaceLogsDir(projectRoot), "supervisor.log");
|
|
58
|
-
}
|
|
59
|
-
function emulatorLogFile(projectRoot) {
|
|
60
|
-
return join$1(workspaceLogsDir(projectRoot), "emulator.log");
|
|
61
|
-
}
|
|
62
|
-
function sharedCompilationCache() {
|
|
63
|
-
return join$1(getConfigDir(), "compilation-cache");
|
|
64
|
-
}
|
|
65
|
-
function sharedCcache() {
|
|
66
|
-
return join$1(getConfigDir(), "ccache");
|
|
67
|
-
}
|
|
68
|
-
//#endregion
|
|
69
|
-
//#region src/workspace/workspace-state.ts
|
|
70
|
-
function readWorkspaceState(root) {
|
|
71
|
-
try {
|
|
72
|
-
const parsed = JSON.parse(readFileSync(workspaceStateFile(root), "utf-8"));
|
|
73
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
74
|
-
return parsed;
|
|
75
|
-
} catch {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function withWorkspaceStateLock(root, fn) {
|
|
80
|
-
const file = workspaceStateFile(root);
|
|
81
|
-
return withDirLock(workspaceStateLock(root), fn, { ensureParent: () => {
|
|
82
|
-
ensureWorkspaceStorage(root);
|
|
83
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
84
|
-
} });
|
|
85
|
-
}
|
|
86
|
-
function writeWorkspaceState(root, patch) {
|
|
87
|
-
return updateWorkspaceState(root, (state) => ({
|
|
88
|
-
...state,
|
|
89
|
-
...patch
|
|
90
|
-
}));
|
|
91
|
-
}
|
|
92
|
-
function updateWorkspaceState(root, update) {
|
|
93
|
-
return withWorkspaceStateLock(root, () => replaceWorkspaceState(root, update(readWorkspaceState(root) ?? {})));
|
|
94
|
-
}
|
|
95
|
-
function replaceWorkspaceState(root, state) {
|
|
96
|
-
const file = workspaceStateFile(root);
|
|
97
|
-
mkdirSync(dirname(file), { recursive: true });
|
|
98
|
-
const tmp = `${file}.tmp-${process.pid}`;
|
|
99
|
-
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`);
|
|
100
|
-
renameSync(tmp, file);
|
|
101
|
-
return state;
|
|
102
|
-
}
|
|
103
|
-
function clearWorkspaceStateKeys(root, keys) {
|
|
104
|
-
if (!existsSync(workspaceStateFile(root))) return;
|
|
105
|
-
withWorkspaceStateLock(root, () => {
|
|
106
|
-
const state = readWorkspaceState(root);
|
|
107
|
-
const file = workspaceStateFile(root);
|
|
108
|
-
if (!state) {
|
|
109
|
-
try {
|
|
110
|
-
rmSync(file, { force: true });
|
|
111
|
-
} catch {}
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
let changed = false;
|
|
115
|
-
for (const key of keys) {
|
|
116
|
-
if (!(key in state)) continue;
|
|
117
|
-
delete state[key];
|
|
118
|
-
changed = true;
|
|
119
|
-
}
|
|
120
|
-
if (!changed) return;
|
|
121
|
-
if (Object.keys(state).length === 0) {
|
|
122
|
-
rmSync(file, { force: true });
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
replaceWorkspaceState(root, state);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
function clearWorkspaceStateKey(root, key, shouldClear) {
|
|
129
|
-
return withWorkspaceStateLock(root, () => {
|
|
130
|
-
const state = readWorkspaceState(root);
|
|
131
|
-
if (!state || !(key in state)) return true;
|
|
132
|
-
if (!shouldClear(state[key])) return false;
|
|
133
|
-
delete state[key];
|
|
134
|
-
const file = workspaceStateFile(root);
|
|
135
|
-
if (Object.keys(state).length === 0) {
|
|
136
|
-
try {
|
|
137
|
-
rmSync(file, { force: true });
|
|
138
|
-
} catch {}
|
|
139
|
-
return true;
|
|
140
|
-
}
|
|
141
|
-
replaceWorkspaceState(root, state);
|
|
142
|
-
return true;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
//#endregion
|
|
146
|
-
export { workspaceLogsDir as _, withWorkspaceStateLock as a, ensureWorkspaceStorage as c, sharedCompilationCache as d, supervisorLogFile as f, workspaceId as g, workspaceDir as h, updateWorkspaceState as i, sharedBuildCache as l, workspaceDerivedData as m, clearWorkspaceStateKeys as n, writeWorkspaceState as o, supervisorPidFile as p, readWorkspaceState as r, emulatorLogFile as s, clearWorkspaceStateKey as t, sharedCcache as u, workspaceName$1 as v, workspaceStateFile as y };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
-
import { dirname, join, resolve } from "node:path";
|
|
3
2
|
import { METRO_NAMED_CACHE_LAYOUT, metroCacheRoot, registerCache, sharedStoreRoot, tagSharedStore } from "@stim-cli/core";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
//#region src/supervisor/metro-store.ts
|
|
6
6
|
function metroStoreName(root) {
|