stim 1.14.0 → 1.16.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 +2 -0
- package/dist/activity-BxwdD81S.mjs +609 -0
- package/dist/agent-device-usage-output-Dpih1Tfa.mjs +411 -0
- package/dist/{android-d6rGq1pA.mjs → android-B_NumVyQ.mjs} +169 -81
- package/dist/{android-LbPFRWVL.mjs → android-Ift4kVvt.mjs} +517 -413
- package/dist/android-cas-8U4DPqeR.mjs +167 -0
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-XpvCrV7q.mjs → android-r2rBL8kV.mjs} +2 -2
- package/dist/{app-install-BpgSgkJj.mjs → app-install-CKWdbXIX.mjs} +128 -151
- package/dist/attempt-Bk2ouQVL.mjs +39 -0
- package/dist/budget-DjrURfQn.mjs +2700 -0
- package/dist/{build-plan-Dcr-3ie0.mjs → build-plan-DjeSb2Xl.mjs} +192 -653
- package/dist/build-slots-rUk77xqh.mjs +132 -0
- package/dist/{cache-manifest-C68QQ0ua.mjs → cache-manifest-DnUHBJaU.mjs} +2 -2
- package/dist/cache-manifest.mjs +1 -1
- package/dist/{chrome-BPCiC3ZX.mjs → chrome-BrcVWQyD.mjs} +1 -1
- package/dist/cli-BkYZ_6hy.mjs +51 -0
- package/dist/cli.mjs +6 -42
- package/dist/client-BTY686R6.mjs +1368 -0
- package/dist/collector-run.mjs +9 -195
- package/dist/{command-output-DVcpw6eE.mjs → command-output-DnJMdEY-.mjs} +1 -1
- package/dist/{config-lvc7d3C2.mjs → config-D0DbpZtM.mjs} +28 -29
- package/dist/{created-devices-CllH_8eb.mjs → created-devices-D5owjN4C.mjs} +2 -2
- package/dist/{dependency-state-DsT7aKeo.mjs → dependency-state-B6cMXZab.mjs} +2 -2
- package/dist/{deps-D9IcKqXS.mjs → deps-urbmfXig.mjs} +3 -3
- package/dist/{detached-entry-DJHoca49.mjs → detached-entry-CiTEgMR1.mjs} +1 -1
- package/dist/dev-client-CroAIjjj.mjs +43 -0
- package/dist/{device-CjuuAJjQ.mjs → device-DZQjF7H5.mjs} +8 -7
- package/dist/device-capacity-BHwxNBlu.mjs +136 -0
- package/dist/device-host-worker.d.mts +1 -0
- package/dist/device-host-worker.mjs +964 -0
- package/dist/device-ios-BadmeL2V.mjs +381 -0
- package/dist/{device-lease-5c3WrVRm.mjs → device-lease-D-hLqx1b.mjs} +43 -36
- package/dist/{device-pool-BiyDyPP-.mjs → device-lease-run-CqjShqWW.mjs} +6 -126
- package/dist/device-pool-CUaEWMMm.mjs +125 -0
- package/dist/{device-remote-D87zEzaq.mjs → device-remote-D5WVWqOq.mjs} +69 -163
- package/dist/{doctor-x9pnU9fq.mjs → doctor-Cimf-gGB.mjs} +241 -103
- package/dist/{error-diagnostics-C5HzcwCW.mjs → error-diagnostics-B9L4Ae0x.mjs} +15 -18
- package/dist/{exec-DK8KaVHK.mjs → exec-CaErVv7t.mjs} +5 -1
- package/dist/{gc-ko6mUAYD.mjs → gc-Bqy4bjEu.mjs} +599 -108
- package/dist/{android-cas-iZK3DOCr.mjs → gradle-BsO1MdsH.mjs} +8 -294
- package/dist/{guide-6R0VNFqI.mjs → guide-B_uyKTxW.mjs} +2511 -239
- package/dist/{guide-status-BZrFPIA_.mjs → guide-status-CjEZMAD4.mjs} +3 -3
- package/dist/hosted-client-a-WmqE2L.mjs +197 -0
- package/dist/hosted-ios-CIWelIqf.mjs +220 -0
- package/dist/hosted-logs-D5g041Q3.mjs +187 -0
- package/dist/hosted-macos-BSZyIb3y.mjs +135 -0
- package/dist/idle-DYVymG92.mjs +1099 -0
- package/dist/idle-shutdown-CTsDnAde.mjs +122 -0
- package/dist/in-use-DvBw0Kxo.mjs +130 -0
- package/dist/{ios-BwDPrnYQ.mjs → ios-BaInn3sW.mjs} +201 -10
- package/dist/ios-Cr1h5gnO.mjs +189 -0
- package/dist/{ios-P1f5nm2n.mjs → ios-aq3QoGI3.mjs} +1159 -633
- package/dist/{ios-device-BiOsSVzd.mjs → ios-device-Ee7sDXfp.mjs} +1 -1
- package/dist/{ios-device-DGglU3E_.mjs → ios-device-FfCN_C8p.mjs} +12 -7
- package/dist/ios-state-DS5UpYTH.mjs +48 -0
- package/dist/{launch-verify-Deg4tB3Z.mjs → launch-verify-2DBRizjo.mjs} +5 -5
- package/dist/logs-CHEVK8zD.mjs +371 -0
- package/dist/machines-BIBUdhpj.mjs +265 -0
- package/dist/macos-CSYEAFmF.mjs +473 -0
- package/dist/macos-run.d.mts +5 -0
- package/dist/macos-run.mjs +2 -0
- package/dist/maintenance-run.d.mts +4 -0
- package/dist/maintenance-run.mjs +254 -0
- package/dist/{metro-CcEo8Fl8.mjs → metro-BeK1ZPz1.mjs} +20 -120
- package/dist/metro-gateway-BJ-rxQAB.mjs +84 -0
- package/dist/{named-ports-Blg8IxOh.mjs → named-ports-Bk_YXEmE.mjs} +6 -59
- package/dist/native-run-NaBrRFtQ.mjs +147 -0
- package/dist/{native-runtime-DjBHRg5m.mjs → native-runtime-DBzRnEKS.mjs} +9 -5
- package/dist/{ndjson-CDY9IkVC.mjs → ndjson-PclOIwVY.mjs} +2 -2
- package/dist/offload-worker.d.mts +122 -0
- package/dist/offload-worker.mjs +606 -0
- package/dist/{ownership-DyYDF5ww.mjs → ownership-DiA16AsN.mjs} +3 -2
- package/dist/ownership-hCkPzGmr.mjs +571 -0
- package/dist/{page-BHUzTDFt.mjs → page-QF_Ke10s.mjs} +7 -2
- package/dist/{ports-BguS83ex.mjs → ports-R2k4Knz3.mjs} +3 -3
- package/dist/prebuild-D2fsca_Z.mjs +213 -0
- package/dist/preview-DhVbvPAZ.mjs +318 -0
- package/dist/process-identity-BmRm1qV0.mjs +12 -0
- package/dist/{project-CWlvEaeN.mjs → project-Du91Ilvc.mjs} +74 -19
- package/dist/pull-request-pxnDCQzn.mjs +322 -0
- package/dist/pull-requests.d.mts +120 -0
- package/dist/pull-requests.mjs +2 -0
- package/dist/recordings-BIXOzVnr.mjs +37 -0
- package/dist/{reload-BiniwsSZ.mjs → reload-rM9jV1fz.mjs} +109 -24
- package/dist/{remote-cache-CcR6o6lI.mjs → remote-cache-C8-V13XN.mjs} +5 -5
- package/dist/run-f4vI6EnK.mjs +119 -0
- package/dist/{server-bare-DGfgyJ5J.mjs → server-bare-CpPGmnmO.mjs} +33 -15
- package/dist/server-expo-CVqO2c35.mjs +2 -0
- package/dist/{server-expo-BVuwQ65v.mjs → server-expo-MC0rHlOC.mjs} +8 -12
- package/dist/settings-BBpMcDbD.mjs +25 -0
- package/dist/{settings-B-fsC-Om.mjs → settings-ZkDzkzvB.mjs} +22 -10
- package/dist/settings-oTSkkNrM.mjs +1439 -0
- package/dist/settings.schema.json +845 -97
- package/dist/{simslim-DrDN4WuV.mjs → simslim-B8-7AoTI.mjs} +8 -132
- package/dist/{slot-launch-D5t8EiMf.mjs → slot-launch-B8VrHxn1.mjs} +11 -8
- package/dist/{spawn-claims-Drw_o-Fb.mjs → spawn-claims-D0XfSe8u.mjs} +1 -1
- package/dist/spawn-entry-jw19m8Nl.mjs +17 -0
- package/dist/stage-CzaiwFsI.mjs +143 -0
- package/dist/start-CX8Ig-U2.mjs +2 -0
- package/dist/{start-s4RXp1wy.mjs → start-ClDfwXa4.mjs} +116 -65
- package/dist/state-3DwSQIBK.mjs +41 -0
- package/dist/state-B4PQFXMW.d.mts +12 -0
- package/dist/{state-Dk9RVXI7.mjs → state-C1jB7Q8q.mjs} +70 -8
- package/dist/{state-DHqvsbqC.mjs → state-DcW6vOd_.mjs} +7 -4
- package/dist/stats-CEZ_i5je.mjs +77 -0
- package/dist/{status-BgAuxESg.mjs → status-BuvBFeII.mjs} +118 -20
- package/dist/{status-BsPAnfOI.mjs → status-Cs7VLg9D.mjs} +542 -283
- package/dist/status-DlKvVJBE.mjs +49 -0
- package/dist/stdout-reader-C8yjre1x.mjs +23 -0
- package/dist/stim-desktop-Cnz8CPnl.mjs +63 -0
- package/dist/stim-footprint.swift +32 -0
- package/dist/{stim-installations-CINXy_su.mjs → stim-installations-QMEI32v1.mjs} +1 -1
- package/dist/stop-B0Yxtmiy.mjs +48 -0
- package/dist/{stop-BzreOWJp.mjs → stop-Bffozsac.mjs} +83 -16
- package/dist/{stop-BWIF_6BK.mjs → stop-Dt_dM16A.mjs} +2 -2
- package/dist/stop-cause-CidxIqup.mjs +97 -0
- package/dist/supervisor-run.d.mts +43 -11
- package/dist/supervisor-run.mjs +363 -24
- package/dist/support-CAP8qDUF.mjs +316 -0
- package/dist/support-D4aYJniO.mjs +201 -0
- package/dist/teardown-CL6vDs2Y.mjs +727 -0
- package/dist/{xcode-Cp5KvK9x.mjs → toolchain-DkUflduf.mjs} +364 -14
- package/dist/trigger-Bemu8ytw.mjs +65 -0
- package/dist/trigger-CXts6qt1.mjs +2 -0
- package/dist/warm-progress-CpGv3Wb6.mjs +732 -0
- package/dist/{web-BsQs1WlO.mjs → web-DWUaMp8P.mjs} +37 -21
- package/dist/web-run.mjs +310 -13
- package/dist/workspace-process-lock-BL7Q0HCO.mjs +57 -0
- package/dist/workspace-state-B8-aJ1_5.mjs +371 -0
- package/dist/workspaces-BV4pdHFz.mjs +306 -0
- package/dist/{worktree-UrQWXSeb.mjs → worktree-K-xj9Db0.mjs} +625 -256
- package/dist/worktree-jnG8Iph5.mjs +2 -0
- package/package.json +10 -5
- package/shim/bundle-response.cjs +28 -12
- package/dist/activity-CYVDcrt3.mjs +0 -356
- package/dist/budget-CGDkhvv_.mjs +0 -1745
- package/dist/build-progress-DxKpwnaS.mjs +0 -247
- package/dist/idle-DXtx3RbX.mjs +0 -191
- package/dist/in-use-DlqBDKqY.mjs +0 -249
- package/dist/logs-Civ4gbBH.mjs +0 -486
- package/dist/merge-state-ytFQCeh4.mjs +0 -262
- package/dist/server-expo-DIHDhvGg.mjs +0 -2
- package/dist/settings-D61iNOsB.mjs +0 -629
- package/dist/start-Cetfvy8l.mjs +0 -2
- package/dist/stats-CFpFGlJV.mjs +0 -62
- package/dist/stats-CX1Z8Tca.mjs +0 -368
- package/dist/stim-desktop-CXt8-Z3J.mjs +0 -40
- package/dist/stop-cause-hjGBOZTG.mjs +0 -1231
- package/dist/worktree-BVrHsYZG.mjs +0 -752
- package/dist/worktree-CHWWvm5v.mjs +0 -2
- package/dist/{metro-store-DzeWkfqW.mjs → metro-store-CDDZHtPl.mjs} +1 -1
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { a as
|
|
7
|
-
import { n as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { E as upsertProject, p as getProject } from "./config-D0DbpZtM.mjs";
|
|
3
|
+
import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
4
|
+
import { n as windowsLauncherArgs } from "./detached-entry-CiTEgMR1.mjs";
|
|
5
|
+
import { _ as stepTimer, l as phaseLine } from "./command-output-DnJMdEY-.mjs";
|
|
6
|
+
import { C as metroTunnelSettingError, G as detectProviders, H as unknownSettingKeys, K as planMetroReach, M as remoteIosSetting, N as resolveCacheProviderConfig, P as resolveSettings, R as settingShapeErrors, S as metroPortSetting, T as ngrokUrlSetting, V as tunnelModeSetting, W as PUBLIC_METRO_ENV, a as SETTING_SHAPE_REMEDY, d as cacheProviderSettingError, f as deviceIdleShutdownMinutesSetting, gt as repoRoot, it as gitCommonDir, j as remoteAndroidSetting, k as publicUrlSetting, x as metroIdleStopMinutesSetting } from "./settings-oTSkkNrM.mjs";
|
|
7
|
+
import { d as readAppConfigText, f as readAppJson, n as appProjectProblem, o as findProjectRoot$1, r as detectIsExpo, t as NO_PROJECT_REFUSAL } from "./project-Du91Ilvc.mjs";
|
|
8
|
+
import { l as resolveProjectMetro, o as pidExists, p as reserveMetroPort, u as signalProcessTree } from "./metro-BeK1ZPz1.mjs";
|
|
9
|
+
import { c as writeWorkspaceState, g as workspaceAgentDeviceDir, i as recordWorkspaceUse, m as supervisorLogFile, n as clearWorkspaceStateKeys, r as readWorkspaceState$1, u as ensureWorkspaceStorage, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
|
|
10
|
+
import { c as stopOwnedMetroForReset, t as budgetGate } from "./budget-DjrURfQn.mjs";
|
|
11
|
+
import { c as readMetroTunnel, i as clearManagedMetroTunnel } from "./state-DcW6vOd_.mjs";
|
|
12
|
+
import { a as workspaceLinks, i as workspaceLinkLine } from "./stim-desktop-Cnz8CPnl.mjs";
|
|
13
|
+
import { n as workspaceProcessLockError, t as withWorkspaceProcessLock } from "./workspace-process-lock-BL7Q0HCO.mjs";
|
|
14
|
+
import { a as terminateChild, c as withManagedTunnelLock, i as stopTunnel, o as withManagedRemoteWorktreeLock, r as startTunnelSequence, t as resolveSupervisorTarget } from "./ownership-hCkPzGmr.mjs";
|
|
15
|
+
import { i as levelRank } from "./ndjson-PclOIwVY.mjs";
|
|
16
|
+
import { t as spawnEntry } from "./spawn-entry-jw19m8Nl.mjs";
|
|
17
|
+
import { d as readProjectConfig } from "./remote-cache-C8-V13XN.mjs";
|
|
15
18
|
import { appendFileSync, mkdirSync, openSync, readFileSync } from "node:fs";
|
|
19
|
+
import { dirname } from "node:path";
|
|
20
|
+
import { EventEmitter } from "node:events";
|
|
16
21
|
import { existsSync as existsSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1 } from "fs";
|
|
17
|
-
import { join } from "path";
|
|
22
|
+
import { join as join$1 } from "path";
|
|
18
23
|
import { IDLE_STOP_KEY, queryLogs } from "@stim-cli/core/state";
|
|
19
|
-
import { basename as basename$1, dirname as dirname$1, join as join$1 } from "node:path";
|
|
20
|
-
import { EventEmitter } from "node:events";
|
|
21
|
-
import { fileURLToPath } from "node:url";
|
|
22
24
|
import chalk from "chalk";
|
|
23
25
|
import { CACHE_PROVIDER_ENV, cacheProviderEnv } from "@stim-cli/cache";
|
|
24
26
|
//#region src/workspace/app-id.ts
|
|
@@ -60,7 +62,7 @@ function detectAndroidPackage(projectRoot) {
|
|
|
60
62
|
return detectAppIds(projectRoot).androidPackage;
|
|
61
63
|
}
|
|
62
64
|
function detectBundleIdFromPbxproj(projectRoot) {
|
|
63
|
-
const iosDir = join(projectRoot, "ios");
|
|
65
|
+
const iosDir = join$1(projectRoot, "ios");
|
|
64
66
|
if (!existsSync$1(iosDir)) return null;
|
|
65
67
|
let entries;
|
|
66
68
|
try {
|
|
@@ -70,7 +72,7 @@ function detectBundleIdFromPbxproj(projectRoot) {
|
|
|
70
72
|
}
|
|
71
73
|
for (const entry of entries) {
|
|
72
74
|
if (!entry.isDirectory() || !entry.name.endsWith(".xcodeproj")) continue;
|
|
73
|
-
const pbx = join(iosDir, entry.name, "project.pbxproj");
|
|
75
|
+
const pbx = join$1(iosDir, entry.name, "project.pbxproj");
|
|
74
76
|
if (!existsSync$1(pbx)) continue;
|
|
75
77
|
let text;
|
|
76
78
|
try {
|
|
@@ -93,7 +95,7 @@ function detectBundleIdFromPbxproj(projectRoot) {
|
|
|
93
95
|
return null;
|
|
94
96
|
}
|
|
95
97
|
function detectAndroidPackageFromGradle(projectRoot) {
|
|
96
|
-
const gradle = join(projectRoot, "android", "app", "build.gradle");
|
|
98
|
+
const gradle = join$1(projectRoot, "android", "app", "build.gradle");
|
|
97
99
|
if (!existsSync$1(gradle)) return null;
|
|
98
100
|
let text;
|
|
99
101
|
try {
|
|
@@ -108,18 +110,6 @@ function detectAndroidPackageFromGradle(projectRoot) {
|
|
|
108
110
|
return null;
|
|
109
111
|
}
|
|
110
112
|
//#endregion
|
|
111
|
-
//#region src/spawn-entry.ts
|
|
112
|
-
const DEV_ENTRIES = {
|
|
113
|
-
"supervisor-run": "./supervisor/run.ts",
|
|
114
|
-
"collector-run": "./collector/run.ts",
|
|
115
|
-
"web-run": "./web/run.ts"
|
|
116
|
-
};
|
|
117
|
-
function spawnEntry(name) {
|
|
118
|
-
const here = fileURLToPath(import.meta.url);
|
|
119
|
-
if (basename$1(dirname$1(here)) === "src") return fileURLToPath(new URL(DEV_ENTRIES[name], import.meta.url));
|
|
120
|
-
return join$1(dirname$1(here), `${name}.mjs`);
|
|
121
|
-
}
|
|
122
|
-
//#endregion
|
|
123
113
|
//#region src/commands/start.ts
|
|
124
114
|
const DEFAULT_WAIT_SECONDS = 60;
|
|
125
115
|
const POLL_MS = 500;
|
|
@@ -154,12 +144,13 @@ function liveSupervisor({ state, project, port, isAlive = pidExists, inspectIden
|
|
|
154
144
|
startedAt: target.startedAt ?? null
|
|
155
145
|
} : null;
|
|
156
146
|
}
|
|
157
|
-
function startFacts({ port, supervisor, logsDir, alreadyRunning }) {
|
|
147
|
+
function startFacts({ root, port, supervisor, logsDir, alreadyRunning }) {
|
|
158
148
|
return {
|
|
159
149
|
port,
|
|
160
150
|
supervisorPid: supervisor?.pid ?? null,
|
|
161
151
|
mode: supervisor?.mode ?? null,
|
|
162
152
|
logsDir,
|
|
153
|
+
...root ? { agentDevice: { stateDir: workspaceAgentDeviceDir(root) } } : {},
|
|
163
154
|
alreadyRunning: Boolean(alreadyRunning)
|
|
164
155
|
};
|
|
165
156
|
}
|
|
@@ -194,14 +185,14 @@ function recordedSupervisorProcess(pid) {
|
|
|
194
185
|
});
|
|
195
186
|
}
|
|
196
187
|
const RECORDED_SUPERVISOR_WAIT_MS = 15e3;
|
|
197
|
-
function providersOnPath() {
|
|
188
|
+
function providersOnPath(mode) {
|
|
198
189
|
return detectProviders((bin) => {
|
|
199
190
|
try {
|
|
200
191
|
return Boolean(getExecutor().findExecutable(bin));
|
|
201
192
|
} catch {
|
|
202
193
|
return false;
|
|
203
194
|
}
|
|
204
|
-
});
|
|
195
|
+
}, mode);
|
|
205
196
|
}
|
|
206
197
|
const DEFAULT_START_DEPS = {
|
|
207
198
|
providers: providersOnPath,
|
|
@@ -260,7 +251,7 @@ function registerStart(program, overrides = {}) {
|
|
|
260
251
|
remedy: "Pass a whole number of seconds, e.g. --wait 90."
|
|
261
252
|
});
|
|
262
253
|
const waitSeconds = wait.seconds;
|
|
263
|
-
const root = findProjectRoot(process.cwd());
|
|
254
|
+
const root = findProjectRoot$1(process.cwd());
|
|
264
255
|
if (!root) return fail(NO_PROJECT_REFUSAL);
|
|
265
256
|
const projectProblem = appProjectProblem(root);
|
|
266
257
|
if (projectProblem) return fail({
|
|
@@ -313,7 +304,8 @@ function registerStart(program, overrides = {}) {
|
|
|
313
304
|
out,
|
|
314
305
|
facts: result.facts,
|
|
315
306
|
waited: result.waited,
|
|
316
|
-
reclaimed: result.reclaimed
|
|
307
|
+
reclaimed: result.reclaimed,
|
|
308
|
+
links: workspaceLinks(root)
|
|
317
309
|
});
|
|
318
310
|
});
|
|
319
311
|
}
|
|
@@ -348,7 +340,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
348
340
|
message: settingError,
|
|
349
341
|
remedy: "Set metro.tunnel to \"ngrok\" and metro.ngrokUrl to an HTTPS URL, or remove metro.ngrokUrl."
|
|
350
342
|
});
|
|
351
|
-
const remote = remoteFlag || remoteIosSetting(settings)
|
|
343
|
+
const remote = remoteFlag || remoteIosSetting(settings)?.kind === "backend" || remoteAndroidSetting(settings) !== null;
|
|
352
344
|
const tunnelMode = tunnelModeSetting(settings) ?? "auto";
|
|
353
345
|
const publicUrl = publicUrlSetting(settings);
|
|
354
346
|
const tunnel = wantsExpoOwnTunnel({
|
|
@@ -376,6 +368,11 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
376
368
|
};
|
|
377
369
|
if (resetCache) {
|
|
378
370
|
await gateBudget();
|
|
371
|
+
const pin = metroPortSetting(root);
|
|
372
|
+
if (pin.port !== null || pin.error) {
|
|
373
|
+
const pinCheck = await resolveWorkspaceMetroPort(root, note, "start", false);
|
|
374
|
+
if (typeof pinCheck !== "number") return fail(pinCheck);
|
|
375
|
+
}
|
|
379
376
|
try {
|
|
380
377
|
await stopOwnedMetroForReset(root);
|
|
381
378
|
} catch (error) {
|
|
@@ -388,9 +385,9 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
388
385
|
}
|
|
389
386
|
note(phaseLine("cache", "clearing this app's Metro transform and file-map caches; devices preserved"));
|
|
390
387
|
}
|
|
391
|
-
const logsDir = workspaceLogsDir(root);
|
|
388
|
+
const logsDir = workspaceLogsDir$1(root);
|
|
392
389
|
const logFile = supervisorLogFile(root);
|
|
393
|
-
const port = await resolvePort(root, note);
|
|
390
|
+
const port = await resolvePort(root, note, fail);
|
|
394
391
|
let publicOrigin = remote ? publicUrl : null;
|
|
395
392
|
let resolution = await resolveProjectMetro(port, root);
|
|
396
393
|
let supervisor = liveSupervisor({
|
|
@@ -510,7 +507,9 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
510
507
|
...tunnel ? ["--tunnel"] : [],
|
|
511
508
|
...resetCache ? ["--reset-cache"] : [],
|
|
512
509
|
"--idle-stop-minutes",
|
|
513
|
-
String(metroIdleStopMinutesSetting(settings))
|
|
510
|
+
String(metroIdleStopMinutesSetting(settings)),
|
|
511
|
+
"--device-idle-minutes",
|
|
512
|
+
String(deviceIdleShutdownMinutesSetting(settings))
|
|
514
513
|
];
|
|
515
514
|
const childEnv = {
|
|
516
515
|
...process.env,
|
|
@@ -540,7 +539,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
540
539
|
return null;
|
|
541
540
|
};
|
|
542
541
|
if (remote && !tunnel && !publicUrl && tunnelMode !== "off") {
|
|
543
|
-
const available = d.providers();
|
|
542
|
+
const available = d.providers(tunnelMode);
|
|
544
543
|
const plan = planMetroReach({
|
|
545
544
|
mode: tunnelMode,
|
|
546
545
|
metroPort: port,
|
|
@@ -554,7 +553,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
554
553
|
remedy: plan.remedy
|
|
555
554
|
});
|
|
556
555
|
if ("start" in plan) {
|
|
557
|
-
const candidates = tunnelMode === "auto" ? available : [plan.start];
|
|
556
|
+
const candidates = tunnelMode === "auto" ? available.filter((provider) => provider !== "tailscale") : [plan.start];
|
|
558
557
|
const expectedStableUrl = ngrokUrlSetting(settings);
|
|
559
558
|
let acquisition;
|
|
560
559
|
try {
|
|
@@ -722,6 +721,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
722
721
|
if ("failed" in acquisition) return fail(acquisition.failed);
|
|
723
722
|
publicOrigin = acquisition.origin;
|
|
724
723
|
managedTunnel = acquisition.tunnel;
|
|
724
|
+
if (managedTunnel.record.provider === "tailscale") note(phaseLine("lan", `tailnet-only Metro: ${publicOrigin}`));
|
|
725
725
|
resolution = await resolveProjectMetro(port, root);
|
|
726
726
|
supervisor = liveSupervisor({
|
|
727
727
|
state: readWorkspaceState$1(root),
|
|
@@ -786,6 +786,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
786
786
|
if (managedTunnelExited()) return failExitedManagedTunnel();
|
|
787
787
|
clearWorkspaceStateKeys(root, [IDLE_STOP_KEY]);
|
|
788
788
|
return startFacts({
|
|
789
|
+
root,
|
|
789
790
|
port,
|
|
790
791
|
supervisor,
|
|
791
792
|
logsDir,
|
|
@@ -838,6 +839,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
838
839
|
requireExpoTunnel();
|
|
839
840
|
if (managedTunnelExited()) return failExitedManagedTunnel();
|
|
840
841
|
return startFacts({
|
|
842
|
+
root,
|
|
841
843
|
port,
|
|
842
844
|
supervisor,
|
|
843
845
|
logsDir,
|
|
@@ -903,6 +905,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
903
905
|
startedAt: null
|
|
904
906
|
};
|
|
905
907
|
return startFacts({
|
|
908
|
+
root,
|
|
906
909
|
port,
|
|
907
910
|
supervisor,
|
|
908
911
|
logsDir,
|
|
@@ -911,7 +914,7 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
911
914
|
};
|
|
912
915
|
const startLocked = async () => {
|
|
913
916
|
try {
|
|
914
|
-
return await withWorkspaceProcessLock(dirname$1(
|
|
917
|
+
return await withWorkspaceProcessLock(dirname(workspaceLogsDir$1(root)), "metro-start", runStart, { external: true });
|
|
915
918
|
} catch (error) {
|
|
916
919
|
if (workspaceProcessLockError(error) !== "timeout") throw error;
|
|
917
920
|
return fail({
|
|
@@ -956,24 +959,69 @@ async function startDevServer({ root, settings, waitSeconds = DEFAULT_WAIT_SECON
|
|
|
956
959
|
};
|
|
957
960
|
}
|
|
958
961
|
}
|
|
959
|
-
async function resolvePort(root, note) {
|
|
962
|
+
async function resolvePort(root, note, fail) {
|
|
963
|
+
const result = await resolveWorkspaceMetroPort(root, note, "start");
|
|
964
|
+
return typeof result === "number" ? result : fail(result);
|
|
965
|
+
}
|
|
966
|
+
async function resolveWorkspaceMetroPort(root, note, command, reserve = true) {
|
|
967
|
+
const setting = metroPortSetting(root);
|
|
968
|
+
if (setting.error) return {
|
|
969
|
+
code: "STIM_BAD_ARG",
|
|
970
|
+
message: setting.error,
|
|
971
|
+
remedy: SETTING_SHAPE_REMEDY
|
|
972
|
+
};
|
|
973
|
+
const pinned = setting.port;
|
|
960
974
|
const project = getProject(root);
|
|
961
975
|
const recorded = project?.metroPort;
|
|
962
|
-
if (
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
976
|
+
if (pinned === null && command === "web") return recorded ?? await reserveMetroPort(root);
|
|
977
|
+
if (recorded) {
|
|
978
|
+
const supervisor = resolveSupervisorTarget({
|
|
979
|
+
state: readWorkspaceState$1(root)?.supervisor,
|
|
980
|
+
record: project.supervisor,
|
|
981
|
+
reservedPort: recorded
|
|
982
|
+
});
|
|
983
|
+
if (supervisor.status !== "none" && supervisor.status !== "stale") {
|
|
984
|
+
if (pinned === null || recorded === pinned) return recorded;
|
|
985
|
+
if (supervisor.status === "unverified") return {
|
|
986
|
+
code: "STIM_BAD_ARG",
|
|
987
|
+
message: `Cannot move this workspace's Metro to metro.port ${pinned}: ${supervisor.reason}.`,
|
|
988
|
+
remedy: `Stop that supervisor with the tool that started it, then retry, or restore metro.port to ${recorded}. Stim leaves unverified processes alone.`
|
|
989
|
+
};
|
|
990
|
+
return {
|
|
991
|
+
code: "STIM_BAD_ARG",
|
|
992
|
+
message: `This workspace's dev server is running on port ${recorded}, and metro.port pins it to ${pinned}.`,
|
|
993
|
+
remedy: "Run `stim stop`, then retry, or unset or restore metro.port."
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
if (pinned !== null) {
|
|
998
|
+
const held = await resolveProjectMetro(pinned, root);
|
|
999
|
+
if (held.notOurs) return {
|
|
1000
|
+
code: "STIM_BAD_ARG",
|
|
1001
|
+
message: `Port ${pinned} is held by something else (${held.notOurs}), and metro.port pins this workspace's Metro to it.`,
|
|
1002
|
+
remedy: "Stop the process on that port, or set another metro.port."
|
|
1003
|
+
};
|
|
1004
|
+
if (recorded === pinned) return recorded;
|
|
1005
|
+
} else if (recorded) {
|
|
1006
|
+
const held = await resolveProjectMetro(recorded, root);
|
|
1007
|
+
if (!held.notOurs) return recorded;
|
|
1008
|
+
const fresh = await reserveMetroPort(root);
|
|
1009
|
+
if (fresh !== recorded) {
|
|
1010
|
+
note(chalk.yellow(`Port ${recorded} is held by something else (${held.notOurs}).`));
|
|
1011
|
+
note(chalk.dim(`Reserved port ${fresh} for this project instead.`));
|
|
1012
|
+
}
|
|
1013
|
+
return fresh;
|
|
1014
|
+
}
|
|
1015
|
+
if (!reserve && pinned !== null) return pinned;
|
|
1016
|
+
try {
|
|
1017
|
+
return await reserveMetroPort(root, void 0, void 0, pinned);
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
return {
|
|
1020
|
+
code: "STIM_BAD_ARG",
|
|
1021
|
+
message: error.message,
|
|
1022
|
+
remedy: "Give each workspace its own metro.port, in the workspace layer or the environment."
|
|
1023
|
+
};
|
|
975
1024
|
}
|
|
976
|
-
return fresh;
|
|
977
1025
|
}
|
|
978
1026
|
async function waitForMetro({ root, port, seconds, aborted = () => false, probe = resolveProjectMetro }) {
|
|
979
1027
|
const deadline = Date.now() + seconds * 1e3;
|
|
@@ -1014,17 +1062,20 @@ function failureEvidence({ logFile, logsDir, sinceTs }) {
|
|
|
1014
1062
|
if (recent.length > 0) lines.push(fellBack ? "Full records: `stim logs`" : "Full records: `stim logs --errors`");
|
|
1015
1063
|
return lines;
|
|
1016
1064
|
}
|
|
1017
|
-
function report({ json, out, facts, waited, reclaimed }) {
|
|
1065
|
+
function report({ json, out, facts, waited, reclaimed, links }) {
|
|
1018
1066
|
if (json) {
|
|
1019
|
-
console.log(JSON.stringify(
|
|
1067
|
+
console.log(JSON.stringify({
|
|
1020
1068
|
...facts,
|
|
1021
|
-
|
|
1022
|
-
|
|
1069
|
+
...links ? { links } : {},
|
|
1070
|
+
...reclaimed.length ? { reclaimed } : {}
|
|
1071
|
+
}));
|
|
1023
1072
|
return;
|
|
1024
1073
|
}
|
|
1025
1074
|
const who = facts.supervisorPid ? `supervisor pid ${facts.supervisorPid}${facts.mode ? ` (${facts.mode})` : ""}` : "started outside Stim";
|
|
1026
1075
|
out(chalk.green(`OK: dev server on port ${facts.port}, ${who}${facts.alreadyRunning ? " (already running)" : ""} ${waited}`));
|
|
1027
1076
|
out(chalk.dim(phaseLine("logs", facts.logsDir)));
|
|
1077
|
+
if (facts.agentDevice) out(chalk.dim(phaseLine("agent-device", `AGENT_DEVICE_STATE_DIR=${facts.agentDevice.stateDir}`)));
|
|
1078
|
+
if (links) console.error(chalk.dim(workspaceLinkLine(links)));
|
|
1028
1079
|
}
|
|
1029
1080
|
//#endregion
|
|
1030
|
-
export { registerStart as a,
|
|
1081
|
+
export { registerStart as a, startDevServer as c, tailLines as d, wantsExpoOwnTunnel as f, detectBundleId as h, readLogTail as i, startFacts as l, detectAppIds as m, liveSupervisor as n, resolveWorkspaceMetroPort as o, detectAndroidPackage as p, parseWait as r, startCommand as s, failureEvidence as t, supervisorEntry as u };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
2
|
+
import { a as updateWorkspaceState, r as readWorkspaceState$1, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { readMacosRecord } from "@stim-cli/core/state";
|
|
5
|
+
//#region src/macos/state.ts
|
|
6
|
+
const macosDir = (root) => join(workspaceDir(root), "macos");
|
|
7
|
+
const macosLogFile = (root) => join(workspaceLogsDir$1(root), "macos.ndjson");
|
|
8
|
+
const macosRuntimeClaim = (root) => join(macosDir(root), "runtime.lock");
|
|
9
|
+
function macosProcess(pid) {
|
|
10
|
+
const processToken = (0, process_identity_exports.captureProcessToken)(pid);
|
|
11
|
+
const start = (0, process_identity_exports.processStartMicros)(pid);
|
|
12
|
+
if (!processToken || start.status !== "running") throw Object.assign(/* @__PURE__ */ new Error(`Cannot verify macOS process ${pid}; refusing unmanaged launch.`), { code: "STIM_CLAIM_UNAVAILABLE" });
|
|
13
|
+
return {
|
|
14
|
+
pid,
|
|
15
|
+
processToken,
|
|
16
|
+
startedAtMicros: start.startedAtMicros
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function requiredMacosRecord(root) {
|
|
20
|
+
const record = readMacosRecord(root);
|
|
21
|
+
if (!record && readWorkspaceState$1(root)?.macos !== void 0) throw Object.assign(/* @__PURE__ */ new Error("The recorded macOS owner is malformed; repair its workspace state before running."), { code: "STIM_MACOS_OWNER_UNVERIFIED" });
|
|
22
|
+
return record;
|
|
23
|
+
}
|
|
24
|
+
function updateMacosRecord(root, owner, patch) {
|
|
25
|
+
let updated = false;
|
|
26
|
+
updateWorkspaceState(root, (state) => {
|
|
27
|
+
const record = readMacosRecord(root);
|
|
28
|
+
if (!record || !(0, process_identity_exports.sameProcessRecord)(record.supervisor, owner)) return state;
|
|
29
|
+
updated = true;
|
|
30
|
+
return {
|
|
31
|
+
...state,
|
|
32
|
+
macos: {
|
|
33
|
+
...record,
|
|
34
|
+
...patch
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
return updated;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { requiredMacosRecord as a, macosRuntimeClaim as i, macosLogFile as n, updateMacosRecord as o, macosProcess as r, macosDir as t };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "@stim-cli/core/state";
|
|
2
|
+
import * as import__stim_cli_core_process_identity from "@stim-cli/core/process-identity";
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region src/supervisor/state.d.ts
|
|
5
|
+
declare const MODE_BARE = "bare-inproc";
|
|
6
|
+
declare const MODE_EXPO = "expo-child";
|
|
7
|
+
declare function clearWorkspaceSupervisor(root: string, expected?: process_identity_d_exports.ProcessRecord | null): boolean;
|
|
8
|
+
declare function clearExpoMetroTunnel(root: string): void;
|
|
9
|
+
declare function writePidFile(root: string, pid: number): string;
|
|
10
|
+
declare function readPidFile(root: string): number | null;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { readPidFile as a, clearWorkspaceSupervisor as i, MODE_EXPO as n, writePidFile as o, clearExpoMetroTunnel as r, MODE_BARE as t };
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { n as ownership_claim_exports, t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
2
|
+
import { o as pidExists } from "./metro-BeK1ZPz1.mjs";
|
|
3
|
+
import { a as updateWorkspaceState, c as writeWorkspaceState, r as readWorkspaceState$1, t as clearWorkspaceStateKey, v as workspaceDir, x as workspaceLogsDir$1 } from "./workspace-state-B8-aJ1_5.mjs";
|
|
4
|
+
import { readFileSync, readlinkSync, rmSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
+
import { rotatedLogPath } from "@stim-cli/core";
|
|
7
|
+
import { WEB_VIEWPORTS } from "@stim-cli/core/state";
|
|
6
8
|
import { hostname } from "node:os";
|
|
7
9
|
//#region src/web/profile.ts
|
|
8
10
|
const SINGLETON_FILES = [
|
|
@@ -56,13 +58,13 @@ function webClaimRoot(root) {
|
|
|
56
58
|
return join(webDir(root), "supervisor.lock");
|
|
57
59
|
}
|
|
58
60
|
function webLogFile(root) {
|
|
59
|
-
return join(workspaceLogsDir(root), "web.ndjson");
|
|
61
|
+
return join(workspaceLogsDir$1(root), "web.ndjson");
|
|
60
62
|
}
|
|
61
63
|
function webSupervisorLogFile(root) {
|
|
62
|
-
return join(workspaceLogsDir(root), "web-supervisor.log");
|
|
64
|
+
return join(workspaceLogsDir$1(root), "web-supervisor.log");
|
|
63
65
|
}
|
|
64
66
|
function browserLogFile(root) {
|
|
65
|
-
return join(workspaceLogsDir(root), "browser.log");
|
|
67
|
+
return join(workspaceLogsDir$1(root), "browser.log");
|
|
66
68
|
}
|
|
67
69
|
function processRecord(value) {
|
|
68
70
|
const record = value;
|
|
@@ -144,5 +146,65 @@ function webFacts(record) {
|
|
|
144
146
|
status: supervisor === "same" && chrome === "running" ? "running" : "orphaned"
|
|
145
147
|
};
|
|
146
148
|
}
|
|
149
|
+
const PAGE_FAILURES = /* @__PURE__ */ new Set(["web_document_failed", "web_page_crashed"]);
|
|
150
|
+
const NAVIGATION = Buffer.from("\"event\":\"web_navigation\"");
|
|
151
|
+
const PAGE_EVENT = "\"event\":\"web_";
|
|
152
|
+
/**
|
|
153
|
+
* The latest page load in the web log's `lines`: the newest `web_navigation` marker, whether a document failure, a
|
|
154
|
+
* crash or the load event followed it, and the newest in-app route change after it. Null before the first
|
|
155
|
+
* navigation.
|
|
156
|
+
*/
|
|
157
|
+
function latestPageLoad(lines) {
|
|
158
|
+
let failure = null;
|
|
159
|
+
let loaded = false;
|
|
160
|
+
let route = null;
|
|
161
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
162
|
+
let record;
|
|
163
|
+
try {
|
|
164
|
+
record = JSON.parse(lines[i]);
|
|
165
|
+
} catch {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (record.event === "web_navigation" && typeof record.url === "string") {
|
|
169
|
+
const moved = route !== null && route !== record.url ? { route } : {};
|
|
170
|
+
if (failure !== null) return {
|
|
171
|
+
url: record.url,
|
|
172
|
+
state: "failed",
|
|
173
|
+
error: failure,
|
|
174
|
+
...moved
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
url: record.url,
|
|
178
|
+
state: loaded ? "loaded" : "loading",
|
|
179
|
+
...moved
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (typeof record.event !== "string") continue;
|
|
183
|
+
if (record.event === "web_route" && typeof record.url === "string") route ??= record.url;
|
|
184
|
+
if (PAGE_FAILURES.has(record.event)) failure = typeof record.msg === "string" ? record.msg : record.event;
|
|
185
|
+
else if (record.event === "web_page_loaded") loaded = true;
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
/** The page lines from the newest navigation on, in the web log or, right after a rotation, its previous file. */
|
|
190
|
+
function pageLines(file) {
|
|
191
|
+
for (const path of [file, rotatedLogPath(file)]) {
|
|
192
|
+
let bytes;
|
|
193
|
+
try {
|
|
194
|
+
bytes = readFileSync(path);
|
|
195
|
+
} catch {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const at = bytes.lastIndexOf(NAVIGATION);
|
|
199
|
+
if (at < 0) continue;
|
|
200
|
+
const start = bytes.lastIndexOf(10, at) + 1;
|
|
201
|
+
return bytes.subarray(start).toString("utf8").split("\n").filter((line) => line.includes(PAGE_EVENT));
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
function readWebPage(root) {
|
|
206
|
+
const lines = pageLines(webLogFile(root));
|
|
207
|
+
return lines ? latestPageLoad(lines) : null;
|
|
208
|
+
}
|
|
147
209
|
//#endregion
|
|
148
|
-
export {
|
|
210
|
+
export { removeSingletonFiles as _, readWebPage as a, webClaimRoot as c, webLogFile as d, webProfileDir as f, liveProfileHolder as g, chromeProcessState as h, clearWebRecord as i, webDir as l, writeWebRecord as m, browserLogFile as n, readWebRecord as o, webSupervisorLogFile as p, cdpEndpoint as r, updateWebRecord as s, CDP_PORT_LABEL as t, webFacts as u };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { B as parseDeviceSlotKey, R as deviceSlotKey } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { t as process_identity_exports } from "./process-identity-BmRm1qV0.mjs";
|
|
3
|
+
import { C as workspaceStateFile, a as updateWorkspaceState, h as supervisorPidFile, o as withWorkspaceStateLock, r as readWorkspaceState, t as clearWorkspaceStateKey } from "./workspace-state-B8-aJ1_5.mjs";
|
|
3
4
|
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { dirname } from "node:path";
|
|
5
6
|
//#region src/supervisor/state.ts
|
|
@@ -22,7 +23,7 @@ function readMetroTunnel(root) {
|
|
|
22
23
|
const startedAt = record.startedAt;
|
|
23
24
|
const processToken = record.processToken;
|
|
24
25
|
const logFile = record.logFile;
|
|
25
|
-
if (provider !== "ngrok" && provider !== "cloudflared" || typeof pid !== "number" || typeof port !== "number") return null;
|
|
26
|
+
if (provider !== "ngrok" && provider !== "cloudflared" && provider !== "tailscale" || typeof pid !== "number" || typeof port !== "number") return null;
|
|
26
27
|
return {
|
|
27
28
|
kind: "managed",
|
|
28
29
|
provider,
|
|
@@ -88,11 +89,13 @@ function readRemoteSession(root) {
|
|
|
88
89
|
const platform = record.platform;
|
|
89
90
|
const startedAt = record.startedAt;
|
|
90
91
|
const webPreviewUrl = record.webPreviewUrl;
|
|
92
|
+
const deviceType = record.deviceType;
|
|
91
93
|
return {
|
|
92
94
|
platform: platform === "ios" || platform === "android" ? platform : null,
|
|
93
95
|
sessionId: id,
|
|
94
96
|
startedAt: typeof startedAt === "string" ? startedAt : null,
|
|
95
|
-
webPreviewUrl: typeof webPreviewUrl === "string" && webPreviewUrl.length > 0 ? webPreviewUrl : null
|
|
97
|
+
webPreviewUrl: typeof webPreviewUrl === "string" && webPreviewUrl.length > 0 ? webPreviewUrl : null,
|
|
98
|
+
deviceType: typeof deviceType === "string" && deviceType.length > 0 ? deviceType : null
|
|
96
99
|
};
|
|
97
100
|
}
|
|
98
101
|
function readRemoteSessionId(root) {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { j as formatBytes } from "./config-D0DbpZtM.mjs";
|
|
2
|
+
import { o as formatLongDuration } from "./command-output-DnJMdEY-.mjs";
|
|
3
|
+
import { gt as repoRoot, it as gitCommonDir } from "./settings-oTSkkNrM.mjs";
|
|
4
|
+
import { o as findProjectRoot$1 } from "./project-Du91Ilvc.mjs";
|
|
5
|
+
import { i as getSwiftpmCacheUsage, n as swiftpmCacheLines, r as getAgentDeviceUsage, t as agentDeviceLines } from "./agent-device-usage-output-Dpih1Tfa.mjs";
|
|
6
|
+
import { archivedUsage, readArchives, readStatsReport, statsProjectKey } from "@stim-cli/core/state";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
//#region src/commands/stats.ts
|
|
9
|
+
const PLATFORMS = ["ios", "android"];
|
|
10
|
+
const PLATFORM_WIDTH = 9;
|
|
11
|
+
const RECENT_PLACEMENTS = 5;
|
|
12
|
+
function statsCommand(program) {
|
|
13
|
+
program.command("stats").description("Show how many `ios` and `android` runs this project and this machine have recorded, how many hit the build cache, and an estimate of the time that cache saved.").option("--json", "print the aggregates as JSON").action(async (opts) => {
|
|
14
|
+
const agentDevice = await getAgentDeviceUsage();
|
|
15
|
+
const swiftpmCache = await getSwiftpmCacheUsage();
|
|
16
|
+
const root = findProjectRoot$1(process.cwd());
|
|
17
|
+
const key = root ? statsProjectKey({
|
|
18
|
+
root,
|
|
19
|
+
commonDir: gitCommonDir(root),
|
|
20
|
+
repoRoot: repoRoot(root)
|
|
21
|
+
}) : null;
|
|
22
|
+
const { report, note } = readStatsReport(key, Date.now());
|
|
23
|
+
report.agentDevice = agentDevice;
|
|
24
|
+
report.swiftpmCache = swiftpmCache;
|
|
25
|
+
if (note) console.error(chalk.dim(note));
|
|
26
|
+
const { machine, project, offload } = report;
|
|
27
|
+
if (opts.json) {
|
|
28
|
+
console.log(JSON.stringify(report));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const lines = [];
|
|
32
|
+
if (project) lines.push(`project ${project.key}`, ...sectionLines(project));
|
|
33
|
+
lines.push("machine", ...sectionLines(machine));
|
|
34
|
+
const usage = archivedUsage(readArchives());
|
|
35
|
+
lines.push("archive", ` archived workspaces: ${usage.count}, ${formatBytes(usage.bytes)}`);
|
|
36
|
+
if (offload.placements.length || Object.keys(offload.machines).length) lines.push(...placementLines(offload));
|
|
37
|
+
const agentLines = agentDeviceLines(report.agentDevice);
|
|
38
|
+
if (agentLines.length) lines.push(...agentLines, chalk.dim(" Stim never trims or deletes the shared runner builds, sessions, logs and other state or the hosted driver dir; a workspace's own agent-device dir goes only with its workspace."));
|
|
39
|
+
lines.push(...swiftpmCacheLines(report.swiftpmCache));
|
|
40
|
+
for (const line of lines) console.log(line);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function sectionLines(scope) {
|
|
44
|
+
const lines = PLATFORMS.filter((platform) => scope[platform]).map((platform) => bucketLine(platform, scope[platform]));
|
|
45
|
+
return lines.length ? lines : [chalk.dim(" no runs recorded")];
|
|
46
|
+
}
|
|
47
|
+
function placementLines(offload) {
|
|
48
|
+
const { here, offloaded, fellBack } = offload.today;
|
|
49
|
+
const lines = ["build placement", ` ${"today".padEnd(PLATFORM_WIDTH)}${here} here, ${offloaded} offloaded, ${fellBack} fell back`];
|
|
50
|
+
for (const [name, { today, total }] of Object.entries(offload.machines)) {
|
|
51
|
+
const saved = total.savedMs === 0 ? "" : `, ${total.savedMs > 0 ? "saved" : "lost"} ~${formatLongDuration(Math.abs(total.savedMs))} (estimated)`;
|
|
52
|
+
lines.push(` ${name}: today ${today.offloaded} offloaded, ${today.fallbacks} fell back; total ${total.offloaded} offloaded (${average(total.offloadedMs, total.offloaded)} avg)${saved}, ${total.fallbacks} fell back`);
|
|
53
|
+
}
|
|
54
|
+
for (const placement of offload.placements.slice(0, RECENT_PLACEMENTS)) {
|
|
55
|
+
const where = placement.decision === "here" ? "here" : `${placement.decision} ${placement.machine ?? ""}`.trim();
|
|
56
|
+
lines.push(chalk.dim(` ${placement.at.slice(0, 16).replace("T", " ")}Z ${placement.platform} ${where}: ${placement.reason}`));
|
|
57
|
+
}
|
|
58
|
+
return lines;
|
|
59
|
+
}
|
|
60
|
+
function bucketLine(platform, bucket) {
|
|
61
|
+
const finished = bucket.runs - bucket.failed;
|
|
62
|
+
const cells = [
|
|
63
|
+
`${bucket.runs} runs${bucket.failed > 0 ? ` (${bucket.failed} failed)` : ""}`,
|
|
64
|
+
`${bucket.hits} hits (${finished > 0 ? `${Math.round(bucket.hits / finished * 100)}%` : "-"})`,
|
|
65
|
+
`cold run ${average(bucket.coldRunMs, bucket.coldRuns)} avg`,
|
|
66
|
+
`hit run ${average(bucket.hitRunMs, bucket.hitRuns)} avg`,
|
|
67
|
+
...bucket.offloadedRuns ? [`offloaded run ${average(bucket.offloadedRunMs ?? 0, bucket.offloadedRuns)} avg (${bucket.offloadedRuns}, last on ${bucket.lastOffloadHost ?? "?"})`] : [],
|
|
68
|
+
`saved ~${formatLongDuration(bucket.timeSavedMs)} (estimated)`,
|
|
69
|
+
`since ${bucket.firstRunAt.slice(0, 10)}`
|
|
70
|
+
];
|
|
71
|
+
return ` ${platform.padEnd(PLATFORM_WIDTH)}${cells.join(" ")}`;
|
|
72
|
+
}
|
|
73
|
+
function average(totalMs, runs) {
|
|
74
|
+
return runs > 0 ? formatLongDuration(Math.round(totalMs / runs)) : "-";
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
77
|
+
export { statsCommand as default };
|