stim 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -155
- package/dist/{android-BRgBYzU0.mjs → android-BPGizezh.mjs} +112 -135
- package/dist/{android-DeYdjjBP.mjs → android-DEgo4oCo.mjs} +2 -2
- package/dist/{android-DWssqHQ8.mjs → android-_y4Ohi5z.mjs} +54 -15
- package/dist/android-cas-compiler.mjs +2 -2
- package/dist/{android-cas-SWIjzeuL.mjs → android-cas-eiExNLf7.mjs} +21 -14
- package/dist/app-install-Uf3a83Tv.mjs +819 -0
- package/dist/{build-lock-CgtsB6TV.mjs → build-lock-DPXPLgTc.mjs} +120 -24
- package/dist/build-progress-CVqkfPC6.mjs +188 -0
- package/dist/{cache-manifest-CYJi8-Hx.mjs → cache-manifest-Dg7OnMrp.mjs} +4 -4
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +22 -19
- package/dist/collector-run.d.mts +2 -0
- package/dist/collector-run.mjs +10 -9
- package/dist/{command-output-B3ycpsYv.mjs → command-output-gByVmIjy.mjs} +11 -2
- package/dist/{config-B7iyKWkL.mjs → config-Cp9lM3wX.mjs} +187 -57
- package/dist/{dependency-state-D0M7oKA7.mjs → dependency-state-Bq5DcLGn.mjs} +2 -2
- package/dist/{deps-oCXVNEqQ.mjs → deps-Cip5vUm1.mjs} +8 -5
- package/dist/{detached-entry-Bpo6ZY_I.mjs → detached-entry-KEu0_AXL.mjs} +1 -1
- package/dist/{device-BUoZyMoR.mjs → dev-client-HyqISM0h.mjs} +1178 -635
- package/dist/{device-RdujjHLB.mjs → device-D4U-xLty.mjs} +13 -20
- package/dist/{device-lease-Ffz_M5t0.mjs → device-lease-Crs-HkJY.mjs} +16 -9
- package/dist/{device-pool-BxRwdufO.mjs → device-pool-CnTAz8X1.mjs} +7 -7
- package/dist/{device-remote-ByN8P6CB.mjs → device-remote-AQ5rQPqr.mjs} +482 -35
- package/dist/{doctor-BMt156qe.mjs → doctor-B_Ei3bZu.mjs} +95 -107
- package/dist/{error-diagnostics-D1Kaf-eT.mjs → error-diagnostics-Vfz83GCF.mjs} +22 -16
- package/dist/exec-jIAlgilk.mjs +132 -0
- package/dist/{gc-v2YcoJvm.mjs → gc-Ckw8RQHi.mjs} +763 -126
- package/dist/{guide-BTAlD1_y.mjs → guide-BiAbhs1J.mjs} +891 -501
- package/dist/{guide-status-Craq9z0t.mjs → guide-status-BAMVU0ZA.mjs} +5 -3
- package/dist/{ios-BcCiI4TS.mjs → ios-BL2NFckr.mjs} +43 -20
- package/dist/{ios-BP04pY5f.mjs → ios-BzUJWk1K.mjs} +141 -175
- package/dist/{ios-device-CauFJiYx.mjs → ios-device-D972i9wf.mjs} +149 -52
- package/dist/{ios-device-CFXA46ez.mjs → ios-device-DPsSm0v_.mjs} +3 -2
- package/dist/launch-verify-Q_OtW1Rf.mjs +365 -0
- package/dist/{logs-CakdBTtm.mjs → logs-CI9NQSK7.mjs} +18 -13
- package/dist/{logs-query-BGL-Pl12.mjs → logs-query-Cqma3WIu.mjs} +36 -28
- package/dist/{metro-C7bcJ0uo.mjs → metro-DrLHaMn2.mjs} +78 -8
- package/dist/{named-ports-DzMOlmaX.mjs → named-ports-CmLQSIRj.mjs} +4 -4
- package/dist/{ndjson-BZwI1NBv.mjs → ndjson-9uFNRwfe.mjs} +36 -3
- package/dist/{ownership-Cp52QAK1.mjs → ownership-D15Op8vN.mjs} +3 -3
- package/dist/{ownership-wolE-0Do.mjs → ownership-DCQPuWEc.mjs} +26 -7
- package/dist/{ports-BIbJaKNW.mjs → ports-BNKoWVWZ.mjs} +3 -3
- package/dist/{process-output-Dl5uKE03.mjs → process-output-Fpl8PYi8.mjs} +1 -1
- package/dist/{project-DDZWf_16.mjs → project-DS112DYB.mjs} +8 -3
- package/dist/{reload-BdypPbjM.mjs → reload-ZNJUo1pl.mjs} +12 -13
- package/dist/{server-bare-BQkyxa_b.mjs → server-bare-DWkkcIxV.mjs} +2 -2
- package/dist/{server-expo-BVAA1OqJ.mjs → server-expo-B_lctBR3.mjs} +8 -7
- package/dist/server-expo-CeILEu86.mjs +2 -0
- package/dist/settings-BKNh5rl4.mjs +376 -0
- package/dist/{settings-BXXorVM2.mjs → settings-D030k0t4.mjs} +464 -152
- package/dist/settings.schema.json +989 -0
- package/dist/{teardown-BJqEzPo_.mjs → sim-pool-KaIsp2Ft.mjs} +14 -419
- package/dist/simslim-B_LsGLuJ.mjs +259 -0
- package/dist/{slot-launch-ZUUe0TQP.mjs → slot-launch-DU9A-gYw.mjs} +4 -4
- package/dist/spawn-claims-Dn3C_N6w.mjs +49 -0
- package/dist/{start-CmxtOKjU.mjs → start-DYkkKF0s.mjs} +27 -31
- package/dist/{state-DZobzxLW.mjs → state-NcJzMEBF.mjs} +5 -3
- package/dist/{stats-CLg5RuDS.mjs → stats-B63-JVAY.mjs} +4 -4
- package/dist/{stats-BYcZ6n1h.mjs → stats-DG9e66Rz.mjs} +66 -5
- package/dist/status-S6ehL4Ui.mjs +932 -0
- package/dist/{stop-C8JW6kKp.mjs → stop-BO28HGqF.mjs} +101 -25
- package/dist/{stop-B1kOpYei.mjs → stop-T1R-cZRz.mjs} +2 -2
- package/dist/supervisor-run.mjs +52 -34
- package/dist/{workspace-process-lock-BYfZz_S-.mjs → workspace-process-lock-DWaiRD0e.mjs} +14 -9
- package/dist/{workspace-state-BT5E3SA2.mjs → workspace-state-DF2gCFhx.mjs} +52 -29
- package/dist/worktree-DKhSF0UX.mjs +2 -0
- package/dist/{worktree-CFLA-6MX.mjs → worktree-LGB-UwgG.mjs} +603 -59
- package/dist/{worktree-FG_ZKKdb.mjs → worktree-R_cUlE7s.mjs} +62 -41
- package/dist/{xcode-B6YaWeg0.mjs → xcode-BZqyxh3e.mjs} +216 -58
- package/package.json +5 -6
- package/skill/SKILL.md +2 -0
- package/dist/app-install-BDbsSgCl.mjs +0 -1175
- package/dist/build-slots-C-oAHRT1.mjs +0 -151
- package/dist/dev-client-BmT-ioFI.mjs +0 -797
- package/dist/exec-B29XNuhP.mjs +0 -77
- package/dist/reclaim-KJ-0uWEF.mjs +0 -361
- package/dist/server-expo-YDDG3eP7.mjs +0 -2
- package/dist/status-DdkLki47.mjs +0 -426
- package/dist/{metro-store-CDDZHtPl.mjs → metro-store-DzeWkfqW.mjs} +1 -1
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-
|
|
3
|
-
import { t as guideStatus } from "./guide-status-
|
|
1
|
+
import { o as findProjectRoot } from "./project-DS112DYB.mjs";
|
|
2
|
+
import { t as ANDROID_AVD_CONFIG_HELP } from "./settings-D030k0t4.mjs";
|
|
3
|
+
import { t as guideStatus } from "./guide-status-BAMVU0ZA.mjs";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
//#
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
summary: "The normal coding-agent workflow, safety rules, and topic routing",
|
|
10
|
-
body: () => `AGENT WORKFLOW
|
|
5
|
+
//#region src/guide/agent.ts
|
|
6
|
+
var agent_default = {
|
|
7
|
+
summary: "The normal coding-agent workflow, safety rules, and topic routing",
|
|
8
|
+
body: () => `AGENT WORKFLOW
|
|
11
9
|
|
|
12
10
|
Use Stim to run React Native and Expo apps without sharing a Metro port or
|
|
13
11
|
device with another workspace. Prefer plain output: it streams each phase and
|
|
@@ -27,12 +25,6 @@ the source checkout is infrastructure, not a workspace: you edit, build, and run
|
|
|
27
25
|
in the worktree, and you keep the seed fit to copy. Every rule below about the
|
|
28
26
|
source checkout's fitness as a seed belongs to this workflow.
|
|
29
27
|
|
|
30
|
-
Doctor reports that fitness -- how far behind the seed is, uncommitted tracked
|
|
31
|
-
changes, an interrupted rebase or merge, a detached HEAD, a diverged branch, a
|
|
32
|
-
branch that is not the default one -- only once the repository has at least
|
|
33
|
-
one linked worktree, so read it from inside the worktree. A single-checkout
|
|
34
|
-
session is never told that its own branch is a problem.
|
|
35
|
-
|
|
36
28
|
MULTIPLE DEVICES
|
|
37
29
|
|
|
38
30
|
Use ios/android --slot <name> to retain multiple devices in one workspace,
|
|
@@ -67,44 +59,18 @@ If warm fails or reports incomplete, resolve the reported failure first.
|
|
|
67
59
|
A warm that cannot record its ownership claim refuses before copying. Follow
|
|
68
60
|
the printed remedy and keep concurrent runs on the same STIM_HOME.
|
|
69
61
|
|
|
70
|
-
Before native
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
fix PATH or the installation before continuing so commands and guidance match.
|
|
80
|
-
Doctor reports cross-volume staging and build-cache copies; read guide settings
|
|
81
|
-
for placement overrides and guide lifecycle options for warm behavior.
|
|
82
|
-
For iOS Debug architecture findings, review the project's overrides and imported
|
|
83
|
-
Podfile helpers using guide lifecycle options. Doctor --fix does not change them.
|
|
84
|
-
For parallel iOS work, review the recommended optional SimSlim setup in
|
|
85
|
-
stim guide lifecycle simslim. If simulator process startup times out, check
|
|
86
|
-
host memory pressure and free memory before retrying. Boot progress reports
|
|
87
|
-
current and highest observed pressure; a timeout does not establish OOM.
|
|
88
|
-
Avoid repeated reboots under unchanged pressure; do not restart other
|
|
89
|
-
workspaces' devices or close their apps without asking. That guide covers
|
|
90
|
-
the recovery steps and profile tradeoffs.
|
|
91
|
-
An Android boot timeout under observed elevated memory pressure gets one
|
|
92
|
-
extra wait while the emulator process this run started is alive. It never
|
|
93
|
-
launches a second emulator. For a timeout, read guide errors STIM_NO_DEVICE
|
|
94
|
-
and free memory by stopping only unneeded devices in workspaces you own;
|
|
95
|
-
ask before closing other apps or devices. Device count alone is not evidence
|
|
96
|
-
of memory pressure.
|
|
97
|
-
For a linked native library carrying Git metadata, add the printed .git entries to
|
|
98
|
-
.fingerprintignore only when the native build does not read Git state.
|
|
62
|
+
Before native work, run doctor for the platform in scope when the STATUS block
|
|
63
|
+
at the top of this topic says it is due. No block means doctor is current and
|
|
64
|
+
Stim is up to date. In the worktree workflow, run it from the linked worktree
|
|
65
|
+
so it also checks the source checkout. Follow each finding's printed remedy,
|
|
66
|
+
and read the routed topic below before acting on one you do not understand. If
|
|
67
|
+
the stim resolved from PATH is older than another installation, fix PATH or the
|
|
68
|
+
installation before continuing so commands and guidance match. Under host
|
|
69
|
+
memory pressure, stop only devices in workspaces you own; ask before closing
|
|
70
|
+
other apps or other workspaces' devices.
|
|
99
71
|
|
|
100
72
|
stim doctor --platform ios # or: --platform android
|
|
101
73
|
|
|
102
|
-
For stale Android CMake launcher findings, stop native builds and run
|
|
103
|
-
stim doctor --fix --platform android in the affected checkout before warming
|
|
104
|
-
more worktrees. It removes affected ignored, untracked generated .cxx
|
|
105
|
-
configurations, including installed native modules; the next build recreates
|
|
106
|
-
them. It preserves source, custom launcher settings, and the shared ccache.
|
|
107
|
-
|
|
108
74
|
# Skip Git creation if the harness already created this linked worktree.
|
|
109
75
|
git worktree add -b <branch> <worktree-path> HEAD
|
|
110
76
|
cd <worktree-path>
|
|
@@ -245,8 +211,14 @@ Ask the user before these actions:
|
|
|
245
211
|
existing Stim ownership record is deleted only when it has no unique commits.
|
|
246
212
|
- worktree remove --force, because it also discards uncommitted and untracked
|
|
247
213
|
files.
|
|
248
|
-
- gc --delete, because it deletes orphaned resources
|
|
249
|
-
|
|
214
|
+
- gc --delete, because it deletes orphaned resources and clears the build
|
|
215
|
+
outputs of every workspace not in use. Run stim gc --json first and show
|
|
216
|
+
the user the entries its sections list (guide facts gc). gc --delete
|
|
217
|
+
--cache all empties the shared build caches and those outputs instead, and
|
|
218
|
+
gc --delete --cache workspaces clears only the outputs; both inspect
|
|
219
|
+
nothing else.
|
|
220
|
+
- gc --delete --worktrees, because it runs worktree remove on every clean,
|
|
221
|
+
idle linked worktree Stim manages, across projects.
|
|
250
222
|
- stop when the workspace owns an EAS session, because it irreversibly ends
|
|
251
223
|
that remote session. For a local device, stop shuts it down but does not
|
|
252
224
|
delete it. An explicit stop shuts down a Stim-owned simulator even when
|
|
@@ -280,6 +252,12 @@ Read the matching guide before acting in these situations:
|
|
|
280
252
|
| Capacity limits | stim guide lifecycle concurrency |
|
|
281
253
|
| Cache statistics from stim stats | stim guide facts stats |
|
|
282
254
|
| Worktree carry-over | stim guide lifecycle options |
|
|
255
|
+
| Doctor finding: seed checkout or cross-volume copy | stim guide lifecycle options |
|
|
256
|
+
| Doctor finding: iOS Debug archs, .cxx, fingerprints | stim guide lifecycle builds |
|
|
257
|
+
| Temporary storage placement | stim guide settings |
|
|
258
|
+
| Read or change a setting (stim settings) | stim guide settings |
|
|
259
|
+
| Parallel iOS, simulator stall, or memory pressure | stim guide lifecycle simslim |
|
|
260
|
+
| Android boot timeout | stim guide errors STIM_NO_DEVICE |
|
|
283
261
|
| gc or orphaned resources | stim guide cleanup gc |
|
|
284
262
|
| worktree remove refusal or --force | stim guide errors remove |
|
|
285
263
|
| Cleanup failure or unverified cleanup ownership | stim guide errors teardown |
|
|
@@ -316,10 +294,12 @@ FULL TOPIC LIST
|
|
|
316
294
|
stim guide cleanup # what reclaims a device, and what deletes
|
|
317
295
|
stim guide cleanup collector # an unproven collector pid; why the app on a phone closed
|
|
318
296
|
stim guide settings # configuration files and supported keys`
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
297
|
+
};
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region src/guide/facts.ts
|
|
300
|
+
const facts = {
|
|
301
|
+
summary: "The --json payloads: `start`, `ios`, `android`, `reload`, `stop`, `status`, `doctor`, `device lock`/`unlock`, `gc`, and the error contract",
|
|
302
|
+
preamble: () => `SLOTS
|
|
323
303
|
Named ios/android runs add slot to their JSON facts. Default-run fields remain
|
|
324
304
|
compatible. status adds a slots array per environment with each named slot's
|
|
325
305
|
ios/android device facts; top-level ios/android still describe default.
|
|
@@ -328,14 +308,37 @@ Named collector, lease-holder, and launch keys use platform:slot internally.
|
|
|
328
308
|
FACTS CONTRACT
|
|
329
309
|
|
|
330
310
|
\`start\`, \`ios\`, \`android\`, \`reload\`, \`stop\`, \`status\`, \`stats\`, \`doctor\`,
|
|
331
|
-
and \`device lock\`/\`device unlock\` each print exactly ONE line of JSON on
|
|
311
|
+
\`gc\`, and \`device lock\`/\`device unlock\` each print exactly ONE line of JSON on
|
|
332
312
|
stdout for \`--json\`. Every other line goes to stderr, so it is always safe
|
|
333
313
|
to pipe. \`logs --json\` is the one exception: it is NDJSON, one record per
|
|
334
|
-
line by design (see \`guide logs\`), not this single-payload contract
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
314
|
+
line by design (see \`guide logs\`), not this single-payload contract.
|
|
315
|
+
|
|
316
|
+
status's unprovisionedWorktrees lists this repository's linked worktrees with
|
|
317
|
+
no Stim environment. \`worktree warm\` does not create one; \`start\`, \`ios\`,
|
|
318
|
+
\`android\` and \`doctor\` register it.
|
|
319
|
+
|
|
320
|
+
status's remoteDevices lists each environment's recorded EAS Simulator
|
|
321
|
+
session. The session is billable while it runs, and it makes the environment
|
|
322
|
+
live. status reads only local records; it does not ask EAS whether the session
|
|
323
|
+
is still running.
|
|
324
|
+
|
|
325
|
+
remoteDevices [{ platform, backend, sessionId, state, startedAt,
|
|
326
|
+
webPreviewUrl }], empty when the workspace has none
|
|
327
|
+
backend "eas"
|
|
328
|
+
state "claimed" Stim's ownership ledger holds this workspace's
|
|
329
|
+
claim, so \`stop\` and \`gc --delete\` can end it
|
|
330
|
+
"unclaimed" the ledger has no claim for this workspace;
|
|
331
|
+
\`stop\` still ends the recorded session
|
|
332
|
+
"unknown" the ledger could not be read
|
|
333
|
+
webPreviewUrl the browser page showing the remote screen, recorded when
|
|
334
|
+
Stim created the session, or null
|
|
335
|
+
|
|
336
|
+
Plain status prints one "remote <platform>: EAS session <id> billable" line
|
|
337
|
+
per session, with the preview URL.`,
|
|
338
|
+
sections: {
|
|
339
|
+
payloads: {
|
|
340
|
+
summary: "every field of the start, ios, android and reload payloads, the error contract, the device rules",
|
|
341
|
+
body: () => ` stim start --json
|
|
339
342
|
|
|
340
343
|
port the Metro port RESERVED for this workspace
|
|
341
344
|
supervisorPid the detached supervisor's pid, or NULL when a dev server was
|
|
@@ -355,11 +358,11 @@ line by design (see \`guide logs\`), not this single-payload contract.`,
|
|
|
355
358
|
deviceName its name, or null
|
|
356
359
|
deviceType the owned simulator's MODEL, as
|
|
357
360
|
\`xcrun simctl list devicetypes\` names it ("iPad Pro 13-inch
|
|
358
|
-
(
|
|
361
|
+
(M5)"). Read from the simulator itself, so a run driven by
|
|
359
362
|
the ios.deviceType setting reports it too, not only a
|
|
360
363
|
\`--device-type\` run. Null on \`--device\` and on a
|
|
361
364
|
simulator Stim does not own
|
|
362
|
-
runtime that simulator's iOS runtime version ("
|
|
365
|
+
runtime that simulator's iOS runtime version ("26.5"), from the same
|
|
363
366
|
record. Null on the same paths as deviceType
|
|
364
367
|
fingerprint the @expo/fingerprint hash of the native inputs, AS STORED.
|
|
365
368
|
A run that had to \`expo prebuild\` or \`pod install\`
|
|
@@ -612,10 +615,10 @@ RULES
|
|
|
612
615
|
\`android --device\` and
|
|
613
616
|
\`ios --device\`, which use a connected physical device Stim never
|
|
614
617
|
creates, boots, or deletes.`
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
618
|
+
},
|
|
619
|
+
devmenu: {
|
|
620
|
+
summary: "why the Expo dev menu or Tools button is or is not over the app, per platform and device kind",
|
|
621
|
+
body: () => ` EVERY DEV-CLIENT DEEP LINK CARRIES disableOnboarding=1
|
|
619
622
|
INSIDE ITS PROJECT URL
|
|
620
623
|
(\`...?url=http%3A%2F%2Fhost%3Aport%2F%3FdisableOnboarding%3D1&disableFab=1\`),
|
|
621
624
|
and expo-dev-launcher finishes its own dev-menu ONBOARDING
|
|
@@ -706,10 +709,129 @@ RULES
|
|
|
706
709
|
developer trust, has no API at all and is always the user's.
|
|
707
710
|
\`guide errors unverified\` has the signature and the
|
|
708
711
|
full commands.`
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
712
|
+
},
|
|
713
|
+
gc: {
|
|
714
|
+
summary: "the gc report payload: mode, sections, reasons, failures, and the gc refusals",
|
|
715
|
+
body: () => ` stim gc [--delete] [--older-than <days>] [--cache <name|all|workspaces>]
|
|
716
|
+
[--worktrees] --json
|
|
717
|
+
|
|
718
|
+
The report the text prints, as one payload. Show the user its sections
|
|
719
|
+
before you run \`gc --delete\`. Under --delete it is the report that run
|
|
720
|
+
acted on: each entry's outcome is a stderr line, \`failures\` counts the
|
|
721
|
+
entries it could not delete, and a nonzero count exits 1. Run
|
|
722
|
+
\`stim gc --json\` again to see what is left.
|
|
723
|
+
|
|
724
|
+
mode "dry-run" | "delete"
|
|
725
|
+
cacheScope the --cache name, or null. When set, devices, project
|
|
726
|
+
entries and locks were not inspected and their sections
|
|
727
|
+
are empty
|
|
728
|
+
olderThan the --older-than days, or null
|
|
729
|
+
worktreeSweep null without --worktrees; otherwise { olderThan, defaulted }:
|
|
730
|
+
the idle days a linked worktree needs, and whether that is
|
|
731
|
+
the default 7 because --older-than was not given
|
|
732
|
+
actionable true when --delete with the same flags reclaims something
|
|
733
|
+
failures null on a dry run; under --delete, the entries it could
|
|
734
|
+
not delete
|
|
735
|
+
sections one array per report section, in the text order. Every key
|
|
736
|
+
is present, empty when there is nothing to report:
|
|
737
|
+
deadProjects { path }
|
|
738
|
+
invalidProjects { path } the registry key is not absolute
|
|
739
|
+
orphanedPorts { project, label, port }
|
|
740
|
+
orphanedWorkspaces { dir, projectRoot, bytes } --delete removes the
|
|
741
|
+
whole workspace directory
|
|
742
|
+
linkedWorktrees { path, idleDays, willRemove, reason, detail }
|
|
743
|
+
only with --worktrees
|
|
744
|
+
parkedSimulators { udid, name, model, runtime, parkedAt, bytes,
|
|
745
|
+
listed }
|
|
746
|
+
parkedEmulators { name, systemImage, parkedAt, bytes, listed }
|
|
747
|
+
orphanedDevices { kind, id, name, bytes, directory }
|
|
748
|
+
staleDevices { kind, id, name, project, slot, idleDays,
|
|
749
|
+
bytes } only with --older-than
|
|
750
|
+
staleDeviceRecords { kind, id, project, slot } --delete clears
|
|
751
|
+
the record only
|
|
752
|
+
orphanedEasSessions { id, name, platform, status, projectScope }
|
|
753
|
+
staleBuildLocks { path, platform, key, pid, projectRoot }
|
|
754
|
+
staleBuildSlots { path, index, pid, projectRoot }
|
|
755
|
+
unresolvedBuildClaims { kind: "lock" | "slot", path } never touched
|
|
756
|
+
buildsInProgress { path, platform, key, pid, projectRoot }
|
|
757
|
+
never touched
|
|
758
|
+
expiredDeviceLeases { path, platform, id, deviceName, holder,
|
|
759
|
+
expiresAt }
|
|
760
|
+
keptDeviceLeases { name, path, detail } never deleted
|
|
761
|
+
deviceSweepNotices { message }
|
|
762
|
+
easSessionSweepNotices { message }
|
|
763
|
+
skipped { path, detail } not classified as dead
|
|
764
|
+
workspaceBuildOutputs { dir, projectRoot, bytes, idleDays, willClear,
|
|
765
|
+
reason, detail } derived-data, gradle-build,
|
|
766
|
+
android-cas and cache-provider of each
|
|
767
|
+
workspace; willClear marks the ones --delete
|
|
768
|
+
would clear
|
|
769
|
+
caches { name, dir, source, bytes, note, willEmpty,
|
|
770
|
+
emptySkipped } alive, not garbage; willEmpty
|
|
771
|
+
marks the ones --delete would empty
|
|
772
|
+
bytes is null when the size is unknown: not measured, or the measurement
|
|
773
|
+
failed. idleDays is null when the last use is unknown. listed is false for
|
|
774
|
+
a parked device that is no longer on this machine, and null when its
|
|
775
|
+
listing was unavailable.
|
|
776
|
+
|
|
777
|
+
reason is null for an entry --delete acts on, and otherwise a stable code
|
|
778
|
+
to branch on; detail is the text line, for the user. Never parse detail.
|
|
779
|
+
workspaceBuildOutputs unresolved | in-use | last-use-unknown |
|
|
780
|
+
recently-used
|
|
781
|
+
linkedWorktrees not-a-worktree | bare-repository |
|
|
782
|
+
source-checkout-unknown | source-checkout |
|
|
783
|
+
locked | in-use | status-unreadable | dirty |
|
|
784
|
+
unpushed-unchecked | unpushed | submodules |
|
|
785
|
+
last-use-unknown | recently-used
|
|
786
|
+
|
|
787
|
+
These print the error contract instead and exit 1:
|
|
788
|
+
|
|
789
|
+
{ "code": "STIM_BAD_ARG", "message": "...", "remedy": "..." }
|
|
790
|
+
|
|
791
|
+
- a --cache name that no shared cache carries; the remedy names the
|
|
792
|
+
caches on this machine
|
|
793
|
+
- --cache together with --worktrees`
|
|
794
|
+
},
|
|
795
|
+
status: {
|
|
796
|
+
summary: "the status payload's build field: a running ios or android build, its phase, and its estimate",
|
|
797
|
+
body: () => ` stim status --json
|
|
798
|
+
|
|
799
|
+
Each entry of environments carries build: null, or the ios or android
|
|
800
|
+
run that holds this workspace's native-run.lock:
|
|
801
|
+
|
|
802
|
+
build { platform, slot, state, phase, startedAt, phaseStartedAt,
|
|
803
|
+
outcome, expectedMs, expectedPhaseMs, basis }
|
|
804
|
+
|
|
805
|
+
state "running" while the run's own native-run claim is live;
|
|
806
|
+
"stale" when that claim was released or its process is
|
|
807
|
+
gone -- the run was killed, and the next run replaces the
|
|
808
|
+
record; "unknown" when the claim set cannot be resolved.
|
|
809
|
+
Never treat a stale record as a build in progress.
|
|
810
|
+
phase prepare | cache-lookup | wait | prebuild | pods |
|
|
811
|
+
compile | install | launch. prepare covers settings,
|
|
812
|
+
Metro and the owned device; wait is waiting on another
|
|
813
|
+
workspace's build of the same fingerprint; install
|
|
814
|
+
includes waiting for the device to boot.
|
|
815
|
+
startedAt when the run started; phaseStartedAt when its phase did
|
|
816
|
+
outcome "cold" once the run reached prebuild, pods or compile,
|
|
817
|
+
"hit" once it reached install without them. Before
|
|
818
|
+
that, the outcome of this project's most recent run.
|
|
819
|
+
expectedMs the median duration of this project's last successful
|
|
820
|
+
runs with that outcome on that platform, or null with
|
|
821
|
+
no history
|
|
822
|
+
expectedPhaseMs the median duration of this phase in those runs, or null
|
|
823
|
+
basis how many runs the medians come from (at most 10)
|
|
824
|
+
|
|
825
|
+
Plain \`stim status\` prints the same as one line per workspace:
|
|
826
|
+
|
|
827
|
+
build: ios compile, 1m10s elapsed -- about 3 min left (median of 4 cold runs)
|
|
828
|
+
|
|
829
|
+
There is no completion fraction: a compile's log volume depends on what
|
|
830
|
+
is already built, so it does not measure progress.`
|
|
831
|
+
},
|
|
832
|
+
stats: {
|
|
833
|
+
summary: "the stats payload, what counts as a run, hit, miss and failed, timeSavedMs, the heartbeat estimate",
|
|
834
|
+
body: () => ` stim stats --json
|
|
713
835
|
|
|
714
836
|
{ "version": 1,
|
|
715
837
|
"project": { "key": "<path>", "ios": <bucket|null>,
|
|
@@ -738,8 +860,13 @@ HOW A RUN IS COUNTED (\`stats\`)
|
|
|
738
860
|
as a hit and is credited nothing: the compile it skipped was paid for in the
|
|
739
861
|
wait, and with no cold run recorded for this project and platform there is
|
|
740
862
|
nothing to compare against, so it credits nothing either. The saved figure
|
|
741
|
-
is therefore an ESTIMATE and is printed as one.
|
|
742
|
-
|
|
863
|
+
is therefore an ESTIMATE and is printed as one. The file is
|
|
864
|
+
$STIM_HOME/stats.json (see \`guide lifecycle builds\`). Beside the
|
|
865
|
+
aggregates it keeps the last 10 successful runs per project, platform and
|
|
866
|
+
outcome (hit or cold) that did not wait for another workspace's build: each
|
|
867
|
+
one's duration and per-phase durations. \`stim status\` estimates a running
|
|
868
|
+
build from them (see \`guide facts status\`); \`stats --json\` does not
|
|
869
|
+
print them.
|
|
743
870
|
|
|
744
871
|
A run also keeps the duration of its own two long phases in that bucket:
|
|
745
872
|
the build phase of a miss that compiled (lastColdBuildMs) and the last
|
|
@@ -758,12 +885,14 @@ HOW A RUN IS COUNTED (\`stats\`)
|
|
|
758
885
|
and a warm run has no long phase to size. That read takes no lock and
|
|
759
886
|
ignores what it cannot read, so nothing about statistics can change a
|
|
760
887
|
run's outcome.`
|
|
761
|
-
}
|
|
762
888
|
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
//#endregion
|
|
892
|
+
//#region src/guide/metro.ts
|
|
893
|
+
var metro_default = {
|
|
894
|
+
summary: "The dev server: `stim start`, the supervisor, and starting your own",
|
|
895
|
+
body: () => `THE DEV SERVER
|
|
767
896
|
|
|
768
897
|
stim start
|
|
769
898
|
stim start --remote # prepare Metro for a remote device
|
|
@@ -777,7 +906,8 @@ another worktree's bundler.
|
|
|
777
906
|
--json one line of facts on stdout, everything else on stderr:
|
|
778
907
|
{ port, supervisorPid, mode, logsDir, alreadyRunning }
|
|
779
908
|
--wait <seconds> how long to wait for server and remote tunnel readiness
|
|
780
|
-
(default 60 for each)
|
|
909
|
+
(default 60 for each). Unlike ios/android/device lock
|
|
910
|
+
--wait, it does not wait for a device lease.
|
|
781
911
|
--remote expose Metro for a remote device
|
|
782
912
|
|
|
783
913
|
Plain \`stim start\` is local and does not create a public tunnel. Remote intent
|
|
@@ -825,7 +955,8 @@ REMOTE DEVICE BACKENDS
|
|
|
825
955
|
The EAS backend needs eas-cli and an account with EAS Simulator access. An
|
|
826
956
|
EAS session is billable. EAS does not inherit the proxy credentials. Always
|
|
827
957
|
tear the session down: \`stop\`, \`worktree remove\`, and \`gc --delete\`
|
|
828
|
-
can end sessions that Stim proves it owns.
|
|
958
|
+
can end sessions that Stim proves it owns. \`stim status\` lists each
|
|
959
|
+
recorded session with its preview URL (see \`guide facts\`).
|
|
829
960
|
|
|
830
961
|
IDEMPOTENT
|
|
831
962
|
A healthy dev server on the reserved port is a no-op: \`start\` prints the
|
|
@@ -904,12 +1035,15 @@ STARTING YOUR OWN BUNDLER STILL WORKS
|
|
|
904
1035
|
and finding output is back to redirecting it to a file yourself. Prefer
|
|
905
1036
|
\`start\`.
|
|
906
1037
|
|
|
907
|
-
\`stop\` leaves an externally started server running
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1038
|
+
\`stop\` leaves an externally started server running and keeps the port
|
|
1039
|
+
reserved while it answers from this project. Stop it with the tool that
|
|
1040
|
+
started it.`
|
|
1041
|
+
};
|
|
1042
|
+
//#endregion
|
|
1043
|
+
//#region src/guide/ports.ts
|
|
1044
|
+
var ports_default = {
|
|
1045
|
+
summary: "Workspace ports for web and API servers that Stim does not manage",
|
|
1046
|
+
body: () => `NAMED SERVER PORTS
|
|
913
1047
|
|
|
914
1048
|
If Stim is not installed globally, replace stim with npx stim.
|
|
915
1049
|
|
|
@@ -961,10 +1095,12 @@ cleanup: versions without ports do not know about named allocations.
|
|
|
961
1095
|
|
|
962
1096
|
A shared API does not get a shared reservation. Pass its port by environment
|
|
963
1097
|
instead of allocating a separate label in every worktree.`
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
1098
|
+
};
|
|
1099
|
+
//#endregion
|
|
1100
|
+
//#region src/guide/logs.ts
|
|
1101
|
+
var logs_default = {
|
|
1102
|
+
summary: "Querying the merged NDJSON timeline, and what --errors means",
|
|
1103
|
+
body: () => `LOGS
|
|
968
1104
|
|
|
969
1105
|
stim logs [filters]
|
|
970
1106
|
|
|
@@ -972,6 +1108,11 @@ Reads every *.ndjson file in the global workspace logs directory, merges them in
|
|
|
972
1108
|
ordered by timestamp, prints what matches, and EXITS. The file set is
|
|
973
1109
|
discovered, not enumerated.
|
|
974
1110
|
|
|
1111
|
+
metro.ndjson, client.ndjson and device.ndjson are size-capped. At about 8 MiB a file
|
|
1112
|
+
becomes <name>.1, replacing the previous .1, and a new file starts. Queries read
|
|
1113
|
+
both generations, so the oldest records drop off first. History and --since
|
|
1114
|
+
reach back only as far as those records.
|
|
1115
|
+
|
|
975
1116
|
EXIT 0 MEANS THE QUERY SUCCEEDED, whether or not records matched. A clean
|
|
976
1117
|
\`stim logs --errors\` check requires exit code 0 AND no matching errors in
|
|
977
1118
|
captured logs. A workspace that has never produced a timeline refuses with
|
|
@@ -1063,7 +1204,7 @@ FLAGS
|
|
|
1063
1204
|
records; use its printed --tail value to include all records before grouping.
|
|
1064
1205
|
To read the complete timeline without the default error-record limit:
|
|
1065
1206
|
stim logs --source all
|
|
1066
|
-
This includes all sources, levels and history, not just the latest errors;
|
|
1207
|
+
This includes all sources, levels and retained history, not just the latest errors;
|
|
1067
1208
|
add --since, --level or --grep to narrow it. --source all selects sources,
|
|
1068
1209
|
not stack depth. For untouched captured records use:
|
|
1069
1210
|
stim logs --source all --json
|
|
@@ -1245,38 +1386,41 @@ WHAT WRITES WHAT
|
|
|
1245
1386
|
|
|
1246
1387
|
A collector is killed and replaced on the next \`ios\` / \`android\` run for
|
|
1247
1388
|
that platform, and reaped by \`stop\`.`
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1389
|
+
};
|
|
1390
|
+
//#endregion
|
|
1391
|
+
//#region src/guide/errors.ts
|
|
1392
|
+
const errors = {
|
|
1393
|
+
summary: "Every refusal Stim can print: an index of codes, and one section for each",
|
|
1394
|
+
sectionHint: "<CODE>",
|
|
1395
|
+
preamble: () => `WHAT STIM REFUSES, AND WHY
|
|
1396
|
+
|
|
1397
|
+
Every refusal listed here carries a stable CODE, whichever command prints it.
|
|
1398
|
+
Branch on the code, never on the message.`,
|
|
1399
|
+
sections: {
|
|
1400
|
+
STIM_EAS_BUILD_MISSING: {
|
|
1401
|
+
summary: "no completed EAS development build matches; build only with session authorization",
|
|
1402
|
+
separator: "--- EAS BUILD CODES (`ios --eas-profile` / `android --eas-profile`) ---",
|
|
1403
|
+
body: () => `STIM_EAS_BUILD_MISSING
|
|
1260
1404
|
No compatible build matches the selected EAS project, profile, platform and
|
|
1261
1405
|
native fingerprint. No device was acquired and no local or cloud build was
|
|
1262
1406
|
started. The remedy prints the exact npx eas-cli build command. Check session
|
|
1263
1407
|
authorization for its potential cost before running it, then retry Stim.
|
|
1264
1408
|
See stim guide lifecycle eas.`
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1409
|
+
},
|
|
1410
|
+
STIM_EAS_UNAVAILABLE: {
|
|
1411
|
+
summary: "EAS lookup/download failed, or another run holds the artifact claim",
|
|
1412
|
+
body: () => `STIM_EAS_UNAVAILABLE
|
|
1269
1413
|
EAS CLI is unavailable, a profile/fingerprint/list/download operation failed,
|
|
1270
1414
|
the response could not be validated, or another run holds the artifact claim.
|
|
1271
1415
|
Follow the printed remedy: inspect the named EAS command or retry once the
|
|
1272
1416
|
holder finishes. This is not proof that a build is missing. No native build
|
|
1273
1417
|
is started. See stim guide lifecycle eas.`
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1418
|
+
},
|
|
1419
|
+
STIM_WORKSPACE_STATE: {
|
|
1420
|
+
summary: "$STIM_HOME/workspaces could not be prepared, or the digest directory belongs to another project",
|
|
1421
|
+
aliases: ["STIM_WORKSPACE_COLLISION"],
|
|
1422
|
+
separator: "--- BUILD-PATH CODES (`stim ios` / `stim android`) ---",
|
|
1423
|
+
body: () => `STIM_WORKSPACE_STATE / STIM_WORKSPACE_COLLISION
|
|
1280
1424
|
Stim could not prepare this project's global workspace directory under
|
|
1281
1425
|
$STIM_HOME/workspaces. Check that STIM_HOME is writable and has free
|
|
1282
1426
|
space. An EPERM on a directory the user CAN write is a sandbox, not a
|
|
@@ -1284,10 +1428,10 @@ code, never on the message.`,
|
|
|
1284
1428
|
readable-name-plus-digest directory already has a workspace.json for a
|
|
1285
1429
|
different canonical project path; do not overwrite it until you identify
|
|
1286
1430
|
which workspace owns it.`
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1431
|
+
},
|
|
1432
|
+
STIM_NO_METRO: {
|
|
1433
|
+
summary: "nothing provably this workspace's dev server holds the reserved port (ios, android, reload)",
|
|
1434
|
+
body: () => `STIM_NO_METRO
|
|
1291
1435
|
Nothing that could be proven to be THIS workspace's dev server holds the
|
|
1292
1436
|
reserved port -- or no port is reserved at all. The gate fires in about a
|
|
1293
1437
|
second, before the device is even booted, rather than after four minutes of
|
|
@@ -1302,26 +1446,26 @@ code, never on the message.`,
|
|
|
1302
1446
|
|
|
1303
1447
|
Reload requires the recorded launch's port to be this workspace's live
|
|
1304
1448
|
Metro. It refuses a missing, changed, unresponsive, or foreign port.`
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1449
|
+
},
|
|
1450
|
+
STIM_NO_FINGERPRINT: {
|
|
1451
|
+
summary: "@expo/fingerprint produced no hash, so the shared cache cannot be addressed",
|
|
1452
|
+
body: () => `STIM_NO_FINGERPRINT
|
|
1309
1453
|
\`@expo/fingerprint\` produced no hash, so the shared build cache cannot be
|
|
1310
1454
|
addressed. Stim uses its declared @expo/fingerprint dependency directly,
|
|
1311
1455
|
independently of the target project's package graph. This is a refusal
|
|
1312
1456
|
rather than a silent full build because an unaddressable cache means every
|
|
1313
1457
|
workspace on the commit compiles from scratch, forever.`
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1458
|
+
},
|
|
1459
|
+
STIM_PREBUILD_FAILED: {
|
|
1460
|
+
summary: "expo prebuild could not generate the native directory",
|
|
1461
|
+
body: () => `STIM_PREBUILD_FAILED
|
|
1318
1462
|
\`expo prebuild\` could not generate the missing native directory. The
|
|
1319
1463
|
extracted output is above the code; the transcript is in
|
|
1320
1464
|
the global workspace logs/build-<platform>.ndjson file.`
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1465
|
+
},
|
|
1466
|
+
STIM_DEPS_FAILED: {
|
|
1467
|
+
summary: "pod install or gradle sync failed; the bundler ladder and BUNDLE_FROZEN",
|
|
1468
|
+
body: () => `STIM_DEPS_FAILED
|
|
1325
1469
|
\`pod install\` (iOS) or the gradle dependency sync (Android) failed. On iOS
|
|
1326
1470
|
this runs only when Podfile.lock and Pods/Manifest.lock disagree, or Pods is
|
|
1327
1471
|
absent -- which is exactly what a carried worktree produces.
|
|
@@ -1349,10 +1493,10 @@ code, never on the message.`,
|
|
|
1349
1493
|
\`yarn install\`, \`bun install\`, \`npm ci\`) or that same pod ladder. The
|
|
1350
1494
|
message names the command, quotes its last lines, and nothing is copied: fix
|
|
1351
1495
|
the source checkout, then warm again.`
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1496
|
+
},
|
|
1497
|
+
STIM_BUILD_FAILED: {
|
|
1498
|
+
summary: "xcodebuild or gradle failed; the two Android APK refusals; a damaged compilation-cache object",
|
|
1499
|
+
body: () => `STIM_BUILD_FAILED
|
|
1356
1500
|
xcodebuild or gradle failed. The EXTRACTED diagnostics are printed (capped),
|
|
1357
1501
|
not the transcript. Read the log path on the next line for the rest.
|
|
1358
1502
|
Two Android refusals share this code without gradle itself failing:
|
|
@@ -1383,10 +1527,10 @@ code, never on the message.`,
|
|
|
1383
1527
|
object, and upgrading the CLI does not clear it. Empty that one cache with
|
|
1384
1528
|
\`gc --delete --cache "compilation cache"\`, then build again. The next
|
|
1385
1529
|
build is a cold one.`
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1530
|
+
},
|
|
1531
|
+
STIM_PATH_TOO_LONG: {
|
|
1532
|
+
summary: "Windows only: the project root leaves no room for the NDK object paths ninja must open",
|
|
1533
|
+
body: () => `STIM_PATH_TOO_LONG (android, Windows only)
|
|
1390
1534
|
The NDK's ninja is not long-path aware, so every CMake object path has to
|
|
1391
1535
|
stay under Windows' MAX_PATH. React Native's codegen objects are named
|
|
1392
1536
|
after their mangled absolute source path, so each carries the project root
|
|
@@ -1402,10 +1546,10 @@ code, never on the message.`,
|
|
|
1402
1546
|
preflight does not inspect that configured path and may refuse it too.
|
|
1403
1547
|
\`doctor --platform android\` reports the same root as a finding for the
|
|
1404
1548
|
emulator's ABI.`
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1549
|
+
},
|
|
1550
|
+
fallbacks: {
|
|
1551
|
+
summary: "release cache-hit notes that are not codes: swap failure, asset gate, uninstall, device fallbacks",
|
|
1552
|
+
body: () => `FALLBACK NOTES THAT ARE NOT CODES (release cache hits)
|
|
1409
1553
|
On a release cache hit Stim regenerates this workspace's JS bundle into a
|
|
1410
1554
|
COPY of the cached artifact before installing it -- \`ios --configuration
|
|
1411
1555
|
Release\` into a copy of the .app, \`android --variant ...Release\` into a
|
|
@@ -1471,10 +1615,10 @@ code, never on the message.`,
|
|
|
1471
1615
|
The same refusal on a FRESHLY BUILT app is a code (STIM_NO_PROFILE,
|
|
1472
1616
|
STIM_PROFILE_MISMATCH, STIM_NO_SIGNING_IDENTITY), not a note: building again
|
|
1473
1617
|
would produce the same app and refuse again.`
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1618
|
+
},
|
|
1619
|
+
STIM_BUILD_WAIT_TIMEOUT: {
|
|
1620
|
+
summary: "waited ~90 minutes for another workspace's build of the same fingerprint",
|
|
1621
|
+
body: () => `STIM_BUILD_WAIT_TIMEOUT
|
|
1478
1622
|
This run was waiting for ANOTHER workspace's build of the same fingerprint
|
|
1479
1623
|
(see \`guide lifecycle concurrency\`), and no artifact arrived within ~90
|
|
1480
1624
|
minutes.
|
|
@@ -1483,10 +1627,10 @@ code, never on the message.`,
|
|
|
1483
1627
|
may have failed. The message names the current pid and lock directory:
|
|
1484
1628
|
check the pid, and if it is not really building, remove that directory and
|
|
1485
1629
|
run the command again.`
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1630
|
+
},
|
|
1631
|
+
STIM_CLAIM_REFUSED: {
|
|
1632
|
+
summary: "an ownership claim blocks the operation; inspect its holder before removing an unresolved claim",
|
|
1633
|
+
body: () => `STIM_CLAIM_REFUSED
|
|
1490
1634
|
A build lock records the holder's process IDENTITY, not just its pid, so a
|
|
1491
1635
|
recycled pid reads as a gone builder rather than a live one, and a builder
|
|
1492
1636
|
busy in a long \`simctl\` or gradle call reads as live rather than as stale.
|
|
@@ -1524,10 +1668,10 @@ code, never on the message.`,
|
|
|
1524
1668
|
Legacy inline \`deletionClaim\` fields in config.json have no process
|
|
1525
1669
|
identity and require separate manual inspection; \`stim guide lifecycle pool\`
|
|
1526
1670
|
describes their field-only recovery.`
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1671
|
+
},
|
|
1672
|
+
STIM_CLAIM_UNAVAILABLE: {
|
|
1673
|
+
summary: "a process identity or warm claim store is unavailable, so the protected operation refuses",
|
|
1674
|
+
body: () => `STIM_CLAIM_UNAVAILABLE
|
|
1531
1675
|
Every ownership claim records the holder's process identity, captured through
|
|
1532
1676
|
the \`unique-pid\` native module. This code is that capture failing: no
|
|
1533
1677
|
prebuilt binary for this platform and architecture, or the OS refusing to
|
|
@@ -1547,10 +1691,10 @@ code, never on the message.`,
|
|
|
1547
1691
|
access to the existing claim store, checking parent permissions, symlink
|
|
1548
1692
|
targets, mount access and sandbox rules, then retry. Do not switch STIM_HOME to evade a claim:
|
|
1549
1693
|
concurrent runs must coordinate through the same store.`
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1694
|
+
},
|
|
1695
|
+
STIM_INSTALL_FAILED: {
|
|
1696
|
+
summary: "simctl, adb, or devicectl refused the artifact; the one signer-conflict retry",
|
|
1697
|
+
body: () => `STIM_INSTALL_FAILED
|
|
1554
1698
|
The artifact built or came from cache, but \`simctl install\` / \`adb install\` /
|
|
1555
1699
|
\`devicectl device install app\` refused it. A signature or architecture
|
|
1556
1700
|
mismatch, or a full device.
|
|
@@ -1569,10 +1713,10 @@ code, never on the message.`,
|
|
|
1569
1713
|
the flavor's id and not the gradle namespace -- and gives you the
|
|
1570
1714
|
\`adb -s <serial> uninstall <applicationId>\` that clears it. Re-running after
|
|
1571
1715
|
that is a cache hit: one install, no build.`
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1716
|
+
},
|
|
1717
|
+
STIM_LAUNCH_FAILED: {
|
|
1718
|
+
summary: "installed but would not start; the developer-trust tap on a phone",
|
|
1719
|
+
body: () => `STIM_LAUNCH_FAILED
|
|
1576
1720
|
Installed, but the app would not start. On Android this usually means no
|
|
1577
1721
|
launchable activity resolved.
|
|
1578
1722
|
On a local iOS simulator, a timed-out launch can mean the simulator cannot
|
|
@@ -1590,41 +1734,41 @@ code, never on the message.`,
|
|
|
1590
1734
|
Trust, then run the command again. It is a per-developer-certificate tap, not
|
|
1591
1735
|
a per-build one -- but an uninstall clears it, including the one Stim's own
|
|
1592
1736
|
signer-conflict retry performs.`
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1737
|
+
},
|
|
1738
|
+
STIM_NO_SCHEME: {
|
|
1739
|
+
summary: "Xcode schemes unavailable or no unambiguous app scheme in ios/",
|
|
1740
|
+
body: () => `STIM_NO_SCHEME
|
|
1597
1741
|
Stim could not list or select an app scheme in ios/. Share the intended app
|
|
1598
1742
|
scheme so xcodebuild can see it. Select an available exact name with
|
|
1599
1743
|
\`stim ios --scheme <name>\`. An unknown explicit name prints available choices.
|
|
1600
1744
|
Without an explicit selector, a workspace
|
|
1601
1745
|
name match wins; otherwise Stim accepts a sole non-test scheme, or a listed
|
|
1602
1746
|
scheme matching app.json. Unmatched ambiguous schemes are refused.`
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1747
|
+
},
|
|
1748
|
+
STIM_NO_PROFILE: {
|
|
1749
|
+
summary: "no or undecodable embedded.mobileprovision; build once from Xcode",
|
|
1750
|
+
separator: "--- iOS SIGNING CODES (`ios --device`, and only there) ---",
|
|
1751
|
+
context: `A simulator build needs no signature, which is why none of these can fire on
|
|
1608
1752
|
the normal path. A device build carries one, and Stim re-seals any bundle it
|
|
1609
1753
|
modifies with the identity the bundle already names -- so it checks, before
|
|
1610
1754
|
spending a build or a bundle, that the check can succeed.`,
|
|
1611
|
-
|
|
1755
|
+
body: () => `STIM_NO_PROFILE
|
|
1612
1756
|
The built or cached .app has no embedded.mobileprovision, or
|
|
1613
|
-
\`
|
|
1757
|
+
\`openssl smime\` could not decode the one it has. The first means the build
|
|
1614
1758
|
produced an unsigned app -- almost always a simulator-sliced artifact.
|
|
1615
1759
|
Set a team and a Development profile for the target's configuration in
|
|
1616
1760
|
Xcode > Signing & Capabilities, then BUILD ONCE FROM XCODE to install the
|
|
1617
1761
|
profile. Stim will not do that step: registering a device or minting a
|
|
1618
1762
|
profile changes your Apple Developer account, so Stim never passes
|
|
1619
1763
|
-allowProvisioningUpdates.`
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1764
|
+
},
|
|
1765
|
+
STIM_PROFILE_MISMATCH: {
|
|
1766
|
+
summary: "the profile is expired, has no ProvisionedDevices, or does not name this UDID",
|
|
1767
|
+
context: `A simulator build needs no signature, which is why none of these can fire on
|
|
1624
1768
|
the normal path. A device build carries one, and Stim re-seals any bundle it
|
|
1625
1769
|
modifies with the identity the bundle already names -- so it checks, before
|
|
1626
1770
|
spending a build or a bundle, that the check can succeed.`,
|
|
1627
|
-
|
|
1771
|
+
body: () => `STIM_PROFILE_MISMATCH
|
|
1628
1772
|
The profile inside the app cannot admit this phone. Three shapes, and the
|
|
1629
1773
|
message names which one and the profile type it found:
|
|
1630
1774
|
- it expired, or carries no ExpirationDate at all;
|
|
@@ -1638,14 +1782,14 @@ spending a build or a bundle, that the check can succeed.`,
|
|
|
1638
1782
|
With --eas-profile, follow the EAS device:create and build commands in the
|
|
1639
1783
|
refusal instead. Registration, signing changes and cloud builds need session
|
|
1640
1784
|
authorization. See stim guide lifecycle eas.`
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1785
|
+
},
|
|
1786
|
+
STIM_NO_SIGNING_IDENTITY: {
|
|
1787
|
+
summary: "no single keychain identity resolves; ios.signingIdentitySha1 for two certificates",
|
|
1788
|
+
context: `A simulator build needs no signature, which is why none of these can fire on
|
|
1645
1789
|
the normal path. A device build carries one, and Stim re-seals any bundle it
|
|
1646
1790
|
modifies with the identity the bundle already names -- so it checks, before
|
|
1647
1791
|
spending a build or a bundle, that the check can succeed.`,
|
|
1648
|
-
|
|
1792
|
+
body: () => `STIM_NO_SIGNING_IDENTITY
|
|
1649
1793
|
No single keychain identity could be resolved to re-seal with. Either
|
|
1650
1794
|
\`security find-identity -v -p codesigning\` lists nothing, or the identity
|
|
1651
1795
|
the artifact's own profile names is absent, or two certificates share that
|
|
@@ -1653,14 +1797,14 @@ spending a build or a bundle, that the check can succeed.`,
|
|
|
1653
1797
|
Open Xcode > Settings > Accounts and download your certificates, or unlock
|
|
1654
1798
|
the login keychain with \`security unlock-keychain\`. For the two-certificate
|
|
1655
1799
|
case, set ios.signingIdentitySha1 to the SHA-1 hash beside the one you want.`
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1800
|
+
},
|
|
1801
|
+
STIM_CODESIGN_FAILED: {
|
|
1802
|
+
summary: "codesign failed on the modified copy; the cache entry is untouched and the run builds fresh",
|
|
1803
|
+
context: `A simulator build needs no signature, which is why none of these can fire on
|
|
1660
1804
|
the normal path. A device build carries one, and Stim re-seals any bundle it
|
|
1661
1805
|
modifies with the identity the bundle already names -- so it checks, before
|
|
1662
1806
|
spending a build or a bundle, that the check can succeed.`,
|
|
1663
|
-
|
|
1807
|
+
body: () => `STIM_CODESIGN_FAILED
|
|
1664
1808
|
\`codesign --force --sign\` or \`codesign --verify --strict\` exited non-zero
|
|
1665
1809
|
on the modified copy. The verbatim codesign stderr is quoted, because it is
|
|
1666
1810
|
the answer: a locked login keychain reports errSecInternalComponent, an
|
|
@@ -1668,14 +1812,14 @@ spending a build or a bundle, that the check can succeed.`,
|
|
|
1668
1812
|
and confirm exactly one identity matches the name. The cache entry itself is
|
|
1669
1813
|
never modified -- the failure is on a temporary copy, and the run builds
|
|
1670
1814
|
fresh.`
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1815
|
+
},
|
|
1816
|
+
STIM_NO_LAN_ADDRESS: {
|
|
1817
|
+
summary: "the Mac has no non-internal IPv4 interface; a tunnel cannot help a phone",
|
|
1818
|
+
separator: "--- iOS DEVICE DEBUG REACHABILITY CODES (`ios --device` in Debug) ---",
|
|
1819
|
+
context: `A phone does not share the host's loopback and USB carries no reverse forward,
|
|
1676
1820
|
so a Debug run on one is wired to a LAN origin instead of localhost. Both codes
|
|
1677
1821
|
fire BEFORE the build, because a refusal that costs a build is a bad refusal.`,
|
|
1678
|
-
|
|
1822
|
+
body: () => `STIM_NO_LAN_ADDRESS
|
|
1679
1823
|
This Mac reports no non-internal IPv4 interface, so there is no address to
|
|
1680
1824
|
give the phone: it is offline, or on nothing but utun/awdl/bridge. Join a
|
|
1681
1825
|
Wi-Fi or Ethernet network, or connect this Mac by cable, and run again.
|
|
@@ -1684,13 +1828,13 @@ fire BEFORE the build, because a refusal that costs a build is a bad refusal.`,
|
|
|
1684
1828
|
ip.txt is read by RCTBundleURLProvider, which prefixes the scheme. A tunnel
|
|
1685
1829
|
cannot be expressed to a phone, so --device ignores metro.publicUrl,
|
|
1686
1830
|
metro.tunnel and metro.ngrokUrl and says so when one is set.`
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1831
|
+
},
|
|
1832
|
+
STIM_LAN_METRO_UNREACHABLE: {
|
|
1833
|
+
summary: "the LAN origin did not answer as this workspace's Metro; ios.lanHost on a multi-NIC Mac",
|
|
1834
|
+
context: `A phone does not share the host's loopback and USB carries no reverse forward,
|
|
1691
1835
|
so a Debug run on one is wired to a LAN origin instead of localhost. Both codes
|
|
1692
1836
|
fire BEFORE the build, because a refusal that costs a build is a bad refusal.`,
|
|
1693
|
-
|
|
1837
|
+
body: () => `STIM_LAN_METRO_UNREACHABLE
|
|
1694
1838
|
The chosen LAN origin did not answer as THIS workspace's Metro: no answer, a
|
|
1695
1839
|
5xx, or a dev server that is not this one -- the message says which.
|
|
1696
1840
|
\`stim start\` prints the port it reserved. On a Mac with several interfaces
|
|
@@ -1700,12 +1844,12 @@ fire BEFORE the build, because a refusal that costs a build is a bad refusal.`,
|
|
|
1700
1844
|
routes a host connection to its own address over loopback, so the gate passes
|
|
1701
1845
|
through a firewall that will block the phone. That evidence only ever arrives
|
|
1702
1846
|
from the phone's own bundle request, which is what \`launched\` reports.`
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1847
|
+
},
|
|
1848
|
+
unverified: {
|
|
1849
|
+
summary: "launched: \"unverified\" with the Local Network path reason, and the routed recovery",
|
|
1850
|
+
context: `A phone does not share the host's loopback and USB carries no reverse forward,
|
|
1707
1851
|
so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
1708
|
-
|
|
1852
|
+
body: () => `LAUNCH UNVERIFIED, LOCAL NETWORK NOT GRANTED (not a code -- a routed remedy)
|
|
1709
1853
|
An app that has not been granted Local Network reaches nothing on the LAN,
|
|
1710
1854
|
and CFNetwork reports each attempt as NSURLErrorDomain -1009 "The Internet
|
|
1711
1855
|
connection appears to be offline." with the path reason
|
|
@@ -1791,17 +1935,18 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1791
1935
|
General > VPN & Device Management) is refused to automation by the same gate
|
|
1792
1936
|
that refuses the app, agent-device's own runner included, so its remedy is
|
|
1793
1937
|
"ask the user" and nothing else. An uninstall clears both.`
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1938
|
+
},
|
|
1939
|
+
STIM_NO_DEVICE: {
|
|
1940
|
+
summary: "no usable phone, or the owned simulator or emulator could not be created or booted",
|
|
1941
|
+
separator: "--- DEVICE AND CAPACITY CODES ---",
|
|
1942
|
+
body: () => `STIM_NO_DEVICE
|
|
1799
1943
|
With \`--device\`, no physical device answered the selection: none connected,
|
|
1800
1944
|
a named serial/UDID that is not connected, several connected with none named
|
|
1801
1945
|
(the refusal lists them), or one that is connected but unusable -- an
|
|
1802
1946
|
unauthorized Android device, or an iPhone that is unpaired or has Developer
|
|
1803
|
-
Mode off
|
|
1804
|
-
into existence: fix the cable, the
|
|
1947
|
+
Mode off, over a cable or over Wi-Fi alike. Hardware is never created or
|
|
1948
|
+
booted, so there is nothing to retry into existence: fix the cable, the
|
|
1949
|
+
trust prompt, or Developer Mode.
|
|
1805
1950
|
Otherwise the owned simulator/emulator could not be created or could not
|
|
1806
1951
|
reach a booted state. \`stim doctor\` checks the toolchain; \`stim status\` says what
|
|
1807
1952
|
Stim thinks it owns. Re-running the command creates a fresh owned device
|
|
@@ -1851,10 +1996,10 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1851
1996
|
not silently boot a different one. Reap it (\`worktree remove\`, or
|
|
1852
1997
|
\`gc --delete\`) and run \`stim ios\` again to create the requested model.
|
|
1853
1998
|
That loses the old sim's app state.`
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1999
|
+
},
|
|
2000
|
+
STIM_DEVICE_BUSY: {
|
|
2001
|
+
summary: "another workspace holds the lease on that phone and the wait ran out",
|
|
2002
|
+
body: () => `STIM_DEVICE_BUSY
|
|
1858
2003
|
Only on a \`--device\` run. Another workspace holds the lease on that phone,
|
|
1859
2004
|
and the wait ran out: the message names the holder root, the device, and the
|
|
1860
2005
|
expiry as a clock time and a remaining duration, and \`--json\` adds
|
|
@@ -1868,10 +2013,25 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1868
2013
|
no token left in its \`state.json\` (its workspace directory was recreated).
|
|
1869
2014
|
The remedy for that last one is \`stim device unlock\`, which releases by
|
|
1870
2015
|
holder rather than by token.`
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
2016
|
+
},
|
|
2017
|
+
STIM_DEVICE_WIRELESS_FAILED: {
|
|
2018
|
+
summary: "an iPhone paired over Wi-Fi timed out or dropped during install or launch; use the cable",
|
|
2019
|
+
body: () => `STIM_DEVICE_WIRELESS_FAILED
|
|
2020
|
+
Only on an \`ios --device\` run whose iPhone devicectl reaches over Wi-Fi
|
|
2021
|
+
(transportType localNetwork). The \`devicectl device install app\` ran past
|
|
2022
|
+
its 15-minute Wi-Fi bound, the phone did not appear in its own process list
|
|
2023
|
+
within the 120-second Wi-Fi launch bound, or devicectl reported that the
|
|
2024
|
+
connection dropped in its own ERROR output (an app's log lines never count).
|
|
2025
|
+
The message names the transport and quotes devicectl. Connect the phone
|
|
2026
|
+
with a cable, keep it unlocked, and run the command again: a cabled phone
|
|
2027
|
+
installs over the cable. A cause devicectl names -- a locked phone, an
|
|
2028
|
+
untrusted host, Developer Mode off, full storage, the developer-trust tap --
|
|
2029
|
+
keeps STIM_INSTALL_FAILED or STIM_LAUNCH_FAILED and its own remedy, even
|
|
2030
|
+
when the step also timed out and even during a signer-conflict reinstall.`
|
|
2031
|
+
},
|
|
2032
|
+
STIM_DEVICE_LOST: {
|
|
2033
|
+
summary: "the lease was gone or re-held at the pre-install check; rerun",
|
|
2034
|
+
body: () => `STIM_DEVICE_LOST
|
|
1875
2035
|
Only on a \`--device\` run. The run held a lease, and the raise before the
|
|
1876
2036
|
install found it gone or held under another token -- another workspace took
|
|
1877
2037
|
the device in that window. The message names the new holder and its expiry.
|
|
@@ -1879,10 +2039,10 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1879
2039
|
AFTER the install has started this is not a failure: the app is already on
|
|
1880
2040
|
the phone, so the run prints one warning, continues, and reports
|
|
1881
2041
|
\`lease: null\` in \`--json\`.`
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2042
|
+
},
|
|
2043
|
+
STIM_AT_CAPACITY: {
|
|
2044
|
+
summary: "concurrency.maxDevices reached; a refusal, not a queue",
|
|
2045
|
+
body: () => `STIM_AT_CAPACITY
|
|
1886
2046
|
Only when concurrency.maxDevices is set (it is UNSET by default, so this never
|
|
1887
2047
|
fires unless you opted in). Booting a NEW owned device would exceed the cap:
|
|
1888
2048
|
the machine already has that many Stim-owned devices booted. It is a refusal, not
|
|
@@ -1893,10 +2053,10 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1893
2053
|
\`ios\` on an environment you already have is idempotent. (The build cap
|
|
1894
2054
|
behaves differently: a compile WAITS for a free slot rather than refusing.
|
|
1895
2055
|
See \`guide lifecycle concurrency\`.)`
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
2056
|
+
},
|
|
2057
|
+
STIM_BUILD_SLOT_TIMEOUT: {
|
|
2058
|
+
summary: "the maxBuilds wait gave up with every slot held by a running process",
|
|
2059
|
+
body: () => `STIM_BUILD_SLOT_TIMEOUT
|
|
1900
2060
|
Only when concurrency.maxBuilds is set. The build cap does not refuse, it
|
|
1901
2061
|
WAITS -- this code is that wait giving up: ~90 minutes elapsed and every one
|
|
1902
2062
|
of the N slots was still held by a running process, or by a holder Stim could
|
|
@@ -1910,50 +2070,50 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1910
2070
|
the message names the directory: remove the slot of a builder that is not
|
|
1911
2071
|
building, or raise concurrency.maxBuilds
|
|
1912
2072
|
(\`guide lifecycle concurrency\`).`
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
2073
|
+
},
|
|
2074
|
+
STIM_NO_REMOTE_SESSION: {
|
|
2075
|
+
summary: "the backend could not use agent-device, or metro.tunnel names an unusable provider",
|
|
2076
|
+
separator: "--- REMOTE-DEVICE CODES (`ios --remote <proxy|eas>` / `android --remote <proxy|eas>`) ---",
|
|
2077
|
+
body: () => `STIM_NO_REMOTE_SESSION
|
|
1918
2078
|
The selected backend could not use agent-device, or metro.tunnel names a
|
|
1919
2079
|
provider or mode this workspace cannot use (e.g. "expo" on a bare RN
|
|
1920
2080
|
project). The remedy line says which. Nothing was created yet.`
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2081
|
+
},
|
|
2082
|
+
STIM_REMOTE_PROXY_CONFIG: {
|
|
2083
|
+
summary: "--remote proxy needs AGENT_DEVICE_DAEMON_BASE_URL and AGENT_DEVICE_DAEMON_AUTH_TOKEN",
|
|
2084
|
+
body: () => `STIM_REMOTE_PROXY_CONFIG
|
|
1925
2085
|
\`--remote proxy\` requires AGENT_DEVICE_DAEMON_BASE_URL and
|
|
1926
2086
|
AGENT_DEVICE_DAEMON_AUTH_TOKEN. These variables provide credentials after
|
|
1927
2087
|
proxy is selected. They never select the backend.`
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
2088
|
+
},
|
|
2089
|
+
STIM_REMOTE_EAS_UNAVAILABLE: {
|
|
2090
|
+
summary: "--remote eas needs eas-cli",
|
|
2091
|
+
body: () => `STIM_REMOTE_EAS_UNAVAILABLE
|
|
1932
2092
|
\`--remote eas\` requires eas-cli. Proxy environment variables do not change
|
|
1933
2093
|
this selection and are not passed to EAS.`
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2094
|
+
},
|
|
2095
|
+
STIM_REMOTE_PLATFORM_MISMATCH: {
|
|
2096
|
+
summary: "the recorded remote session belongs to the other platform; stop, then rerun",
|
|
2097
|
+
body: () => `STIM_REMOTE_PLATFORM_MISMATCH
|
|
1938
2098
|
This workspace already has a recorded remote session, and it belongs to the
|
|
1939
2099
|
OTHER platform ("Session <id> belongs to android, not ios"). A workspace
|
|
1940
2100
|
holds one remote session, and Stim will not end the recorded one to make
|
|
1941
2101
|
room -- it may be mid-run for whoever started it. Run \`stim stop\` for this
|
|
1942
2102
|
workspace, then re-run with the platform you want. Nothing was created here.`
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2103
|
+
},
|
|
2104
|
+
STIM_REMOTE_SESSION_STATE: {
|
|
2105
|
+
summary: "the EAS session was created but its state could not be recorded, so Stim stopped it",
|
|
2106
|
+
body: () => `STIM_REMOTE_SESSION_STATE
|
|
1947
2107
|
The EAS session was created and is healthy, but recording it in this
|
|
1948
2108
|
workspace's state failed (an unwritable STIM_HOME, a full disk). A session
|
|
1949
2109
|
nothing references is a session nothing will ever stop, so Stim stopped the
|
|
1950
2110
|
one it had just created and removed its ownership claim before reporting:
|
|
1951
2111
|
this code means nothing is running and nothing is still billing. Repair the
|
|
1952
2112
|
state storage the message names, then run the remote command again.`
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
2113
|
+
},
|
|
2114
|
+
STIM_REMOTE_SESSION_CLEANUP: {
|
|
2115
|
+
summary: "Stim could not prove an EAS session ended; eas simulator:stop --id",
|
|
2116
|
+
body: () => `STIM_REMOTE_SESSION_CLEANUP
|
|
1957
2117
|
Stim tried to end an EAS session and could not PROVE it ended: \`eas
|
|
1958
2118
|
simulator:stop\` failed, or its output did not confirm the stop, or the
|
|
1959
2119
|
session stopped but its claim in the machine ledger could not be removed.
|
|
@@ -1962,10 +2122,10 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1962
2122
|
\`eas simulator:stop --id <id>\` -- and for a ledger that outlived its
|
|
1963
2123
|
session, the ledger path to repair. The same code covers a recorded session
|
|
1964
2124
|
that could not be verified before replacement: inspect it, then \`stim stop\`.`
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
2125
|
+
},
|
|
2126
|
+
STIM_REMOTE_METRO_WRONG: {
|
|
2127
|
+
summary: "the tunnel reaches a Metro that is not this workspace's",
|
|
2128
|
+
body: () => `STIM_REMOTE_METRO_WRONG
|
|
1969
2129
|
The gate that proves a tunnel still reaches THIS workspace's Metro failed --
|
|
1970
2130
|
before a session or a build, whether the tunnel is Expo's own, one Stim
|
|
1971
2131
|
started (metro.tunnel: cloudflared/ngrok/auto), or a named metro.publicUrl.
|
|
@@ -1974,39 +2134,39 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
1974
2134
|
port), and it now serves ANOTHER workspace's dev server -- healthy, and
|
|
1975
2135
|
wrong. Re-run \`stim start\` (it prints the port it reserved) and, for a
|
|
1976
2136
|
manual tunnel, rebuild it against that port.`
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2137
|
+
},
|
|
2138
|
+
STIM_REMOTE_METRO_UNREACHABLE: {
|
|
2139
|
+
summary: "a remote start could not create its managed tunnel or tell the device where Metro is",
|
|
2140
|
+
body: () => `STIM_REMOTE_METRO_UNREACHABLE
|
|
1981
2141
|
A remote start could not create its selected managed tunnel, or the device
|
|
1982
2142
|
could not be told where Metro is. Follows the same remedy as
|
|
1983
2143
|
STIM_NO_REMOTE_SESSION's tunnel guidance -- set metro.tunnel, or use
|
|
1984
2144
|
metro.publicUrl for an existing endpoint.`
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2145
|
+
},
|
|
2146
|
+
STIM_RELOAD_AMBIGUOUS: {
|
|
2147
|
+
summary: "both owned apps are live; name the platform",
|
|
2148
|
+
separator: "--- RELOAD CODES (`stim reload [ios|android]`) ---",
|
|
2149
|
+
body: () => `STIM_RELOAD_AMBIGUOUS
|
|
1990
2150
|
Both owned apps are live. Name ios or android; Stim never guesses.`
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2151
|
+
},
|
|
2152
|
+
STIM_RELOAD_RELEASE: {
|
|
2153
|
+
summary: "the live app has embedded JS; run a Debug build first",
|
|
2154
|
+
body: () => `STIM_RELOAD_RELEASE
|
|
1995
2155
|
The live app was launched with embedded JavaScript. Run the platform command
|
|
1996
2156
|
with a Debug configuration or variant first.`
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2157
|
+
},
|
|
2158
|
+
STIM_RELOAD_STOPPED: {
|
|
2159
|
+
summary: "the recorded app is gone, its device is not live and owned, or the process could not be proven",
|
|
2160
|
+
aliases: ["STIM_RELOAD_UNOWNED", "STIM_RELOAD_PROBE_FAILED"],
|
|
2161
|
+
body: () => `STIM_RELOAD_STOPPED / STIM_RELOAD_UNOWNED / STIM_RELOAD_PROBE_FAILED
|
|
2002
2162
|
The recorded app is gone, its exact device is not live and owned by this
|
|
2003
2163
|
workspace, or simctl/adb could not prove the process exists. No launch or
|
|
2004
2164
|
device lifecycle action is taken; follow the printed platform-command or
|
|
2005
2165
|
process-probe remedy.`
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2166
|
+
},
|
|
2167
|
+
STIM_RELOAD_FAILED: {
|
|
2168
|
+
summary: "the reload failed; the remedy differs by shape -- read it before acting",
|
|
2169
|
+
body: () => `STIM_RELOAD_FAILED
|
|
2010
2170
|
The Metro websocket reload did not reach a peer Stim could identify. Two
|
|
2011
2171
|
shapes reach this code and the remedy differs. Read it rather than assuming.
|
|
2012
2172
|
|
|
@@ -2032,27 +2192,27 @@ so a Debug run on one is wired to a LAN origin instead of localhost.`,
|
|
|
2032
2192
|
MORE THAN ONE MATCHING PEER IS NOT A FAILURE. A workspace Metro serves one
|
|
2033
2193
|
app, so several matching peers are that app on several devices. Stim reloads
|
|
2034
2194
|
every one of them and reports the count in the facts as targets.`
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2195
|
+
},
|
|
2196
|
+
STIM_WORKTREE_REMOVAL_IN_PROGRESS: {
|
|
2197
|
+
summary: "a managed remote start found worktree remove holding the lock; wait, then rerun",
|
|
2198
|
+
separator: "--- DEV-SERVER CODES (`stim start`) ---",
|
|
2199
|
+
body: () => `STIM_WORKTREE_REMOVAL_IN_PROGRESS
|
|
2040
2200
|
A managed remote start found that \`stim worktree remove\` owns the
|
|
2041
2201
|
worktree lock. The start did not register the project or create a tunnel.
|
|
2042
2202
|
Wait for removal to finish, then run \`stim start --remote\` again.`
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2203
|
+
},
|
|
2204
|
+
STIM_REMOTE_START_REQUIRED: {
|
|
2205
|
+
summary: "a running server cannot gain a remote tunnel; stop, then start --remote, or metro.publicUrl",
|
|
2206
|
+
body: () => `STIM_REMOTE_START_REQUIRED
|
|
2047
2207
|
A healthy bare or Expo server was started without its required remote
|
|
2048
2208
|
tunnel. A running server cannot gain that option. For a Stim supervisor,
|
|
2049
2209
|
run \`stim stop\`, then \`stim start --remote\`. For an external server,
|
|
2050
2210
|
configure metro.publicUrl or let Stim supervise the server.`
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2211
|
+
},
|
|
2212
|
+
STIM_BARE_DEPS: {
|
|
2213
|
+
summary: "the supervisor cannot host Metro from the project's node_modules; the @stim-cli/metro capture note",
|
|
2214
|
+
aliases: ["STIM_BARE_LOAD", "STIM_BARE_API"],
|
|
2215
|
+
body: () => `STIM_BARE_DEPS / STIM_BARE_LOAD / STIM_BARE_API (bare RN)
|
|
2056
2216
|
The supervisor hosts Metro out of the PROJECT's node_modules, so metro,
|
|
2057
2217
|
@react-native/dev-middleware and @react-native-community/cli-server-api must
|
|
2058
2218
|
be installed there and must match the project's React Native. DEPS = not
|
|
@@ -2064,25 +2224,25 @@ captured" (in metro.ndjson, bare RN)
|
|
|
2064
2224
|
The dev server is serving; only capture is missing, so \`logs\` would report
|
|
2065
2225
|
a quiet timeline for a broken build. Install \`@stim-cli/metro\` as a
|
|
2066
2226
|
devDependency of the project.`
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2227
|
+
},
|
|
2228
|
+
STIM_EXPO_BIN: {
|
|
2229
|
+
summary: "node_modules/.bin/expo is missing; install dependencies",
|
|
2230
|
+
body: () => `STIM_EXPO_BIN (Expo)
|
|
2071
2231
|
node_modules/.bin/expo does not exist. Install the project's dependencies.`
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2232
|
+
},
|
|
2233
|
+
STIM_METRO_TIMEOUT: {
|
|
2234
|
+
summary: "the supervisor is alive but Metro or the tunnel was not ready within the wait; --wait 180",
|
|
2235
|
+
body: () => `STIM_METRO_TIMEOUT
|
|
2076
2236
|
"The dev server did not answer on port <n> within <s>s."
|
|
2077
2237
|
The supervisor is alive, but Metro or its requested Expo tunnel is not ready.
|
|
2078
2238
|
\`start\` has already
|
|
2079
2239
|
printed the last lines of the global workspace logs/supervisor.log above this -- read
|
|
2080
2240
|
them. A cold Metro on a large graph can genuinely need more than the default
|
|
2081
2241
|
60s: re-run with \`--wait 180\`. Otherwise \`stim stop\`, then \`start\`.`
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2242
|
+
},
|
|
2243
|
+
STIM_SUPERVISOR_EXITED: {
|
|
2244
|
+
summary: "the dev server failed outright; the quoted supervisor.log tail is the real error",
|
|
2245
|
+
body: () => `STIM_SUPERVISOR_EXITED
|
|
2086
2246
|
"The supervisor exited (<code|signal>) before the dev server came up"
|
|
2087
2247
|
The dev server failed outright, and the quoted evidence is the real error:
|
|
2088
2248
|
the supervisor.log tail if it wrote one, plus this attempt's error records
|
|
@@ -2097,11 +2257,11 @@ captured" (in metro.ndjson, bare RN)
|
|
|
2097
2257
|
Stim's processes. For a legacy record, stop the server with the tool that
|
|
2098
2258
|
started it before retrying. Never reconstruct ownership from a process
|
|
2099
2259
|
name, port, or wall-clock timestamp.`
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2260
|
+
},
|
|
2261
|
+
STIM_BAD_ARG: {
|
|
2262
|
+
summary: "an argument, setting, directory, flavor, or device name refused before anything starts",
|
|
2263
|
+
aliases: ["STIM_NO_PROJECT"],
|
|
2264
|
+
body: () => `STIM_BAD_ARG / STIM_NO_PROJECT
|
|
2105
2265
|
The command refused before doing anything: an unusable --wait value, a known
|
|
2106
2266
|
setting with the wrong type ("Invalid <key> setting <value>. Expected <shape>."
|
|
2107
2267
|
-- \`guide settings\` names the type each key takes), an invalid
|
|
@@ -2127,16 +2287,25 @@ captured" (in metro.ndjson, bare RN)
|
|
|
2127
2287
|
or android.systemImage setting is checked the same way, and the check applies
|
|
2128
2288
|
even when this workspace ALREADY owns a device, so a name that could never
|
|
2129
2289
|
create anything is caught rather than left to a later run.
|
|
2290
|
+
\`gc --json --cache <name>\` refuses with STIM_BAD_ARG when no shared cache
|
|
2291
|
+
carries the name; the remedy names the caches on this machine. \`gc\`
|
|
2292
|
+
refuses --cache together with --worktrees the same way.
|
|
2293
|
+
A working directory with no package.json above it gets the same
|
|
2294
|
+
STIM_NO_PROJECT refusal from \`start\`, \`ios\`, \`android\`, \`stop\`,
|
|
2295
|
+
\`reload\`, \`logs\`, \`doctor\` and \`device lock|unlock\`. With \`--json\` the { code, message, remedy } object
|
|
2296
|
+
is on stdout, except \`logs --json\`, whose stdout stays empty NDJSON; the
|
|
2297
|
+
refusal is on stderr. \`stop\` outside a project refuses rather than
|
|
2298
|
+
reporting that nothing was running.
|
|
2130
2299
|
These errors are caught before the port is reserved and before any build or
|
|
2131
2300
|
device work, so nothing was started. The one listing they need
|
|
2132
2301
|
(\`simctl list runtimes\`, the SDK's system-images directory) runs only when
|
|
2133
2302
|
a name was actually given, and a listing that fails is reported as
|
|
2134
2303
|
STIM_NO_DEVICE naming the tool, never as a crash.`
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2304
|
+
},
|
|
2305
|
+
STIM_LOCK_REFUSED: {
|
|
2306
|
+
summary: "a directory lock is held by a removal, which is never waited out",
|
|
2307
|
+
separator: "--- COORDINATION CODES (any command that shares a resource) ---",
|
|
2308
|
+
body: () => `STIM_LOCK_REFUSED
|
|
2140
2309
|
A directory lock that serialises two commands over the same thing -- this
|
|
2141
2310
|
workspace's managed tunnel, its managed remote worktree, the machine's EAS
|
|
2142
2311
|
project ledger -- is held by a REMOVAL, and a removal is never waited out:
|
|
@@ -2145,10 +2314,10 @@ captured" (in metro.ndjson, bare RN)
|
|
|
2145
2314
|
\`workspace removal\` -- both are \`stim worktree remove\`). Let it finish,
|
|
2146
2315
|
then run the command again. \`start --remote\` reports this same case as
|
|
2147
2316
|
STIM_WORKTREE_REMOVAL_IN_PROGRESS instead.`
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2317
|
+
},
|
|
2318
|
+
STIM_LOCK_TIMEOUT: {
|
|
2319
|
+
summary: "a lock held past the wait; workspace-process and short directory locks",
|
|
2320
|
+
body: () => `STIM_LOCK_TIMEOUT
|
|
2152
2321
|
The same locks, held by an ordinary command that is still running, for
|
|
2153
2322
|
longer than the wait -- 60s by default, 4 minutes for the remote-session and
|
|
2154
2323
|
EAS project locks, and ~90 minutes for the \`worktree warm\` lock, which one
|
|
@@ -2180,11 +2349,11 @@ captured" (in metro.ndjson, bare RN)
|
|
|
2180
2349
|
These paths still time out; verify that no holder is running before removing
|
|
2181
2350
|
only the named directory. Standalone Metro and Expo cache packages use the
|
|
2182
2351
|
same core protocol and do not require the Stim CLI.`
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2352
|
+
},
|
|
2353
|
+
teardown: {
|
|
2354
|
+
summary: "an unmanaged port, an unverified supervisor, and a failed device teardown",
|
|
2355
|
+
separator: "--- TEARDOWN AND WORKSPACE REFUSALS ---",
|
|
2356
|
+
body: () => `"metro refusing to kill port <n>: ... runs from <dir>, outside
|
|
2188
2357
|
<project>" (stop)
|
|
2189
2358
|
Stim only signals processes it launched and whose saved identity still
|
|
2190
2359
|
matches. Stop an externally started server with the tool that started it.
|
|
@@ -2204,14 +2373,22 @@ captured" (in metro.ndjson, bare RN)
|
|
|
2204
2373
|
reserved. Re-run \`stop\`, or signal it yourself: kill -9 -<n> (note the
|
|
2205
2374
|
minus -- it is a process group).
|
|
2206
2375
|
|
|
2376
|
+
"metro refusing to signal it: the identity of dev server pid <n> left by
|
|
2377
|
+
the supervisor could not be verified" (stop)
|
|
2378
|
+
"metro dev server pid <n> left by the supervisor did not exit" (stop)
|
|
2379
|
+
The supervisor is gone but the dev server it started may still run. Stim
|
|
2380
|
+
signals it only while its saved identity matches, and on macOS and Linux
|
|
2381
|
+
never escalates to SIGKILL. The record and the port reservation are KEPT for a retry. Check
|
|
2382
|
+
\`ps -p <n>\`, stop it yourself if it is still running, then re-run \`stop\`.
|
|
2383
|
+
|
|
2207
2384
|
"teardown failed: <reason>"
|
|
2208
2385
|
Stim could not release the owned device and keeps its record for a retry.
|
|
2209
2386
|
\`worktree remove\` exits 1 without removing the worktree while the device is
|
|
2210
2387
|
still tracked. Fix the reported cause and re-run.`
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2388
|
+
},
|
|
2389
|
+
remove: {
|
|
2390
|
+
summary: "worktree remove refused a dirty tree: what it restores itself and what --force discards",
|
|
2391
|
+
body: () => `"Refusing to remove <path>: uncommitted changes / untracked files / commits
|
|
2215
2392
|
not on any remote" (worktree remove)
|
|
2216
2393
|
A native build rewrites tracked files, and Stim now RESTORES the one class
|
|
2217
2394
|
it can prove is not work: when the only dirt left is \`pod install\` churn
|
|
@@ -2231,10 +2408,10 @@ not on any remote" (worktree remove)
|
|
|
2231
2408
|
refusal actually named.
|
|
2232
2409
|
Use --force only when you genuinely intend to discard work; it deletes
|
|
2233
2410
|
uncommitted and untracked files permanently.`
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2411
|
+
},
|
|
2412
|
+
STIM_MAIN_DIRTY: {
|
|
2413
|
+
summary: "warm --refresh will not move a source checkout with local work or an operation in progress",
|
|
2414
|
+
body: () => `STIM_MAIN_DIRTY
|
|
2238
2415
|
\`worktree warm --refresh\` writes to the SOURCE CHECKOUT, and it refuses one
|
|
2239
2416
|
it cannot move: tracked files with uncommitted changes (the refusal names
|
|
2240
2417
|
them), or a rebase or merge in progress. Untracked files are not a reason to
|
|
@@ -2244,28 +2421,28 @@ not on any remote" (worktree remove)
|
|
|
2244
2421
|
or \`git -C <source-checkout> rebase --abort\`. Nothing was installed or
|
|
2245
2422
|
copied. Plain \`stim worktree warm\` does not care: it copies from a dirty
|
|
2246
2423
|
source checkout exactly as it always has.`
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2424
|
+
},
|
|
2425
|
+
STIM_MAIN_DETACHED: {
|
|
2426
|
+
summary: "warm --refresh needs a branch to fast-forward, not a detached HEAD",
|
|
2427
|
+
body: () => `STIM_MAIN_DETACHED
|
|
2251
2428
|
The source checkout's HEAD is detached, so there is no branch to fast-forward
|
|
2252
2429
|
and no upstream to fast-forward it to. Run
|
|
2253
2430
|
\`git -C <source-checkout> checkout <branch>\` and warm again. \`--refresh\`
|
|
2254
2431
|
never picks a branch for you; a checkout whose job is to seed worktrees
|
|
2255
2432
|
should sit on a branch someone chose.`
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2433
|
+
},
|
|
2434
|
+
STIM_MAIN_DIVERGED: {
|
|
2435
|
+
summary: "the source checkout is both ahead of and behind its upstream; warm --refresh will not merge",
|
|
2436
|
+
body: () => `STIM_MAIN_DIVERGED
|
|
2260
2437
|
The source checkout's branch has commits its upstream does not, AND its
|
|
2261
2438
|
upstream has commits it does not. A fast-forward is impossible, and
|
|
2262
2439
|
\`--refresh\` will not merge or reset someone else's checkout to make one:
|
|
2263
2440
|
that decision is yours. Rebase or merge it yourself, then warm again. The
|
|
2264
2441
|
message reports both counts. Nothing was installed or copied.`
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2442
|
+
},
|
|
2443
|
+
STIM_DEPS_INCOMPLETE: {
|
|
2444
|
+
summary: "the last install recorded for the lockfile on disk now did not finish, so warm will not copy it",
|
|
2445
|
+
body: () => `STIM_DEPS_INCOMPLETE
|
|
2269
2446
|
\`worktree warm\` refuses to copy dependencies the source checkout never
|
|
2270
2447
|
finished installing. \`--refresh\` records a COMPLETED install of the lockfile
|
|
2271
2448
|
it read under ~/.stim/warm-installs; an install that failed, or whose process
|
|
@@ -2283,20 +2460,20 @@ not on any remote" (worktree remove)
|
|
|
2283
2460
|
repository before its first \`--refresh\` -- copies as it always has.
|
|
2284
2461
|
In a monorepo the record is keyed on the directory that owns the lockfile,
|
|
2285
2462
|
which is usually the repository root, so every app of it reads the same one.`
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2463
|
+
},
|
|
2464
|
+
warm: {
|
|
2465
|
+
summary: "worktree warm claim storage refusals and recovery",
|
|
2466
|
+
body: () => `Both plain warm and --refresh require an ownership claim.
|
|
2290
2467
|
Permission-denied or read-only claim storage reports STIM_CLAIM_UNAVAILABLE
|
|
2291
2468
|
and names the path. Restore access to the existing claim store and retry.
|
|
2292
2469
|
A non-directory claim ancestor reports STIM_CLAIM_REFUSED and names the
|
|
2293
2470
|
blocking file. Inspect it and use the printed move-aside command to preserve
|
|
2294
2471
|
its contents before retrying. See guide errors STIM_CLAIM_UNAVAILABLE and
|
|
2295
2472
|
guide errors STIM_CLAIM_REFUSED for the recovery details.`
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2473
|
+
},
|
|
2474
|
+
carry: {
|
|
2475
|
+
summary: "worktree warm copy results, lockfile mismatches, and remedies",
|
|
2476
|
+
body: () => `"carry incomplete: ... ignored entries copied, ... kept, ... failed"
|
|
2300
2477
|
(worktree warm)
|
|
2301
2478
|
At least one entry could not be copied. The command exits 1 and names each
|
|
2302
2479
|
failure. Existing entries stay untouched; any files already published remain.
|
|
@@ -2325,11 +2502,11 @@ not on any remote" (worktree remove)
|
|
|
2325
2502
|
the app is ready, unless \`--refresh\` installed them in the SOURCE CHECKOUT
|
|
2326
2503
|
first; even then the copy can still carry a lockfile this branch does not
|
|
2327
2504
|
have, which is exactly what these carry warnings report.`
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2505
|
+
},
|
|
2506
|
+
environment: {
|
|
2507
|
+
summary: "npx registry E401/E404, the Node floor, no free Metro port, the reservation race",
|
|
2508
|
+
separator: "--- ENVIRONMENT ---",
|
|
2509
|
+
body: () => `"npm error code E401 / E404" while \`npx\` resolves the stim package
|
|
2333
2510
|
The repo probably pins a private registry in \`.npmrc\`, so \`npx\` looked for
|
|
2334
2511
|
the package there instead of on npm. Use the public registry for this command:
|
|
2335
2512
|
|
|
@@ -2350,10 +2527,10 @@ not on any remote" (worktree remove)
|
|
|
2350
2527
|
"Could not reserve a Metro port after 5 attempts"
|
|
2351
2528
|
Several commands raced for the same ports and each one lost. Nothing is
|
|
2352
2529
|
wrong; retry.`
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2530
|
+
},
|
|
2531
|
+
sandbox: {
|
|
2532
|
+
summary: "running under a sandboxing harness: EPERM under STIM_HOME, CoreSimulatorService, adb",
|
|
2533
|
+
body: () => `RUNNING UNDER A SANDBOX
|
|
2357
2534
|
|
|
2358
2535
|
An agent harness that sandboxes shell commands typically permits writes
|
|
2359
2536
|
inside the project and blocks the rest. Three things Stim needs sit outside
|
|
@@ -2400,21 +2577,37 @@ not on any remote" (worktree remove)
|
|
|
2400
2577
|
|
|
2401
2578
|
A git credential helper is often blocked too. It prints \`failed to store\`
|
|
2402
2579
|
on a fetch that otherwise succeeded, and is safe to ignore.`
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2580
|
+
},
|
|
2581
|
+
STIM_CONFIG_CORRUPT: {
|
|
2582
|
+
summary: "~/.stim/config.json is not a valid JSON object and Stim never resets it",
|
|
2583
|
+
body: () => `STIM_CONFIG_CORRUPT ("Stim config at <path> is not valid JSON",
|
|
2584
|
+
"... is not a JSON object",
|
|
2585
|
+
"... has a projects that is not an object",
|
|
2586
|
+
"... has a projects entry "<key>" that is not an object")
|
|
2407
2587
|
Any command can raise it: every command reads ~/.stim/config.json first.
|
|
2408
|
-
The file holding every owned-device record will not parse
|
|
2588
|
+
The file holding every owned-device record will not parse into an object,
|
|
2589
|
+
or its projects or repos registry or one of their entries is not an object
|
|
2590
|
+
(a bare [], null or number counts as corrupt, not empty), and Stim never
|
|
2409
2591
|
resets it for you -- a silent reset would orphan every simulator it names.
|
|
2410
2592
|
Repair the file, or move it aside (\`mv <path> <path>.broken\`) and accept
|
|
2411
2593
|
that the devices it recorded become orphans you delete by hand.`
|
|
2412
|
-
|
|
2594
|
+
},
|
|
2595
|
+
STIM_RELATIVE_PATH: {
|
|
2596
|
+
summary: "STIM_HOME, STIM_BUILD_CACHE or STIM_METRO_CACHE is set to a relative path",
|
|
2597
|
+
body: () => `STIM_RELATIVE_PATH ("<NAME>=<value> is not an absolute path")
|
|
2598
|
+
Any command refuses before it reads or writes state. A relative value would
|
|
2599
|
+
resolve against each process's working directory, so the CLI, Metro and the
|
|
2600
|
+
Expo build-cache provider would each use a different store. Set the named
|
|
2601
|
+
variable to an absolute path, or unset it to use the default. Metro and the
|
|
2602
|
+
cache provider, which cannot refuse, ignore a relative value with a warning.`
|
|
2413
2603
|
}
|
|
2414
|
-
}
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2604
|
+
}
|
|
2605
|
+
};
|
|
2606
|
+
//#endregion
|
|
2607
|
+
//#region src/guide/lifecycle.ts
|
|
2608
|
+
const lifecycle = {
|
|
2609
|
+
summary: "The full worktree -> start -> ios/android -> logs -> teardown flow, with sections for builds, devices and flags",
|
|
2610
|
+
preamble: () => `ENVIRONMENT LIFECYCLE
|
|
2418
2611
|
|
|
2419
2612
|
Two workflows share steps 2 through 6.
|
|
2420
2613
|
|
|
@@ -2588,8 +2781,10 @@ Permanent local deletion lives in exactly TWO commands: \`worktree remove\`
|
|
|
2588
2781
|
(the workspace you name) and \`gc --delete\` (the machine). For a local device,
|
|
2589
2782
|
\`stop\` shuts it down and never deletes it. For a recorded EAS session,
|
|
2590
2783
|
\`stop\` irreversibly ends the session. Externally started servers are left
|
|
2591
|
-
alone, even when they use the reserved port
|
|
2592
|
-
|
|
2784
|
+
alone, even when they use the reserved port, and the reservation is kept while
|
|
2785
|
+
one answers from the project. A dev server whose supervisor died is stopped
|
|
2786
|
+
only when its recorded process identity still matches. There is no
|
|
2787
|
+
\`--delete\` flag on \`stop\`.
|
|
2593
2788
|
|
|
2594
2789
|
CAPACITY
|
|
2595
2790
|
A booted iOS sim is roughly 1-2 GB of RAM, an Android emulator 2-3 GB. On a
|
|
@@ -2598,14 +2793,25 @@ CAPACITY
|
|
|
2598
2793
|
machine, not just this one.
|
|
2599
2794
|
|
|
2600
2795
|
TWO REPORTS, TWO QUESTIONS
|
|
2601
|
-
"What is running" is \`stim status\`: live state, right now
|
|
2796
|
+
"What is running" is \`stim status\`: live state, right now, including
|
|
2797
|
+
each running ios or android build's phase and time left (see
|
|
2798
|
+
\`guide facts status\`). "How much the
|
|
2602
2799
|
cache saved" is \`stim stats\`: aggregate counters for this project and for
|
|
2603
2800
|
the machine, with a hit rate and an estimate of the time saved (see
|
|
2604
|
-
\`guide facts stats\`)
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2801
|
+
\`guide facts stats\`).
|
|
2802
|
+
|
|
2803
|
+
WAITING FOR A CHANGE
|
|
2804
|
+
To wait for a device, a build or a dev server instead of polling, run
|
|
2805
|
+
\`stim status --watch --json\`. It keeps running and prints one complete
|
|
2806
|
+
status payload per line: one at once, then one each time the payload
|
|
2807
|
+
changes, never two identical ones in a row. It reacts to Stim state files,
|
|
2808
|
+
the EAS session ledger, adb device arrivals and departures, and simulator
|
|
2809
|
+
state, and recomputes every 30 seconds as a fallback. Ctrl+C, SIGTERM or
|
|
2810
|
+
closing its stdout ends it with exit 0. Without --json it reprints the human view on change.`,
|
|
2811
|
+
sections: {
|
|
2812
|
+
eas: {
|
|
2813
|
+
summary: "download a matching EAS development build; explicit profile, costs, cache and miss remedies",
|
|
2814
|
+
body: () => `EAS DEVELOPMENT BUILDS
|
|
2609
2815
|
|
|
2610
2816
|
stim ios --eas-profile ios-simulator
|
|
2611
2817
|
stim android --eas-profile development
|
|
@@ -2678,10 +2884,10 @@ flag exists, and Stim never starts a cloud build or falls back to local
|
|
|
2678
2884
|
compilation in this mode. Authentication, network, invalid output or download
|
|
2679
2885
|
failures produce STIM_EAS_UNAVAILABLE, with the failed EAS command to inspect.
|
|
2680
2886
|
If another run holds the artifact claim, wait for it to finish and retry.`
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2887
|
+
},
|
|
2888
|
+
readiness: {
|
|
2889
|
+
summary: "implement optional pending/ready app logs, deadlines, errors, and platform isolation",
|
|
2890
|
+
body: () => `OPTIONAL APP READINESS
|
|
2685
2891
|
|
|
2686
2892
|
No package or SDK is needed. This applies to debug ios/android launches with
|
|
2687
2893
|
Metro verification enabled, not release builds or --no-metro-check.
|
|
@@ -2741,10 +2947,10 @@ including when device logs are unavailable, the default check applies.
|
|
|
2741
2947
|
The app declares readiness; Stim does not inspect a rendered frame. This does
|
|
2742
2948
|
not change launched JSON semantics or the need to inspect the expected UI and
|
|
2743
2949
|
stim logs --errors. A reload request does not run this launch check.`
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2950
|
+
},
|
|
2951
|
+
verification: {
|
|
2952
|
+
summary: "reproduce the affected behavior, verify the change on the reported device, and retain proof",
|
|
2953
|
+
body: () => `VERIFY THE CHANGE
|
|
2748
2954
|
|
|
2749
2955
|
For a UI change or bug fix, decide what observable result would prove the task
|
|
2750
2956
|
is complete. A successful build, a live process, or an empty log query does
|
|
@@ -2774,10 +2980,10 @@ not prove that result.
|
|
|
2774
2980
|
|
|
2775
2981
|
For a change without a UI effect, use the relevant runtime output or test
|
|
2776
2982
|
result as proof instead of requiring an unrelated screenshot.`
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2983
|
+
},
|
|
2984
|
+
progress: {
|
|
2985
|
+
summary: "phase lines, the label set, heartbeats and their ~ estimate, what warm, start, stop and remove print",
|
|
2986
|
+
body: () => `PROGRESS ON A LONG RUN
|
|
2781
2987
|
Native build progress goes to stderr. In \`--json\` mode, stdout carries only
|
|
2782
2988
|
the result payload. Plain \`start\` also prints progress on stdout. Every
|
|
2783
2989
|
progress line has the same shape -- two spaces, a label padded to eleven
|
|
@@ -2897,10 +3103,10 @@ result as proof instead of requiring an unrelated screenshot.`
|
|
|
2897
3103
|
until it returns; the next heartbeat then lands on the grid, which is why an
|
|
2898
3104
|
elapsed value can jump. Read the phase lines, not the wall clock, before
|
|
2899
3105
|
killing a run.`
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
3106
|
+
},
|
|
3107
|
+
pool: {
|
|
3108
|
+
summary: "parked and adopted simulators: what park and adoption clear or keep, the model and runtime match",
|
|
3109
|
+
body: () => ` THE SIMULATOR POOL
|
|
2904
3110
|
\`worktree remove\` PARKS this workspace's owned simulator instead of
|
|
2905
3111
|
deleting it, and the next workspace that wants the same model and runtime
|
|
2906
3112
|
ADOPTS it. A simulator that has booted before boots in about 9s; a freshly
|
|
@@ -3021,10 +3227,10 @@ result as proof instead of requiring an unrelated screenshot.`
|
|
|
3021
3227
|
Set the Android bound to 0 when a project needs a fresh device. Status lists
|
|
3022
3228
|
parked Android emulators; GC reports their system image, age and disk size.
|
|
3023
3229
|
`
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3230
|
+
},
|
|
3231
|
+
builds: {
|
|
3232
|
+
summary: "optional cache warm-up, build optimizations, fingerprints, .fingerprintignore, install unchanged, runtime state",
|
|
3233
|
+
body: () => `OPTIONAL CACHE WARM-UP FOR REPEATED NATIVE WORK
|
|
3028
3234
|
When several native worktrees are coming, build the source checkout once to
|
|
3029
3235
|
seed the shared caches before warming the linked worktrees. Skip this extra
|
|
3030
3236
|
build for one-off or JavaScript-only work. For local simulator or emulator
|
|
@@ -3091,7 +3297,9 @@ Runtime state is stored outside the project tree under
|
|
|
3091
3297
|
$STIM_HOME/workspaces/<project>--<digest>/ (default ~/.stim/workspaces/).
|
|
3092
3298
|
The aggregate run counters \`stats\` prints live beside it in
|
|
3093
3299
|
$STIM_HOME/stats.json, one bucket per project and platform plus a machine-wide
|
|
3094
|
-
one
|
|
3300
|
+
one, and the last 10 successful runs per project, platform and cache outcome
|
|
3301
|
+
that size \`status\`'s build estimate. The running build itself is the
|
|
3302
|
+
activeBuild key of the workspace's state.json, cleared when the run exits.
|
|
3095
3303
|
No .gitignore entry is created or required.
|
|
3096
3304
|
Native preparation can change project files: expo prebuild generates native
|
|
3097
3305
|
sources, and pod install can update Podfile.lock. Review those changes before
|
|
@@ -3320,10 +3528,10 @@ WHAT MAKES THE CACHE ACTUALLY HIT: .FINGERPRINTIGNORE
|
|
|
3320
3528
|
mismatch naming the differing sources. Untracked, non-gitignored files under
|
|
3321
3529
|
ios/ or android/ count too -- they are hashed like any other source, so a
|
|
3322
3530
|
stray file there moves the key on your machine and nowhere else.`
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3531
|
+
},
|
|
3532
|
+
concurrency: {
|
|
3533
|
+
summary: "waiting on another workspace's build, --no-build-cache, concurrency.maxBuilds and maxDevices",
|
|
3534
|
+
body: () => `ONE COMPILE PER FINGERPRINT, ACROSS EVERY WORKSPACE
|
|
3327
3535
|
The cache makes the SECOND workspace on a commit free -- but only once the
|
|
3328
3536
|
first has finished. Three agents starting within the same minute all miss it,
|
|
3329
3537
|
and without this all three compile the same app at once, fighting for the
|
|
@@ -3347,10 +3555,15 @@ WHAT MAKES THE CACHE ACTUALLY HIT: .FINGERPRINTIGNORE
|
|
|
3347
3555
|
Nothing can deadlock on it. The lock records the holder's process IDENTITY,
|
|
3348
3556
|
so a builder that crashes, is killed, or whose build simply fails frees it:
|
|
3349
3557
|
the waiters see a released lock with no artifact, and one of them takes over
|
|
3350
|
-
and builds.
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3558
|
+
and builds. The xcodebuild, Gradle, pod install or expo prebuild it spawned
|
|
3559
|
+
is recorded on the lock, its build slot and the workspace's native run, so a
|
|
3560
|
+
builder killed while that tool keeps running (SIGTERM to the stim pid alone)
|
|
3561
|
+
frees them only when the tool exits. A recycled builder pid reads as a gone
|
|
3562
|
+
builder, and a builder busy in a long synchronous tool call reads as live --
|
|
3563
|
+
age is never a reason to take a lock. A state that cannot be decided (a
|
|
3564
|
+
truncated claim, an identity token that does not decode, a builder killed
|
|
3565
|
+
between spawning its build tool and recording it, a recorded build tool
|
|
3566
|
+
whose pid was since reused) is STIM_CLAIM_REFUSED: Stim names the claim and
|
|
3354
3567
|
the command that removes it rather than guessing. A process whose own identity
|
|
3355
3568
|
cannot be captured takes no lock and no slot, and refuses with
|
|
3356
3569
|
STIM_CLAIM_UNAVAILABLE rather than building unprotected. The
|
|
@@ -3394,26 +3607,28 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3394
3607
|
|
|
3395
3608
|
\`stim doctor\` prints one note echoing the caps and the current live count,
|
|
3396
3609
|
but ONLY when a cap is set. \`stim gc\` reports stale build slots the way it
|
|
3397
|
-
reports stale build locks, and \`gc --delete\` clears them.
|
|
3398
|
-
\`stim
|
|
3399
|
-
the two env vars (see \`guide settings\`).`
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3610
|
+
reports stale build locks, and \`gc --delete\` clears them. Set the caps
|
|
3611
|
+
with \`stim settings set concurrency.maxBuilds 2\`, by editing
|
|
3612
|
+
~/.stim/config.json, or via the two env vars (see \`guide settings\`).`
|
|
3613
|
+
},
|
|
3614
|
+
options: {
|
|
3615
|
+
summary: "every flag per command, Android variants and flavors, the per-run simulator model, runtime and system image",
|
|
3616
|
+
body: () => `THE OPTION SURFACE, IN FULL
|
|
3404
3617
|
start --json --wait <seconds> --remote --reset-cache
|
|
3405
|
-
ios --slot <name> --json --no-metro-check --no-build-cache --scheme <name> --configuration <name> --device-type <name> --runtime <version> --simulator-app <xcode|siniulator> --device [udid] --wait <seconds> --no-wait --remote <proxy|eas>
|
|
3618
|
+
ios --slot <name> --json --no-metro-check --no-build-cache --scheme <name> --configuration <name> --device-type <name> --runtime <version> --simulator-app <xcode|siniulator|stim-desktop> --device [udid] --wait <seconds> --no-wait --remote <proxy|eas>
|
|
3406
3619
|
android --slot <name> --json --no-metro-check --no-build-cache --variant <name> --system-image <id> --device [serial] --wait <seconds> --no-wait --remote <proxy|eas>
|
|
3407
3620
|
reload [ios|android] --json
|
|
3408
3621
|
device lock <ios|android> [id] --slot <name> --for <duration> --wait <seconds> --json;
|
|
3409
3622
|
unlock [ios|android] --slot <name> --json
|
|
3410
3623
|
logs --slot <name> --source --level --since --grep --tail --follow --errors --json
|
|
3411
3624
|
stop --slot <name> --json
|
|
3412
|
-
status --json
|
|
3625
|
+
status --json --watch (already machine-wide)
|
|
3413
3626
|
stats --json (this project and machine-wide)
|
|
3627
|
+
settings --json; get <key> --scope <layer> --json;
|
|
3628
|
+
set <key> <value> --scope <layer> --json; unset <key> --scope <layer> --json
|
|
3414
3629
|
doctor --json --fix --platform <ios|android>
|
|
3415
3630
|
(--platform keeps shared checks and filters native findings)
|
|
3416
|
-
gc --delete --older-than <days> --cache <name|all>
|
|
3631
|
+
gc --delete --older-than <days> --cache <name|all|workspaces> --worktrees --json
|
|
3417
3632
|
worktree warm --refresh; remove [path] --force
|
|
3418
3633
|
|
|
3419
3634
|
DEVICE SLOTS
|
|
@@ -3424,7 +3639,7 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3424
3639
|
the workspace's existing assignment.
|
|
3425
3640
|
|
|
3426
3641
|
stim ios --slot phone
|
|
3427
|
-
stim ios --slot tablet --device-type "iPad Pro 13-inch (
|
|
3642
|
+
stim ios --slot tablet --device-type "iPad Pro 13-inch (M5)"
|
|
3428
3643
|
stim ios --slot hardware --device <udid>
|
|
3429
3644
|
stim android --slot second-phone
|
|
3430
3645
|
stim logs --slot tablet --source device
|
|
@@ -3459,6 +3674,12 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3459
3674
|
worktrees of the same Git repository; the source checkout must be available.
|
|
3460
3675
|
Running it in the source checkout refuses.
|
|
3461
3676
|
|
|
3677
|
+
\`stim doctor\` reports the source checkout's fitness as a seed -- how far
|
|
3678
|
+
behind its upstream it is, uncommitted tracked changes, an interrupted rebase
|
|
3679
|
+
or merge, a detached HEAD, a diverged branch, a branch that is not the
|
|
3680
|
+
default one -- only once the repository has at least one linked worktree. A
|
|
3681
|
+
single-checkout session is never told that its own branch is a problem.
|
|
3682
|
+
|
|
3462
3683
|
\`--refresh\` WRITES TO THE SOURCE CHECKOUT before the copy, which is why it
|
|
3463
3684
|
is opt-in: it checks the upstream, fetches changes when needed, and fast-forwards
|
|
3464
3685
|
whatever branch is checked out there to its \`@{upstream}\`, and installs
|
|
@@ -3588,8 +3809,8 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3588
3809
|
|
|
3589
3810
|
\`ios --device-type <name>\` and \`ios --runtime <version>\` choose the
|
|
3590
3811
|
MODEL and the iOS version of the simulator this workspace owns --
|
|
3591
|
-
\`--device-type "iPad Pro 13-inch (
|
|
3592
|
-
says "happens on iPad on iOS
|
|
3812
|
+
\`--device-type "iPad Pro 13-inch (M5)" --runtime 26.5\` is how a ticket that
|
|
3813
|
+
says "happens on iPad on iOS 26.5" gets reproduced without writing a
|
|
3593
3814
|
\`.stim.json\`. \`android --system-image <id>\` is the Android half, taking
|
|
3594
3815
|
the sdkmanager package id
|
|
3595
3816
|
("system-images;android-36;google_apis;arm64-v8a"). Each overrides its
|
|
@@ -3620,10 +3841,10 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3620
3841
|
version it was made with. The --json payload reports what was actually
|
|
3621
3842
|
used: \`deviceType\` and \`runtime\` on iOS, \`systemImage\` on Android,
|
|
3622
3843
|
read from the device itself, so a settings-driven run reports them too.`
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3844
|
+
},
|
|
3845
|
+
devices: {
|
|
3846
|
+
summary: "ios --device and android --device on a phone: what the run skips, signing, the LAN wiring, the collector",
|
|
3847
|
+
body: () => ` \`android --device [serial]\` installs and launches on a physical device
|
|
3627
3848
|
connected to this machine instead of this workspace's owned emulator. With
|
|
3628
3849
|
no serial it takes the first device it can lease (\`guide lifecycle lease\`).
|
|
3629
3850
|
It cannot be combined with --remote.
|
|
@@ -3648,6 +3869,24 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3648
3869
|
\`android --device\`, it leases the phone for the run
|
|
3649
3870
|
(\`guide lifecycle lease\`).
|
|
3650
3871
|
|
|
3872
|
+
AN IPHONE PAIRED OVER WI-FI is a device too: devicectl reports its
|
|
3873
|
+
transportType as localNetwork. Only a physical iPhone or iPad counts
|
|
3874
|
+
(devicectl platform iOS, reality physical); an Apple TV, a Vision Pro, a
|
|
3875
|
+
simulator, or a paired phone devicectl reports unavailable is never picked.
|
|
3876
|
+
A UDID that names a Wi-Fi phone is accepted. With no UDID, a healthy
|
|
3877
|
+
cabled iPhone always wins, and a busy one is waited for; a Wi-Fi one is
|
|
3878
|
+
taken only when no cabled one is paired with Developer Mode on, and a busy
|
|
3879
|
+
refusal names any free Wi-Fi phone so \`--device <udid>\` can take it.
|
|
3880
|
+
The transport is read again just before the install, so a cable pulled
|
|
3881
|
+
during the build still gets Wi-Fi treatment, and the run prints one
|
|
3882
|
+
\`device\` line saying the install and launch go over Wi-Fi. Over Wi-Fi
|
|
3883
|
+
each devicectl install step may take 15 minutes instead of 5 and the launch
|
|
3884
|
+
120 seconds instead of 45; the lease is raised before each step, including
|
|
3885
|
+
the uninstall and reinstall of a signer conflict. A Wi-Fi install or launch
|
|
3886
|
+
that times out or loses the phone fails with STIM_DEVICE_WIRELESS_FAILED,
|
|
3887
|
+
and the remedy is the cable. Metro is unaffected: a Debug app reaches it
|
|
3888
|
+
over the LAN either way.
|
|
3889
|
+
|
|
3651
3890
|
\`stop\` releases this workspace's leases and stops its log collectors.
|
|
3652
3891
|
On a physical iPhone that also closes the app, because its collector owns
|
|
3653
3892
|
the devicectl launch session. \`gc --delete\` removes expired lease files;
|
|
@@ -3729,10 +3968,10 @@ OPT-IN CONCURRENCY LIMITS (UNLIMITED BY DEFAULT)
|
|
|
3729
3968
|
by hashing the installed container; there is no cheap equivalent through
|
|
3730
3969
|
devicectl, so a device run always installs. It is an upgrade install: the
|
|
3731
3970
|
app's data, and the Local Network permission the phone granted it, survive.`
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3971
|
+
},
|
|
3972
|
+
lease: {
|
|
3973
|
+
summary: "run-scoped leases, --wait and --no-wait, device lock and unlock, which phone an id-less --device picks",
|
|
3974
|
+
body: () => `THE DEVICE LEASE ON A \`--device\` RUN
|
|
3736
3975
|
A physical device is shared, so a \`--device\` run takes a lease on it. The
|
|
3737
3976
|
lease step sits AFTER the build (a build touches no device) and before the
|
|
3738
3977
|
install, and the run releases what it took when the command exits: on
|
|
@@ -3800,13 +4039,15 @@ HOLDING A DEVICE ACROSS RUNS
|
|
|
3800
4039
|
|
|
3801
4040
|
THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
|
|
3802
4041
|
Candidates are the connected devices the resolver already accepts: on iOS,
|
|
3803
|
-
|
|
3804
|
-
in the \`device\` state that is not an emulator, TCP
|
|
3805
|
-
in order:
|
|
4042
|
+
paired, with Developer Mode on, over a cable or Wi-Fi; on Android, every
|
|
4043
|
+
serial adb reports in the \`device\` state that is not an emulator, TCP
|
|
4044
|
+
serials included. Then, in order:
|
|
3806
4045
|
|
|
3807
4046
|
1. the device this workspace already leases, when it is among them;
|
|
3808
4047
|
2. otherwise the first one not leased -- or leased and EXPIRED -- in
|
|
3809
|
-
case-folded id order.
|
|
4048
|
+
case-folded id order. On iOS a Wi-Fi iPhone is considered only when
|
|
4049
|
+
no cabled candidate is connected: a busy cabled phone is waited for,
|
|
4050
|
+
not skipped for a Wi-Fi one.
|
|
3810
4051
|
|
|
3811
4052
|
Ids are sorted on, never names: adb has no name without one \`getprop\` per
|
|
3812
4053
|
serial, and models repeat.
|
|
@@ -3826,10 +4067,10 @@ THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
|
|
|
3826
4067
|
The chosen device is on the phase line and in \`--json\` (\`udid\` or
|
|
3827
4068
|
\`serial\`, plus \`deviceName\`), so an agent can hand the same id to its
|
|
3828
4069
|
device tool.`
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
4070
|
+
},
|
|
4071
|
+
release: {
|
|
4072
|
+
summary: "Release configurations and ...Release variants: Metro skipped, process-proven launch, the JS swap",
|
|
4073
|
+
body: () => ` A VARIANT WHOSE NAME ENDS IN "Release" IS A RELEASE BUILD (\`release\`,
|
|
3833
4074
|
\`productionRelease\`), and that is the whole opt-in -- there is no second
|
|
3834
4075
|
flag. It is the Android half of \`ios --configuration Release\` and behaves
|
|
3835
4076
|
the same way: AGP's bundle task embeds the JS, so Metro is skipped ENTIRELY
|
|
@@ -3902,10 +4143,10 @@ THE POOL: WHICH DEVICE AN ID-LESS \`--device\` PICKS
|
|
|
3902
4143
|
builds the \`iphoneos\` slice for a cabled iPhone and keys its cache
|
|
3903
4144
|
\`-device\` instead of \`-sim\`, but does not install it yet. Archives,
|
|
3904
4145
|
\`.ipa\` export, store signing and distribution stay out of scope.`
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
4146
|
+
},
|
|
4147
|
+
simslim: {
|
|
4148
|
+
summary: "recommended SimSlim profiles and recovery from host memory pressure",
|
|
4149
|
+
body: () => `SIMSLIM FOR PARALLEL IOS WORK
|
|
3909
4150
|
SimSlim is recommended as an optional way to reduce simulator background
|
|
3910
4151
|
services and memory use, especially with several workspaces. Review which
|
|
3911
4152
|
services your app and tests need; a slim profile can disable those features.
|
|
@@ -3952,8 +4193,9 @@ HOST MEMORY PRESSURE AND STALLED SIMULATORS
|
|
|
3952
4193
|
a final boot-state query can take 30 seconds. After boot, Stim opens the owned
|
|
3953
4194
|
simulator in the selected Xcode's Device Hub on Xcode 27, or Simulator on
|
|
3954
4195
|
older Xcode. Top-level iosSimulatorApp in the machine config can select
|
|
3955
|
-
Siniulator instead; see guide settings. Override it for one
|
|
3956
|
-
\`stim ios --simulator-app siniulator
|
|
4196
|
+
Siniulator or Stim Desktop instead; see guide settings. Override it for one
|
|
4197
|
+
local run with \`stim ios --simulator-app siniulator\`,
|
|
4198
|
+
\`--simulator-app stim-desktop\`, or \`--simulator-app xcode\`. This also
|
|
3957
4199
|
opens an already running owned simulator without rebooting it or saving the
|
|
3958
4200
|
preference. The flag refuses physical and remote targets, including ios.remote.
|
|
3959
4201
|
Opening the window is best-effort
|
|
@@ -3974,12 +4216,14 @@ HOST MEMORY PRESSURE AND STALLED SIMULATORS
|
|
|
3974
4216
|
agents' simulators or heavy apps. Rebooting a simulator under the same pressure
|
|
3975
4217
|
can repeat the stall. Consider fewer concurrent builds/devices (guide lifecycle
|
|
3976
4218
|
concurrency) and a reviewed SimSlim profile for future runs.`
|
|
3977
|
-
}
|
|
3978
4219
|
}
|
|
3979
|
-
}
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
4220
|
+
}
|
|
4221
|
+
};
|
|
4222
|
+
//#endregion
|
|
4223
|
+
//#region src/guide/cleanup.ts
|
|
4224
|
+
const cleanup = {
|
|
4225
|
+
summary: "Where simulators come from, and how they get reclaimed",
|
|
4226
|
+
preamble: () => `DEVICE SLOTS
|
|
3983
4227
|
|
|
3984
4228
|
Cleanup enumerates every slot. stop --slot <name> keeps the shared server and
|
|
3985
4229
|
other slots; plain stop and worktree remove handle the whole workspace.
|
|
@@ -3997,11 +4241,17 @@ WHAT RECLAIMS AN OWNED DEVICE
|
|
|
3997
4241
|
stim gc --delete sweeps stim-* devices no project references, and
|
|
3998
4242
|
clears verified parked simulators and emulators
|
|
3999
4243
|
stim gc --delete --older-than <days>
|
|
4000
|
-
also reaps the device of a
|
|
4001
|
-
|
|
4002
|
-
still on disk
|
|
4003
|
-
|
|
4004
|
-
|
|
4244
|
+
also reaps the device of a workspace no Stim
|
|
4245
|
+
command has used in that long, even though the
|
|
4246
|
+
project is still on disk
|
|
4247
|
+
stim gc --delete --worktrees
|
|
4248
|
+
runs \`stim worktree remove\` on every clean, idle,
|
|
4249
|
+
Stim-managed linked worktree (\`guide cleanup gc\`)
|
|
4250
|
+
|
|
4251
|
+
\`worktree remove\` and \`gc --delete\` are the only two commands that delete;
|
|
4252
|
+
\`gc --delete --worktrees\` deletes only through \`worktree remove\`. \`gc
|
|
4253
|
+
--delete\` also clears workspace build outputs (\`guide cleanup disk\`) and
|
|
4254
|
+
orphaned workspace directories, never a checkout. \`stim stop\` shuts a device
|
|
4005
4255
|
DOWN and leaves it assigned, which is what makes returning to a branch cost a
|
|
4006
4256
|
boot rather than a create, a provision and a reinstall.
|
|
4007
4257
|
|
|
@@ -4021,17 +4271,65 @@ start the counters over. A file this version cannot read -- unparseable, or
|
|
|
4021
4271
|
written by a newer Stim -- costs one dim line on stderr and is otherwise left
|
|
4022
4272
|
alone; only the next \`ios\` or \`android\` run moves an unparseable one aside
|
|
4023
4273
|
to stats.json.corrupt-<unix ms> and starts a new one.`,
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4274
|
+
sections: {
|
|
4275
|
+
gc: {
|
|
4276
|
+
summary: "what gc and worktree remove delete, keep and refuse: orphans, stale records, locks, leases, EAS sessions",
|
|
4277
|
+
body: () => `LINKED WORKTREES
|
|
4028
4278
|
\`stim worktree remove\` works with any linked worktree, warmed or not.
|
|
4029
4279
|
Git registration identifies the worktree; a Stim registry entry is not
|
|
4030
|
-
required.
|
|
4031
|
-
|
|
4280
|
+
required. Before it reclaims anything, the command refuses a worktree git
|
|
4281
|
+
has locked (unlock it first; --force does not override) and, without
|
|
4282
|
+
--force, uncommitted or unpushed work and initialized submodules. It then
|
|
4283
|
+
reclaims any owned resources it finds and removes the linked checkout.
|
|
4284
|
+
When git still refuses the removal, the kept ownership record no longer
|
|
4285
|
+
names the devices that were parked or deleted. A workspace that is in use
|
|
4286
|
+
(see IN USE below) keeps its directory, devices and registry entry, and the
|
|
4287
|
+
command reports why. Git-created
|
|
4032
4288
|
branches stay. A branch with an existing Stim ownership record is deleted
|
|
4033
4289
|
only when it has no unique commits.
|
|
4034
4290
|
|
|
4291
|
+
IN USE
|
|
4292
|
+
gc and worktree remove never delete a workspace's directory, build outputs
|
|
4293
|
+
or checkout while it is in use: its dev server supervisor is running or
|
|
4294
|
+
cannot be verified, a \`stim ios\`, \`stim android\` or \`stim stop\` run
|
|
4295
|
+
holds its native-run.lock, a live or unresolvable build lock or slot names it,
|
|
4296
|
+
or its managed tunnel or managed remote lock is held. The deletion holds
|
|
4297
|
+
native-run.lock itself, so no native run can start partway through. A lock
|
|
4298
|
+
that names no workspace blocks nothing, because every build also holds its
|
|
4299
|
+
own workspace's native-run.lock; gc lists it with the command that removes
|
|
4300
|
+
it. \`worktree remove\` re-checks uncommitted and unpushed work under its
|
|
4301
|
+
removal locks, just before it reclaims anything. A project root whose
|
|
4302
|
+
existence cannot be read (a permission error) is never treated as deleted.
|
|
4303
|
+
|
|
4304
|
+
SWEEPING FINISHED WORKTREES
|
|
4305
|
+
\`gc --worktrees\` is opt-in; no cache or age flag implies it. It looks at
|
|
4306
|
+
every registered project root and every workspace.json root, grouped by
|
|
4307
|
+
git worktree, and reports each worktree with the reason it is kept:
|
|
4308
|
+
source checkout, bare, locked, in use, dirty (untracked files count; pod
|
|
4309
|
+
install churn alone does not), unpushed (commits no remote-tracking ref or
|
|
4310
|
+
other local branch reaches), initialized submodules, or recently used.
|
|
4311
|
+
Idle means no recorded use for --older-than days, 7 without it; a worktree
|
|
4312
|
+
whose last use is unknown is kept. --cache with --worktrees is refused with
|
|
4313
|
+
STIM_BAD_ARG; run them separately.
|
|
4314
|
+
stim gc --worktrees --older-than 3 # report only
|
|
4315
|
+
stim gc --delete --worktrees --older-than 3 # remove the clean idle ones
|
|
4316
|
+
With --delete it runs the \`stim worktree remove\` pipeline, never --force,
|
|
4317
|
+
on each removable worktree. That pipeline re-inspects the worktree and
|
|
4318
|
+
re-checks use and idleness under the removal locks, then parks devices and
|
|
4319
|
+
handles the branch exactly as a manual \`stim worktree remove\`. A worktree
|
|
4320
|
+
that became busy or recently used since the report is kept with the reason.
|
|
4321
|
+
A worktree that fails is reported, gc exits 1, and the sweep continues.
|
|
4322
|
+
|
|
4323
|
+
ORPHANED WORKSPACE DIRECTORIES
|
|
4324
|
+
A worktree deleted with \`git worktree remove\`, \`rm -rf\` or a /tmp wipe
|
|
4325
|
+
leaves its $STIM_HOME/workspaces/<name> directory behind with no registry
|
|
4326
|
+
entry. \`gc\` reads each directory's workspace.json and reports it under
|
|
4327
|
+
"Orphaned workspace directories" when the recorded project root is gone,
|
|
4328
|
+
its volume is mounted, no registry key equals it or sits under it, and the
|
|
4329
|
+
workspace is not in use. \`gc --delete\` re-checks each one, then removes
|
|
4330
|
+
it. A directory with a missing or unparseable workspace.json, or a root on
|
|
4331
|
+
an unmounted volume, is reported under Skipped and never deleted.
|
|
4332
|
+
|
|
4035
4333
|
NAMED SERVER PORTS
|
|
4036
4334
|
worktree remove stops TCP listeners on each named allocation and releases
|
|
4037
4335
|
the ports. gc reports named allocations for missing workspaces; gc --delete
|
|
@@ -4095,7 +4393,8 @@ A device leaks when a project is abandoned WITHOUT either delete path -- the
|
|
|
4095
4393
|
sim survives with nothing pointing at it. \`stim gc\` (no flag, writes
|
|
4096
4394
|
nothing, always safe) reports those; \`gc --delete\` reaps them, and in the same
|
|
4097
4395
|
run drops the dead config ENTRIES those projects left behind and frees their
|
|
4098
|
-
Metro ports.
|
|
4396
|
+
Metro ports. \`stim gc --json\` prints the same report as one payload
|
|
4397
|
+
(\`guide facts gc\`); show the user its sections before \`gc --delete\`.
|
|
4099
4398
|
|
|
4100
4399
|
REMOTE EAS SESSIONS
|
|
4101
4400
|
Plain \`stim gc\` is a dry run. \`gc --delete\` can stop active stim-* EAS
|
|
@@ -4131,10 +4430,10 @@ THE ONE CASE GC WILL NOT REAP
|
|
|
4131
4430
|
it found, so you can judge. Delete them yourself:
|
|
4132
4431
|
xcrun simctl delete <udid>
|
|
4133
4432
|
avdmanager delete avd -n <name>`
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4433
|
+
},
|
|
4434
|
+
collector: {
|
|
4435
|
+
summary: "log collector reaping: an unproven collector pid, and why the app on a phone closed",
|
|
4436
|
+
body: () => `WHAT ELSE STOP REAPS
|
|
4138
4437
|
The device-log collectors (\`simctl log stream\` / \`adb logcat\`) that
|
|
4139
4438
|
\`ios\` / \`android\` attach after launch. They are recorded in
|
|
4140
4439
|
the global workspace state.json, and nothing outside this workspace can name them,
|
|
@@ -4188,12 +4487,14 @@ THE ONE CASE GC WILL NOT REAP
|
|
|
4188
4487
|
is gone, and the unrelated process is never signalled. A missing, malformed,
|
|
4189
4488
|
or unreadable identity leaves the record unverified and kept for a retry.
|
|
4190
4489
|
Wall-clock timestamps and command names are not ownership proof.`
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4490
|
+
},
|
|
4491
|
+
disk: {
|
|
4492
|
+
summary: "disk usage, workspace build outputs, AVD and build-log sizes, the data partition, trimming the shared caches",
|
|
4493
|
+
body: () => `DISK
|
|
4195
4494
|
Logs, state, pidfiles and Xcode DerivedData are under the global workspace
|
|
4196
|
-
directory, and \`worktree remove\` reclaims them.
|
|
4495
|
+
directory, and \`worktree remove\` reclaims them. \`gc --delete\` clears the
|
|
4496
|
+
build outputs of workspaces nobody is using (WORKSPACE BUILD OUTPUTS
|
|
4497
|
+
below) and keeps the rest. Gradle retains its normal
|
|
4197
4498
|
project build directories while sharing task outputs through its build cache.
|
|
4198
4499
|
|
|
4199
4500
|
Android AVDs normally live under ~/.android/avd, and a booted owned AVD can
|
|
@@ -4235,6 +4536,28 @@ project needs another size. Android userdata grows but does not shrink, so the
|
|
|
4235
4536
|
setting applies only to a newly created AVD; recreate the environment to adopt
|
|
4236
4537
|
a changed value.
|
|
4237
4538
|
|
|
4539
|
+
WORKSPACE BUILD OUTPUTS
|
|
4540
|
+
Each workspace directory holds derived-data/, gradle-build/, android-cas/
|
|
4541
|
+
and cache-provider/. \`gc\` reports them as one detected cache, "Workspace
|
|
4542
|
+
build outputs", with a per-workspace size, last use and verdict. Plain
|
|
4543
|
+
\`gc --delete\` clears them for every workspace not in use (see \`guide
|
|
4544
|
+
cleanup gc\`), before anything else. \`--older-than <days>\` limits that to
|
|
4545
|
+
workspaces idle at least that long, and keeps one whose last use is
|
|
4546
|
+
unknown. \`--cache workspaces\` acts on them alone; \`--cache all\` includes
|
|
4547
|
+
them. Only those four directories go: workspace.json, state.json, logs/,
|
|
4548
|
+
locks and device records stay, so the workspace keeps its devices and ports.
|
|
4549
|
+
stim gc --delete --cache workspaces --older-than 7
|
|
4550
|
+
Last use is the newest of the lastUsedAt that start, ios, android, reload
|
|
4551
|
+
and worktree warm record in state.json, lastBuild.startedAt,
|
|
4552
|
+
supervisor.startedAt and the mtimes under logs/, so a dev server that keeps
|
|
4553
|
+
logging keeps its workspace in use.
|
|
4554
|
+
The same time decides \`--older-than\` device reaping, and a workspace with
|
|
4555
|
+
no evidence of use keeps its device.
|
|
4556
|
+
The next build of an unchanged app installs from the shared build cache.
|
|
4557
|
+
After a native change the Xcode compilation cache speeds the rebuild, but on
|
|
4558
|
+
React Native 0.86 Swift does not use it (explicit modules are off), so that
|
|
4559
|
+
build recompiles Swift.
|
|
4560
|
+
|
|
4238
4561
|
SHARED BUILD CACHES
|
|
4239
4562
|
The caches that make a second workspace fast are alive by design and never
|
|
4240
4563
|
included in a plain \`gc --delete\`. Every \`gc\` run reports them anyway,
|
|
@@ -4253,24 +4576,68 @@ SHARED BUILD CACHES
|
|
|
4253
4576
|
The Gradle build cache under GRADLE_USER_HOME (default ~/.gradle) is
|
|
4254
4577
|
report-only because every Gradle build shares it. Stim reports its size
|
|
4255
4578
|
but never prunes or empties it, including with --older-than or --cache all.
|
|
4579
|
+
|
|
4256
4580
|
Trim rather than empty. Emptying costs the next build in every project the
|
|
4257
4581
|
time the cache was saving.`
|
|
4258
|
-
}
|
|
4259
4582
|
}
|
|
4260
|
-
}
|
|
4583
|
+
}
|
|
4584
|
+
};
|
|
4585
|
+
const SETTINGS_SCHEMA_URL = `https://unpkg.com/stim/dist/settings.schema.json`;
|
|
4586
|
+
//#endregion
|
|
4587
|
+
//#region src/guide/index.ts
|
|
4588
|
+
const TOPICS = {
|
|
4589
|
+
agent: agent_default,
|
|
4590
|
+
facts,
|
|
4591
|
+
metro: metro_default,
|
|
4592
|
+
ports: ports_default,
|
|
4593
|
+
logs: logs_default,
|
|
4594
|
+
errors,
|
|
4595
|
+
lifecycle,
|
|
4596
|
+
cleanup,
|
|
4261
4597
|
settings: {
|
|
4262
4598
|
summary: "Settings Stim reads, and where they can live",
|
|
4263
4599
|
body: () => `SETTINGS
|
|
4264
4600
|
|
|
4265
|
-
|
|
4266
|
-
|
|
4601
|
+
Settings are JSON: machine layers in ~/.stim/config.json and a committed
|
|
4602
|
+
.stim.json. Command-line selectors override their matching settings.
|
|
4603
|
+
|
|
4604
|
+
stim settings --json every setting: effective value, origin
|
|
4605
|
+
(workspace, repo, committed, machine, env,
|
|
4606
|
+
default), and each layer's value
|
|
4607
|
+
stim settings get <key> [--scope <layer>] [--json]
|
|
4608
|
+
stim settings set <key> <value> --scope <layer> [--json]
|
|
4609
|
+
stim settings unset <key> --scope <layer> [--json]
|
|
4610
|
+
|
|
4611
|
+
<layer> is machine, workspace (this project's entry), repo (this repository's
|
|
4612
|
+
git common dir), or committed (.stim.json). Each key accepts only the layers
|
|
4613
|
+
Stim reads it from; --scope may be omitted when a key has one layer. Strings
|
|
4614
|
+
and choices are passed as-is; booleans, numbers, arrays, and objects as JSON
|
|
4615
|
+
(\`'["node_modules"]'\`). A value of the wrong shape, a layer the key is not
|
|
4616
|
+
read from, or an unknown key refuses with STIM_BAD_ARG naming the expected
|
|
4617
|
+
shape, before anything is written. Writes to the machine file take its lock
|
|
4618
|
+
and replace it atomically; a committed write keeps the file's other keys and
|
|
4619
|
+
indentation. Run \`stim settings\` from the app directory: workspace and
|
|
4620
|
+
committed resolve from the nearest package.json, repo from its Git
|
|
4621
|
+
repository. worktree.exclude and worktree.defaultBranch are read only from
|
|
4622
|
+
the repo layer and the repository root's .stim.json.
|
|
4623
|
+
|
|
4624
|
+
android.keystorePassword is sensitive: its value prints as ******** in every
|
|
4625
|
+
output, and a committed .stim.json takes only an \`env:\` or \`file:\`
|
|
4626
|
+
reference, never the password itself.
|
|
4627
|
+
|
|
4628
|
+
The JSON Schema for .stim.json ships in the stim package as
|
|
4629
|
+
dist/settings.schema.json. Point an editor at it with a top-level
|
|
4630
|
+
"$schema": "${SETTINGS_SCHEMA_URL}"; Stim ignores
|
|
4631
|
+
that key. $defs.machine describes the machine settings, and every setting
|
|
4632
|
+
carries its dotted key, layers, and environment override under "x-stim".
|
|
4267
4633
|
|
|
4268
4634
|
Resolution order, first match wins:
|
|
4269
|
-
1.
|
|
4270
|
-
2. repo
|
|
4635
|
+
1. workspace ~/.stim/config.json, under this project's entry
|
|
4636
|
+
2. repo ~/.stim/config.json, under this repo's git common dir
|
|
4271
4637
|
3. committed .stim.json beside the app's package.json
|
|
4272
|
-
4. machine
|
|
4638
|
+
4. machine ~/.stim/config.json, top-level optimizations only
|
|
4273
4639
|
5. Stim default
|
|
4640
|
+
An environment override, where a setting has one, wins over every layer.
|
|
4274
4641
|
|
|
4275
4642
|
The committed file is plain JSON and travels with the app. Each monorepo app
|
|
4276
4643
|
reads its own file, never an ancestor's runtime settings. A single-app repository
|
|
@@ -4291,8 +4658,7 @@ An app's .stim.json can contain:
|
|
|
4291
4658
|
"runtime": "26.2",
|
|
4292
4659
|
"simslimProfile": ".simslim/dev.json"
|
|
4293
4660
|
},
|
|
4294
|
-
"android": { "variant": "productionDebug" }
|
|
4295
|
-
"caches": ["~/.myapp-metro-cache"]
|
|
4661
|
+
"android": { "variant": "productionDebug" }
|
|
4296
4662
|
}
|
|
4297
4663
|
|
|
4298
4664
|
KEYS STIM READS
|
|
@@ -4496,16 +4862,21 @@ ${ANDROID_AVD_CONFIG_HELP.map((line) => ` ${line}`).joi
|
|
|
4496
4862
|
store Stim injects for you (bare in-process, or the
|
|
4497
4863
|
Expo config override) stays local-only.
|
|
4498
4864
|
cache.options free-form object handed to that module's factory. It
|
|
4499
|
-
merges key by key
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4865
|
+
merges key by key from the layer that names the
|
|
4866
|
+
provider, higher layers that name none, and lower
|
|
4867
|
+
layers that name the same provider resolved from the
|
|
4868
|
+
same directory. Options in a layer naming another
|
|
4869
|
+
provider, or in a lower layer naming none, are
|
|
4870
|
+
ignored. Keep secrets out of the committed file: read
|
|
4871
|
+
them from the environment or the machine layers.
|
|
4504
4872
|
|
|
4505
4873
|
Each setting takes its documented type: string, array of strings, number,
|
|
4506
|
-
boolean, or object.
|
|
4507
|
-
|
|
4508
|
-
|
|
4874
|
+
boolean, or object. ios.remote, android.remote, metro.tunnel,
|
|
4875
|
+
optimizations.android.compilerCache and optimizations.android.pch take only
|
|
4876
|
+
their listed choices. A value of the wrong
|
|
4877
|
+
type or outside those choices is refused by name on every command that resolves
|
|
4878
|
+
settings, \`stim ios\` included, so a wrong shape never falls back to a default
|
|
4879
|
+
silently. \`stim doctor\` reports it as a finding
|
|
4509
4880
|
instead of refusing. The exception is \`optimizations.android.casToolchain\`:
|
|
4510
4881
|
an invalid value warns and falls back to ccache, or no compiler cache when
|
|
4511
4882
|
\`compilerCache\` is \`none\`. \`doctor\` also reports the invalid setting.
|
|
@@ -4519,19 +4890,22 @@ removed -- check this list rather than assuming it still applies.
|
|
|
4519
4890
|
problem. It reports, as notes naming the key, the file it came from, and the
|
|
4520
4891
|
line that clears it: a setting whose path no longer exists, a setting that needs
|
|
4521
4892
|
a companion the config does not supply, a key Stim no longer reads, and a
|
|
4522
|
-
config file that is not valid JSON. It skips the \`projects\`
|
|
4523
|
-
entry for a deleted checkout is normal and \`gc\` owns the
|
|
4893
|
+
config file that is not a valid JSON object. It skips the \`projects\`
|
|
4894
|
+
registry, where an entry for a deleted checkout is normal and \`gc\` owns the
|
|
4895
|
+
cleanup.
|
|
4524
4896
|
|
|
4525
4897
|
CONCURRENCY LIMITS ARE MACHINE-LEVEL, NOT A PER-PROJECT SETTING
|
|
4526
4898
|
The caps above are not in the layered settings -- they are not per-project,
|
|
4527
4899
|
because the resource they share (cores, RAM, booted simulators) is the whole
|
|
4528
4900
|
machine's. They live under a top-level \`concurrency\` key in
|
|
4529
|
-
~/.stim/config.json,
|
|
4901
|
+
~/.stim/config.json, set with \`stim settings set\` or by hand:
|
|
4530
4902
|
|
|
4531
4903
|
{
|
|
4532
4904
|
"concurrency": { "maxBuilds": 2, "maxDevices": 3 }
|
|
4533
4905
|
}
|
|
4534
4906
|
|
|
4907
|
+
The keys are concurrency.maxBuilds and concurrency.maxDevices.
|
|
4908
|
+
|
|
4535
4909
|
or via the environment, which overrides the file:
|
|
4536
4910
|
|
|
4537
4911
|
STIM_MAX_BUILDS=2 STIM_MAX_DEVICES=3 stim ios
|
|
@@ -4548,16 +4922,24 @@ or Simulator on older Xcode. To use an installed Siniulator instead:
|
|
|
4548
4922
|
|
|
4549
4923
|
{ "iosSimulatorApp": "siniulator" }
|
|
4550
4924
|
|
|
4925
|
+
To show the booted simulator in Stim Desktop and open no simulator window:
|
|
4926
|
+
|
|
4927
|
+
{ "iosSimulatorApp": "stim-desktop" }
|
|
4928
|
+
|
|
4929
|
+
Stim Desktop selects the workspace that owns the simulator and focuses that
|
|
4930
|
+
device. It only displays the simulator; it never boots or shuts it down.
|
|
4931
|
+
|
|
4551
4932
|
Override the preference for one local launch with
|
|
4552
|
-
\`stim ios --simulator-app siniulator
|
|
4933
|
+
\`stim ios --simulator-app siniulator\`, \`stim ios --simulator-app stim-desktop\`,
|
|
4934
|
+
or \`stim ios --simulator-app xcode\`.
|
|
4553
4935
|
The flag also opens an already running owned simulator without rebooting it.
|
|
4554
4936
|
It leaves the saved preference unchanged and refuses physical or remote targets.
|
|
4555
4937
|
|
|
4556
4938
|
Stim still creates and boots its owned simulator. An invalid value refuses
|
|
4557
|
-
before boot. Opening a window remains best-effort, so install Siniulator
|
|
4558
|
-
selecting it. By default, closing a Siniulator device
|
|
4559
|
-
simulator. Enable "Leave simulator running after window
|
|
4560
|
-
Settings if Stim should keep it running. See \`guide lifecycle simslim\` for
|
|
4939
|
+
before boot. Opening a window remains best-effort, so install Siniulator or
|
|
4940
|
+
Stim Desktop before selecting it. By default, closing a Siniulator device
|
|
4941
|
+
window shuts down that simulator. Enable "Leave simulator running after window
|
|
4942
|
+
is closed" in Siniulator Settings if Stim should keep it running. See \`guide lifecycle simslim\` for
|
|
4561
4943
|
window behavior.
|
|
4562
4944
|
|
|
4563
4945
|
THE DEVICE POOL BOUNDS ARE MACHINE-LEVEL TOO
|
|
@@ -4713,7 +5095,8 @@ The example shows the defaults. Full setting names and behavior:
|
|
|
4713
5095
|
auto keeps library/project policy, with PCH off by default when Stim supplies
|
|
4714
5096
|
ccache. on/off overrides Gradle CMAKE_DISABLE_PRECOMPILE_HEADERS arguments;
|
|
4715
5097
|
CMake target-level overrides still win. on does not fix stock ccache's
|
|
4716
|
-
cross-worktree PCH limitations.
|
|
5098
|
+
cross-worktree PCH limitations. A value outside auto|on|off is refused by
|
|
5099
|
+
name.
|
|
4717
5100
|
optimizations.android.gradleBuildCache
|
|
4718
5101
|
false passes --no-build-cache to Gradle, overriding org.gradle.caching=true.
|
|
4719
5102
|
optimizations.android.targetAbiOnly
|
|
@@ -4747,9 +5130,10 @@ swaps, and the doctor fingerprint checkout select a writable directory on the
|
|
|
4747
5130
|
relevant filesystem. App/APK preparation uses the artifact volume. Worktree
|
|
4748
5131
|
warm copies directly to the destination and does not use temporary storage.
|
|
4749
5132
|
A system temporary directory on that
|
|
4750
|
-
volume is preferred, then a writable ancestor of the relevant path
|
|
4751
|
-
is private and outside Git working trees, so
|
|
4752
|
-
Git status or git add. If no safe location
|
|
5133
|
+
volume is preferred, then a writable ancestor of the relevant path outside
|
|
5134
|
+
the shared build cache. Staging is private and outside Git working trees, so
|
|
5135
|
+
ignored secrets cannot enter Git status or git add. If no safe location
|
|
5136
|
+
exists, the operation refuses.
|
|
4753
5137
|
|
|
4754
5138
|
Set STIM_TMPDIR or top-level tempDir in $STIM_HOME/config.json (default
|
|
4755
5139
|
~/.stim/config.json) to override placement. STIM_TMPDIR takes precedence.
|
|
@@ -4775,16 +5159,22 @@ cp -c can silently fall back to copying and exit successfully.
|
|
|
4775
5159
|
CACHE LOCATIONS ARE MACHINE-LEVEL TOO
|
|
4776
5160
|
The shared build cache and Metro transform cache default to living under
|
|
4777
5161
|
~/.stim. To relocate them (say, to an external disk), set a top-level
|
|
4778
|
-
\`caches\` key in ~/.stim/config.json
|
|
5162
|
+
\`caches\` key in ~/.stim/config.json (\`stim settings set caches.buildCache
|
|
5163
|
+
<path>\`, or by hand) -- absolute paths:
|
|
4779
5164
|
|
|
4780
5165
|
{
|
|
4781
5166
|
"caches": { "buildCache": "/Volumes/SSD/stim/build-cache",
|
|
4782
5167
|
"metroCache": "/Volumes/SSD/stim/metro-cache" }
|
|
4783
5168
|
}
|
|
4784
5169
|
|
|
4785
|
-
|
|
5170
|
+
caches.buildCache and caches.metroCache are the keys; STIM_BUILD_CACHE /
|
|
5171
|
+
STIM_METRO_CACHE in the environment override the file.
|
|
4786
5172
|
The CLI and both cache packages resolve these identically, so every process
|
|
4787
|
-
finds the same store regardless of shell profile. A relative path
|
|
5173
|
+
finds the same store regardless of shell profile. A relative path in the file
|
|
5174
|
+
is ignored. A relative STIM_HOME, STIM_BUILD_CACHE or STIM_METRO_CACHE makes
|
|
5175
|
+
every command refuse with STIM_RELATIVE_PATH; Metro and the Expo build-cache
|
|
5176
|
+
provider, which must not break the bundler, ignore it with a warning and use
|
|
5177
|
+
the next source.
|
|
4788
5178
|
The Metro value is a PARENT root. The sanitized package name is appended below
|
|
4789
5179
|
it, so apps remain separately reportable and prunable. Earlier releases used an
|
|
4790
5180
|
overridden Metro root as one flat store. A new registration replaces that legacy
|
|
@@ -4794,7 +5184,7 @@ A marked store that later becomes another override parent remains visible but is
|
|
|
4794
5184
|
report-only while its marked child exists. Root-level legacy files remain
|
|
4795
5185
|
untouched for manual cleanup.
|
|
4796
5186
|
|
|
4797
|
-
|
|
5187
|
+
REGISTER A CACHE WITH GC
|
|
4798
5188
|
There is no 'cache' command. A cache registers itself from code instead, once,
|
|
4799
5189
|
and every 'gc' report shows it from then on, tagged (registered):
|
|
4800
5190
|
|