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,31 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { O as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import { n as
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { n as
|
|
1
|
+
import { t as getExecutor } from "./exec-CaErVv7t.mjs";
|
|
2
|
+
import { _ as loadConfig$1, p as getProject, s as configCorruptRepair, u as getConcurrencyLimits } from "./config-D0DbpZtM.mjs";
|
|
3
|
+
import { d as quotedPath, f as refuseNoProject, l as phaseLine, u as plural } from "./command-output-DnJMdEY-.mjs";
|
|
4
|
+
import { B as settingsLayers, Ct as filesystemDevice, Et as temporaryRoot, H as unknownSettingKeys, I as settingOrigin, M as remoteIosSetting, O as projectOptimizations, P as resolveSettings, R as settingShapeErrors, U as webSettings, Y as compilerCacheFallbackMessage, Z as resolveOptimizations, a as SETTING_SHAPE_REMEDY, b as mergeSettingsLayers, dt as listWorktrees, ft as locallyKnownUpstream, gt as repoRoot, i as SETTINGS_WITH_RESOLVE_TIME_FALLBACK, it as gitCommonDir, j as remoteAndroidSetting, n as PATH_SETTINGS, nt as dirtyFingerprintFiles, vt as resolveSourceCheckout, wt as makeTemporaryDirectory, y as iosSimSlimProfileSetting } from "./settings-oTSkkNrM.mjs";
|
|
5
|
+
import { c as isPackageResolvable, n as appProjectProblem, o as findProjectRoot$1, r as detectIsExpo } from "./project-Du91Ilvc.mjs";
|
|
6
|
+
import { _ as workspaceDerivedData, d as sharedBuildCache } from "./workspace-state-B8-aJ1_5.mjs";
|
|
7
|
+
import { i as inspectBudget, n as budgetLine, z as inspectWatchmanMemory } from "./budget-DjrURfQn.mjs";
|
|
8
|
+
import { C as diffFingerprintSources, D as fingerprintProject, h as listBuildLocks } from "./device-lease-D-hLqx1b.mjs";
|
|
9
|
+
import { n as listBuildSlots } from "./build-slots-rUk77xqh.mjs";
|
|
10
|
+
import { D as hostSystemImageArch, O as listAdbDevices, ft as parkedMaxSetting, o as androidHome, ot as POOL_SETTING_REMEDY } from "./android-B_NumVyQ.mjs";
|
|
11
|
+
import { A as hostMemoryPressureAdvice, c as iosRuntimeMatches, j as readHostMemoryPressure, p as listIosRuntimes, u as listAllIosSims, y as pickDefaultIosCreation } from "./ios-BaInn3sW.mjs";
|
|
12
|
+
import { C as podInstallCommand, D as projectCmakeLauncher, S as bundlerPin, f as ccacheEnabled, i as macosToolchain, m as detectXcodeMajor, n as androidToolchain, r as iosToolchain, t as androidRequirements } from "./toolchain-DkUflduf.mjs";
|
|
13
|
+
import { b as realIo, h as inspectBuildMachines, o as offloadCheck, u as simulatorRuntime } from "./client-BTY686R6.mjs";
|
|
14
|
+
import { n as inspectDeviceHostMachines } from "./machines-BIBUdhpj.mjs";
|
|
15
|
+
import { a as findChrome, t as CHROME_INSTALL_REMEDY } from "./chrome-BrcVWQyD.mjs";
|
|
16
|
+
import { i as liveOwnedDeviceCount } from "./device-capacity-BHwxNBlu.mjs";
|
|
17
|
+
import { d as androidPathRoomRemedy, l as androidPathRoom, n as apkOutputsDir, t as androidSdkRefusal, u as androidPathRoomMessage } from "./gradle-BsO1MdsH.mjs";
|
|
18
|
+
import { h as resolveRuntime, p as resolveDeviceType } from "./support-D4aYJniO.mjs";
|
|
19
|
+
import { f as resolveEasCliBin, i as checkEasAuth$1, l as ownerFromConfig, u as providerFromConfig } from "./remote-cache-C8-V13XN.mjs";
|
|
20
|
+
import { _ as easCliSupport, g as MIN_EAS_CLI_SIMULATOR_VERSION, s as readInstalledEasCliVersion, v as easCliUpgradeRemedy } from "./device-remote-D5WVWqOq.mjs";
|
|
21
|
+
import { n as inspectStimVersions, t as compareStimVersions } from "./stim-installations-QMEI32v1.mjs";
|
|
22
|
+
import { n as simslimIsOnPath, r as MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION } from "./simslim-B8-7AoTI.mjs";
|
|
23
|
+
import { r as resolveAndroidCompilerCache, t as readAndroidCasToolchain } from "./android-cas-8U4DPqeR.mjs";
|
|
24
|
+
import { r as maintenanceStatus, t as maintenanceLine } from "./status-DlKvVJBE.mjs";
|
|
25
|
+
import { n as recordDoctorRun } from "./guide-status-CjEZMAD4.mjs";
|
|
26
|
+
import { n as hasInstalledDependencies, r as installedNpmTreeIsValid, t as dependencyState } from "./dependency-state-B6cMXZab.mjs";
|
|
22
27
|
import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
|
|
23
|
-
import {
|
|
28
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
24
29
|
import { existsSync as existsSync$1, lstatSync as lstatSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, renameSync as renameSync$1, rmSync as rmSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
25
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "path";
|
|
26
|
-
import { readJsonObject, settingDefinition } from "@stim-cli/core/state";
|
|
27
|
-
import { basename as basename$1, dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "node:path";
|
|
28
30
|
import { homedir } from "os";
|
|
31
|
+
import { dirname as dirname$1, isAbsolute as isAbsolute$1, join as join$1, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "path";
|
|
32
|
+
import { InvalidArgumentError } from "commander";
|
|
33
|
+
import { isJsonObject, maintenanceNdjsonFile, readHostedAppMetadata, readHostedSessions, readJsonObject, readStats, settingDefinition } from "@stim-cli/core/state";
|
|
29
34
|
import chalk from "chalk";
|
|
30
35
|
import * as expoFingerprint from "@expo/fingerprint";
|
|
31
36
|
//#region src/diagnostics/sandbox.ts
|
|
@@ -48,8 +53,8 @@ function detectHarness(env = process.env) {
|
|
|
48
53
|
function expandHome(value, home) {
|
|
49
54
|
const v = value.trim();
|
|
50
55
|
if (v === "~" || v === "$HOME") return home;
|
|
51
|
-
if (v.startsWith("~/")) return join(home, v.slice(2));
|
|
52
|
-
if (v.startsWith("$HOME/")) return join(home, v.slice(6));
|
|
56
|
+
if (v.startsWith("~/")) return join$1(home, v.slice(2));
|
|
57
|
+
if (v.startsWith("$HOME/")) return join$1(home, v.slice(6));
|
|
53
58
|
return v;
|
|
54
59
|
}
|
|
55
60
|
/**
|
|
@@ -59,7 +64,7 @@ function expandHome(value, home) {
|
|
|
59
64
|
*/
|
|
60
65
|
function sandboxBlocksStimHome(stimHome, home = homedir()) {
|
|
61
66
|
const dir = expandHome(stimHome, home);
|
|
62
|
-
const probe = join(dir, `.probe-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
|
67
|
+
const probe = join$1(dir, `.probe-${process.pid}-${Math.random().toString(36).slice(2)}`);
|
|
63
68
|
try {
|
|
64
69
|
mkdirSync$1(dir, { recursive: true });
|
|
65
70
|
writeFileSync$1(probe, "");
|
|
@@ -72,14 +77,14 @@ function sandboxBlocksStimHome(stimHome, home = homedir()) {
|
|
|
72
77
|
}
|
|
73
78
|
/** Where a per-user, gitignored Claude Code settings file belongs for this project. */
|
|
74
79
|
function claudeLocalSettingsPath(root) {
|
|
75
|
-
return join(root, ".claude", "settings.local.json");
|
|
80
|
+
return join$1(root, ".claude", "settings.local.json");
|
|
76
81
|
}
|
|
77
82
|
/** Every settings file that may already carry the allowance, most local first. */
|
|
78
83
|
function allowanceSearchPaths(settingsRoot, home = homedir()) {
|
|
79
84
|
return [
|
|
80
85
|
claudeLocalSettingsPath(settingsRoot),
|
|
81
|
-
join(settingsRoot, ".claude", "settings.json"),
|
|
82
|
-
join(home, ".claude", "settings.json")
|
|
86
|
+
join$1(settingsRoot, ".claude", "settings.json"),
|
|
87
|
+
join$1(home, ".claude", "settings.json")
|
|
83
88
|
];
|
|
84
89
|
}
|
|
85
90
|
function isPlainObject(value) {
|
|
@@ -119,7 +124,7 @@ function nested(source, ...keys) {
|
|
|
119
124
|
function covers(entry, target, home) {
|
|
120
125
|
const posix = (value) => {
|
|
121
126
|
const expanded = expandHome(value, home);
|
|
122
|
-
return sep === "/" ? expanded : expanded.replaceAll(sep, "/");
|
|
127
|
+
return sep$1 === "/" ? expanded : expanded.replaceAll(sep$1, "/");
|
|
123
128
|
};
|
|
124
129
|
const e = posix(entry).replace(/\/+\*+$/, "").replace(/\/+$/, "");
|
|
125
130
|
const t = posix(target).replace(/\/+$/, "");
|
|
@@ -191,7 +196,7 @@ function applyClaudeAllowance(path, allowance) {
|
|
|
191
196
|
status: "refused",
|
|
192
197
|
reason: `${path} holds a "${blocker}" that is not an object, so Stim cannot merge into it without discarding that value.`
|
|
193
198
|
};
|
|
194
|
-
mkdirSync$1(dirname(path), { recursive: true });
|
|
199
|
+
mkdirSync$1(dirname$1(path), { recursive: true });
|
|
195
200
|
const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
196
201
|
writeFileSync$1(tmp, `${JSON.stringify(withAllowance(existing, allowance), null, 2)}\n`);
|
|
197
202
|
try {
|
|
@@ -252,14 +257,14 @@ function checkStorageLayout(projectRoot, { platform, host = process.platform, de
|
|
|
252
257
|
const source = resolveSourceCheckout(target);
|
|
253
258
|
check("Worktree copy", ["path" in source ? source.path : target, target], "Keep the source checkout and linked worktree on the same volume to share file blocks when warming.");
|
|
254
259
|
const cache = sharedBuildCache();
|
|
255
|
-
check("Cached app/APK staging", [cache, stagingRoot(join
|
|
260
|
+
check("Cached app/APK staging", [cache, stagingRoot(join(cache, "artifact.app"))], temporaryFix);
|
|
256
261
|
const cacheFix = "Place STIM_BUILD_CACHE / machine caches.buildCache on the build-output volume, or accept the full-copy cost of keeping the cache on a separate volume.";
|
|
257
|
-
if ((platform === "ios" || platform !== "android" && existsSync(join
|
|
258
|
-
const output = join
|
|
262
|
+
if ((platform === "ios" || platform !== "android" && existsSync(join(projectRoot, "ios"))) && host === "darwin") {
|
|
263
|
+
const output = join(workspaceDerivedData(projectRoot), "Build", "Products");
|
|
259
264
|
check("iOS build-cache storage", [output, cache], cacheFix);
|
|
260
|
-
check("iOS device app staging", [output, stagingRoot(join
|
|
265
|
+
check("iOS device app staging", [output, stagingRoot(join(output, "artifact.app"))], temporaryFix);
|
|
261
266
|
}
|
|
262
|
-
if (platform === "android" || platform !== "ios" && existsSync(join
|
|
267
|
+
if (platform === "android" || platform !== "ios" && existsSync(join(projectRoot, "android"))) check("Android build-cache storage", [apkOutputsDir(projectRoot), cache], cacheFix);
|
|
263
268
|
} catch (error) {
|
|
264
269
|
findings.push({
|
|
265
270
|
level: "cost",
|
|
@@ -343,23 +348,23 @@ function parseIosDebugArchitectures(output) {
|
|
|
343
348
|
};
|
|
344
349
|
}
|
|
345
350
|
function inspectIosDebugArchitectures(projectRoot) {
|
|
346
|
-
const iosRoot = join
|
|
351
|
+
const iosRoot = join(projectRoot, "ios");
|
|
347
352
|
if (!existsSync(iosRoot)) return [];
|
|
348
353
|
const findings = [];
|
|
349
354
|
const unknown = [];
|
|
350
355
|
let projects;
|
|
351
356
|
try {
|
|
352
|
-
projects = readdirSync(iosRoot).filter((name) => name.endsWith(".xcodeproj")).toSorted().map((name) => join
|
|
357
|
+
projects = readdirSync(iosRoot).filter((name) => name.endsWith(".xcodeproj")).toSorted().map((name) => join(iosRoot, name));
|
|
353
358
|
} catch {
|
|
354
359
|
projects = [];
|
|
355
360
|
}
|
|
356
361
|
if (!projects.length) unknown.push("app project");
|
|
357
|
-
const pods = join
|
|
362
|
+
const pods = join(iosRoot, "Pods", "Pods.xcodeproj");
|
|
358
363
|
if (existsSync(pods)) projects.push(pods);
|
|
359
|
-
else if (existsSync(join
|
|
364
|
+
else if (existsSync(join(iosRoot, "Podfile"))) unknown.push("Pods project (not generated)");
|
|
360
365
|
const deadline = Date.now() + 6e4;
|
|
361
366
|
for (const project of projects) {
|
|
362
|
-
const label = relative
|
|
367
|
+
const label = relative(projectRoot, project);
|
|
363
368
|
const timeoutMs = Math.min(3e4, deadline - Date.now());
|
|
364
369
|
if (timeoutMs <= 0) {
|
|
365
370
|
unknown.push(label);
|
|
@@ -421,13 +426,13 @@ function children(path) {
|
|
|
421
426
|
}
|
|
422
427
|
}
|
|
423
428
|
function moduleRoots(root) {
|
|
424
|
-
const modules = [join
|
|
425
|
-
const dependencies = join
|
|
429
|
+
const modules = [join(root, "android", "app")];
|
|
430
|
+
const dependencies = join(root, "node_modules");
|
|
426
431
|
for (const name of children(dependencies)) {
|
|
427
432
|
if (name.startsWith(".")) continue;
|
|
428
|
-
const entry = join
|
|
429
|
-
const packages = name.startsWith("@") ? children(entry).map((child) => join
|
|
430
|
-
modules.push(...packages.map((pkg) => join
|
|
433
|
+
const entry = join(dependencies, name);
|
|
434
|
+
const packages = name.startsWith("@") ? children(entry).map((child) => join(entry, child)) : [entry];
|
|
435
|
+
modules.push(...packages.map((pkg) => join(pkg, "android")));
|
|
431
436
|
}
|
|
432
437
|
return modules;
|
|
433
438
|
}
|
|
@@ -435,7 +440,7 @@ function cacheFiles(base, depth = 0) {
|
|
|
435
440
|
const files = [];
|
|
436
441
|
for (const name of children(base)) {
|
|
437
442
|
if (depth === 0 && /^stim-[a-f0-9]{16}$/.test(name)) continue;
|
|
438
|
-
const path = join
|
|
443
|
+
const path = join(base, name);
|
|
439
444
|
const entry = lstatSync(path);
|
|
440
445
|
if (entry.isSymbolicLink()) continue;
|
|
441
446
|
if (name === "CMakeCache.txt" && entry.isFile()) files.push(path);
|
|
@@ -444,8 +449,8 @@ function cacheFiles(base, depth = 0) {
|
|
|
444
449
|
return files;
|
|
445
450
|
}
|
|
446
451
|
function readCxxLauncherStates(root) {
|
|
447
|
-
return moduleRoots(root).flatMap((module) => cacheFiles(join
|
|
448
|
-
path: relative
|
|
452
|
+
return moduleRoots(root).flatMap((module) => cacheFiles(join(module, ".cxx")).map((path) => ({
|
|
453
|
+
path: relative(root, path),
|
|
449
454
|
launcher: parseCmakeCacheLauncher(readFileSync(path, "utf8"))
|
|
450
455
|
})));
|
|
451
456
|
}
|
|
@@ -455,13 +460,13 @@ function declaredLauncher(module) {
|
|
|
455
460
|
"build.gradle.kts",
|
|
456
461
|
"CMakeLists.txt"
|
|
457
462
|
].some((name) => {
|
|
458
|
-
const path = join
|
|
463
|
+
const path = join(module, name);
|
|
459
464
|
return existsSync(path) && Boolean(projectCmakeLauncher(readFileSync(path, "utf8")));
|
|
460
465
|
});
|
|
461
466
|
}
|
|
462
467
|
function contained(root, path) {
|
|
463
|
-
const rel = relative
|
|
464
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep
|
|
468
|
+
const rel = relative(root, path);
|
|
469
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
|
|
465
470
|
}
|
|
466
471
|
function selectedCompilerCache(root) {
|
|
467
472
|
try {
|
|
@@ -485,24 +490,24 @@ function repairCxxLauncherState(root) {
|
|
|
485
490
|
};
|
|
486
491
|
if (selectedCompilerCache(root) !== "ccache") return result;
|
|
487
492
|
if (!getExecutor().findExecutable("ccache")) return result;
|
|
488
|
-
const appOverrides = declaredLauncher(join
|
|
493
|
+
const appOverrides = declaredLauncher(join(root, "android", "app"));
|
|
489
494
|
const targets = readCxxLauncherStates(root).filter(({ launcher }) => {
|
|
490
495
|
if (!launcher) return true;
|
|
491
496
|
const command = launcher.split(";")[0]?.trim();
|
|
492
|
-
return Boolean(command && isAbsolute
|
|
497
|
+
return Boolean(command && isAbsolute(command) && basename(command) === "ccache" && !existsSync(command));
|
|
493
498
|
});
|
|
494
499
|
for (const state of targets) {
|
|
495
|
-
const target = dirname
|
|
496
|
-
const label = relative
|
|
500
|
+
const target = dirname(join(root, state.path));
|
|
501
|
+
const label = relative(root, target);
|
|
497
502
|
try {
|
|
498
503
|
let cxx = target;
|
|
499
|
-
while (contained(root, cxx) && basename
|
|
500
|
-
if (basename
|
|
501
|
-
if (appOverrides || declaredLauncher(dirname
|
|
504
|
+
while (contained(root, cxx) && basename(cxx) !== ".cxx") cxx = dirname(cxx);
|
|
505
|
+
if (basename(cxx) !== ".cxx" || target === cxx) throw new Error("unrecognized generated CMake layout");
|
|
506
|
+
if (appOverrides || declaredLauncher(dirname(cxx))) throw new Error("project configures its own compiler launcher");
|
|
502
507
|
const canonicalTarget = realpathSync(target);
|
|
503
508
|
if (!contained(canonicalRoot, canonicalTarget)) throw new Error("generated directory resolves outside this checkout");
|
|
504
|
-
if (realpathSync(cxx) !== join
|
|
505
|
-
const gitPath = relative
|
|
509
|
+
if (realpathSync(cxx) !== join(realpathSync(dirname(cxx)), ".cxx")) throw new Error(".cxx is a symbolic link");
|
|
510
|
+
const gitPath = relative(canonicalRoot, canonicalTarget);
|
|
506
511
|
if (getExecutor().runFile("git", [
|
|
507
512
|
"ls-files",
|
|
508
513
|
"-z",
|
|
@@ -643,7 +648,7 @@ function compilerCacheFinding({ fallback, optimizations, file }) {
|
|
|
643
648
|
function missingPath(value, projectRoot, exists, trim = false) {
|
|
644
649
|
const opened = trim ? value.trim() : value;
|
|
645
650
|
if (opened.trim() === "") return null;
|
|
646
|
-
const path = isAbsolute
|
|
651
|
+
const path = isAbsolute(opened) ? opened : resolve(projectRoot, opened);
|
|
647
652
|
if (exists(path)) return null;
|
|
648
653
|
return opened === opened.trim() ? path : JSON.stringify(path);
|
|
649
654
|
}
|
|
@@ -657,15 +662,42 @@ function finding(level, title, detail, fix) {
|
|
|
657
662
|
fix
|
|
658
663
|
};
|
|
659
664
|
}
|
|
665
|
+
function checkOffloadCandidate(placements, machines, peers, now) {
|
|
666
|
+
if (machines.length || !peers.some((peer) => isJsonObject(peer) && peer.OS === "macOS" && peer.Online === true)) return null;
|
|
667
|
+
const cold = placements.filter((placement) => {
|
|
668
|
+
const age = now - Date.parse(placement.at);
|
|
669
|
+
return placement.decision === "here" && !placement.failed && (placement.buildMs ?? 0) > 0 && age >= 0 && age <= 6048e5;
|
|
670
|
+
});
|
|
671
|
+
if (cold.length < 3) return null;
|
|
672
|
+
const average = cold.reduce((total, placement) => total + placement.buildMs, 0) / cold.length;
|
|
673
|
+
if (average <= 18e4) return null;
|
|
674
|
+
return {
|
|
675
|
+
code: "offload-candidate",
|
|
676
|
+
...finding("note", "Builds could run on another Mac", `Cold builds averaged ~${Math.round(average / 6e4)} min over ${cold.length} builds this week.`, "In Stim Desktop, open Settings > Build machines > Add.")
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function readOffloadCandidate(tailnetStatus, now, host) {
|
|
680
|
+
if (host !== "darwin") return null;
|
|
681
|
+
try {
|
|
682
|
+
const entries = loadConfig$1()?.offload?.machines;
|
|
683
|
+
const machines = Array.isArray(entries) ? entries.filter((entry) => typeof entry === "string") : [];
|
|
684
|
+
const placements = readStats().record?.placements ?? [];
|
|
685
|
+
if (machines.length || placements.length < 3) return null;
|
|
686
|
+
const status = tailnetStatus();
|
|
687
|
+
return checkOffloadCandidate(placements, machines, isJsonObject(status) && isJsonObject(status.Peer) ? Object.values(status.Peer) : [], now);
|
|
688
|
+
} catch {
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
660
692
|
function mainCheckoutProjectRoot(projectRoot) {
|
|
661
693
|
const currentRepoRoot = repoRoot(projectRoot);
|
|
662
694
|
if (!currentRepoRoot) return projectRoot;
|
|
663
695
|
try {
|
|
664
696
|
const source = resolveSourceCheckout(currentRepoRoot);
|
|
665
697
|
if ("refusal" in source) return projectRoot;
|
|
666
|
-
const projectRel = relative(currentRepoRoot, realpathSync$1(projectRoot));
|
|
698
|
+
const projectRel = relative$1(currentRepoRoot, realpathSync$1(projectRoot));
|
|
667
699
|
if (projectRel.startsWith("..")) return projectRoot;
|
|
668
|
-
return resolve(source.path, projectRel);
|
|
700
|
+
return resolve$1(source.path, projectRel);
|
|
669
701
|
} catch {
|
|
670
702
|
return projectRoot;
|
|
671
703
|
}
|
|
@@ -684,11 +716,11 @@ function brokenPodLinks(podsRoot) {
|
|
|
684
716
|
}
|
|
685
717
|
}
|
|
686
718
|
function hasIosWarmOutput(root) {
|
|
687
|
-
if (existsSync$1(join(root, "ios", "build"))) return true;
|
|
719
|
+
if (existsSync$1(join$1(root, "ios", "build"))) return true;
|
|
688
720
|
const derivedData = workspaceDerivedData(root);
|
|
689
|
-
if (existsSync$1(join(derivedData, "Build", "Products"))) return true;
|
|
721
|
+
if (existsSync$1(join$1(derivedData, "Build", "Products"))) return true;
|
|
690
722
|
try {
|
|
691
|
-
return readdirSync$1(derivedData).some((entry) => /^scheme-[a-f0-9]{64}$/.test(entry) && existsSync$1(join(derivedData, entry, "Build", "Products")));
|
|
723
|
+
return readdirSync$1(derivedData).some((entry) => /^scheme-[a-f0-9]{64}$/.test(entry) && existsSync$1(join$1(derivedData, entry, "Build", "Products")));
|
|
692
724
|
} catch {
|
|
693
725
|
return false;
|
|
694
726
|
}
|
|
@@ -717,8 +749,8 @@ function mainOperation(root) {
|
|
|
717
749
|
"--git-dir"
|
|
718
750
|
])?.trim();
|
|
719
751
|
if (!gitDir) return null;
|
|
720
|
-
if (existsSync$1(join(gitDir, "rebase-merge")) || existsSync$1(join(gitDir, "rebase-apply"))) return "rebase";
|
|
721
|
-
return existsSync$1(join(gitDir, "MERGE_HEAD")) ? "merge" : null;
|
|
752
|
+
if (existsSync$1(join$1(gitDir, "rebase-merge")) || existsSync$1(join$1(gitDir, "rebase-apply"))) return "rebase";
|
|
753
|
+
return existsSync$1(join$1(gitDir, "MERGE_HEAD")) ? "merge" : null;
|
|
722
754
|
}
|
|
723
755
|
function dirtyTrackedPaths(root) {
|
|
724
756
|
return (getExecutor().runFileQuiet("git", [
|
|
@@ -782,9 +814,9 @@ function checkMainCheckout(projectRoot, { npmTreeValid, brokenPods = void 0, ups
|
|
|
782
814
|
if ((npmTreeValid === void 0 ? installedNpmTreeIsValid(dependencies.root) : npmTreeValid) === false) findings.push(finding("cost", "The source checkout dependency tree is stale", `npm reports that ${dependencies.root}/node_modules does not match the project dependency graph. Copying it makes each worktree start from the same invalid state.`, `Run \`${installCommand}\` before creating native worktrees, or let \`stim worktree warm --refresh\` run it from a linked worktree.`));
|
|
783
815
|
}
|
|
784
816
|
}
|
|
785
|
-
const podfileLock = join(mainRoot, "ios", "Podfile.lock");
|
|
786
|
-
const podManifest = join(mainRoot, "ios", "Pods", "Manifest.lock");
|
|
787
|
-
const podsRoot = join(mainRoot, "ios", "Pods");
|
|
817
|
+
const podfileLock = join$1(mainRoot, "ios", "Podfile.lock");
|
|
818
|
+
const podManifest = join$1(mainRoot, "ios", "Pods", "Manifest.lock");
|
|
819
|
+
const podsRoot = join$1(mainRoot, "ios", "Pods");
|
|
788
820
|
if (localIos && existsSync$1(podfileLock)) {
|
|
789
821
|
let podsState = null;
|
|
790
822
|
if (!existsSync$1(podManifest)) podsState = "missing";
|
|
@@ -794,18 +826,18 @@ function checkMainCheckout(projectRoot, { npmTreeValid, brokenPods = void 0, ups
|
|
|
794
826
|
podsState = "stale";
|
|
795
827
|
}
|
|
796
828
|
if (podsState) {
|
|
797
|
-
const iosRoot = join(mainRoot, "ios");
|
|
829
|
+
const iosRoot = join$1(mainRoot, "ios");
|
|
798
830
|
const podCommand = `cd ${quotedPath(iosRoot)} && ${podInstallCommand(mainRoot)}`;
|
|
799
831
|
findings.push(finding("cost", `The source checkout CocoaPods state is ${podsState}`, `ios/Pods cannot be reused safely because its Manifest.lock ${podsState === "missing" ? "is absent" : "does not match ios/Podfile.lock"}.`, `Run \`${podCommand}\` before creating native worktrees, or let \`stim worktree warm --refresh\` run it from a linked worktree.`));
|
|
800
832
|
}
|
|
801
833
|
const broken = brokenPods === void 0 && existsSync$1(podsRoot) ? brokenPodLinks(podsRoot) : brokenPods || [];
|
|
802
834
|
if (broken.length) {
|
|
803
|
-
const iosRoot = join(mainRoot, "ios");
|
|
835
|
+
const iosRoot = join$1(mainRoot, "ios");
|
|
804
836
|
const podCommand = `cd ${quotedPath(iosRoot)} && ${podInstallCommand(mainRoot, "--clean-install")}`;
|
|
805
837
|
findings.push(finding("cost", "The source checkout CocoaPods state has broken links", `${broken.length} symlink${broken.length === 1 ? "" : "s"} under ios/Pods point to missing files. Worktrees copy these broken links and can fail during compilation. First: ${broken[0]}.`, `Run \`${podCommand}\` before creating native worktrees.`));
|
|
806
838
|
}
|
|
807
839
|
}
|
|
808
|
-
const coldPlatforms = [localIos && existsSync$1(join(mainRoot, "ios")) && !hasIosWarmOutput(mainRoot) ? "iOS" : null, platform !== "ios" && existsSync$1(join(mainRoot, "android")) && !existsSync$1(join(mainRoot, "android", "build")) && !existsSync$1(join(mainRoot, "android", "app", "build")) ? "Android" : null].filter((coldPlatform) => coldPlatform !== null);
|
|
840
|
+
const coldPlatforms = [localIos && existsSync$1(join$1(mainRoot, "ios")) && !hasIosWarmOutput(mainRoot) ? "iOS" : null, platform !== "ios" && existsSync$1(join$1(mainRoot, "android")) && !existsSync$1(join$1(mainRoot, "android", "build")) && !existsSync$1(join$1(mainRoot, "android", "app", "build")) ? "Android" : null].filter((coldPlatform) => coldPlatform !== null);
|
|
809
841
|
if (coldPlatforms.length) findings.push(finding("note", `The source checkout has no ${coldPlatforms.join(" or ")} warm build output`, "The shared Stim artifact or compilation cache can still be warm. Building the source checkout once gives later native worktrees the strongest warm starting point.", `When more native worktrees are expected, run \`stim start\`, \`stim ${coldPlatforms[0] === "iOS" ? "ios" : "android"}\`, and \`stim stop\` from ${mainRoot}.`));
|
|
810
842
|
if (linkedWorktrees === void 0 ? hasLinkedWorktree(projectRoot) : linkedWorktrees) findings.push(...seedFindings(mainRoot, upstream === void 0 ? locallyKnownUpstream(mainRoot) : upstream));
|
|
811
843
|
return findings;
|
|
@@ -861,7 +893,7 @@ function checkCcacheInstalled(onPath) {
|
|
|
861
893
|
}
|
|
862
894
|
function launcherPath(launcher) {
|
|
863
895
|
const command = launcher?.split(";")[0]?.trim();
|
|
864
|
-
return command && isAbsolute(command) ? command : null;
|
|
896
|
+
return command && isAbsolute$1(command) ? command : null;
|
|
865
897
|
}
|
|
866
898
|
function checkCxxCompilerLauncher({ states, ccacheOnPath, launcherExists = existsSync$1 }) {
|
|
867
899
|
const missing = states.map((state) => ({
|
|
@@ -933,7 +965,7 @@ function checkEasBuildDownload({ easJson = false, remoteEas = false, easCliResol
|
|
|
933
965
|
return finding("cost", easCli.version ? `eas-cli ${easCli.version} cannot download EAS builds for --eas-profile` : "The eas-cli version could not be read for --eas-profile", `\`stim ios --eas-profile\` and \`stim android --eas-profile\` download a finished EAS development build with \`eas build:download --build-id\`, which needs eas-cli ${MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION} or later. Older versions refuse with STIM_EAS_UNAVAILABLE before any download.`, `${easCliUpgradeRemedy(MIN_EAS_CLI_BUILD_DOWNLOAD_VERSION)}.`);
|
|
934
966
|
}
|
|
935
967
|
function projectEasBuildDownloadFinding(projectRoot, remoteBackends, lookupEasCli) {
|
|
936
|
-
const easJson = existsSync$1(join(projectRoot, "eas.json"));
|
|
968
|
+
const easJson = existsSync$1(join$1(projectRoot, "eas.json"));
|
|
937
969
|
return checkEasBuildDownload({
|
|
938
970
|
easJson,
|
|
939
971
|
remoteEas: remoteBackends.includes("eas"),
|
|
@@ -953,7 +985,7 @@ function checkIosHost(platform, host) {
|
|
|
953
985
|
}
|
|
954
986
|
function checkXcodeEnvLineEndings(projectRoot, platform, host) {
|
|
955
987
|
if (platform === "android" || host !== "win32") return null;
|
|
956
|
-
const xcodeEnv = join(projectRoot, "ios", ".xcode.env");
|
|
988
|
+
const xcodeEnv = join$1(projectRoot, "ios", ".xcode.env");
|
|
957
989
|
if (!existsSync$1(xcodeEnv)) return null;
|
|
958
990
|
let content;
|
|
959
991
|
try {
|
|
@@ -964,10 +996,14 @@ function checkXcodeEnvLineEndings(projectRoot, platform, host) {
|
|
|
964
996
|
if (!content.includes("\r")) return null;
|
|
965
997
|
return finding("cost", "ios/.xcode.env has CRLF line endings", "An EAS build uploads the working-tree bytes of ios/.xcode.env, and Xcode sources that file with sh on the build worker, where each carriage return becomes part of the line and the build fails with `: command not found`. On Windows the usual cause is core.autocrlf=true rewriting the file at checkout.", "Run `git config core.autocrlf input` then `git checkout -- ios/.xcode.env`, or add `ios/.xcode.env text eol=lf` to .gitattributes and check the file out again.");
|
|
966
998
|
}
|
|
967
|
-
function
|
|
999
|
+
function configuredRemoteBackends(projectSettings, platform) {
|
|
1000
|
+
const iosTarget = remoteIosSetting(projectSettings);
|
|
1001
|
+
return [.../* @__PURE__ */ new Set([...platform !== "android" ? [iosTarget?.kind === "backend" ? iosTarget.backend : null] : [], ...platform !== "ios" ? [remoteAndroidSetting(projectSettings)] : []])].filter((backend) => backend !== null);
|
|
1002
|
+
}
|
|
1003
|
+
function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null, easAuth = checkEasAuth$1, concurrency = getConcurrencyLimits, liveDevices = null, activeBuilds = null, remoteEnv = process.env, lookupAgentDevice = null, lookupEasCli = null, lookupSimSlim = null, memoryPressure = readHostMemoryPressure, lookupCcache = null, lookupChrome, tailnetStatus = realIo.status, now = Date.now, platform, host = process.platform } = {}) {
|
|
968
1004
|
const localIos = platform !== "android" && host === "darwin";
|
|
969
1005
|
const read = (rel) => {
|
|
970
|
-
const p = join(projectRoot, rel);
|
|
1006
|
+
const p = join$1(projectRoot, rel);
|
|
971
1007
|
if (!existsSync$1(p)) return null;
|
|
972
1008
|
try {
|
|
973
1009
|
return readFile(p, "utf-8");
|
|
@@ -983,15 +1019,15 @@ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null,
|
|
|
983
1019
|
});
|
|
984
1020
|
if (machineSettings.corrupt) return [machineSettings.corrupt];
|
|
985
1021
|
const projectSettings = machineSettings.settings;
|
|
986
|
-
const pkg = readJsonObject(join(projectRoot, "package.json"));
|
|
987
|
-
const appConfig = readJsonObject(join(projectRoot, "app.json"));
|
|
1022
|
+
const pkg = readJsonObject(join$1(projectRoot, "package.json"));
|
|
1023
|
+
const appConfig = readJsonObject(join$1(projectRoot, "app.json"));
|
|
988
1024
|
const dynamicConfig = appConfig ? null : [
|
|
989
1025
|
"app.config.ts",
|
|
990
1026
|
"app.config.js",
|
|
991
1027
|
"app.config.mjs"
|
|
992
|
-
].find((f) => existsSync$1(join(projectRoot, f))) || null;
|
|
993
|
-
const podfileProperties = readJsonObject(join(projectRoot, "ios", "Podfile.properties.json"));
|
|
994
|
-
const podfile = read(join("ios", "Podfile"));
|
|
1028
|
+
].find((f) => existsSync$1(join$1(projectRoot, f))) || null;
|
|
1029
|
+
const podfileProperties = readJsonObject(join$1(projectRoot, "ios", "Podfile.properties.json"));
|
|
1030
|
+
const podfile = read(join$1("ios", "Podfile"));
|
|
995
1031
|
const metroConfig = read("metro.config.js") ?? read("metro.config.cjs");
|
|
996
1032
|
const isExpo = detectIsExpo(projectRoot);
|
|
997
1033
|
const expoRange = (pkg?.dependencies)?.expo || "";
|
|
@@ -1040,7 +1076,7 @@ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null,
|
|
|
1040
1076
|
profileError: simslimProfileError,
|
|
1041
1077
|
onPath: simslimProfile ? lookupSimSlim ? lookupSimSlim() : simslimIsOnPath() : false
|
|
1042
1078
|
});
|
|
1043
|
-
const remoteBackends =
|
|
1079
|
+
const remoteBackends = configuredRemoteBackends(projectSettings, platform);
|
|
1044
1080
|
const daemonInEnv = Boolean(remoteEnv.AGENT_DEVICE_DAEMON_BASE_URL?.trim() && remoteEnv.AGENT_DEVICE_DAEMON_AUTH_TOKEN?.trim());
|
|
1045
1081
|
const agentDeviceOnPath = remoteBackends.length ? lookupAgentDevice ? lookupAgentDevice() : agentDeviceIsOnPath() : false;
|
|
1046
1082
|
const easCliResolvable = remoteBackends.includes("eas") ? lookupEasCli ? lookupEasCli() : Boolean(resolveEasCliBin(projectRoot)) : false;
|
|
@@ -1080,6 +1116,7 @@ function runDoctor(projectRoot, { readFile = readFileSync$1, xcodeMajor = null,
|
|
|
1080
1116
|
easFinding,
|
|
1081
1117
|
easBuildDownloadFinding,
|
|
1082
1118
|
concurrencyFinding,
|
|
1119
|
+
readOffloadCandidate(tailnetStatus, now(), host),
|
|
1083
1120
|
memoryAdvice ? finding("cost", "Host memory pressure can stall the iOS simulator", memoryAdvice, "Free host memory, then retry. Run `stim guide lifecycle simslim` for the optional memory reduction setup.") : null,
|
|
1084
1121
|
simslimFinding,
|
|
1085
1122
|
...remoteFindings,
|
|
@@ -1105,13 +1142,13 @@ function checkAndroidPathRoom(projectRoot, platform, host, hostArch = process.ar
|
|
|
1105
1142
|
};
|
|
1106
1143
|
}
|
|
1107
1144
|
function checkAndroidSdk(projectRoot, platform) {
|
|
1108
|
-
const androidDir = join(projectRoot, "android");
|
|
1145
|
+
const androidDir = join$1(projectRoot, "android");
|
|
1109
1146
|
if (platform === "ios" || platform !== "android" && !existsSync$1(androidDir)) return null;
|
|
1110
1147
|
const sdkPath = androidHome();
|
|
1111
1148
|
const refusal = androidSdkRefusal({
|
|
1112
1149
|
sdkPath,
|
|
1113
1150
|
sdkExists: existsSync$1(sdkPath),
|
|
1114
|
-
hasLocalProperties: existsSync$1(join(androidDir, "local.properties"))
|
|
1151
|
+
hasLocalProperties: existsSync$1(join$1(androidDir, "local.properties"))
|
|
1115
1152
|
});
|
|
1116
1153
|
if (!refusal) return null;
|
|
1117
1154
|
return {
|
|
@@ -1120,7 +1157,7 @@ function checkAndroidSdk(projectRoot, platform) {
|
|
|
1120
1157
|
};
|
|
1121
1158
|
}
|
|
1122
1159
|
function androidCcacheFindings(projectRoot, platform, lookupCcache) {
|
|
1123
|
-
if (platform !== "android" && !existsSync$1(join(projectRoot, "android"))) return [];
|
|
1160
|
+
if (platform !== "android" && !existsSync$1(join$1(projectRoot, "android"))) return [];
|
|
1124
1161
|
const onPath = lookupCcache ? lookupCcache() : ccacheIsOnPath();
|
|
1125
1162
|
let cxx;
|
|
1126
1163
|
try {
|
|
@@ -1183,7 +1220,7 @@ function checkFingerprintParity({ projectHash, worktreeHash, changed = [], dirty
|
|
|
1183
1220
|
}
|
|
1184
1221
|
function gitMetadataAt(path) {
|
|
1185
1222
|
try {
|
|
1186
|
-
const git = lstatSync$1(join(path, ".git"));
|
|
1223
|
+
const git = lstatSync$1(join$1(path, ".git"));
|
|
1187
1224
|
return git.isFile() || git.isDirectory();
|
|
1188
1225
|
} catch {
|
|
1189
1226
|
return false;
|
|
@@ -1198,14 +1235,14 @@ function listDirectory(dir) {
|
|
|
1198
1235
|
}
|
|
1199
1236
|
function hasLinkedPackageWithGit(projectRoot) {
|
|
1200
1237
|
const root = repoRoot(projectRoot) ?? projectRoot;
|
|
1201
|
-
for (let dir = projectRoot;; dir = dirname(dir)) {
|
|
1202
|
-
if (linkedPackageWithGitIn(join(dir, "node_modules"))) return true;
|
|
1203
|
-
if (dir === root || dirname(dir) === dir || relative(root, dirname(dir)).startsWith("..")) return false;
|
|
1238
|
+
for (let dir = projectRoot;; dir = dirname$1(dir)) {
|
|
1239
|
+
if (linkedPackageWithGitIn(join$1(dir, "node_modules"))) return true;
|
|
1240
|
+
if (dir === root || dirname$1(dir) === dir || relative$1(root, dirname$1(dir)).startsWith("..")) return false;
|
|
1204
1241
|
}
|
|
1205
1242
|
}
|
|
1206
1243
|
function linkedPackageWithGitIn(nodeModules) {
|
|
1207
|
-
return listDirectory(nodeModules).filter((entry) => !entry.startsWith(".")).flatMap((entry) => entry.startsWith("@") ? listDirectory(join(nodeModules, entry)).map((child) => join(entry, child)) : [entry]).some((name) => {
|
|
1208
|
-
const root = join(nodeModules, name);
|
|
1244
|
+
return listDirectory(nodeModules).filter((entry) => !entry.startsWith(".")).flatMap((entry) => entry.startsWith("@") ? listDirectory(join$1(nodeModules, entry)).map((child) => join$1(entry, child)) : [entry]).some((name) => {
|
|
1245
|
+
const root = join$1(nodeModules, name);
|
|
1209
1246
|
try {
|
|
1210
1247
|
return lstatSync$1(root).isSymbolicLink() && gitMetadataAt(root);
|
|
1211
1248
|
} catch {
|
|
@@ -1257,14 +1294,14 @@ async function detectFingerprintParity(projectRoot, { createFingerprint = expoFi
|
|
|
1257
1294
|
"--git-dir"
|
|
1258
1295
|
], { timeoutMs: 1e4 }) == null) return null;
|
|
1259
1296
|
if (hasInstalledDependencies(projectRoot)) return null;
|
|
1260
|
-
const platform = selectedPlatform ?? (existsSync$1(join(projectRoot, "ios")) ? "ios" : existsSync$1(join(projectRoot, "android")) ? "android" : void 0);
|
|
1297
|
+
const platform = selectedPlatform ?? (existsSync$1(join$1(projectRoot, "ios")) ? "ios" : existsSync$1(join$1(projectRoot, "android")) ? "android" : void 0);
|
|
1261
1298
|
let base;
|
|
1262
1299
|
try {
|
|
1263
1300
|
base = makeTemporaryDirectory(projectRoot, "stim-parity-");
|
|
1264
1301
|
} catch {
|
|
1265
1302
|
return null;
|
|
1266
1303
|
}
|
|
1267
|
-
const worktree = join(base, "head");
|
|
1304
|
+
const worktree = join$1(base, "head");
|
|
1268
1305
|
if (exec.runFileQuiet("git", [
|
|
1269
1306
|
"-C",
|
|
1270
1307
|
projectRoot,
|
|
@@ -1327,11 +1364,65 @@ async function detectFingerprintParity(projectRoot, { createFingerprint = expoFi
|
|
|
1327
1364
|
}
|
|
1328
1365
|
}
|
|
1329
1366
|
//#endregion
|
|
1367
|
+
//#region src/device-host/agent-driver.ts
|
|
1368
|
+
function hostedAgentDriverFinding(driver, apps) {
|
|
1369
|
+
if (apps === 0 || driver !== void 0 && driver !== "none") return null;
|
|
1370
|
+
return {
|
|
1371
|
+
code: "hosted-agent-driver",
|
|
1372
|
+
level: "note",
|
|
1373
|
+
title: `${apps === 1 ? "A hosted app runs" : `${apps} hosted apps run`} with no agent driver`,
|
|
1374
|
+
detail: "The client's coding agent cannot drive these apps because `hosting.agentDriver` is none, so stim-server starts no driver. agent-device confines macOS control to one macos-app lease and iOS control to one simulator through its daemon policy.",
|
|
1375
|
+
fix: "stim settings set hosting.agentDriver agent-device, with agent-device 0.21.20 or later"
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
function runningHostedApps() {
|
|
1379
|
+
try {
|
|
1380
|
+
return readHostedSessions().filter((session) => {
|
|
1381
|
+
if (!["macos", "ios"].includes(session.platform) || session.state !== "ready" || !session.appAttempt) return false;
|
|
1382
|
+
try {
|
|
1383
|
+
return readHostedAppMetadata(session.id, session.appAttempt).state === "installed";
|
|
1384
|
+
} catch {
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1387
|
+
}).length;
|
|
1388
|
+
} catch {
|
|
1389
|
+
return 0;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
/** Notes installed hosted macOS and iOS apps on this Mac while `hosting.agentDriver` starts no driver. */
|
|
1393
|
+
function inspectHostedAgentDriver() {
|
|
1394
|
+
const hosting = loadConfig$1()?.hosting;
|
|
1395
|
+
return hostedAgentDriverFinding(isJsonObject(hosting) ? hosting.agentDriver : void 0, runningHostedApps());
|
|
1396
|
+
}
|
|
1397
|
+
//#endregion
|
|
1330
1398
|
//#region src/commands/doctor.ts
|
|
1331
1399
|
function parseDoctorPlatform(value) {
|
|
1332
1400
|
if (value === "ios" || value === "android") return value;
|
|
1333
1401
|
throw new InvalidArgumentError("expected one of: ios, android");
|
|
1334
1402
|
}
|
|
1403
|
+
/**
|
|
1404
|
+
* The simulator runtime `stim ios` would build for here: the one `ios.runtime` names, else the workspace's own
|
|
1405
|
+
* simulator's, else the one it would create a simulator on.
|
|
1406
|
+
*/
|
|
1407
|
+
function iosTargetRuntime(root) {
|
|
1408
|
+
try {
|
|
1409
|
+
const settings = resolveSettings({
|
|
1410
|
+
projectPath: root,
|
|
1411
|
+
gitCommonDir: gitCommonDir(root),
|
|
1412
|
+
repoRoot: repoRoot(root) ?? root
|
|
1413
|
+
});
|
|
1414
|
+
const runtimes = listIosRuntimes();
|
|
1415
|
+
const runtime = resolveRuntime(null, settings);
|
|
1416
|
+
if (runtime) return runtimes.find((each) => iosRuntimeMatches(each, runtime))?.identifier ?? null;
|
|
1417
|
+
const udid = getProject(root)?.platforms?.ios?.deviceUdid;
|
|
1418
|
+
const own = typeof udid === "string" ? simulatorRuntime(udid) : null;
|
|
1419
|
+
if (own) return own;
|
|
1420
|
+
const deviceType = resolveDeviceType(null, settings) ?? void 0;
|
|
1421
|
+
return pickDefaultIosCreation([], runtimes, { deviceType })?.runtimeId ?? null;
|
|
1422
|
+
} catch {
|
|
1423
|
+
return null;
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1335
1426
|
function doctorTarget(platform) {
|
|
1336
1427
|
if (platform === "ios") return "iOS";
|
|
1337
1428
|
if (platform === "android") return "Android";
|
|
@@ -1434,8 +1525,8 @@ function applySandboxFix(root, env = process.env) {
|
|
|
1434
1525
|
console.error(chalk.dim("Added writes to Stim's state directory, the simulator XPC service, and local port binding. Claude Code reads project settings from the directory a session starts in, so this file only counts for sessions rooted there. Restart the session for it to take effect."));
|
|
1435
1526
|
}
|
|
1436
1527
|
function doctorCommand(program, version, inspectVersions = inspectStimVersions, host = process.platform) {
|
|
1437
|
-
program.command("doctor").description("Inspect the source checkout and report project state that can make native worktrees slow or invalid. The checkout is left untouched unless --fix is passed; --platform filters native findings. Each run in a React Native or Expo app is recorded in Stim state so guide can say when doctor is due.").option("--json", "print the findings as JSON").option("--platform <platform>", "report shared findings plus only this native platform: ios or android", parseDoctorPlatform).option("--fix", "repair the sandbox allowance when the report names it, and stale Android .cxx configurations in this checkout. Stop native builds first. Generated CMake output must be ignored and untracked; custom launcher settings and source files are preserved.").action(async (opts) => {
|
|
1438
|
-
const root = findProjectRoot(process.cwd());
|
|
1528
|
+
program.command("doctor").description("Inspect the source checkout and report project state that can make native worktrees slow or invalid. The checkout is left untouched unless --fix is passed; --platform filters native findings. Each run in a React Native or Expo app is recorded in Stim state so guide can say when doctor is due.").option("--json", "print the findings as JSON").option("--platform <platform>", "report shared findings plus only this native platform: ios or android", parseDoctorPlatform).option("--fix", "repair the sandbox allowance when the report names it, and stale Android .cxx configurations in this checkout; ask each machine in offload.machines for build access. Stop native builds first. Generated CMake output must be ignored and untracked; custom launcher settings and source files are preserved.").action(async (opts) => {
|
|
1529
|
+
const root = findProjectRoot$1(process.cwd());
|
|
1439
1530
|
if (!root) {
|
|
1440
1531
|
refuseNoProject({ json: Boolean(opts.json) });
|
|
1441
1532
|
return;
|
|
@@ -1470,19 +1561,62 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions,
|
|
|
1470
1561
|
if (shadowed) findings.push(shadowed);
|
|
1471
1562
|
const budget = await inspectBudget(root);
|
|
1472
1563
|
findings.push(...budget.findings);
|
|
1564
|
+
const watchman = await inspectWatchmanMemory();
|
|
1565
|
+
if (watchman) findings.push(watchman);
|
|
1566
|
+
const checksIos = opts.platform !== "android" && host === "darwin";
|
|
1567
|
+
const checksAndroid = opts.platform === "android" || opts.platform === void 0 && (existsSync(join(root, "android")) || detectIsExpo(root));
|
|
1568
|
+
const checksMacos = host === "darwin" && opts.platform === void 0 && existsSync(join(root, "Package.swift"));
|
|
1569
|
+
const offloadTargets = () => [
|
|
1570
|
+
...checksIos ? [{
|
|
1571
|
+
platform: "ios",
|
|
1572
|
+
local: iosToolchain(),
|
|
1573
|
+
runtime: iosTargetRuntime(root),
|
|
1574
|
+
cocoapodsPinned: bundlerPin(root) !== null
|
|
1575
|
+
}] : [],
|
|
1576
|
+
...checksAndroid ? [{
|
|
1577
|
+
platform: "android",
|
|
1578
|
+
local: androidToolchain(),
|
|
1579
|
+
requires: androidRequirements(root)
|
|
1580
|
+
}] : [],
|
|
1581
|
+
...checksMacos ? [{
|
|
1582
|
+
platform: "macos",
|
|
1583
|
+
local: macosToolchain()
|
|
1584
|
+
}] : []
|
|
1585
|
+
];
|
|
1586
|
+
const buildMachines = await inspectBuildMachines({
|
|
1587
|
+
fix: opts.fix === true,
|
|
1588
|
+
check: checksIos || checksAndroid || checksMacos ? offloadCheck(root, offloadTargets) : null
|
|
1589
|
+
});
|
|
1590
|
+
findings.push(...buildMachines.findings);
|
|
1591
|
+
const deviceHosts = await inspectDeviceHostMachines({ fix: opts.fix === true });
|
|
1592
|
+
findings.push(...deviceHosts.findings);
|
|
1593
|
+
const agentDriver = inspectHostedAgentDriver();
|
|
1594
|
+
if (agentDriver) findings.push(agentDriver);
|
|
1595
|
+
const maintenance = maintenanceStatus();
|
|
1596
|
+
const maintenanceLines = [
|
|
1597
|
+
phaseLine("maintenance.mode", maintenance.mode),
|
|
1598
|
+
phaseLine("maintenance log", maintenanceNdjsonFile()),
|
|
1599
|
+
phaseLine("last pass", maintenanceLine(maintenance, false) ?? "no pass has run yet")
|
|
1600
|
+
];
|
|
1473
1601
|
if (opts.json) {
|
|
1474
1602
|
console.log(JSON.stringify({
|
|
1475
1603
|
project: root,
|
|
1476
1604
|
platform: opts.platform ?? null,
|
|
1477
1605
|
stim,
|
|
1478
1606
|
budget: budget.report,
|
|
1607
|
+
maintenance: {
|
|
1608
|
+
...maintenance,
|
|
1609
|
+
logPath: maintenanceNdjsonFile()
|
|
1610
|
+
},
|
|
1611
|
+
buildMachines: buildMachines.machines,
|
|
1612
|
+
deviceHosts: deviceHosts.machines,
|
|
1479
1613
|
findings
|
|
1480
1614
|
}));
|
|
1481
1615
|
recordDoctorRun(root, opts.platform, version);
|
|
1482
1616
|
return;
|
|
1483
1617
|
}
|
|
1484
1618
|
if (findings.length === 0) {
|
|
1485
|
-
const lines = doctorSuccessLines(opts.platform, stim, budget.report);
|
|
1619
|
+
const lines = [...doctorSuccessLines(opts.platform, stim, budget.report), ...maintenanceLines];
|
|
1486
1620
|
for (const [index, line] of lines.entries()) if (index === 1) console.log(chalk.green(line));
|
|
1487
1621
|
else if (line && !line.startsWith(" ")) console.log(chalk.bold(line));
|
|
1488
1622
|
else console.log(chalk.dim(line));
|
|
@@ -1491,7 +1625,11 @@ function doctorCommand(program, version, inspectVersions = inspectStimVersions,
|
|
|
1491
1625
|
}
|
|
1492
1626
|
const ordered = findings.toSorted((a, b) => a.level === b.level ? 0 : a.level === "cost" ? -1 : 1);
|
|
1493
1627
|
console.log(chalk.bold(`Doctor (${doctorTarget(opts.platform)})`));
|
|
1494
|
-
for (const line of [
|
|
1628
|
+
for (const line of [
|
|
1629
|
+
...stimVersionLines(stim),
|
|
1630
|
+
...budgetLines(budget.report),
|
|
1631
|
+
...maintenanceLines
|
|
1632
|
+
]) console.log(chalk.dim(line));
|
|
1495
1633
|
for (const f of ordered) {
|
|
1496
1634
|
const tag = f.level === "cost" ? chalk.yellow("costs time") : chalk.dim("note");
|
|
1497
1635
|
console.log(`\n${tag} ${chalk.bold(f.title)}`);
|